Gstreamer 动态更改源元素
Gstreamer change source element dynamically
我有一个GStreamer管道,可以从rtspsrc元素中提取视频。 rtspsrc 元素连接到 rtpjpegdepay 元素。 我希望能够即时更改 RTSP URL。 到目前为止,我一直在做的是:
1( 断开 RTSPSRC 与 Depay 元素的链接
2( 使用新的 RTSP URL 创建新的源元素
3(并链接到depay元素。
我遇到的问题是新的 RTSP 源元素未正确链接到 depay 元素,从而导致段错误。 我需要一些帮助来弄清楚如何动态更改 rtspsrc URL(当管道仍在播放时(。
管道创建:
GstBus *bus;
guint busWatchId;
GstElement *src, *depay, *parser, *decoder, *vpe, *filter, *sink;
GstCaps *vpeCaps;
m_loop = g_main_loop_new(NULL, FALSE);
//create pipeline elements
m_cameraStream = gst_pipeline_new("display_pipeline");
src = gst_element_factory_make("rtspsrc", "rtspsrc");
depay = gst_element_factory_make("rtpjpegdepay", "depay");
parser = gst_element_factory_make("jpegparse", NULL);
decoder = gst_element_factory_make("ducatijpegdec", NULL);
vpe = gst_element_factory_make("vpe", NULL);
filter = gst_element_factory_make("capsfilter", NULL);
sink = gst_element_factory_make("waylandsink", NULL);
if(!(m_cameraStream || src || depay || parser || decoder || vpe || filter || sink)){
qFatal("could not create pipeline elements");
exit(1);
}
g_object_set(G_OBJECT(src), "location", "rtsp://192.168.50.29/av0_1", "latency", 0, NULL);
g_signal_connect(src, "pad-added", G_CALLBACK(on_rtsp_pad_added), depay);
//add src caps?
vpeCaps = gst_caps_from_string("video/x-raw, format=NV12, width=800, height=480"); //change this when Tomas' patch hits
if(!vpeCaps){
qFatal("cannot create caps");
exit(1);
}
g_object_set(G_OBJECT(filter), "caps", vpeCaps, NULL);
g_object_set(G_OBJECT(sink), "sync", false, NULL);
//add and link elements to create full pipeline
gst_bin_add_many(GST_BIN(m_cameraStream), src, depay, parser, decoder, vpe, sink, NULL);
if(!gst_element_link_many(depay, parser, decoder, vpe, sink, NULL)){
qFatal("cannot link elements");
exit(1);
}
gst_caps_unref(vpeCaps);
bus = gst_pipeline_get_bus(GST_PIPELINE(m_cameraStream));
busWatchId = gst_bus_add_watch(bus, GstBusFunc(bus_call), m_loop);
gst_object_unref(bus);
RTSP->Depay 链接回调函数:
gchar *name;
GstElement *depay;
GstCaps *caps;
qDebug("on_rtsp_pad_added");
caps = gst_caps_from_string("application/x-rtp");
name = gst_pad_get_name(pad);
qDebug("on_rtsp_pad_added, rtspsrc pad name: %s", name);
depay = GST_ELEMENT(data);
if(!gst_element_link_pads_filtered(element, name, depay, "sink", caps)){
qFatal("pad_added: failed to link elements");
}
g_free(name);
gst_element_set_state(m_cameraStream, GST_STATE_PLAYING);
g_main_loop_run(m_loop);
源更改功能:
qDebug("slot_changeSource");
//gst_element_set_state(m_cameraStream, GST_STATE_PAUSED); //GST_STATE_NULL: segfault in pad_added
//GST_STATE_PAUSED: pauses, never returns to playing or on_rtsp_pad_added
//GST_STATE_PLAYING(left playing): same as NULL
GstElement* rtspsrc = gst_bin_get_by_name(GST_BIN(m_cameraStream), "rtspsrc");
if(rtspsrc){
qDebug("rtspsrc found");
GstElement* depay = gst_bin_get_by_name(GST_BIN(m_cameraStream), "depay");
if(depay){
qDebug("depay found");
gst_element_unlink(rtspsrc, depay);
gst_bin_remove(GST_BIN(m_cameraStream), rtspsrc);
GstElement* newSource = gst_element_factory_make("rtspsrc", "rtspsrc");
g_object_set(G_OBJECT(newSource), "location", "rtsp://192.168.50.29/av0_1", "latency", 0, NULL);
g_signal_connect(newSource, "pad-added", G_CALLBACK(on_rtsp_pad_added), depay); //needed in the same way as the previous rtspsrc
gst_bin_add(GST_BIN(m_cameraStream), newSource);
gst_element_sync_state_with_parent(newSource);
//gst_element_set_state(m_cameraStream, GST_STATE_PLAYING);
}
gst_element_set_state(rtspsrc, GST_STATE_NULL);
gst_object_unref(rtspsrc);
}
我尝试过的其他事情:
1(探测RTSP元素的src垫,以确保元素中没有任何数据。 这似乎是一个坏主意,因为此时 rtsp 元素是新创建的。
2( 将管道设置为暂停或 NULL,然后更改源元素。 这会导致管道永久暂停。
引用:
Gstreamer邮件列表
文档
好的,所以我相信我已经找到了答案,我将在这里发布这个,以拯救任何偶然发现这个问题的人。
答案是创建一对垫探针来处理管道中的数据清除。 我通过创建两个 pad 探测器回调来实现这一点:一个用于捕获管道以开始刷新过程,另一个用于在管道刷新后处理 rtspsrc 元素的重新创建。 第一个焊盘探头可以放在任何地方,所以我把它放在我的depay元件上。 第二个焊盘探头必须位于最后一个数据处理元素的源上。 所以不是最终的接收器元素。 对于上面的管道,这是"vpe"元素。
为此,我将流结束 (EOS( 信号传递给 depay 元素,然后在 vpe 元素的 src pad 处进行垫探测回调,以在 EOS 退出 VPE 时捕获它。 如果EOS到达waylandsink,管道将简单地关闭,你必须重新启动整个事情。
vpe = gst_bin_get_by_name(GST_BIN(data), "vpe");
srcPad = gst_element_get_static_pad(vpe, "src");
gst_pad_add_probe(srcPad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, event_probe, data, NULL);
//push EOS into the element, wait for the EOS to appear on the srcpad
depay = gst_bin_get_by_name(GST_BIN(data), "depay");
sinkPad = gst_element_get_static_pad(depay, "sink");
gst_pad_send_event(sinkPad, gst_event_new_eos());
return GST_PAD_PROBE_OK;
以及处理该EOS的回调:
static GstPadProbeReturn event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data){
GstElement *rtspsrcOld, *rtspsrcNew, *depay;
qDebug("event_probe");
if(GST_EVENT_TYPE(GST_PAD_PROBE_INFO_DATA(info)) != GST_EVENT_EOS){
return GST_PAD_PROBE_PASS;
}
gst_pad_remove_probe(pad, GST_PAD_PROBE_INFO_ID(info));
rtspsrcOld = gst_bin_get_by_name(GST_BIN(data), "rtspsrc");
if(rtspsrcOld){
qDebug("found rtspsrcOld");
depay = gst_bin_get_by_name(GST_BIN(data), "depay");
gst_element_unlink(rtspsrcOld, depay);
gst_bin_remove(GST_BIN(data), rtspsrcOld); //remove old rtspsrc from pipeline, should unlink from depay automatically.
rtspsrcNew = gst_element_factory_make("rtspsrc", "rtspsrc");
g_object_set(rtspsrcNew, "location", NEW_URI, "latency", 0, NULL);
g_signal_connect(G_OBJECT(rtspsrcNew), "pad-added", G_CALLBACK(on_rtsp_pad_added), data);
gst_bin_add(GST_BIN(data), rtspsrcNew);
gst_element_set_state(GST_ELEMENT(data), GST_STATE_PLAYING);
return GST_PAD_PROBE_DROP;
}
return GST_PAD_PROBE_DROP;
}
我试图做同样的事情。我刚开始使用gstreamer。在理解了T. Wallis的意思之后,我想用一个简单的管道来测试它。不幸的是,新的 rtspsrc 元素与管道的最终链接不起作用。但是,我认为错误在其他地方。我将再次浏览代码并阅读 gstreamer 的动态管道操作过程。但我不确定,我是否能够这么快找到错误。这是我的代码(这是我第一次在堆栈溢出上发帖,对不起潜在的nogos(:
#include <gst/gst.h>
#include <gst/gstpad.h>
#include <gst/rtsp/gstrtsp.h>
#include <unistd.h>
#include <time.h>
#include <stdbool.h>
typedef struct _CustomData {
GstElement *streaming_pipe;
GstElement *src;
GstElement *depay;
GstElement *decoder;
GstElement *sink;
GMainLoop *m_loop;
gboolean change_url;
gboolean url1;
clock_t startT;
} CustomData;
static void on_rtsp_pad_added(GstElement *element, GstPad *new_pad, CustomData *data){
gchar *name;
GstCaps *caps;
caps = gst_caps_from_string("application/x-rtp");
name = gst_pad_get_name(new_pad);
if(!gst_element_link_pads_filtered(element, name, data->depay, "sink", caps)){
g_print("npad_added: failed to link elements"); //ERROR when linking the new rtspsrc after breaking up the pipeline
}
g_free(name);
data->startT = clock();
}
static GstPadProbeReturn event_probe(GstPad *pad, GstPadProbeInfo *info, CustomData *data){
GstElement *rtspsrcOld, *rtspsrcNew, *depay;
if(GST_EVENT_TYPE(GST_PAD_PROBE_INFO_DATA(info)) != GST_EVENT_EOS){
g_print("n Not an EOS event; pass probe return");
return GST_PAD_PROBE_PASS;
}
gst_pad_remove_probe(pad, GST_PAD_PROBE_INFO_ID(info));
rtspsrcOld = gst_bin_get_by_name(GST_BIN(data->streaming_pipe), "rtspsrc");
if(rtspsrcOld){
depay = gst_bin_get_by_name(GST_BIN(data->streaming_pipe), "depay");
gst_element_unlink(rtspsrcOld, depay);
gst_bin_remove(GST_BIN(data->streaming_pipe), rtspsrcOld); //remove old rtspsrc from pipeline, should unlink from depay automatically.
rtspsrcNew = gst_element_factory_make("rtspsrc", "rtspsrc123");
g_object_set(rtspsrcNew, "location", "rtsp://xxxx/axis-media/media.amp?videocodec=h264&resolution=480x270", "latency", 0, NULL);
g_signal_connect(rtspsrcNew, "pad-added", G_CALLBACK(on_rtsp_pad_added), data);
gst_bin_add(GST_BIN(data->streaming_pipe), rtspsrcNew);
gst_element_set_state(GST_ELEMENT(data->streaming_pipe), GST_STATE_PLAYING);
g_print("n set playingn");
return GST_PAD_PROBE_DROP;
}
return GST_PAD_PROBE_DROP;
}
static GstPadProbeReturn cb_have_data (GstPad *pad, GstPadProbeInfo *info, CustomData *data) {
g_print("nPROBE CALLBACK!");
g_print("Time: %f", ((double) (clock() - data->startT)) / CLOCKS_PER_SEC);
if(((double) (clock() - data->startT)) / CLOCKS_PER_SEC > 0.04){
data->change_url = true;
data->startT = clock();
}
if(data->change_url){
g_print("nIF PROBE CALLBACK!");
GstPad *srcPad, *sinkPad;
srcPad = gst_element_get_static_pad(data->decoder, "src");
gst_pad_add_probe(srcPad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, event_probe, data, NULL);
//push EOS into the element, wait for the EOS to appear on the srcpad
sinkPad = gst_element_get_static_pad(data->depay, "sink");
gst_pad_send_event(sinkPad, gst_event_new_eos());
data->change_url = false;
}
return GST_PAD_PROBE_OK;
}
int main(int argc, char *argv[])
{
/* Initialize GStreamer */
gst_init (&argc, &argv);
CustomData data;
GstStateChangeReturn ret;
GstPad *pad;
data.m_loop = g_main_loop_new(NULL, FALSE);
//create pipeline elements
data.streaming_pipe = gst_pipeline_new("display_pipeline");
data.src = gst_element_factory_make("rtspsrc", "rtspsrc");
data.depay = gst_element_factory_make("rtph264depay", "depay");
data.decoder = gst_element_factory_make("avdec_h264", "decoder");
data.sink = gst_element_factory_make("autovideosink", NULL);
data.change_url = false;
data.url1 = false;
if(!(data.streaming_pipe || data.src || data.depay || data.decoder || data.sink)){
g_print("could not create pipeline elements");
exit(1);
}
g_object_set(G_OBJECT(data.src), "location", "rtsp://xxxx/axis-media/media.amp", "latency", 0, NULL);
g_signal_connect(data.src, "pad-added", G_CALLBACK(on_rtsp_pad_added), &data);
//add and link elements to create full pipeline
gst_bin_add_many(GST_BIN(data.streaming_pipe), data.src, data.depay, data.decoder, data.sink, NULL);
if(!gst_element_link_many(data.depay, data.decoder, data.sink, NULL)){
g_print("cannot link elements");
exit(1);
}
pad = gst_element_get_static_pad (data.depay, "src");
if(pad == NULL){
g_print("COULD NOT GET STATIC PAD");
}
gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
(GstPadProbeCallback) cb_have_data, &data, NULL);
gst_object_unref (pad);
ret = gst_element_set_state (data.streaming_pipe, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) {
g_printerr ("Unable to set the pipeline to the playing state.n");
gst_object_unref (data.streaming_pipe);
return -1;
}
g_main_loop_run (data.m_loop);
}
- 输出没有重复元素的动态数组(收缩数组)C++
- 访问动态分配列表中的元素
- 如何为 c++ 的不同变量类型的结构元素创建动态数组?
- 是否可以使用 new 指定具有宏常量的动态分配数组的元素?
- 动态分配列表 - 创建一个函数,用于删除所有包含偶数值的元素
- 在动态数组中添加/删除C++元素
- 是否可以使用宏来访问动态数组或向量中的元素或为其赋值
- 存储指向动态数组元素的指针
- c++ 使用动态分配运算符反向数组元素
- 我正在丢失动态分配的数组中的元素
- 通过动态分配插入列表元素
- Gstreamer 动态更改源元素
- 在指向对象的指针的动态数组上插入新元素
- C++ rezing 动态数组最多可以处理一定数量的元素,但在某些时候会崩溃并显示错误 (0XC0000005)
- 删除动态分配数组的 1 个元素
- C++:指针元素的向量在销毁时是否会自动释放每个指针所指向的动态内存?
- 动态地添加元素
- C++ 如何使用类方法正确访问动态数组元素
- 使用动态分配创建数组并将元素插入其中
- 如何初始化vlaue,并将其逐个元素动态分配给数组