So, I've been walking through the tutorials and trying to work out the
exercises for my own edification. The exercise: Dynamic pad linking has traditionally been a difficult topic for a lot of programmers. Prove that you have achieved its mastery by instantiating an autovideosink (probably with an ffmpegcolorspace in front) and link it to the demuxer when the right pad appears. Hint: You are already printing on screen the type of the video pads. So, I've played around with this and am kind of stuck. It sure seems like I need to add a tee to the pipeline, then attach the audio converter and video converter. But the basic tutorial #3 doesn't really seem to mention tees (they aren't mentioned in the tutorial at all until basic tutorial 7). Am I barking up the wrong tree here? Anyone have the solved exercise that they can pass on? It feels like cheating, but hey, I'd love to see 'the right way' Here's the original Tuturial code for v.10 #include <gst/gst.h> /* Structure to contain all our information, so we can pass it to callbacks */ typedef struct _CustomData { GstElement *pipeline; GstElement *source; GstElement *convert; GstElement *sink; } CustomData; /* Handler for the pad-added signal */ static void pad_added_handler (GstElement *src, GstPad *pad, CustomData *data); int main(int argc, char *argv[]) { CustomData data; GstBus *bus; GstMessage *msg; GstStateChangeReturn ret; gboolean terminate = FALSE; /* Initialize GStreamer */ gst_init (&argc, &argv); /* Create the elements */ data.source = gst_element_factory_make ("uridecodebin", "source"); data.convert = gst_element_factory_make ("audioconvert", "convert"); data.sink = gst_element_factory_make ("autoaudiosink", "sink"); /* Create the empty pipeline */ data.pipeline = gst_pipeline_new ("test-pipeline"); if (!data.pipeline || !data.source || !data.convert || !data.sink) { g_printerr ("Not all elements could be created.\n"); return -1; } /* Build the pipeline. Note that we are NOT linking the source at this * point. We will do it later. */ gst_bin_add_many (GST_BIN (data.pipeline), data.source, data.convert , data.sink, NULL); if (!gst_element_link (data.convert, data.sink)) { g_printerr ("Elements could not be linked.\n"); gst_object_unref (data.pipeline); return -1; } /* Set the URI to play */ g_object_set (data.source, "uri", "http://docs.gstreamer.com/media/sintel_trailer-480p.webm", NULL); /* Connect to the pad-added signal */ g_signal_connect (data.source, "pad-added", G_CALLBACK (pad_added_handler), &data); /* Start playing */ ret = gst_element_set_state (data.pipeline, 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.pipeline); return -1; } /* Listen to the bus */ bus = gst_element_get_bus (data.pipeline); do { msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS); /* Parse message */ if (msg != NULL) { GError *err; gchar *debug_info; switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_ERROR: gst_message_parse_error (msg, &err, &debug_info); g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message); g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none"); g_clear_error (&err); g_free (debug_info); terminate = TRUE; break; case GST_MESSAGE_EOS: g_print ("End-Of-Stream reached.\n"); terminate = TRUE; break; case GST_MESSAGE_STATE_CHANGED: /* We are only interested in state-changed messages from the pipeline */ if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data.pipeline)) { GstState old_state, new_state, pending_state; gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state); g_print ("Pipeline state changed from %s to %s:\n", gst_element_state_get_name (old_state), gst_element_state_get_name (new_state)); } break; default: /* We should not reach here */ g_printerr ("Unexpected message received.\n"); break; } gst_message_unref (msg); } } while (!terminate); /* Free resources */ gst_object_unref (bus); gst_element_set_state (data.pipeline, GST_STATE_NULL); gst_object_unref (data.pipeline); return 0; } /* This function will be called by the pad-added signal */ static void pad_added_handler (GstElement *src, GstPad *new_pad, CustomData *data) { GstPad *sink_pad = gst_element_get_static_pad (data->convert, "sink"); GstPadLinkReturn ret; GstCaps *new_pad_caps = NULL; GstStructure *new_pad_struct = NULL; const gchar *new_pad_type = NULL; g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (new_pad), GST_ELEMENT_NAME (src)); /* If our converter is already linked, we have nothing to do here */ if (gst_pad_is_linked (sink_pad)) { g_print (" We are already linked. Ignoring.\n"); goto exit; } /* Check the new pad's type */ new_pad_caps = gst_pad_get_caps (new_pad); new_pad_struct = gst_caps_get_structure (new_pad_caps, 0); new_pad_type = gst_structure_get_name (new_pad_struct); if (!g_str_has_prefix (new_pad_type, "audio/x-raw")) { g_print (" It has type '%s' which is not raw audio. Ignoring.\n", new_pad_type); goto exit; } /* Attempt the link */ ret = gst_pad_link (new_pad, sink_pad); if (GST_PAD_LINK_FAILED (ret)) { g_print (" Type is '%s' but link failed.\n", new_pad_type); } else { g_print (" Link succeeded (type '%s').\n", new_pad_type); } exit: /* Unreference the new pad's caps, if we got them */ if (new_pad_caps != NULL) gst_caps_unref (new_pad_caps); /* Unreference the sink pad */ gst_object_unref (sink_pad); } --- This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
On Mon, 1 Aug 2016, at 11:11 AM, Mike Grommet wrote:
> So, I've been walking through the tutorials and trying to work out the > exercises for my own edification. > > The exercise: > > Dynamic pad linking has traditionally been a difficult topic for a lot > of programmers. Prove that you have achieved its mastery by > instantiating an autovideosink (probably with an ffmpegcolorspace in > front) and link it to the demuxer when the right pad appears. Hint: You > are already printing on screen the type of the video pads. > > So, I've played around with this and am kind of stuck. It sure seems > like I need to add a tee to the pipeline, then attach the audio > converter and video converter. > > But the basic tutorial #3 doesn't really seem to mention tees (they > aren't mentioned in the tutorial at all until basic tutorial 7). > > Am I barking up the wrong tree here? Anyone have the solved exercise > that they can pass on? It feels like cheating, but hey, I'd love to see > 'the right way' A tee is almost certainly not what you want here (it just provides the same data on two pads, so it's not going to separate your audio and video for example). Could you describe exactly what problem you see when using the code you posted? -- Arun _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
The example code you've posted adds an audioconvert -> autoaudiosink stage. I think from what you're saying, you want to add a videoconvert -> autovideosink stage as well? If so, the procedure is that same as for linking the audioconverter. In main(), create your videoconvert and autovideosink elements, link them and add them to the pipeline. In the pad added handler, you'll need to decide whether to link the newly added pad to the audioconvert or videoconvert element based upon the pad caps; if it's audio/x-raw, link to the audioconvert element, if it's video/x-raw, link to the videoconvert element.On 4 August 2016 at 13:43, Arun Raghavan <[hidden email]> wrote: On Mon, 1 Aug 2016, at 11:11 AM, Mike Grommet wrote: _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
In reply to this post by Mike Grommet
Hey there. I go this working. Here is the solution I used.
#include <gst/gst.h> /* Structure to contain all our information, so we can pass it to callbacks */ typedef struct _CustomData { GstElement *pipeline; GstElement *source; GstElement *convert; GstElement *sink; GstElement *video_convert, *video_sink;//for video } CustomData; /* Handler for the pad-added signal */ static void pad_added_handler (GstElement *src, GstPad *pad, CustomData *data); int main(int argc, char *argv[]) { CustomData data; GstBus *bus; GstMessage *msg; GstStateChangeReturn ret; gboolean terminate = FALSE; /* Initialize GStreamer */ gst_init (&argc, &argv); /* Create the elements */ data.source = gst_element_factory_make ("uridecodebin", "source"); data.convert = gst_element_factory_make ("audioconvert", "convert"); data.sink = gst_element_factory_make ("autoaudiosink", "sink"); /* * Dynamic pad linking has traditionally been a difficult topic for a lot of programmers. * Prove that you have achieved its mastery by instantiating an autovideosink (probably with an videoconvert in front) * and link it to the demuxer when the right pad appears. * Hint: You are already printing on screen the type of the video pads. */ /* * FYI * * data.video_convert = gst_element_factory_make ("videoconvert", "convert"); data.video_sink = gst_element_factory_make ("autovideosink", "sink"); * * (john-test:10082): GStreamer-WARNING **: Name 'convert' is not unique in bin 'test-pipeline', not adding (john-test:10082): GStreamer-WARNING **: Name 'sink' is not unique in bin 'test-pipeline', not adding * */ data.video_convert = gst_element_factory_make ("videoconvert", "vid_convert"); data.video_sink = gst_element_factory_make ("autovideosink", "vid_sink"); /* Create the empty pipeline */ data.pipeline = gst_pipeline_new ("test-pipeline"); if (!data.pipeline || !data.source || !data.convert || !data.sink || !data.video_convert || !data.video_sink) { g_printerr ("Not all elements could be created.\n"); return -1; } /* Build the pipeline. Note that we are NOT linking the source at this */ gst_bin_add_many (GST_BIN (data.pipeline), data.source, data.convert, data.sink, data.video_convert, data.video_sink, NULL); if (!gst_element_link (data.convert, data.sink)) { g_printerr ("audio Elements could not be linked.\n"); gst_object_unref (data.pipeline); return -1; } if (!gst_element_link (data.video_convert, data.video_sink)) { g_printerr ("video Elements could not be linked.\n"); gst_object_unref (data.pipeline); return -1; } /* Set the URI to play */ g_object_set (data.source, "uri", "https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm", NULL); /* Connect to the pad-added signal */ g_signal_connect (data.source, "pad-added", G_CALLBACK (pad_added_handler), &data); /* Start playing */ ret = gst_element_set_state (data.pipeline, 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.pipeline); return -1; } /* Listen to the bus */ bus = gst_element_get_bus (data.pipeline); do { msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS); /* Parse message */ if (msg != NULL) { GError *err; gchar *debug_info; switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_ERROR: gst_message_parse_error (msg, &err, &debug_info); g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message); g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none"); g_clear_error (&err); g_free (debug_info); terminate = TRUE; break; case GST_MESSAGE_EOS: g_print ("End-Of-Stream reached.\n"); terminate = TRUE; break; case GST_MESSAGE_STATE_CHANGED: /* We are only interested in state-changed messages from the pipeline */ if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data.pipeline)) { GstState old_state, new_state, pending_state; gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state); g_print ("Pipeline state changed from %s to %s:\n", gst_element_state_get_name (old_state), gst_element_state_get_name (new_state)); } break; default: /* We should not reach here */ g_printerr ("Unexpected message received.\n"); break; } gst_message_unref (msg); } } while (!terminate); /* Free resources */ gst_object_unref (bus); gst_element_set_state (data.pipeline, GST_STATE_NULL); gst_object_unref (data.pipeline); return 0; } /* This function will be called by the pad-added signal */ static void pad_added_handler (GstElement *src, GstPad *new_pad, CustomData *data) { GstPad *sink_pad = NULL; GstPadLinkReturn ret; GstCaps *new_pad_caps = NULL; GstStructure *new_pad_struct = NULL; const gchar *new_pad_type = NULL; g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (new_pad), GST_ELEMENT_NAME (src)); /* Check the new pad's type */ new_pad_caps = gst_pad_get_current_caps (new_pad); new_pad_struct = gst_caps_get_structure (new_pad_caps, 0); new_pad_type = gst_structure_get_name (new_pad_struct); if (g_str_has_prefix (new_pad_type, "audio/x-raw")) { g_print ("init audio GstPad\n"); sink_pad = gst_element_get_static_pad (data->convert, "sink"); } else if(g_str_has_prefix (new_pad_type, "video/x-raw")) { g_print ("init video GstPad\n"); sink_pad = gst_element_get_static_pad (data->video_convert, "sink"); } else { g_print ("It has type '%s' which is not raw audio or video. Ignoring.\n", new_pad_type); goto exit; } /* If our converter is already linked, we have nothing to do here */ if (gst_pad_is_linked (sink_pad)) { g_print ("We are already linked. Ignoring.\n"); goto exit; } /* Attempt the link */ ret = gst_pad_link (new_pad, sink_pad); if (GST_PAD_LINK_FAILED (ret)) { g_print ("Type is '%s' but link failed for reason '%i'.\n", new_pad_type, ret); } else { g_print ("Link succeeded (type '%s').\n", new_pad_type); } exit: /* Unreference the new pad's caps, if we got them */ if (new_pad_caps != NULL) gst_caps_unref (new_pad_caps); /* Unreference the sink pad */ gst_object_unref (sink_pad); } -- Sent from: http://gstreamer-devel.966125.n4.nabble.com/ _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
Free forum by Nabble | Edit this page |