ffmpeg新版本解码API overview

对于编解码 API 有不懂的地方,官方文档是最值得阅读的。
此文对 ffmpeg4.4 版本编解码 API 的官方说明进行了翻译,如下文:

avcodec_send_packet()/avcodec_receive_frame() 为解码 API,
avcodec_send_frame()/avcodec_receive_packet() 为编码 API,
他们对输入输出进行了解耦。

音频、视频的编解码 API 非常相似,他们的工作原理如下:

流程

  1. 像往常一样建立并打开 AVCodecContext

  2. 发送有效的输入:

    • 对于解码,调用 avcodec_send_packet() 给解码器喂压缩数据:AVPacket
    • 对于编码,调用 avcodec_send_frame() 给编码器发送未压缩的音频或视频帧:AVFrame
      在这两种情况下,建议将 AVPackets 和 AVFrames 使用引用计数,不然 libavcodec 可能得拷贝输入数据(libavformat 总是返回引用计数的 AVPackets,而 av_frame_get_buffer 分配引用计数的 AVFrames)。
  3. 循环接收输出。定期调用对应的 avcodec_receive_*() 函数并处理他们的输出:

    • 对于解码,调用 avcodec_receive_frame() 。如果成功,会返回解压缩的视频或音频数据 AVFrame
    • 对于编码,调用 avcodec_receive_packet() 。如果成功,会返回压缩的数据包 AVPacket

    重复调用上述函数,直到它返回 AVERROR(EAGAIN) 或错误。AVERROR(EAGAIN) 返回值表示需要新的输入数据才能返回新的输出。在这种情况下,继续发送输入数据。对于每个输入 frame/packet,解码器通常会返回 1 个输出 frame/packet,但也可以是 0 或大于 1 个。

    在编码或解码开始时,编解码器可能会接收多个输入 frames/packets 而不返回一个 frame,直到其内部缓冲区被填满。 如果您按照上述步骤进行操作,这种情况已被良好处理。

    从理论上讲,发送输入可能会导致 EAGAIN – 只有在没有收到任何输出时才会发生这种情况。 您可以使用它来构建除上述建议之外的解码或编码的循环。 例如,可以试着在每次循环中发送新的输入,并在返回 EAGAIN 时接收输出。

流结束的情况

文件流结束后需要“刷新”(耗尽)编解码器,因为编解码器可能会在内部缓冲多个帧或数据包以提高性能,或出于必要的原因(考虑到 B 帧的情况)。
处理如下:

  1. 发送 “NULL” 数据包到 avcodec_send_packet()(解码)或 avcodec_send_frame()(编码)函数,而不是输入有效的数据。 这将进入 draining 模式。
  2. 循环调用 avcodec_receive_frame()(解码)或 avcodec_receive_packet()(编码)函数直到返回 AVERROR_EOF。函数将不会返回 AVERROR(EAGAIN),除非你忘记进入 draining 模式。
  3. 在解码重新恢复之前,必须使用 avcodec_flush_buffers() 重置编解码器。

其它

强烈建议使用上述 API。但是也可以脱离这个固定模式去调用函数。例如,您可以重复调用 avcodec_send_packet() 而无需调用 avcodec_receive_frame()。在这种情况下,avcodec_send_packet() 将成功,直到编解码器的内部缓冲区被填满(通常在初始化输入后,每个输出帧的大小为 1),然后返回 AVERROR(EAGAIN) 拒绝输入。一旦开始被拒绝输入,你别无选择,只能至少去读取一些输出。
并非所有编解码器都会遵循严格且可预测的数据流;唯一的保证是,一端的 send/receive 调用返回 AVERROR(EAGAIN) 意味着另一端的 receive/send 调用将成功,或者至少不会因 AVERROR(EAGAIN) 而失败。通常,没有编解码器会允许输入/输出的无限制缓冲。
至此。

原文如下:
 * @ingroup libavc
 * @defgroup lavc_encdec send/receive encoding and decoding API overview
 * @{
 *
 * The avcodec_send_packet()/avcodec_receive_frame()/avcodec_send_frame()/
 * avcodec_receive_packet() functions provide an encode/decode API, which
 * decouples input and output.
 *
 * The API is very similar for encoding/decoding and audio/video, and works as
 * follows:
 * - Set up and open the AVCodecContext as usual.
 * - Send valid input:
 *   - For decoding, call avcodec_send_packet() to give the decoder raw
 *     compressed data in an AVPacket.
 *   - For encoding, call avcodec_send_frame() to give the encoder an AVFrame
 *     containing uncompressed audio or video.
 *
 *   In both cases, it is recommended that AVPackets and AVFrames are
 *   refcounted, or libavcodec might have to copy the input data. (libavformat
 *   always returns refcounted AVPackets, and av_frame_get_buffer() allocates
 *   refcounted AVFrames.)
 * - Receive output in a loop. Periodically call one of the avcodec_receive_*()
 *   functions and process their output:
 *   - For decoding, call avcodec_receive_frame(). On success, it will return
 *     an AVFrame containing uncompressed audio or video data.
 *   - For encoding, call avcodec_receive_packet(). On success, it will return
 *     an AVPacket with a compressed frame.
 *
 *   Repeat this call until it returns AVERROR(EAGAIN) or an error. The
 *   AVERROR(EAGAIN) return value means that new input data is required to
 *   return new output. In this case, continue with sending input. For each
 *   input frame/packet, the codec will typically return 1 output frame/packet,
 *   but it can also be 0 or more than 1.
 *
 * At the beginning of decoding or encoding, the codec might accept multiple
 * input frames/packets without returning a frame, until its internal buffers
 * are filled. This situation is handled transparently if you follow the steps
 * outlined above.
 *
 * In theory, sending input can result in EAGAIN - this should happen only if
 * not all output was received. You can use this to structure alternative decode
 * or encode loops other than the one suggested above. For example, you could
 * try sending new input on each iteration, and try to receive output if that
 * returns EAGAIN.
 *
 * End of stream situations. These require "flushing" (aka draining) the codec,
 * as the codec might buffer multiple frames or packets internally for
 * performance or out of necessity (consider B-frames).
 * This is handled as follows:
 * - Instead of valid input, send NULL to the avcodec_send_packet() (decoding)
 *   or avcodec_send_frame() (encoding) functions. This will enter draining
 *   mode.
 * - Call avcodec_receive_frame() (decoding) or avcodec_receive_packet()
 *   (encoding) in a loop until AVERROR_EOF is returned. The functions will
 *   not return AVERROR(EAGAIN), unless you forgot to enter draining mode.
 * - Before decoding can be resumed again, the codec has to be reset with
 *   avcodec_flush_buffers().
 *
 * Using the API as outlined above is highly recommended. But it is also
 * possible to call functions outside of this rigid schema. For example, you can
 * call avcodec_send_packet() repeatedly without calling
 * avcodec_receive_frame(). In this case, avcodec_send_packet() will succeed
 * until the codec's internal buffer has been filled up (which is typically of
 * size 1 per output frame, after initial input), and then reject input with
 * AVERROR(EAGAIN). Once it starts rejecting input, you have no choice but to
 * read at least some output.
 *
 * Not all codecs will follow a rigid and predictable dataflow; the only
 * guarantee is that an AVERROR(EAGAIN) return value on a send/receive call on
 * one end implies that a receive/send call on the other end will succeed, or
 * at least will not fail with AVERROR(EAGAIN). In general, no codec will
 * permit unlimited buffering of input or output.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值