Pads have different grandparents dynamically connecting main pipeline to a secondary bin
Matteo
locatster at gmail.com
Sun Nov 21 17:16:09 UTC 2021
Hello,
At the end I found that creating two separate bins and adding them to the
pipeline does not raise the "pads have different grandparents" problem.
But now I have another problem, after I add the second bin to the pipeline
it takes seconds to start playing, in particular I see in the log that it
starts playing after a "unlocked after timeout" clock event.
I will attach the code that does this:
-It creates the bin videotestsrc -> tee (with allow-not-linked) and adds it
to the main pipeline
- Sets main pipeline to play
- It creates a secondary bin queue -> autovideosink
- After 5 seconds:
- It requests the pad on the tee and creates a ghost pad adding it to the
primary bin
- It requests the sink pad on the queue and creates a ghost pad adding it
to the secondary bin
- It adds secondary bin to pipeline
- It sets secondary bin to play
- It links the ghost pads of the primary and secondary bins
#include <stdio.h>
#include <stdlib.h>
#include <gst/gst.h>
#define PIPELINE_MAIN_STRING "videotestsrc ! tee name=split
allow-not-linked=true"
struct context
{
GstElement *main_pipeline;
GstElement *primary_bin;
GstElement *tee_element;
GstPad *tee_pad;
GstPad *tee_pad_ghost;
GMainLoop *app_loop;
GstElement *secondary_bin;
GstElement *link_element_in_secondary_bin;
GstPad *link_element_pad;
GstPad *link_element_pad_ghost;
} ctx = {0};
static int
create_main_pipeline()
{
int ret = 0;
gchar *pipeline_string = NULL;
GstElement *testsrc;
if (!(ctx.main_pipeline = gst_pipeline_new("main_pipeline")))
{
fprintf(stderr, "Error creating main pipeline\n");
return -1;
}
if (!(ctx.primary_bin = gst_bin_new("primary_bin")))
{
fprintf(stderr, "Erorr creating primary bin\n");
return -1;
}
if (!(testsrc = gst_element_factory_make("videotestsrc", "test_src")))
{
fprintf(stderr, "Erorr creating test source\n");
return -1;
}
if (!(ctx.tee_element = gst_element_factory_make("tee", "tee")))
{
fprintf(stderr, "Error creating tee\n");
return -1;
}
g_object_set(ctx.tee_element, "allow-not-linked", 1, NULL);
gst_bin_add_many(GST_BIN(ctx.primary_bin), testsrc, ctx.tee_element,
NULL);
if (!(gst_element_link_many(testsrc, ctx.tee_element, NULL)))
{
fprintf(stderr, "Error linking elements\n");
return -1;
}
if (!(gst_bin_add(GST_BIN(ctx.main_pipeline), ctx.primary_bin)))
{
fprintf(stderr, "Error adding primary bin to main pipeline\n");
return -1;
}
return 0;
}
static int
create_secondary_bin()
{
GstElement *fakesink;
if (!(ctx.secondary_bin = gst_bin_new("testbin")))
{
fprintf(stderr, "Error creating secondary bin\n");
return -1;
}
if (!(ctx.link_element_in_secondary_bin =
gst_element_factory_make("queue", "secondary_bin_queue")))
{
fprintf(stderr, "Error creating queue in secondary bin\n");
return -1;
}
if (!(fakesink = gst_element_factory_make("autovideosink",
"seconday_bin_fakesink")))
{
fprintf(stderr, "Error creating fakesink in secondary bin\n");
return -1;
}
gst_bin_add_many(GST_BIN(ctx.secondary_bin),
ctx.link_element_in_secondary_bin, fakesink, NULL);
gst_element_link(ctx.link_element_in_secondary_bin, fakesink);
return 0;
}
static int
request_pads()
{
GstPadTemplate *source_pad_template;
//MAIN
if (!(source_pad_template =
gst_element_class_get_pad_template(GST_ELEMENT_GET_CLASS(ctx.tee_element),
"src_%u")))
{
fprintf(stderr, "Error getting source pad template\n");
return -1;
}
if (!(ctx.tee_pad = gst_element_request_pad(ctx.tee_element,
source_pad_template, NULL,
NULL)))
{
fprintf(stderr, "Error requesting main pipeline tee pad\n");
return -1;
}
if (!(ctx.tee_pad_ghost = gst_ghost_pad_new(NULL, ctx.tee_pad)))
{
fprintf(stderr, "Error creating ghost pad\n");
return -1;
}
gst_pad_set_active(ctx.tee_pad_ghost, TRUE);
if (!gst_element_add_pad(ctx.primary_bin, ctx.tee_pad_ghost))
{
fprintf(stderr, "Error adding ghost pad to Main pipeline\n");
return -1;
}
//SECONDARY
if (!(ctx.link_element_pad =
gst_element_get_static_pad(ctx.link_element_in_secondary_bin, "sink")))
{
fprintf(stderr, "Error requesting sink pad\n");
return -1;
}
if (!(ctx.link_element_pad_ghost = gst_ghost_pad_new(NULL,
ctx.link_element_pad)))
{
fprintf(stderr, "Error creating ghost pad\n");
return -1;
}
gst_pad_set_active(ctx.link_element_pad_ghost, TRUE);
if (!gst_element_add_pad(ctx.secondary_bin, ctx.link_element_pad_ghost))
{
fprintf(stderr, "Error adding ghost pad to BIN\n");
return -1;
}
return 0;
}
static int
connect_secondary_bin()
{
if (request_pads() < 0)
return -1;
if (!(gst_bin_add(GST_BIN(ctx.main_pipeline), ctx.secondary_bin)))
{
fprintf(stderr, "Error adding bin to main pipeline\n");
return -1;
}
fprintf(stdout, "SETTING NEW TO PLAY\n");
if (gst_element_set_state(ctx.secondary_bin, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE)
{
fprintf(stderr, "Error setting secondary bin in play mode\n");
return -1;
}
fprintf(stdout, "LINKING PADS\n");
if (gst_pad_link(ctx.tee_pad_ghost, ctx.link_element_pad_ghost) !=
GST_PAD_LINK_OK)
{
fprintf(stderr, "Error connecting source pad to sink pad\n");
return -1;
}
// if (!(gst_pad_link(ctx.tee_pad_ghost, ctx.link_element_pad_ghost)))
// {
// fprintf(stderr, "Error connecting source pad to sink pad\n");
// return -1;
// }
return 0;
}
// static GstPadProbeReturn
// event_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
// {
// fprintf(stderr, "TE\n");
// 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));
// fprintf(stderr, "Starting DISCONNECTION\n");
// gst_element_set_state(ctx.secondary_bin, GST_STATE_NULL);
// gst_bin_remove(GST_BIN(ctx.main_pipeline), ctx.secondary_bin);
// gst_element_release_request_pad(ctx.tee_element, ctx.tee_pad_ghost);
// gst_element_release_request_pad(ctx.tee_element, ctx.tee_pad);
// gst_object_unref(ctx.tee_pad);
// gst_object_unref(ctx.tee_pad_ghost);
// fprintf(stderr, "DISCONNECTION DONE\n");
// return GST_PAD_PROBE_DROP;
// }
// static GstPadProbeReturn
// pad_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
// {
// fprintf(stderr, "PAD PROBE 1\n");
// gst_pad_remove_probe(pad, GST_PAD_PROBE_INFO_ID(info));
// fprintf(stderr, "Add another probe\n");
// gst_pad_add_probe(ctx.tee_pad_ghost,
// GST_PAD_PROBE_TYPE_BLOCK |
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback)event_probe_cb,
NULL, NULL);
// fprintf(stderr, "Sending EOS\n");
// if (!(gst_pad_send_event(ctx.link_element_pad_ghost,
gst_event_new_eos())))
// {
// fprintf(stderr, "Error sending EOS to sink PAD\n");
// return GST_PAD_PROBE_OK;
// }
// fprintf(stderr, "EOS sent\n");
// return GST_PAD_PROBE_OK;
// }
// static gboolean
// timeout_cb(gpointer user_data)
// {
// gst_pad_add_probe(ctx.tee_pad_ghost,
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
// (GstPadProbeCallback)pad_probe_cb, (gpointer)NULL,
NULL);
// return FALSE;
// }
static gboolean
timeout2_cb(gpointer user_data)
{
if (connect_secondary_bin() < 0)
exit(1);
return FALSE;
}
int main()
{
gst_init(NULL, NULL);
if (!(ctx.app_loop = g_main_loop_new(NULL, FALSE)))
{
fprintf(stderr, "Error allocating main application loop\n");
exit(1);
}
if (create_main_pipeline() < 0)
exit(1);
if (create_secondary_bin() < 0)
exit(1);
if (gst_element_set_state(ctx.main_pipeline, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE)
{
fprintf(stderr, "Error during set to play of pipeline\n");
exit(1);
}
g_timeout_add(5000, (GSourceFunc)timeout2_cb, NULL);
//g_timeout_add(10000, (GSourceFunc)timeout_cb, NULL);
g_main_loop_run(ctx.app_loop);
}
What could be the problem?
Thank you very much
Matteo
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/gstreamer-devel/attachments/20211121/256475a9/attachment.htm>
More information about the gstreamer-devel
mailing list