使用libavcodec/libavformat编码多流时的PTS/DTS问题排查
解决FFmpeg编码MOV时DTS非单调递增的问题
问题原因
你手动给AVPacket设置DTS的方式存在两个核心问题:
- MPEG2编码器本身会根据帧类型(I/P/B帧)生成正确的DTS/PTS,手动覆盖会破坏编码器的时间戳逻辑;
- 你试图跨流(视频用偶数DTS、音频用奇数DTS)强制交错,但MOV封装要求每个独立流的DTS必须单调递增,这种跨流的DTS分配会导致单一流内部的DTS顺序混乱。
解决步骤
1. 移除手动设置的DTS和不必要标志
不要手动设置videoPkt.dts、audioPkt.dts,也不要随意添加AV_PKT_FLAG_KEY(编码器会自动为关键帧设置该标志)。
2. 正确转换时间戳
编码器输出的Packet时间戳基于自身的time_base,需要转换为输出流的time_base后再写入封装器,使用av_packet_rescale_ts完成转换。
3. 修正后的代码示例
视频编码部分
// 按编码器time_base递增pts,假设fps为25,每帧+1对应1/25秒 videoFrame->pts = frameCounter; if(avcodec_send_frame(videoContext, videoFrame) < 0) { std::cout << "Failed to send video frame " << frameCounter << std::endl; return; } AVPacket videoPkt; av_init_packet(&videoPkt); videoPkt.data = nullptr; videoPkt.size = 0; videoPkt.stream_index = 0; // 注意:avcodec_receive_packet可能返回多个packet(比如B帧),需循环接收 while(avcodec_receive_packet(videoContext, &videoPkt) == 0) { // 将时间戳从编码器time_base转换为输出流time_base av_packet_rescale_ts(&videoPkt, videoContext->time_base, outputFormatContext->streams[0]->time_base); if(av_interleaved_write_frame(outputFormatContext, &videoPkt) != 0) { std::cout << "Failed to write video packet" << std::endl; } av_packet_unref(&videoPkt); }
音频编码部分
// 音频pts按编码器time_base递增,比如采样率48000,每帧含1024样本,则每次+1024 audioFrame->pts = audioFrameCounter; if(avcodec_send_frame(audioContext, audioFrame) < 0) { std::cout << "Failed to send audio frame " << audioFrameCounter << std::endl; return; } AVPacket audioPkt; av_init_packet(&audioPkt); audioPkt.data = nullptr; audioPkt.size = 0; audioPkt.stream_index = 1; while(avcodec_receive_packet(audioContext, &audioPkt) == 0) { av_packet_rescale_ts(&audioPkt, audioContext->time_base, outputFormatContext->streams[1]->time_base); if(av_interleaved_write_frame(outputFormatContext, &audioPkt) != 0) { std::cout << "Failed to write audio packet" << std::endl; } av_packet_unref(&audioPkt); }
4. 额外注意事项
- 音视频的
time_base要分别正确设置:视频编码器time_base设为AVRational{1, fps},音频编码器time_base设为AVRational{1, sample_rate}; - 依赖
av_interleaved_write_frame自动处理音视频帧的交错,无需手动干预时间戳的跨流顺序; - 确保每个流的pts是连续递增的,视频按帧计数递增,音频按样本数递增。
内容的提问来源于stack exchange,提问作者WalleyM
相关产品推荐
相关产品推荐

