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
相关产品推荐
相关产品推荐

