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

GStreamer运行时从v4l2src切换到filesrc失败的问题求助

GStreamer运行时从v4l2src切换到filesrc失败的问题求助

大家好,我刚接触GStreamer,现在在做一个基于GLib的C项目,核心需求是在运行时动态切换RTSP流的视频源。目前我已经实现了v4l2src(本地摄像头)和videotestsrc之间的无缝切换,但切换到filesrc(本地MP4文件)时却一直失败,想请教下大家怎么解决这个问题。

我的实现流程

首先是RTSP服务器的初始化代码,我定义了一个静态Pipeline,里面留了identity节点作为后续挂载不同视频源的入口:

#define STATIC_PIPELINE \
    "identity name=split ! x264enc tune=zerolatency speed-preset=superfast " \
    "bitrate=1500 key-int-max=30 ! rtph264pay name=pay0 config-interval=1"

GstRTSPMountPoints * mounts;
GstRTSPMediaFactory * factory;

gst_init( NULL, NULL );
server->gstRtsp = gst_rtsp_server_new();
mounts = gst_rtsp_server_get_mount_points( server->gstRtsp );
factory = gst_rtsp_media_factory_new();

gst_rtsp_server_set_address( server->gstRtsp, aAddress );
gst_rtsp_server_set_service( server->gstRtsp, aPort );
gst_rtsp_media_factory_set_launch( factory, STATIC_PIPELINE );
gst_rtsp_mount_points_add_factory( mounts, aMountPath, factory );
gst_rtsp_media_factory_set_shared( factory, FALSE );

g_signal_connect( factory, "media-configure", (GCallback)MediaConfigureCb, NULL );

然后在MediaConfigureCb回调中完成初始源的设置,以及后续的源切换触发:

static void MediaConfigureCb(GstRTSPMediaFactory *factory, GstRTSPMedia *media, gpointer user_data) {
    GstElement *pipeline = gst_rtsp_media_get_element(media);
    GstElement *identity = gst_bin_get_by_name(GST_BIN(pipeline), "split");

    CustomMediaContext *ctx = g_new0(CustomMediaContext, 1);
    ctx->pipeline = pipeline;
    ctx->identity = identity;
    ctx->dynamic_bin = NULL;

    // 设置pipeline的is-live属性
    if (GST_IS_PIPELINE(ctx->pipeline)) {
        g_object_set(GST_PIPELINE(ctx->pipeline), "is-live", FALSE, NULL);
    }

    g_object_set_data_full(G_OBJECT(media), "custom-media-context", ctx, g_free);

    // 初始源设置为摄像头v4l2src
    SwitchSource(ctx, "v4l2src is-live=true ! videoconvert ! video/x-raw,format=I420,framerate=30/1");
    
    // 等待几秒后切换到videotestsrc,这一步是完全成功的
    // (等待逻辑此处省略)
    SwitchSource(ctx, "videotestsrc is-live=true ! videoconvert ! video/x-raw,format=I420,framerate=30/1");
}

切换源的核心函数SwitchSource实现:

static void SwitchSource(CustomMediaContext *ctx, const gchar *source_desc) {
    GstElement *new_bin = gst_parse_bin_from_description(source_desc, TRUE, NULL);
    GstPad *identity_sink = gst_element_get_static_pad(ctx->identity, "sink");

    // 移除旧的源Bin
    if (ctx->dynamic_bin) {
        gst_element_set_state(ctx->dynamic_bin, GST_STATE_NULL);
        gst_bin_remove(GST_BIN(ctx->pipeline), ctx->dynamic_bin);
    }

    // 添加新的源Bin并同步状态
    gst_bin_add(GST_BIN(ctx->pipeline), new_bin);
    gst_element_sync_state_with_parent(new_bin);

    // 链接新Bin的src pad到identity的sink pad
    GstPad *new_src_pad = gst_element_get_static_pad(new_bin, "src");
    if (gst_pad_link(new_src_pad, identity_sink) != GST_PAD_LINK_OK) {
        g_printerr("SwitchSource: Failed to link to identity\n");
    }

    ctx->dynamic_bin = new_bin;

    // 释放资源
    gst_object_unref(identity_sink);
    gst_object_unref(new_src_pad);
}

成功的场景

当我用以下终端命令播放RTSP流时,能正常看到摄像头画面,几秒后也能成功切换到测试图:

gst-launch-1.0 rtspsrc location="{location}" latency=0 buffer-mode=auto name=d ! decodebin ! videoconvert ! waylandsink

失败的场景

但当我尝试切换到filesrc时,就会触发错误。切换调用的代码是:

SwitchSource(ctx, "filesrc location={locationToMp4File} ! decodebin name=dec ! queue ! videoconvert ! video/x-raw,framerate=30/1");

此时播放终端会输出以下错误:

Pipeline is live and does not need PREROLL ...
Progress: (open) Opening Stream
Pipeline is PREROLLED ...
Prerolled, waiting for progress to finish...
Progress: (connect) Connecting to {server}
Progress: (open) Retrieving server options
Progress: (open) Retrieving media info
ERROR: from element /GstPipeline:pipeline0/GstRTSPSrc:d: Unhandled error
Additional debug info:
../gst/rtsp/gstrtspsrc.c(6795): gst_rtspsrc_send (): /GstPipeline:pipeline0/GstRTSPSrc:d:
Service Unavailable (503)
ERROR: pipeline doesn't want to preroll.
Setting pipeline to NULL ...
Freeing pipeline ...

我的困惑

我知道decodebin的pad是动态创建的,需要处理pad-added回调,但自己尝试了几次都没搞定。另外我只需要传输视频流,不需要音频。想请教下大家,我应该怎么修改代码才能让filesrc的源成功切换进去?

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 07:35:30