美文网首页Android高级进阶Android开发Android开发经验谈
谈谈FFmpeg的解码流程? 说说你能够认识的函数作用

谈谈FFmpeg的解码流程? 说说你能够认识的函数作用

作者: 初壹十五a | 来源:发表于2020-04-07 18:11 被阅读0次

    面试官: 谈谈FFmpeg的解码流程? 说说你能够认识的函数作用
    心理分析:基本上只要是做视频 音频 这是一个避不开的话题。如果回答的好 基本是一个加分项。没有多少开发者能够把它弄懂。面试官问这个问题的时候是非常期待的。如果你能准确的说出来 已经成功了一大半

    接下来,会问你解码的过程,那些函数的作用 重点再用上
    求职者: 大致了解相关的过程即可

    1.1 音频解码过程

    音频解码过程如下图所示:


    1.2. FFmpeg流程

    1.3 关键函数说明:

    • avcodec_find_decoder:根据指定的AVCodecID查找注册的解码器。
    • av_parser_init:初始化AVCodecParserContext。
    • avcodec_alloc_context3:为AVCodecContext分配内存。
    • avcodec_open2:打开解码器。
    • av_parser_parse2:解析获得一个Packet。
    • avcodec_send_packet:将AVPacket压缩数据给解码器。
    • avcodec_receive_frame:获取到解码后的AVFrame数据。
    • av_get_bytes_per_sample: 获取每个sample中的字节数

    1.4 关键数据结构说明:

    • AVCodecParser:用于解析输入的数据流并把它分成一帧一帧的压缩编码数据。比较形象的说法就是把长长的一段连续的数据“切割”成一段段的数据。

    1.5 avcodec编解码API介绍

    avcodec_send_packet、avcodec_receive_frame的API是FFmpeg3版本加入的。为了正确的使用它们,有必要阅读FFmpeg的文档说明[2]。

    FFmpeg提供了两组函数,分别用于编码和解码:

    • 解码:avcodec_send_packet()avcodec_receive_frame()
    • 解码:avcodec_send_frame()avcodec_receive_packet()

    API的设计与编解码的流程非常贴切。

    建议的使用流程如下:

    1. 像以前一样设置并打开AVCodecContext
    2. 输入有效的数据:
    • 解码:调用avcodec_send_packet()给解码器传入包含原始的压缩数据的AVPacket对象。
    • 编码:调用 avcodec_send_frame()给编码器传入包含解压数据的AVFrame对象。
    • 两种情况下推荐AVPacketAVFrame都使用refcounted(引用计数)的模式,否则libavcodec可能需要对输入的数据进行拷贝。

    1.6在一个循环体内去接收codec的输出,.

    即周期性地调用avcodec_receive_()来接收codec输出的数据:

    • 解码:调用avcodec_receive_frame(),如果成功会返回一个包含未压缩数据的AVFrame
    • 编码:调用avcodec_receive_packet(),如果成功会返回一个包含压缩数据的AVPacket
    • 反复地调用avcodec_receive_packet()直到返回 AVERROR(EAGAIN)或其他错误。返回AVERROR(EAGAIN)错误表示codec需要新的输入来输出更多的数据。对于每个输入的packet或frame,codec一般会输出一个frame或packet,但是也有可能输出0个或者多于1个。
    1. 流处理结束的时候需要flush(洗刷) codec。因为codec可能在内部缓冲多个frame或packet,出于性能或其他必要的情况(如考虑B帧的情况)。 处理流程如下:
    • 调用avcodec_send_()传入的AVFrame或AVPacket指针设置为NULL。 这将开启draining mode(排水模式)。
    • 反复地调用avcodec_receive_()直到返回AVERROR_EOF的错误,这个方法这个时候不会返回AVERROR(EAGAIN)的错误,除非你忘记了开启draining mode。
    • codec可以重新开启,但是需要先调用 avcodec_flush_buffers()来重置codec。

    说明:

    1. 编码或者解码刚开始的时候,codec可能接收了多个输入的frame或packet后还没有输出数据,直到内部的buffer被填充满。上面的使用流程可以处理这种情况。
    2. 理论上调用avcodec_send_()的时候可能会发生AVERROR(EAGAIN)的错误,这只应该在有输出数据没有被接收的情况,你可以依赖这个机制来实现区别于上面建议流程的处理方式,比如反复地调用avcodec_send_(),出现AVERROR(EAGAIN)错误的时候再去调用avcodec_receive_()
    3. 并不是所有的codec都遵循一个严格、可预测的数据处理流程,唯一可以保证的是 “调用avcodec_send_\()/avcodec_receive_\()返回AVERROR(EAGAIN)的时候去avcodec_receive_\()/avcodec_send_\()会成功,否则不应该返回AVERROR(EAGAIN)的错误。”一般来说,任何codec都不允许无限制地缓冲输入或者输出。
    4. 在同一个AVCodecContext上混合使用新旧API是不允许的,这将导致未定义的行为。

    更多面试内容,面试专题,flutter视频 全套,音视频从0到高手开发。
    关注GitHub:https://github.com/xiangjiana/Android-MS
    免费获取面试PDF合集

    相关文章

      网友评论

        本文标题:谈谈FFmpeg的解码流程? 说说你能够认识的函数作用

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