一、概述
本文会讲到的内容:
1、FFmpeg结构
2、FFmpeg解码
3、FFmpeg的时间timebase
4、FFmpeg编码
5、FFmpeg封装mp4
二、FFmpeg结构
![](https://img.haomeiwen.com/i9352478/621d73858d3adff7.png)
AVFormatContext:文件信息上下文,其中就包含了流信息结构AVStream
AVStream:流信息,其中就包含具体的音视频格式信息AVCodecContext
AVCodecContext:具体的音视频格式信息。要解码音视频,需要从这里拿到相关信息,比如AVCodecID
AVPacket:未解码的音视频内容。比如视频的每一帧数据,就体现在一个packet中
AVFrame:解码后的音视频内容。
通过FFmpeg解析mp4的过程来理解:
![](https://img.haomeiwen.com/i9352478/239ed15d57010786.png)
思考
1、如何得到音频的编码格式?
AVFormatContext->AVStream->AVCodecContext->AVCodecID
2、如何得到这个mp4的总时间?
AVFormatContext->duration
3、如何得到视频的分辨率?
AVCodecContext->width、height
三、FFmpeg解码
1、解码H264(Annex-B)
Annex-B:H264其中一种表示格式。一般运用在网络传输中。
一般是以0x00000001或者0x000001开头,视频帧分为I、P、B帧。
I帧还会带上sps,pps信息,有这两个信息才可以正常解码。
0000000167+(SPS的内容)+0000000168+(PPS的内容)+0000000165+(IDR主帧的内容):
标志位计算公式:code&0x1F,通过公式计算,得到:
SPS:0x07
PPS:0x08
IDR:0x05
0x67 & 0x1F = 0x07,所以0x67是sps的标志位。
![](https://img.haomeiwen.com/i9352478/eab8eda2896f0a57.gif)
解码的部分代码:
![](https://img.haomeiwen.com/i9352478/0f15ed77f9f506fc.png)
思考
这里的解码器AVCodecContext不需要配置参数就可以解码成功,为什么?
1、可以得到具体的NAL
2、可以得到解码需要的信息
因为前面提到的sps,pps已经携带了解码的一些信息,比如分辨率,格式等等。FFmpeg会自动解析,然后进行解码。
p2p流通过Annex-B这种格式传H264。好处是每一个主帧都是独立的,就算前面的主帧携带的sps、pps有错,导致解码失败。后面的主帧也不受影响,还是可以解码成功。这样的容错性就更好。
2、解码H264(AVCC)
AVCC:H264其中一种表示格式。一般运用在mp4封装格式中。
与Annex-B区别有两点:一个是参数集(SPS, PPS)组织格式,一个是分隔。
Annex-B:使用start code分隔NAL(start code为三字节或四字节,0x000001或0x00000001,一般是四字节);SPS和PPS按流的方式写在头部。
![](https://img.haomeiwen.com/i9352478/c782dea81f0dde90.png)
组成:
extradata+NAL长度+NAL+NAL长度+NAL。。。
NAL长度所占字节、SPS与PPS等包含在extradata中
extradata格式:
![](https://img.haomeiwen.com/i9352478/fed133a80bccb10b.jpeg)
举个例子:
![](https://img.haomeiwen.com/i9352478/c4a0c33ffb825c16.png)
![](https://img.haomeiwen.com/i9352478/66d4da54640e3fcd.png)
思考
FFmpeg如何解码AVCC格式的H264?
解码的两大条件:
1、可以得到具体的NAL
2、可以得到解码需要的信息
前面提到了。必现要有extradata。才可以得到拆分出具体的NAL,并且extradata也包含了sps,pps等的解码需要的信息。
解码AVCC的H264:
![](https://img.haomeiwen.com/i9352478/cc428c882138069c.png)
3、如何得到extradata
a、从mp4文件中解析得到
AVFormatContext->AVStream->AVCodecContext->extradata
b、自己构造
(1)、直接构造extradata
![](https://img.haomeiwen.com/i9352478/770271d87103f70d.png)
(2)、先创建Annex-B格式的extradata,再通过ffmpeg自带函数转成AVCC的extradata
-先构造Annex-B方式的extradata:
![](https://img.haomeiwen.com/i9352478/723bc4849571bbdd.png)
-extradata(Annex-B) ----> extradata(AVCC)
![](https://img.haomeiwen.com/i9352478/c1184dac9e8eb878.png)
四、timebase
timebase:视频处理中的一种时间单位
基本的时间单位:时、分、秒、毫秒
视频中最小单位为帧,帧都是毫秒级别
帧率为15,那么每帧时间为:1000/15=66.6666毫秒
1、不用浮点型
2、精度更高
只能扩大倍速了,比如扩大100倍,那么每一帧就是6666,这时候就得定义一种新的单位,可以转换为我们认知的时间:秒。
最终的数值都可以转化为秒。
比如,100毫秒,就是0.1秒
100*(1/1000) = 0.1秒
这里的timebase = 1/1000,表示 1秒=1000 毫秒。所以timebase包含了与秒的对应关系。
思考
1、刚才的6666,它的timebase是多少呢?
6666*timebase = 0.066秒
timebase = 1/100000
![](https://img.haomeiwen.com/i9352478/18f31d3520d8b1fe.png)
2、上面的pkt_pts_time是怎么得出来的?
timebase = 1/15360
pts = 1024
pts_time = 1024 * (1/15360) = 0.066667
五、FFmpeg编码
YUV 编码为 H264
![](https://img.haomeiwen.com/i9352478/db20c4b5daf7f73e.png)
解码代码:
![](https://img.haomeiwen.com/i9352478/fa47797dec140d71.png)
是否这样就可以编码成功了呢?像解码一样,不需要参数?
引出的编码相关的问题:
1、每一帧压缩百分比多少,即编码大小未知
2、每一帧的分辨率未知
3、每一帧的原图片格式未知。YUV420? YUV422
所以这些东西都需要配置。
AVCodecContext的编码参数配置:
![](https://img.haomeiwen.com/i9352478/9457c798748d11cb.png)
思考
1、如果编码的分辨率不按图片的分辨率设置会怎样?
设置多少,编码多少。如果图片分辨率1600X1200,我设置成800X600。结果如下:
![](https://img.haomeiwen.com/i9352478/60c62513cb28bd39.png)
2、如何控制编码后帧的大小?
a、通过修改码流参数,bit_rate
有时候你会发现,码流改小了很多,但编码后的大小变化不大
b、设置正确的timebase值
只有设置了正确的timebase,在改变bit_rate后,编码后的大小才能正确改变。
可以根据AVFrame中的timebase,具体你可以看它的pts值,推断大概的timebase。
比如:
你以帧率为15来算,那么每一帧的时间为1/15秒
1、比如第二帧 pts为1,那么1xtimebase = 1/15,所以timebase为(AVRational){1, 15}
2、比如第二帧pts为1024,同理1024xtimebase = 1/15,所以timebase为1/15除以1024,所以为(AVRational){1, 15360}
六、FFmpeg封装mp4
![](https://img.haomeiwen.com/i9352478/2b1547645e7f429d.png)
重点1:AVCodecContext的配置
需要配置正确的AVCodecContext->extradata
1、Annex-B的H264,配置对应的extradata(解码时候有提到)
2、AVCC的H264,配置对应的extradata
重点2:配置正确的timebase
如果合成的mp4播放速度不对,很大概率都是timebase设置错误了。
控制倍速播放等等,也通过修改timebase值,达到修改了每一帧的展示时间。
思考
timebase由1/15 改成 1/30,会怎样?
原本某帧的pts=30,30(1/15) = 2,就是这帧在第2秒才展示
30(1/30) = 1,这帧变为第1秒展示,所以播放速度快了一倍
网友评论