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

FFmpeg生成MP4:ffprobe显示100帧/包但av_interleaved_write_frame仅调用50次

问题原因分析

你观察到的av_interleaved_write_frame调用次数(50次)与ffprobe检测到的100个AVPacket数量不一致,核心原因有两点:

1. H.264编码器的帧缓存机制

H.264编码器(如FFmpeg默认的x264)为实现高效的帧间预测(尤其是B帧),会在内部缓存多帧数据,不会每输入一帧就立刻输出对应的AVPacket。编码器需要积累足够的帧完成预测、压缩优化后,才会批量输出数据包。在你循环发送100帧的过程中,编码器仅输出了50个数据包,剩余50个被暂时缓存。

2. 刷新阶段的数据包未被计数

你的代码仅在循环发送帧的过程中对av_interleaved_write_frame调用次数做了统计(call_write变量),但刷新编码器阶段(发送nullptr到avcodec_send_frame)输出的数据包没有被统计:

// 刷新编码器
ret = avcodec_send_frame(outCodecCtx, nullptr);
if (ret < 0) {
    std::cerr << "刷新编码器失败:" << std::endl;
    return -1;
}

while (ret >= 0) {
    AVPacket* pkt = av_packet_alloc();
    if (!pkt) {
        std::cerr << "分配数据包失败" << std::endl;
        return -1;
    }
    ret = avcodec_receive_packet(outCodecCtx, pkt);

    // 将数据包写入输出文件
    if (ret == 0)
    {
        pkt->stream_index = outStream->index;
        pkt->duration = av_rescale_q(1, outCodecCtx->time_base, outStream->time_base);
        ret = av_interleaved_write_frame(outFormatCtx, pkt); // 此处调用未被计数
        av_packet_unref(pkt);
        if (ret < 0) {
            std::cerr << "写入数据包到输出文件失败:" << std::endl;
            return -1;
        }
    }
}

这部分代码会输出编码器缓存的剩余50个数据包,所以av_interleaved_write_frame实际总调用次数是50(循环阶段)+50(刷新阶段)=100次,和ffprobe检测结果完全对应。

另外,你的代码中PTS设置存在异常:

yuvFrame->pts = av_rescale_q(frame_count*frame_count, outCodecCtx->time_base, outStream->time_base);

用frame_count*frame_count会导致PTS呈平方增长,不符合正常时间戳线性递增规则,虽未影响最终帧数量,但可能导致播放时间异常,建议改为线性增长的PTS,比如:

yuvFrame->pts = frame_count;

再通过av_rescale_q转换为流的时间基准即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 06:11:59