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

GStreamer UDP流显示+录制管线随时间延迟增长问题求助

问题描述

以下是我用于显示和录制UDP源输入流的管线。当前遇到的问题是:流的播放和录制延迟会随时间不断升高,初始状态无延迟,但若我仅单独显示流,则不存在延迟问题。
请问有人能够指出问题可能的来源吗?

初始管线代码:

pipeline = gst_parse_launch("udpsrc name=source ! rtpjitterbuffer mode=0 ! rtph264depay ! h264parse ! avdec_h264 ! tee name = t ! queue ! avenc_mpeg4 bitrate=10000000 ! matroskamux name=matrox !filesink name=myFile t. ! queue ! videoconvert ! d3dvideosink name=mysink sync=false", &error);

多谢。

编辑补充:我完整的保存和显示代码如下:

void MainWindow::SaveVideo()
{
        std::string strPathVideo = m_VideoPath + CreateFileName("mkv");
        GError* error = NULL;
        GstElement* source;
        GstElement* filesink;
        GstElement* matrox;
        GstElement* clocktime;
        //GstElement* compression;
        GstElement* textoverlay;
        GstElement* sink;
        GstPad* padsink;
        GstCaps* caps = gst_caps_new_simple("application/x-rtp",
            "media", G_TYPE_STRING, "video",
            "payload", G_TYPE_INT, 96,
            "encoding-name", G_TYPE_STRING, "H264",
            NULL);

(*ptrstats).pipeline = gst_parse_launch("udpsrc name=source ! rtpjitterbuffer mode=0 ! rtph264depay ! h264parse ! avdec_h264 ! textoverlay halignment=center valignment=top name=text ! tee name = t ! queue ! avenc_mpeg4 bitrate=10000000 ! matroskamux name=matrox !filesink name=myFile t. ! queue ! videoconvert ! d3dvideosink name=mysink sync=false", &error);
            textoverlay = gst_bin_get_by_name(GST_BIN((*ptrstats).pipeline), "text");
            g_object_set(G_OBJECT(textoverlay), "text", m_text.ToStdString(), NULL);
        }

        if (!(*ptrstats).pipeline) {
             outfile << "Save : ", error->message ,"\n";
             exit(1);
        }
        sink = gst_bin_get_by_name(GST_BIN((*ptrstats).pipeline), "mysink");

        filesink = gst_bin_get_by_name(GST_BIN((*ptrstats).pipeline), "myFile");
        g_object_set(filesink, "location", strPathVideo.c_str(), NULL);

        //compression = gst_bin_get_by_name(GST_BIN((*ptrstats).pipeline), "compression");
        //g_object_set(G_OBJECT(compression), "bitrate", m_intcompression, NULL);

        matrox = gst_bin_get_by_name(GST_BIN((*ptrstats).pipeline), "matrox");
        g_object_set(G_OBJECT(matrox), "offset-to-zero", true, NULL);

        source = gst_bin_get_by_name(GST_BIN((*ptrstats).pipeline), "source");
        g_object_set(G_OBJECT(source), "caps", caps, NULL);
        g_object_set(G_OBJECT(source), "port", m_port, NULL);

        textoverlay = gst_bin_get_by_name(GST_BIN((*ptrstats).pipeline), "text");
        g_object_set(G_OBJECT(textoverlay), "text", m_text.ToStdString(), NULL);

        padsink = gst_element_get_static_pad(sink, "sink");
        gst_pad_add_probe(padsink, GST_PAD_PROBE_TYPE_BUFFER, (GstPadProbeCallback)buffer_sink, ptrstats, NULL);
        gst_object_unref(padsink);

        (*ptrstats).bus = gst_element_get_bus(GST_ELEMENT((*ptrstats).pipeline));

    #ifdef __WXGTK__
        GstElement* sink = gst_bin_get_by_name(GST_BIN((*ptrstats).pipeline), "mysink");
        gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(sink), m_xid);
    #elif defined __WXMSW__

        WXWidget hwnd = (*ptrstats).m_renderWindow->GetHandle();
        gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(sink),
            reinterpret_cast<guintptr>(hwnd));
    #endif

        PlayHelper();
    
}

void MainWindow::PlayHelper()
{
    GstStateChangeReturn ret =
        gst_element_set_state((*ptrstats).pipeline, GST_STATE_PLAYING);

    if (ret == GST_STATE_CHANGE_FAILURE)
    {
        outfile << "Playhelper : Unable to set the pipeline to the playing state.\n";
        wxLogWarning("Unable to set the pipeline to the playing state.");
        gst_object_unref((*ptrstats).pipeline);
        (*ptrstats).pipeline = NULL;

    }
}

解答

问题根因

  • tee元件的运行机制是必须等所有输出分支的当前帧处理完成,才会接收上游的下一帧数据。你的录制分支需要做MPEG4软编码、MKV封装,运算量远高于显示分支,一旦编码速度跟不上输入的视频帧率,就会阻塞整个上游链路,导致视频帧持续积压,延迟越来越高。单独跑播放管线时没有编码环节的性能瓶颈,所以不会出现延迟上涨的问题。
  • tee后连接的两个queue元件没有配置缓冲上限,默认配置允许队列最多缓存数秒的视频数据,性能不足时队列会被逐步填满,进一步推高延迟。
  • 你当前的实现逻辑是先把原始H264流解码,叠加字幕后再重新编码为MPEG4格式,额外增加了大量编解码CPU开销,是最核心的性能瓶颈来源。

解决方案

最优方案(优先使用)

如果不需要把叠加的字幕写入录制文件,直接跳过二次编解码,把原始UDP输入的H264流直接写入文件,完全消除编解码的性能开销,改造后的管线逻辑如下:

udpsrc name=source ! rtpjitterbuffer mode=0 ! rtph264depay ! h264parse ! tee name=t
t. ! queue ! matroskamux name=matrox ! filesink name=myFile sync=false async=false
t. ! queue ! avdec_h264 ! textoverlay halignment=center valignment=top name=text ! videoconvert ! d3dvideosink name=mysink sync=false

该方案会大幅降低CPU占用,从根源上避免性能不足导致的延迟上涨问题。

需录制字幕场景的优化方案

如果确实需要把叠加字幕后的画面写入录制文件,可做以下优化:

  1. 给tee后的所有queue元件增加缓冲限制,避免队列无限积压:把两个queue都替换为queue max-size-buffers=4 max-size-time=20000000,限制队列最多缓存200ms的视频数据。
  2. 录制分支关闭时钟同步,避免拖慢整个管线:给matroskamux和filesink都加上sync=false async=false属性。
  3. 把软编码avenc_mpeg4替换为Windows平台硬编码元件d3d11h264enc,编码速度提升数倍,大幅降低CPU占用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 07:15:07