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

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),音频直接复用输入流,错误源自音频流。

问题原因

  1. 循环流时间戳回退:RTSP循环流在完成一次循环后,音频数据包的DTS会重置为初始值,但MP4复用器要求DTS必须严格单调递增,重置后的DTS小于等于之前的最大值,触发校验报错。
  2. 复用逻辑缺失时间戳修正:当前remux函数仅做了时间基转换,未跟踪音频流已写入的最大DTS,也未处理循环后的时间戳连续性问题。
  3. 未识别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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 06:38:07