最简单的基于FFmpeg的移动端例子:IOS 视频解码器-保存

时间:2024-04-22 13:07:11

=====================================================

最简单的基于FFmpeg的移动端例子系列文章列表:

最简单的基于FFmpeg的移动端例子:Android HelloWorld

最简单的基于FFmpeg的移动端例子:Android 视频解码器

最简单的基于FFmpeg的移动端例子:Android 视频解码器-单个库版

最简单的基于FFmpeg的移动端例子:Android 推流器

最简单的基于FFmpeg的移动端例子:Android 视频转码器

最简单的基于FFmpeg的移动端例子附件:Android 自带播放器

最简单的基于FFmpeg的移动端例子附件:SDL Android HelloWorld

最简单的基于FFmpeg的移动端例子:IOS HelloWorld

最简单的基于FFmpeg的移动端例子:IOS 视频解码器

最简单的基于FFmpeg的移动端例子:IOS 推流器

最简单的基于FFmpeg的移动端例子:IOS 视频转码器

最简单的基于FFmpeg的移动端例子附件:IOS自带播放器

最简单的基于FFmpeg的移动端例子:Windows Phone HelloWorld

=====================================================

本文记录iOS平台下基于FFmpeg的视频解码器。该示例C语言的源代码来自于《最简单的基于FFMPEG+SDL的视频播放器》。相关的概念就不再重复记录了。

最简单的基于FFmpeg的移动端例子:IOS 视频解码器-保存

源代码

项目的目录结构如图所示。

最简单的基于FFmpeg的移动端例子:IOS 视频解码器-保存

