神刀安全网

跨平台ffmpeg播放器开发(三)对FFmpeg解码的函数以及解码的数据结构进行分析(附iOS平台解码代码)

github源码地址

前言

在上一节我们已经配置好了Xcode环境,所以这一节我们将会对其做更深入的了解,下面的文章是基于雷博的文章写的,使用Xcode进行编写.

FFmpeg库简介

跨平台ffmpeg播放器开发(三)对FFmpeg解码的函数以及解码的数据结构进行分析(附iOS平台解码代码)
FFmpeg库简介

FFmpeg解码流程图

跨平台ffmpeg播放器开发(三)对FFmpeg解码的函数以及解码的数据结构进行分析(附iOS平台解码代码)
FFmpeg函数解码的流程图

  • FFmpeg所有的初始化都要用到”av_register_all()”这个函数来注册所有的组件

  • 接下来”avformat_open_input()”是打开视频流

  • “avformat_find_stream_info()”打开视频文件,查看视频流信息(例如这个视频是多宽多高,解码器类型)

  • “avcodec_find_decoder()”找出视频的解码器

  • “avcodec_open2()”将它打开

接下来进入一个循环

  • “av_read_frame()”调用时它会读取一帧的压缩数据(h.264码流)

  • 读取完后它会执行”Get Packet”,若为true则说明读取到了数据,则进行下一步,若没读取到则说明视频流已经读取完毕就退出了

  • “AVPacket”是一个结构体,里面装的是h.264

  • “avcodec_decode_video2()”这是解码中最重要的函数,他负责将AVPacket->AVFream

  • “AVFream”里面装的是yuv数据

  • “show on screen”这一步我们后边会使用SDL将它展示在我们的屏幕上,然后再重新读取数据,进入循环

这就是FFmpeg解码的一个基本流程

跨平台ffmpeg播放器开发(三)对FFmpeg解码的函数以及解码的数据结构进行分析(附iOS平台解码代码)
雷哥对FFmpeg解码函数的简介

FFmpeg解码的数据结构

跨平台ffmpeg播放器开发(三)对FFmpeg解码的函数以及解码的数据结构进行分析(附iOS平台解码代码)
FFmpeg解码的数据结构

跨平台ffmpeg播放器开发(三)对FFmpeg解码的函数以及解码的数据结构进行分析(附iOS平台解码代码)
这是雷哥对上图的简介

下面我对上图介绍不详细的地方进行一些补充

  • AVStream是一个数组,数量是不确定的,一般第0个都是视频流,第1个都是音频流

  • AVCodec指明了编码器是什么类型的

  • AVCodecContext被更新了,现在使用AVCodecParameters,但是很多api并没有更新所以我们依旧使用AVCodecContext

FFmpeg数据结构的内容

跨平台ffmpeg播放器开发(三)对FFmpeg解码的函数以及解码的数据结构进行分析(附iOS平台解码代码)

跨平台ffmpeg播放器开发(三)对FFmpeg解码的函数以及解码的数据结构进行分析(附iOS平台解码代码)

跨平台ffmpeg播放器开发(三)对FFmpeg解码的函数以及解码的数据结构进行分析(附iOS平台解码代码)

iOS平台下写的一个最简单的解码部分

是照着雷哥的C++代码仿的,AVCodecContext这个结构体过时了,但因为API没更新所以我继续使用了,原文没有备注,这里的备注都是我添加的,如有错误欢迎指出,谢谢.github源码地址,后面的代码更新都会在这个仓储.

