C+FFmpeg处理音视频流时DTS非单调递增错误解决
FFmpeg转码MP4时DTS非单调递增错误的解决方法
这个错误的核心原因是:MP4封装器要求每个输出流的DTS(解码时间戳)必须严格单调递增,多流共同处理时,若未正确维护各流独立的时间戳基准、未按全局时间顺序输出数据包,就会触发该校验错误。以下是针对性的解决步骤:
1. 为每个输出流维护独立的时间戳偏移基准
视频和音频流的原始时间戳起始点往往不同,转码时需各自重置时间戳基准,确保每个流的时间戳从合理值开始递增:
- 给每个输出流定义专属的偏移变量,比如在自定义的
OutputStream结构体中加入pts_offset、dts_offset和first_pkt标记:typedef struct OutputStream { AVStream *stream; AVCodecContext *codec_ctx; int64_t pts_offset; int64_t dts_offset; int first_pkt; // 标记是否为当前流的第一个数据包 } OutputStream; - 处理当前流的第一个数据包时,将其PTS/DTS设为偏移基准,后续数据包的时间戳都减去该基准:
if (out_stream->first_pkt) { out_stream->pts_offset = out_pkt->pts; out_stream->dts_offset = out_pkt->dts; out_stream->first_pkt = 0; } out_pkt->pts -= out_stream->pts_offset; out_pkt->dts -= out_stream->dts_offset;
2. 严格按输出流的时间基准转换时间戳
转码后的数据包不能直接复用解码器输出的时间戳,必须转换为输出流的time_base:
out_pkt->pts = av_rescale_q_rnd(out_pkt->pts, out_stream->codec_ctx->time_base, out_stream->stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX); out_pkt->dts = av_rescale_q_rnd(out_pkt->dts, out_stream->codec_ctx->time_base, out_stream->stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX); out_pkt->duration = av_rescale_q(out_pkt->duration, out_stream->codec_ctx->time_base, out_stream->stream->time_base); out_pkt->pos = -1; // 重置位置标记,交给封装器自动处理
3. 按全局时间顺序输出数据包
不能交替处理完视频/音频数据包后直接写入封装器,需要先缓存转码后的所有数据包,再按全局时间戳排序后输出:
- 用队列存储转码后的数据包,每个数据包携带流索引和全局时间戳(转换为同一时间基准,比如微秒)
- 每次从队列中取出时间最早的数据包,调用
av_interleaved_write_frame写入封装器(该函数也会自动做部分交错处理,但手动排序更可靠)
4. 修正编码器的时间基准设置
确保编码器的time_base配置符合对应流的规范:
- 视频编码器:通常设置为帧率的倒数
out_video_codec_ctx->time_base = av_inv_q(in_video_stream->r_frame_rate); - 音频编码器:设置为采样率的倒数
out_audio_codec_ctx->time_base = (AVRational){1, out_audio_codec_ctx->sample_rate};
5. 重置数据包的流索引
转码后的数据包必须设置正确的stream_index为输出流的索引,而非输入流的索引:
out_pkt->stream_index = out_stream->stream->index;
按上述步骤调整后,每个流的时间戳会保持严格单调递增,同时全局数据包按时间顺序写入封装器,即可解决DTS校验错误。
内容的提问来源于stack exchange,提问作者M.Hakim
相关产品推荐
相关产品推荐

