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
相关产品推荐
相关产品推荐

