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占用,从根源上避免性能不足导致的延迟上涨问题。
需录制字幕场景的优化方案
如果确实需要把叠加字幕后的画面写入录制文件,可做以下优化:
- 给tee后的所有queue元件增加缓冲限制,避免队列无限积压:把两个
queue都替换为queue max-size-buffers=4 max-size-time=20000000,限制队列最多缓存200ms的视频数据。 - 录制分支关闭时钟同步,避免拖慢整个管线:给
matroskamux和filesink都加上sync=false async=false属性。 - 把软编码
avenc_mpeg4替换为Windows平台硬编码元件d3d11h264enc,编码速度提升数倍,大幅降低CPU占用。
内容的提问来源于stack exchange,提问作者Arnaud Tullio
相关产品推荐
相关产品推荐

