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

直播流PTS值异常:FFmpeg接收UDP流时DTS/PTS跳变问题求助

问题:UDP流接收中FFmpeg音视频PTS/DTS跳变导致卡顿

使用FFmpeg源码接收UDP网络视频流时,音视频包的DTS和PTS偶尔会同时跳变——从较大值突然降到相差数十倍的极小值,直接影响音视频同步,导致播放卡顿,需要代码层面的解决方案。


收流写入缓冲区的处理代码

//read video package
if(pAvPacket->stream_index == pThis->m_iVideoStreamIndex)
{
    std::cout<<"Video_Packet_DTS: "<<pAvPacket->dts<<"   Video_Packet_PTS: "<<pAvPacket->pts<<std::endl;
    
     //Video frame rate assignment
    if(pThis->m_pVideoTimeBase->num > 0 && pAvPacket->duration > 0)
        pThis->m_iVideoFPS = (pThis->m_pVideoTimeBase->den / pThis->m_pVideoTimeBase->num) / pAvPacket->duration;

    if(pThis->m_iDecodeMode == DECODE_MODE_ONLY_CURRENT_COLLECTION)
        pThis->m_videoDecodeThreadState = THREAD_NEED_STOP;     //stop the thread
    else
        pThis->m_videoDecodeThreadState = THREAD_NEED_RUN;      //make the thread run

    if(pThis->m_iMultiMediaType != MULTI_MEDIA_TYPE_FILE
            && pAvPacket->flags == AV_PKT_FLAG_KEY)
    {
            pThis->m_bIsFindIFrame = YTRUE;
    }

    VideoFramesCount ++;
    pThis->m_iReadVideoPacketCount ++;
    if(pThis->m_iDecodeMode != DECODE_MODE_ONLY_CHECK_NET && pThis->m_iDecodeMode != DECODE_MODE_AUDIO && pThis->m_bIsFindIFrame)
        YGlobCircleBufferWrite<AVPacket *>(pThis->m_videoPacketBuffer, &pAvPacket, 1);
    else
        av_packet_unref(pAvPacket);
    pAvPacket = YNULL;
}

运行时打印的PTS/DTS信息

Video_Packet_DTS: 8590470992   Video_Packet_PTS: 8590470992
Video_Packet_DTS: 8590474592   Video_Packet_PTS: 8590474592
Video_Packet_DTS: 8590478192   Video_Packet_PTS: 8590478192
Video_Packet_DTS: 8590481792   Video_Packet_PTS: 8590481792
Video_Packet_DTS: 550800   Video_Packet_PTS: 550800
Video_Packet_DTS: 554400   Video_Packet_PTS: 554400
Video_Packet_DTS: 558000   Video_Packet_PTS: 558000
Video_Packet_DTS: 561600   Video_Packet_PTS: 561600
Video_Packet_DTS: 565200   Video_Packet_PTS: 565200

错误日志信息

[h264 @ 04fea380] non-existing PPS 0 referenced
[h264 @ 04fea380] decode_slice_header error
[h264 @ 04fea380] no frame!
[swscaler @ 19b04600] Warning: data is not aligned! This can lead to a speed loss
[mp3float @ 04feadc0] overread, skip -6 enddists: -2 -2
[mpegts @ 04fcbf40] DTS 550800 < 8590481792 out of order
[mp3float @ 04feadc0] overread, skip -7 enddists: -6 -6
[mp3float @ 04feadc0] overread, skip -5 enddists: -2 -2

代码层面解决方案

  • 检测并修正时间戳跳变
    维护全局时间戳偏移量timestamp_offset,初始为0。每次收到包时:

    1. 记录上一个有效包的PTS值(仅记录关键帧的PTS,避免非关键帧干扰)
    2. 计算当前包PTS与上一个有效PTS的差值,若差值为负且绝对值超过10倍单帧时长,判定为跳变
    3. 更新偏移量:timestamp_offset = 上一个有效PTS - 当前PTS + timestamp_offset
    4. 对后续所有包的PTS/DTS加上该偏移量,保证时间戳连续
      注意:必须在收到关键帧后再应用修正,避免非关键帧依赖旧时间戳导致解码失败。
  • 重置解码上下文
    检测到时间戳跳变时,调用avcodec_flush_buffers()清空解码器缓存,丢弃缓冲区中未解码的旧包,等待新关键帧到来后重新启动解码流程,避免旧数据干扰新流解析。

  • 增强UDP流容错性
    如果是MPEG-TS封装的UDP流,在打开流时设置mpegts_flags=resync,让FFmpeg的TS解析器自动处理流重新同步;如果是RTP封装流,设置reorder_queue_size参数开启包序重组,减少无序包导致的时间戳异常。

  • 修正FPS计算逻辑
    当前整数除法会导致FPS精度丢失,改为浮点计算更准确:

    if(pThis->m_pVideoTimeBase->num > 0 && pAvPacket->duration > 0) {
        double frame_duration = av_q2d(*pThis->m_pVideoTimeBase) * pAvPacket->duration;
        pThis->m_iVideoFPS = 1.0 / frame_duration;
    }
    

    准确的单帧时长能更精准地判断时间戳跳变。

内容的提问来源于stack exchange,提问作者watermelon_seven

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 04:05:27