视频解码过程
视频解码过程如下图所示:
⼀般解出来的是420p

FFmpeg流程
这里的流程是和音频的解码过程一样的,不同的只有在存储YUV数据的时候的形式
存储YUV 数据
如果知道YUV 数据的格式
前提:这里我们打开的h264文件,默认是YUV420P 格式的,
我们可以通过 AVFrame->frame 获得,获得的值如果是视频就 是 AVPixelFormat。
我们可以通过 AVPixelFormat ,知道该视频的编码是啥?
在正常情况下,我们需要判断AVPixelFormat是那种类型,当前代码中并没有判断是因为我们默认使用的YUV420P,那么怎么存储这个YUV420P呢?
首先我们这里要明白,一个AVFrame就是一张图片,假设AVframe 我们存储的是322 * 356 ,322并不是16的整倍数,322/16 = 20......2 也就是说一行会有2个字节的剩余
那么这个剩余的2个字节,怎么办呢?会多给14个字节和剩余的2个字节 结合起来。
因此如果我们用和音频类似的写法: fwrite(frame->data[0], 1, frame->width * frame->height, outfile) 去写,就会有问题,因为要保证这里 width是16的整倍数
这时候就要用到 ffmpeg 的AVFrame给我们提供的 linesize[x]了,
核心代码
// 一般H264默认为 AV_PIX_FMT_YUV420P, 具体怎么强制转为 AV_PIX_FMT_YUV420P 在音视频合成输出的时候讲解
// frame->linesize[1] 因为有字节对齐的问题。
// 这里先回顾一下 音频的处理方式,在交错模式的时候,使用的 声道数*每个声道有多少个音频样本 * 每个样本占用多少个字节,这是因为音频上 没有字节对齐的问题
//字节对齐问题的根本是因为 ,对于一张 322 * 356 的图片来说 ,322并不是16的整倍数,322/16 = 20......2 也就是说一行会有2个字节的剩余
//那么这个剩余的2个字节,怎么办呢?会多给14个字节和剩余的2个字节 结合起来。
//因此如果我们用和音频类似的写法: fwrite(frame->data[0], 1, frame->width * frame->height, outfile) 去写,就会有问题,因为要保证这里 width是16的整倍数
//这时候就要用到 ffmpeg 的AVFrame给我们提供的 linesize[x]了,
// uint8_t *data[AV_NUM_DATA_POINTERS]:
// 指向实际的帧数据的指针数组。
// 对于视频帧,这通常是图像平面(如YUV中的Y、U、V平面)。
// 对于音频帧,这通常是音频通道的数据指针。
// int linesize[AV_NUM_DATA_POINTERS]:
// 每一行(视频)或每一个音频通道(音频)的大小。
// 对于视频,这通常是图像宽度的字节数。如果图像的宽度 除以 16 有余数,则这个值会凑成16的倍数。
// 对于音频,这通常是这个通道的字节数大小。 在交错模式下: 理论上等于 声道数 * 每个声道有多少个音频样本 * 每个样本占用多少个字节
// 但是,测试发现,在第一个AVFrame包和最后一个 AVframe的时候,linesize[0]的值 比 声道数 * 每个声道有多少个音频样本 * 每个样本占用多少个字节 大于64.
//了解了linesize[]的意义,对于一个avframe,就是包含了一帧,就是一张图片,
//YUV420P的存储方式是这样的 YYYYYYYYUUVV
// 那么对于 一张 YUV420P (322 * 120)的图片来看,有多少个Y 呢?多少个U,多少个V呢?
// Y的个数为:有 120行,一行一行的存储,每一行的实际大小为322, 但是存储322个Y后,就结束了吗?没有 ,因为有字节对齐问题,因此每次存储完322后,还要跳过14个字节,也就是实际大小为linesize[0],
//我们先将Y全部存储完毕。
//再存储U,U的个数是多少呢?这里要回头看一下YUV420P存储结构图,这里只是结论:宽高均是Y的一半,因此这里要注意存储U的写法
//V的存储和U是一样的。
// 正确写法 linesize[]代表每行的字节数量,所以每行的偏移是linesize[],但是真正存储的值 Y 是宽度,
for(int j=0; j<frame->height; j++)
fwrite(frame->data[0] + j * frame->linesize[0], 1, frame->width, outfile);
for(int j=0; j<frame->height/2; j++)
fwrite(frame->data[1] + j * frame->linesize[1], 1, frame->width/2, outfile);
for(int j=0; j<frame->height/2; j++)
fwrite(frame->data[2] + j * frame->linesize[2], 1, frame->width/2, outfile);
// 错误写法 用source.200kbps.766x322_10s.h264测试时可以看出该种方法是错误的
// 写入y分量
// fwrite(frame->data[0], 1, frame->width * frame->height, outfile);//Y
// // 写入u分量
// fwrite(frame->data[1], 1, (frame->width) *(frame->height)/4,outfile);