C代码位于ViewController.m文件中,内容如下所示。

  1. /**
  2. * 最简单的基于FFmpeg的视频解码器-IOS
  3. * Simplest FFmpeg IOS Decoder
  4. *
  5. * 雷霄骅 Lei Xiaohua
  6. * leixiaohua1020@126.com
  7. * 中国传媒大学/数字电视技术
  8. * Communication University of China / Digital TV Technology
  9. * http://blog.****.net/leixiaohua1020
  10. *
  11. * 本程序是IOS平台下最简单的基于FFmpeg的视频解码器。
  12. * 它可以将输入的视频数据解码成YUV像素数据。
  13. *
  14. * This software is the simplest decoder based on FFmpeg in IOS.
  15. * It can decode video stream to raw YUV data.
  16. *
  17. */
  18. #import "ViewController.h"
  19. #include <libavcodec/avcodec.h>
  20. #include <libavformat/avformat.h>
  21. #include <libavutil/imgutils.h>
  22. #include <libswscale/swscale.h>
  23. @interface ViewController ()
  24. @end
  25. @implementation ViewController
  26. - (void)viewDidLoad {
  27. [super viewDidLoad];
  28. // Do any additional setup after loading the view, typically from a nib.
  29. }
  30. - (void)didReceiveMemoryWarning {
  31. [super didReceiveMemoryWarning];
  32. // Dispose of any resources that can be recreated.
  33. }
  34. - (IBAction)clickDecodeButton:(id)sender {
  35. AVFormatContext *pFormatCtx;
  36. int             i, videoindex;
  37. AVCodecContext  *pCodecCtx;
  38. AVCodec         *pCodec;
  39. AVFrame *pFrame,*pFrameYUV;
  40. uint8_t *out_buffer;
  41. AVPacket *packet;
  42. int y_size;
  43. int ret, got_picture;
  44. struct SwsContext *img_convert_ctx;
  45. FILE *fp_yuv;
  46. int frame_cnt;
  47. clock_t time_start, time_finish;
  48. double  time_duration = 0.0;
  49. char input_str_full[500]={0};
  50. char output_str_full[500]={0};
  51. char info[1000]={0};
  52. NSString *input_str= [NSString stringWithFormat:@"resource.bundle/%@",self.inputurl.text];
  53. NSString *output_str= [NSString stringWithFormat:@"resource.bundle/%@",self.outputurl.text];
  54. NSString *input_nsstr=[[[NSBundle mainBundle]resourcePath] stringByAppendingPathComponent:input_str];
  55. NSString *output_nsstr=[[[NSBundle mainBundle]resourcePath] stringByAppendingPathComponent:output_str];
  56. sprintf(input_str_full,"%s",[input_nsstr UTF8String]);
  57. sprintf(output_str_full,"%s",[output_nsstr UTF8String]);
  58. printf("Input Path:%s\n",input_str_full);
  59. printf("Output Path:%s\n",output_str_full);
  60. av_register_all();
  61. avformat_network_init();
  62. pFormatCtx = avformat_alloc_context();
  63. if(avformat_open_input(&pFormatCtx,input_str_full,NULL,NULL)!=0){
  64. printf("Couldn't open input stream.\n");
  65. return ;
  66. }
  67. if(avformat_find_stream_info(pFormatCtx,NULL)<0){
  68. printf("Couldn't find stream information.\n");
  69. return;
  70. }
  71. videoindex=-1;
  72. for(i=0; i<pFormatCtx->nb_streams; i++)
  73. if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){
  74. videoindex=i;
  75. break;
  76. }
  77. if(videoindex==-1){
  78. printf("Couldn't find a video stream.\n");
  79. return;
  80. }
  81. pCodecCtx=pFormatCtx->streams[videoindex]->codec;
  82. pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
  83. if(pCodec==NULL){
  84. printf("Couldn't find Codec.\n");
  85. return;
  86. }
  87. if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){
  88. printf("Couldn't open codec.\n");
  89. return;
  90. }
  91. pFrame=av_frame_alloc();
  92. pFrameYUV=av_frame_alloc();
  93. out_buffer=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P,  pCodecCtx->width, pCodecCtx->height,1));
  94. av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize,out_buffer,
  95. AV_PIX_FMT_YUV420P,pCodecCtx->width, pCodecCtx->height,1);
  96. packet=(AVPacket *)av_malloc(sizeof(AVPacket));
  97. img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
  98. pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
  99. sprintf(info,   "[Input     ]%s\n", [input_str UTF8String]);
  100. sprintf(info, "%s[Output    ]%s\n",info,[output_str UTF8String]);
  101. sprintf(info, "%s[Format    ]%s\n",info, pFormatCtx->iformat->name);
  102. sprintf(info, "%s[Codec     ]%s\n",info, pCodecCtx->codec->name);
  103. sprintf(info, "%s[Resolution]%dx%d\n",info, pCodecCtx->width,pCodecCtx->height);
  104. fp_yuv=fopen(output_str_full,"wb+");
  105. if(fp_yuv==NULL){
  106. printf("Cannot open output file.\n");
  107. return;
  108. }
  109. frame_cnt=0;
  110. time_start = clock();
  111. while(av_read_frame(pFormatCtx, packet)>=0){
  112. if(packet->stream_index==videoindex){
  113. ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
  114. if(ret < 0){
  115. printf("Decode Error.\n");
  116. return;
  117. }
  118. if(got_picture){
  119. sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
  120. pFrameYUV->data, pFrameYUV->linesize);
  121. y_size=pCodecCtx->width*pCodecCtx->height;
  122. fwrite(pFrameYUV->data[0],1,y_size,fp_yuv);    //Y
  123. fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv);  //U
  124. fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv);  //V
  125. //Output info
  126. char pictype_str[10]={0};
  127. switch(pFrame->pict_type){
  128. case AV_PICTURE_TYPE_I:sprintf(pictype_str,"I");break;
  129. case AV_PICTURE_TYPE_P:sprintf(pictype_str,"P");break;
  130. case AV_PICTURE_TYPE_B:sprintf(pictype_str,"B");break;
  131. default:sprintf(pictype_str,"Other");break;
  132. }
  133. printf("Frame Index: %5d. Type:%s\n",frame_cnt,pictype_str);
  134. frame_cnt++;
  135. }
  136. }
  137. av_free_packet(packet);
  138. }
  139. //flush decoder
  140. //FIX: Flush Frames remained in Codec
  141. while (1) {
  142. ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
  143. if (ret < 0)
  144. break;
  145. if (!got_picture)
  146. break;
  147. sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
  148. pFrameYUV->data, pFrameYUV->linesize);
  149. int y_size=pCodecCtx->width*pCodecCtx->height;
  150. fwrite(pFrameYUV->data[0],1,y_size,fp_yuv);    //Y
  151. fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv);  //U
  152. fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv);  //V
  153. //Output info
  154. char pictype_str[10]={0};
  155. switch(pFrame->pict_type){
  156. case AV_PICTURE_TYPE_I:sprintf(pictype_str,"I");break;
  157. case AV_PICTURE_TYPE_P:sprintf(pictype_str,"P");break;
  158. case AV_PICTURE_TYPE_B:sprintf(pictype_str,"B");break;
  159. default:sprintf(pictype_str,"Other");break;
  160. }
  161. printf("Frame Index: %5d. Type:%s\n",frame_cnt,pictype_str);
  162. frame_cnt++;
  163. }
  164. time_finish = clock();
  165. time_duration=(double)(time_finish - time_start);
  166. sprintf(info, "%s[Time      ]%fus\n",info,time_duration);
  167. sprintf(info, "%s[Count     ]%d\n",info,frame_cnt);
  168. sws_freeContext(img_convert_ctx);
  169. fclose(fp_yuv);
  170. av_frame_free(&pFrameYUV);
  171. av_frame_free(&pFrame);
  172. avcodec_close(pCodecCtx);
  173. avformat_close_input(&pFormatCtx);
  174. NSString * info_ns = [NSString stringWithFormat:@"%s", info];
  175. self.infomation.text=info_ns;
  176. }
  177. @end

运行结果

App在手机上运行后的结果如下图所示。单击“Decode”,将会把位于resource.bundle中的“sintel.mov”文件解码为“sintel.yuv”文件并存储于相同的目录下。

最简单的基于FFmpeg的移动端例子:IOS 视频解码器-保存

生成的文件如下图所示。

 最简单的基于FFmpeg的移动端例子:IOS 视频解码器-保存

下载

simplest ffmpeg mobile

项目主页

Github:https://github.com/leixiaohua1020/simplest_ffmpeg_mobile

开源中国:https://git.oschina.net/leixiaohua1020/simplest_ffmpeg_mobile

SourceForge:https://sourceforge.net/projects/simplestffmpegmobile/

****工程下载地址:http://download.****.net/detail/leixiaohua1020/8924391

本解决方案包含了使用FFmpeg在移动端处理多媒体的各种例子:

转至:http://blog.****.net/leixiaohua1020/article/details/47072257