Bootstrap

[C/C++][FFmpeg] 关于avcodec_send_frame(encoder_ctx, NULL) 的解释

使用FFmpeg,明明看起来已经写完文件了,但是临近末尾还要执行下面这段

// 刷新编码器
avcodec_send_frame(encoder_ctx, NULL);
while (avcodec_receive_packet(encoder_ctx, packet) >= 0) {
    av_interleaved_write_frame(output_format_ctx, packet);
    av_packet_unref(packet);
}

为什么要执行avcodec_send_frame(encoder_ctx, NULL)?

在使用 FFmpeg 进行视频编码时,编码器内部会使用缓存来提高编码效率。这种缓存行为导致编码器在接收到输入帧时,可能不会立刻生成完整的输出数据,而是会积累一定数量的帧后再批量输出。因此,在编码完成后需要显式地通知编码器不再有更多的帧输入,从而触发编码器将剩余缓存的数据输出,这就是刷新编码器的作用。

分析
  1. avcodec_send_frame(encoder_ctx, NULL):

    • 这是将 NULL 发送给编码器,表示没有更多的输入帧。这个调用告诉编码器可以结束编码过程,输出它缓存的所有数据。
  2. avcodec_receive_packet(encoder_ctx, packet):

    • 在发送 NULL 后,编码器可能会生成剩余的数据包。这个循环用于接收这些数据包,直到 avcodec_receive_packet 返回一个负数(表示没有更多数据)。
    • 如果没有这个步骤,编码器内部缓存的数据可能会丢失,导致最后几帧的数据没有被写入输出文件。
  3. av_interleaved_write_frame(output_format_ctx, packet):

    • 将接收到的编码数据包写入输出文件,确保所有数据都保存到文件中。

为什么需要?

  • 防止数据丢失:确保所有数据都被编码并保存到输出文件。如果没有这一步,最后的一些缓存帧可能不会被写入输出文件,导致视频不完整。
  • 帧延迟问题:编码器内部可能存在延迟,例如 B 帧编码(双向预测帧),需要未来帧的信息才能生成完整的数据。如果不刷新编码器,这些帧可能会丢失。

实例场景

考虑一个场景,如果视频编码器使用了B 帧(双向预测帧),这些帧可能依赖于未来的帧数据。因此,即使已经处理完所有输入帧,编码器仍可能需要生成一些帧来完成编码。通过调用 avcodec_send_frame(encoder_ctx, NULL) 可以触发编码器生成所有可能的剩余帧,确保没有任何帧丢失。

小结一下

  • 这段代码是为了确保所有数据都被完全编码并写入输出文件
  • 在视频编码结束时,这是一个标准操作步骤,用来清空编码器缓存
  • 即使在编码关键帧时,也可能会有一些缓存数据需要被刷新,这对保证视频文件的完整性非常重要。
;