美文网首页
FFmpeg总结

FFmpeg总结

作者: Johnny_Wu | 来源:发表于2021-09-30 16:48 被阅读0次

    一、概述

    本文会讲到的内容:
    1、FFmpeg结构
    2、FFmpeg解码
    3、FFmpeg的时间timebase
    4、FFmpeg编码
    5、FFmpeg封装mp4

    二、FFmpeg结构

    image.png

    AVFormatContext:文件信息上下文,其中就包含了流信息结构AVStream

    AVStream:流信息,其中就包含具体的音视频格式信息AVCodecContext

    AVCodecContext:具体的音视频格式信息。要解码音视频,需要从这里拿到相关信息,比如AVCodecID

    AVPacket:未解码的音视频内容。比如视频的每一帧数据,就体现在一个packet中

    AVFrame:解码后的音视频内容。

    通过FFmpeg解析mp4的过程来理解:

    image.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的标志位。

    哪天你看到0000000127,标志位为0x27,0x27&0x1F = 0x07,所以它也是sps的标志。 image.gif

    解码的部分代码:

    image.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按流的方式写在头部。

    AVCC:使用NALU长度(固定字节,通常为4字节)分隔NAL,在头部包含extradata(或sequence header)的结构体。 image.png
    组成:

    extradata+NAL长度+NAL+NAL长度+NAL。。。
    NAL长度所占字节、SPS与PPS等包含在extradata中

    extradata格式:

    image.jpeg

    举个例子:


    image.png image.png

    思考
    FFmpeg如何解码AVCC格式的H264?
    解码的两大条件:
    1、可以得到具体的NAL
    2、可以得到解码需要的信息
    前面提到了。必现要有extradata。才可以得到拆分出具体的NAL,并且extradata也包含了sps,pps等的解码需要的信息。

    解码AVCC的H264:

    image.png

    3、如何得到extradata

    a、从mp4文件中解析得到
    AVFormatContext->AVStream->AVCodecContext->extradata

    b、自己构造
    (1)、直接构造extradata


    image.png

    (2)、先创建Annex-B格式的extradata,再通过ffmpeg自带函数转成AVCC的extradata
    -先构造Annex-B方式的extradata:


    image.png

    -extradata(Annex-B) ----> extradata(AVCC)


    image.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

    image.png

    2、上面的pkt_pts_time是怎么得出来的?
    timebase = 1/15360
    pts = 1024
    pts_time = 1024 * (1/15360) = 0.066667

    五、FFmpeg编码

    YUV 编码为 H264

    编码代码: image.png
    解码代码: image.png

    是否这样就可以编码成功了呢?像解码一样,不需要参数?

    引出的编码相关的问题:
    1、每一帧压缩百分比多少,即编码大小未知
    2、每一帧的分辨率未知
    3、每一帧的原图片格式未知。YUV420? YUV422
    所以这些东西都需要配置。

    AVCodecContext的编码参数配置:

    image.png

    思考
    1、如果编码的分辨率不按图片的分辨率设置会怎样?
    设置多少,编码多少。如果图片分辨率1600X1200,我设置成800X600。结果如下:

    image.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

    image.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秒展示,所以播放速度快了一倍

    相关文章

      网友评论

          本文标题:FFmpeg总结

          本文链接:https://www.haomeiwen.com/subject/dimidktx.html