-(void)decode{          //初始化所有组件         av_register_all();          //声明上下文         AVFormatContext *pFormatCtx;          //初始化上下文         pFormatCtx = avformat_alloc_context();          //获取文件路径         NSString * filePath = [[NSBundle mainBundle]pathForResource:@"ds.mov" ofType:nil];          const char * path = [filePath UTF8String];          //打开视频流         if(avformat_open_input(&pFormatCtx,path,NULL,NULL)!=0){              NSLog(@"不能打开流");              return ;         }          //查看视频流信息         if(avformat_find_stream_info(pFormatCtx,NULL)<0){              NSLog(@"不能成功查看视频流信息");              return ;         }          int i,videoIndex;          videoIndex = -1;          //对上下文中的视频流进行遍历         for (i = 0; i<pFormatCtx->nb_streams; i++) {              //找到视频流信息后跳出循环             if(pFormatCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO){                  videoIndex=i;                  break;              }         }          //若videoIndex还为初值那么说明没有找到视频流         if(videoIndex==-1){              NSLog(@"没有找到视频流");              return ;         }          //声明编码器上下文结构体         //这里新版本不再使用AVCodecContext这个结构体了,具体原因我也不太清楚,好像是AVCodecContext过于臃肿         AVCodecContext * pCodecCtx;          pCodecCtx = pFormatCtx->streams[videoIndex]->codec;          //声明解码器类型         AVCodec *pCodec;          //查找解码器         pCodec = avcodec_find_decoder(pCodecCtx->codec_id);          if (pCodec == NULL) {              NSLog(@"解码器没找到");              return;         }           //打开解码器         if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){             NSLog(@"解码器打开失败");             return;         }          //解码后的数据         AVFrame *pFream,*pFreamYUV;          pFream = av_frame_alloc();          pFreamYUV = av_frame_alloc();          uint8_t *out_buffer;          //分配内存         //根据像素格式,宽高分配         out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));          //用ptr中的内容根据文件格式(YUV…) 和分辨率填充picture。这里由于是在初始化阶段,所以填充的可能全是零。         avpicture_fill((AVPicture*)pFreamYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);          //解码前的数据         AVPacket *packet;          //开辟空间         packet =(AVPacket *)av_malloc(sizeof(AVPacket));          /*******************************输出信息*********************************************/          NSLog(@"--------------- File Information ----------------");          //打印视频信息,av_dump_format()是一个手工调试的函数,能使我们看到pFormatCtx->streams里面有什么内容         av_dump_format(pFormatCtx, 0, path, 0);          NSLog(@"-------------------------------------------------");          //主要用来对图像进行变化,这里是为了缩放,把黑边裁去         struct SwsContext * img_convert_ctx;           /**          该函数包含以下参数:          srcW:源图像的宽          srcH:源图像的高          srcFormat:源图像的像素格式          dstW:目标图像的宽          dstH:目标图像的高          dstFormat:目标图像的像素格式          flags:设定图像拉伸使用的算法          成功执行的话返回生成的SwsContext,否则返回NULL。          */         img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,                                          pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);          //解码序号         int frame_cnt = 0;          int got_picture_ptr = 0;          //循环读取每一帧         while (av_read_frame(pFormatCtx, packet)>=0) {              //若为视频流信息             if (packet->stream_index == videoIndex) {                  //解码一帧数据,输入一个压缩编码的结构体AVPacket,输出一个解码后的结构体AVFrame。                 int ret = avcodec_decode_video2(pCodecCtx, pFream, &got_picture_ptr, packet);                  //当解码失败                 if (ret < 0) {                      NSLog(@"解码失败");                      return;                 }                  if (got_picture_ptr) {                     //处理图像数据,用于转换像素                     //裁剪                     //data解码后的图像像素数据                     //linesize对视频来说是一行像素的大小                     sws_scale(img_convert_ctx, (const uint8_t * const *)pFream->data, pFream->linesize, 0, pCodecCtx->height, pFreamYUV->data, pFreamYUV->linesize);                      NSLog(@"解码序号%d",frame_cnt);                      frame_cnt ++;                 }             }              //销毁packet             av_free_packet(packet);         }          //销毁         sws_freeContext(img_convert_ctx);          av_frame_free(&pFreamYUV);          av_frame_free(&pFream);          avcodec_close(pCodecCtx);          avformat_close_input(&pFormatCtx);     }

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 跨平台ffmpeg播放器开发(三)对FFmpeg解码的函数以及解码的数据结构进行分析(附iOS平台解码代码)

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址