RTSP流转MP4时音频流出现DTS非单调递增错误求助
解决FFmpeg libav音频流DTS非单调递增错误
问题场景
我使用以下FFmpeg命令循环推送RTSP流:
ffmpeg -re -stream_loop -1 -i ./ffmpeg_c_test/small_bunny_1080p_60fps.mp4 -ac 2 -f rtsp -rtsp_transport tcp rtsp://localhost:8554/mystream
自研程序调用av_interleaved_write_frame时,持续收到错误:
ERROR "Application provided invalid, non monotonically increasing dts to muxer in stream 1: 6874 >= 6874"
输出格式为MP4,视频转码采用AV1(libsvtav1),音频直接复用输入流,错误源自音频流。
问题原因
- 循环流时间戳回退:RTSP循环流在完成一次循环后,音频数据包的DTS会重置为初始值,但MP4复用器要求DTS必须严格单调递增,重置后的DTS小于等于之前的最大值,触发校验报错。
- 复用逻辑缺失时间戳修正:当前
remux函数仅做了时间基转换,未跟踪音频流已写入的最大DTS,也未处理循环后的时间戳连续性问题。 - 未识别RTSP循环特性:RTSP循环流不会发送EOF信号,而是持续推送初始时间戳的数据包,程序无对应处理逻辑。
修复方案
1. 新增时间戳跟踪字段
在StreamingContext结构体中添加字段,记录音频流已写入的最大DTS:
typedef struct StreamingContext{ AVFormatContext* avfc; const AVCodec *video_avc; const AVCodec *audio_avc; AVStream *video_avs; AVStream *audio_avs; AVCodecContext *video_avcc; AVCodecContext *audio_avcc; int video_index; int audio_index; char* filename; struct SwsContext *sws_ctx; int64_t audio_max_dts; // 新增:跟踪音频已写入的最大DTS }StreamingContext;
初始化时将audio_max_dts设为AV_NOPTS_VALUE:
StreamingContext *encoder = (StreamingContext *)calloc(1, sizeof(StreamingContext)); encoder->audio_max_dts = AV_NOPTS_VALUE;
2. 预计算音频流总时长
在prepare_decoder执行完成后,计算音频流的总时长(转换为输出时间基),用于循环时修正时间戳:
// main函数中,prepare_decoder之后添加 int64_t audio_stream_duration; if (decoder->audio_avs->duration != AV_NOPTS_VALUE) { // 直接使用流的duration字段转换时间基 audio_stream_duration = av_rescale_q(decoder->audio_avs->duration, decoder->audio_avs->time_base, encoder->audio_avs->time_base); } else { // 备选:如果duration不可用,通过采样率和总帧数计算 audio_stream_duration = av_rescale_q(decoder->audio_avcc->frame_size * decoder->audio_avcc->codecpar->frame_count, av_make_q(1, decoder->audio_avcc->sample_rate), encoder->audio_avs->time_base); }
3. 修改remux函数处理时间戳回退
更新remux函数,检测到DTS回退时,累加音频流总时长修正时间戳:
int remux(AVPacket **pkt, AVFormatContext **avfc, AVRational decoder_tb, AVRational encoder_tb, int64_t *audio_max_dts, int64_t audio_stream_duration) { (*pkt)->duration = av_rescale_q((*pkt)->duration, decoder_tb, encoder_tb); (*pkt)->pos = -1; av_packet_rescale_ts(*pkt, decoder_tb, encoder_tb); // 处理循环流的DTS回退问题 if (*audio_max_dts != AV_NOPTS_VALUE && (*pkt)->dts <= *audio_max_dts) { (*pkt)->dts += audio_stream_duration; (*pkt)->pts += audio_stream_duration; } // 更新已写入的最大DTS if (*audio_max_dts == AV_NOPTS_VALUE || (*pkt)->dts > *audio_max_dts) { *audio_max_dts = (*pkt)->dts; } if (av_interleaved_write_frame(*avfc, *pkt) < 0) { logging("Error while copying Stream Packet."); return -1; } return 0; }
4. 传递参数调用remux
修改main函数中的音频处理逻辑,传递新增的跟踪参数:
else if (decoder->avfc->streams[input_packet->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { if (remux(&input_packet, &encoder->avfc, decoder->audio_avs->time_base, encoder->audio_avs->time_base, &encoder->audio_max_dts, audio_stream_duration)) return -1; }
额外优化建议
- 视频流循环处理:若视频流也出现时间戳回退问题,可复用相同逻辑跟踪视频最大DTS并修正。
- 动态循环检测:对于时长未知的流,可通过连续数据包的DTS突变(突然远小于上一个DTS)自动识别循环,无需预计算总时长。
内容的提问来源于stack exchange,提问作者user16570427
相关产品推荐
相关产品推荐

