ffmpeg解码yuv数据

参与了公司的开发,需要将h264的数据转为yuv,然后再winform里面实时显示,
再大牛的帮助下,开始明白了一点,我把简单的步骤记一下。
网上有个博客,<code> http://blog.csdn.net/leixiaohua1020</code>
里面记录了关于解码,编码方方面面的知识。
在解码的dll编写有四个部分,加载decoder,卸载decoder,开始解码和将yuv数据转为rgb数据,
先初始化一些变量,

AVFormatContext 是储存需要转码的文件的结构体,
AVCodeContext   是解码器的结构体,
AVFrame         是转码后一帧数据所存储的结构体,
uint8_t         指向数据地址的指针,
AVPacket        存储解码前数据的结构体,
struct SwsContext *img_convert_ctx   转码所需要的结构体,
<b>
    av_register_all();   注册所有的编解码器
    avformat_network_init();  初始化
    pFormatCtx = avformat_alloc_context();  这是一个重要的数据对象,存储
原视频的height,width,timesize,framedata。
</b>
avformat_open_input(&pFormatCtx, filepath, NULL, NULL) 打开需要解码的文件
avformat_find_stream_info(pFormatCtx, NULL)  分析该源文件有可以解码的流码
pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO 找到视频流的开始点
pCodecCtx = pFormatCtx->streams[videoindex]->codec; 找到文件流的类型
pCodec = avcodec_find_decoder(pCodecCtx->codec_id); 找到解码文件的解码器编号
avcodec_open2(pCodecCtx, pCodec, NULL)<0)  pCodec == NULL 如果没有找到解码器,
就退出。
out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height)); //一帧大小的缓冲区
avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);  //将pFrame的大小设为out_buffer
packet = (AVPacket *)av_malloc(sizeof(AVPacket)); //初始化packet
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); // 获取转码的参数
av_read_frame(pFormatCtx, packet)// 读取一帧数据
avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);// 如果包中的流是视频数据,就将它转码.
其中的got_picture可以认为是一个标志,如果解码成功则不为NULL,
<b>
sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
                    pFrameYUV->data, pFrameYUV->linesize);// 转码的数据
</b>
现在的pFrameYUv里面就是我们需要的yuv数据。

<blockquote>
1.aviocontext ffmepg管理输入输出的结构体,输入数据的缓存。
2.avformatcontext 它是FFMPEG解封装(flv,mp4,rmvb,avi)功能的结构体
3.AVCodec 是存储编解码器信息的结构体
4.AVInputFormat //音视频文件的解封装器
5.AVIOContext 管理输入输出数据的结构体
6.AVStream是存储每一个视频/音频流信息的结构体
7.muxer是指合并文件,即将视频文件、音频文件和字幕文件合并为某一个视频格式
//公共操作函数
8.int(*get_buffer)(struct AVCodecContext *c, AVFrame pic);
9.void(
release_buffer)(struct AVCodecContext *c, AVFrame pic);
10.int(
reget_buffer)(struct AVCodecContext *c, AVFrame *pic);
11.av_dump_format文件信息输出到标准错误输出里。
12.avcodec_alloc_context3():为AVCodecContext分配内存。
13.avcodec_open2():打开解码器。
14.avcodec_decode_video2():解码一帧数据。
15.av_parser_init():初始化AVCodecParserContext。av_parser_parse2():解析获得一个Packet。
16.AVFrame:存储一帧解码后的像素数据AVPacket:存储一帧(一般情况下)压缩编码数据
17.avformat_alloc_context():创建AVFormatContext结构体。
18.avformat_new_stream()创建AVStream结构体
19.avformat_new_stream()中会调用avcodec_alloc_context3()创建AVCodecContext结构体。
20.codec 编解码器,parsers 解析器,
21.ffmpeg进行图像数据格式的转换以及图片的缩放应用中

sws_getContext 函数可以看做是初始化函数
int srcW,int srcH 为原始图像数据的高和宽;

  int dstW,int dstH 为输出图像数据的高和宽;

  enum AVPixelFormat srcFormat 为输入和输出图片数据的类型;eg:AV_PIX_FMT_YUV420、PAV_PIX_FMT_RGB24;

  int flags 为scale算法种类;eg:SWS_BICUBIC、SWS_BICUBLIN、SWS_POINT、SWS_SINC;

  SwsFilter *srcFilter ,SwsFilter *dstFilter,const double *param 可以不用管,全为NULL即可;

22.sws_scale 函数则为执行函数,它的参数定义分别为:

  struct SwsContext *c 为sws_getContext函数返回的值;

  const uint8_t *const srcSlice[],uint8_t *const dst[] 为输入输出图像数据各颜色通道的buffer指针数组;

  const int srcStride[],const int dstStride[] 为输入输出图像数据各颜色通道每行存储的字节数数组;     

  int srcSliceY 为从输入图像数据的第多少列开始逐行扫描,通常设为0;

  int srcSliceH 为需要扫描多少行,通常为输入图像数据的高度;

23.ffmpeg avpacket每一个包是一个完整的数据帧,来暂存解复用之后、解码之前的媒体数据(一个音/视频帧、一个字幕包等)及附加信息(解码时间戳、显示时间戳、时长等)
24.avframe存储的是解码后的数据 avpacket是解码前的数据
================================================
25.将yuv数据保存和将它绘制出来是不同的解析过程。

</blockquote>

    原文作者:jeffleefree
    原文地址: https://www.jianshu.com/p/53006eadb1b3
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