You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FFmpeg多线程解码丢失帧,如何获取未解码的最终帧?

解决FFmpeg多线程解码丢帧问题

你遇到的问题是FF_THREAD_FRAME模式下的正常行为——解码器需要缓存与线程数等量的帧来填充线程池,所以前期发送数据包后不会立刻输出解码帧;当所有输入数据包发送完毕后,若不主动刷新解码器缓存,这些缓存的帧就会被丢弃,导致最后一批帧无法解码。

具体解决步骤:

  1. 正常处理输入数据包:循环读取并发送数据包到解码器,直到av_read_frame()返回EOF(无更多输入)。
  2. 发送空数据包触发刷新:在所有输入数据包发送完成后,调用avcodec_send_packet(codec_ctx, NULL),这会告诉解码器已无新输入,需要输出所有缓存的解码帧。
  3. 循环接收剩余帧:持续调用avcodec_receive_frame(),直到它返回AVERROR_EOF,此时所有缓存的帧都会被取出。

修正后的代码示例:

AVPacket pkt = {0};
AVFrame *frame = av_frame_alloc();
int ret;
AVCodecContext *codec_ctx = ...; // 你的解码器上下文
AVFormatContext *fmt_ctx = ...;   // 你的格式上下文

// 正常读取并解码数据包
while (av_read_frame(fmt_ctx, &pkt) == 0) {
    ret = avcodec_send_packet(codec_ctx, &pkt);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "发送数据包失败: %s\n", av_err2str(ret));
        av_packet_unref(&pkt);
        continue;
    }

    // 尝试接收所有当前可用的解码帧
    while (ret >= 0) {
        ret = avcodec_receive_frame(codec_ctx, frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            break;
        } else if (ret < 0) {
            av_log(NULL, AV_LOG_ERROR, "接收帧失败: %s\n", av_err2str(ret));
            goto cleanup;
        }

        // 处理解码后的帧(如保存、显示)
        process_decoded_frame(frame);
        av_frame_unref(frame);
    }

    av_packet_unref(&pkt);
}

// 发送空数据包,触发解码器刷新缓存
ret = avcodec_send_packet(codec_ctx, NULL);
if (ret < 0 && ret != AVERROR_EOF) {
    av_log(NULL, AV_LOG_ERROR, "刷新发送失败: %s\n", av_err2str(ret));
    goto cleanup;
}

// 接收所有缓存的剩余帧
while (ret >= 0) {
    ret = avcodec_receive_frame(codec_ctx, frame);
    if (ret == AVERROR_EOF) {
        break;
    } else if (ret == AVERROR(EAGAIN)) {
        continue;
    } else if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "刷新接收失败: %s\n", av_err2str(ret));
        goto cleanup;
    }

    process_decoded_frame(frame);
    av_frame_unref(frame);
}

cleanup:
av_frame_free(&frame);
av_packet_free(&pkt);
// 其他资源清理...

额外注意事项:

  • 避免使用废弃的av_stream->codec,改用avcodec_parameters_to_context(codec_ctx, av_stream->codecpar)来初始化解码器上下文,旧API可能导致兼容性问题。
  • avcodec_send_packet(NULL)返回AVERROR_EOF是正常现象,无需报错,只需继续接收帧直到返回AVERROR_EOF即可。

内容的提问来源于stack exchange,提问作者Patrick McKeever

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 14:25:19