Change pipeline encoder h264 to h265 at runtime

Anton Pryima zingfrid at gmail.com
Mon Dec 7 12:12:19 UTC 2020


Hello,

>From my quick look, I can suggest next:
You're blocking Downstream at the decodebin's pad. But as I understand from
your code, EOS event travels downstream from the encoder to udpsink.
So, you should consider or block upstream on the udpsink, or catch EOS
event before it went downstream, or re-initialize udpsink (through
READY->PLAYING) STATES again.
But IMHO, you should avoid sending EOS (as you do not actually have EOS,
'cos you're planning to continue streaming with another encoding)

Best regards,
Anton.


On Mon, Dec 7, 2020 at 1:25 AM MustafaBkrc <mustafa.bkrc93 at gmail.com> wrote:

> Hello,
>
> I have an issue about changing GStreamer encoder elements, h264 to h265, at
> runtime. I followed the instruction and used example code from gstreamer
> pipeline manipulation.
>
>
> https://gstreamer.freedesktop.org/documentation/application-development/advanced/pipeline-manipulation.html?gi-language=c#dynamically-changing-the-pipeline
> <
> https://gstreamer.freedesktop.org/documentation/application-development/advanced/pipeline-manipulation.html?gi-language=c#dynamically-changing-the-pipeline>
>
>
> I can successfully change the h264 to h265 encoder element at runtime but I
> think there are something left about the h264 encoder signature in the
> pipeline and also I cannot get the frame from pipeline  these is the output
> from ffplay command (ffplay  udp://@:9000?listen -analyzeduration 1M)
>
>
> https://i.stack.imgur.com/auV14.png
>
> I wonder how can I overcome this issue, is it about a timing issue or
> something? I would be very appreciated of any help. Thanks.
>
> This is the full code
>
>     #include <iostream>
>     #include <gst/gst.h>
>     #include <thread>
>     #include <unistd.h>
>
>     using namespace std;
>
>     /// Example Pipeline ///
>     //gst-launch-1.0 filesrc
> location=/home/ubuntu18/Desktop/BigBuckBunny.mp4 ! video/x-raw,
> width=1920,
>     //height=1080, format=NV16_LE32, framerate=60/1 ! decodebin ! x264enc !
> mpegtsmux alignment=7 !
>     //udpsink host=127.0.0.1 port=9000 --gst-debug=3
>
>     static gboolean my_bus_callback (GstBus * bus, GstMessage * message,
> gpointer data);
>
>         struct GstreamerStream
>         {
>             GstElement *pipeline;
>             GstElement *filesrc;
>             GstElement *capsfilter;
>             GstElement *decodebin;
>             GstElement *x264enc;
>             GstElement *x265enc;
>             GstElement *mpegtsmux1;
>             GstElement *udpsink1 ;
>
>             GstPad *decodebinPad;
>
>             GMainLoop *loop;
>             GstBus    *bus;
>             GstMessage  *msg;
>         };
>
>         void signal_cb (GstElement* object, GstPad* pad, gpointer
> user_data)
>         {
>             auto data = reinterpret_cast<GstreamerStream*>(user_data);
>             GstPad *decodebin_src_pad= gst_element_get_static_pad (object,
> "src%u");
>             GstPad* x264enc_sink_pad =
> gst_element_get_static_pad(data->x264enc,"sink");
>
>             g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME
> (pad), GST_ELEMENT_NAME (object));
>
>             /* If our converter is already linked, we have nothing to do
> here */
>             if (gst_pad_is_linked (pad)) {
>               g_print ("We are already linked. Ignoring.\n");
>             }
>
>             /* Attempt the link */
>             auto ret = gst_pad_link (pad, x264enc_sink_pad);
>
>             if (GST_PAD_LINK_FAILED (ret)) {
>               g_print ("Type is '%s' but link failed.\n", pad);
>             } else {
>               g_print ("Link succeeded (type '%s').\n", pad);
>               data->decodebinPad = pad;
>             }
>
>             gst_object_unref (x264enc_sink_pad);
>         }
>
>         static GstPadProbeReturn
>         event_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer
> user_data)
>         {
>             auto stream =  reinterpret_cast<GstreamerStream*>(user_data);
>
>             GstElement *next = stream->x265enc;
>
>             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));
>
>             g_print ("Switching from '%s' to '%s'..\n", GST_OBJECT_NAME
> (stream->x264enc),
>                 GST_OBJECT_NAME (next));
>
>             gst_element_set_state (stream->x264enc, GST_STATE_NULL);
>
>             /* remove unlinks automatically */
>             GST_DEBUG_OBJECT (stream->pipeline, "removing %"
> GST_PTR_FORMAT,
> stream->x264enc);
>             gst_bin_remove (GST_BIN (stream->pipeline), stream->x264enc);
>
>             GST_DEBUG_OBJECT (stream->pipeline, "adding   %"
> GST_PTR_FORMAT,
> next);
>             gst_bin_add (GST_BIN (stream->pipeline), next);
>
>             auto enc265sinkpad = gst_element_get_static_pad(next,"sink");
>             if(!gst_pad_link(stream->decodebinPad,enc265sinkpad))
>               std::cout << "Linked src and sink pad success " << std::endl;
>
>             GST_DEBUG_OBJECT (stream->pipeline, "linking..");
>
>             gst_element_link_many (next, stream->mpegtsmux1, NULL);
>             gst_element_sync_state_with_parent(next);
>             GST_DEBUG_OBJECT (stream->pipeline, "done");
>
>             auto elem =
> gst_bin_get_by_name(GST_BIN(stream->pipeline),"x265enc_elem");
>             if(elem)
>                 std::cout <<" ***** Element name : " <<
> GST_OBJECT_NAME(elem) << " *****" << std::endl;
>             else
>             {
>                 auto elem2 =
> gst_bin_get_by_name(GST_BIN(stream->pipeline),"x264enc_elem");
>                 std::cout <<" ***** Element name : " <<
> GST_OBJECT_NAME(elem2) << " *****" << std::endl;
>             }
>
>           return GST_PAD_PROBE_DROP;
>         }
>
>
>         static GstPadProbeReturn
>         pad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer
> user_data)
>         {
>           GstPad *srcpad, *sinkpad;
>           auto stream = reinterpret_cast<GstreamerStream*>(user_data);
>
>           GST_DEBUG_OBJECT (pad, "pad is blocked now");
>
>           /* remove the probe first */
>           gst_pad_remove_probe (pad, GST_PAD_PROBE_INFO_ID (info));
>           auto filesrcPad =
> gst_element_get_static_pad(stream->filesrc,"src");
>
>           /* install new probe for EOS */
>           srcpad = gst_element_get_static_pad (stream->x264enc, "src");
>
>           gst_pad_add_probe (srcpad,
> static_cast<GstPadProbeType>(GST_PAD_PROBE_TYPE_BLOCK |
>               GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM), event_probe_cb,
> user_data, NULL);
>           gst_object_unref (srcpad);
>
>           /* push EOS into the element, the probe will be fired when the
>            * EOS leaves the effect and it has thus drained all of its data
> */
>           sinkpad = gst_element_get_static_pad (stream->x264enc, "sink");
>           gst_pad_send_event (sinkpad, gst_event_new_eos ());
>
>           gst_object_unref (sinkpad);
>
>           return GST_PAD_PROBE_OK;
>         }
>
>         static gboolean
>         timeout_cb (gpointer user_data)
>         {
>             auto stream = reinterpret_cast<GstreamerStream*>(user_data);
>             auto blockPad = stream->decodebinPad;
>
>             std::cout  << "Pad name : " << (GST_DEBUG_PAD_NAME(blockPad))
> <<
> std::endl;
>
>           gst_pad_add_probe (blockPad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
>               pad_probe_cb, user_data, NULL);
>
>
>           return TRUE;
>         }
>
>         int main()
>         {
>
>             gst_init(NULL,NULL);
>
>             static GstreamerStream stream;
>             stream.pipeline =
> gst_element_factory_make("pipeline","pipeline_elem");
>             stream.filesrc =
> gst_element_factory_make("filesrc","filesrc_elem");
>             stream.capsfilter =
> gst_element_factory_make("capsfilter","capsfilter_elem");
>             stream.decodebin =
> gst_element_factory_make("decodebin","decodebin_elem");
>
>             stream.x264enc =
> gst_element_factory_make("x264enc","x264enc_elem");
>             stream.x265enc =
> gst_element_factory_make("x265enc","x265enc_elem");
>             stream.mpegtsmux1 =
> gst_element_factory_make("mpegtsmux","mpegtsmux_element");
>             stream.udpsink1 =
> gst_element_factory_make("udpsink","udpsink_element");
>
>             if(!stream.pipeline, !stream.filesrc || !stream.capsfilter ||
> !stream.decodebin  || !stream.x264enc || !stream.mpegtsmux1 ||
> !stream.udpsink1)
>             {
>                 g_error("Element create error");
>             }
>
>
>
> g_object_set(stream.filesrc,"location","/home/mbkrc/Desktop/ElephantsDream.mp4",NULL);
>
>
>             g_object_set(stream.mpegtsmux1,"alignment",7,NULL);
>
> g_object_set(stream.udpsink1,"host","127.0.0.1","port",9000,"sync", FALSE,
> "async", FALSE,NULL);
>             g_object_set (G_OBJECT (stream.x264enc), "bitrate", 1000,
> NULL);
>
>
>
>
> gst_bin_add_many(GST_BIN(stream.pipeline),stream.filesrc,stream.capsfilter,stream.decodebin,stream.x264enc,
>                              stream.mpegtsmux1,stream.udpsink1,NULL);
>
>
>            auto newCaps = gst_caps_new_simple("video/x-raw",
>                    "width", G_TYPE_INT, 1920,
>                    "height", G_TYPE_INT, 1080,
>                    "framerate", GST_TYPE_FRACTION, 60, 1, NULL);
>
>            g_object_set(stream.capsfilter,"caps",newCaps,NULL);
>
>
>
> gst_element_link_many(stream.filesrc,stream.capsfilter,stream.decodebin,NULL);
>
>
>
> if(!gst_element_link_many(stream.x264enc,stream.mpegtsmux1,stream.udpsink1,NULL))
>                 std::cerr << "Link Failed" << std::endl;
>
>
>
> g_signal_connect(stream.decodebin,"pad-added",(GCallback)signal_cb,&stream);
>
>             stream.bus = gst_pipeline_get_bus (GST_PIPELINE
> (stream.pipeline));
>             auto bus_watch_id = gst_bus_add_watch (stream.bus,
> my_bus_callback, stream.loop);
>             gst_object_unref (stream.bus);
>
>
>             gst_element_set_state(stream.pipeline,GST_STATE_PLAYING);
>
>             std::thread th{[&]()
>                            {
>                             sleep(5);
>                             timeout_cb(&stream);
>                            }};
>
>             stream.loop = g_main_loop_new (NULL, FALSE);
>             g_main_loop_run (stream.loop);
>
>             /* clean up */
>             gst_element_set_state (stream.pipeline, GST_STATE_NULL);
>             gst_object_unref (stream.pipeline);
>             g_source_remove (bus_watch_id);
>             g_main_loop_unref (stream.loop);
>
>             return 0;
>         }
>
>         static gboolean
>         my_bus_callback (GstBus * bus, GstMessage * message, gpointer data)
>         {
>           g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message));
>           auto loop = reinterpret_cast<GMainLoop*>(data);
>
>           switch (GST_MESSAGE_TYPE (message)) {
>             case GST_MESSAGE_ERROR:{
>               GError *err;
>               gchar *debug;
>
>               gst_message_parse_error (message, &err, &debug);
>               g_print ("Error: %s\n", err->message);
>               g_error_free (err);
>               g_free (debug);
>
>               g_main_loop_quit (loop);
>               break;
>             }
>           case GST_MESSAGE_ASYNC_DONE:
>           {
>               std::cout << "Asyn Done : " << std::endl;
>               break;
>           }
>             case GST_MESSAGE_EOS:
>               /* end-of-stream */
>               g_main_loop_quit (loop);
>               break;
>             default:
>               /* unhandled message */
>               break;
>           }
>         }
>         `
>
>
>  Hello,
>
> I have an issue about changing GStreamer encoder elements, h264 to h265, at
> runtime. I followed the instruction and used example code from [gstreamer
> pipeline manipulation at runtime][1]
>
>
> I can successfully change the h264 to h265 encoder element at runtime but I
> think there are something left about the h264 encoder signature in the
> pipeline and also I cannot get the frame from pipeline  these is the output
> from ffplay command (ffplay  udp://@:9000?listen -analyzeduration
>
> 1M)org/documentation/application-development/advanced/pipeline-manipulation.html?gi-language=c#dynamically-changing-the-pipeline
>   [2]: https://i.stack.imgur.com/auV14.png
>
> I wonder how can I overcome this issue, is it about a timing issue or
> something? I would be very appreciated of any help. Thanks.
>
> This is the full code
>
>     #include <iostream>
>     #include <gst/gst.h>
>     #include <thread>
>     #include <unistd.h>
>
>     using namespace std;
>
>     /// Example Pipeline ///
>     //gst-launch-1.0 filesrc
> location=/home/ubuntu18/Desktop/BigBuckBunny.mp4 ! video/x-raw,
> width=1920,
>     //height=1080, format=NV16_LE32, framerate=60/1 ! decodebin ! x264enc !
> mpegtsmux alignment=7 !
>     //udpsink host=127.0.0.1 port=9000 --gst-debug=3
>
>     static gboolean my_bus_callback (GstBus * bus, GstMessage * message,
> gpointer data);
>
>         struct GstreamerStream
>         {
>             GstElement *pipeline;
>             GstElement *filesrc;
>             GstElement *capsfilter;
>             GstElement *decodebin;
>             GstElement *x264enc;
>             GstElement *x265enc;
>             GstElement *mpegtsmux1;
>             GstElement *udpsink1 ;
>
>             GstPad *decodebinPad;
>
>             GMainLoop *loop;
>             GstBus    *bus;
>             GstMessage  *msg;
>         };
>
>         void signal_cb (GstElement* object, GstPad* pad, gpointer
> user_data)
>         {
>             auto data = reinterpret_cast<GstreamerStream*>(user_data);
>             GstPad *decodebin_src_pad= gst_element_get_static_pad (object,
> "src%u");
>             GstPad* x264enc_sink_pad =
> gst_element_get_static_pad(data->x264enc,"sink");
>
>             g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME
> (pad), GST_ELEMENT_NAME (object));
>
>             /* If our converter is already linked, we have nothing to do
> here */
>             if (gst_pad_is_linked (pad)) {
>               g_print ("We are already linked. Ignoring.\n");
>             }
>
>             /* Attempt the link */
>             auto ret = gst_pad_link (pad, x264enc_sink_pad);
>
>             if (GST_PAD_LINK_FAILED (ret)) {
>               g_print ("Type is '%s' but link failed.\n", pad);
>             } else {
>               g_print ("Link succeeded (type '%s').\n", pad);
>               data->decodebinPad = pad;
>             }
>
>             gst_object_unref (x264enc_sink_pad);
>         }
>
>         static GstPadProbeReturn
>         event_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer
> user_data)
>         {
>             auto stream =  reinterpret_cast<GstreamerStream*>(user_data);
>
>             GstElement *next = stream->x265enc;
>
>             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));
>
>             g_print ("Switching from '%s' to '%s'..\n", GST_OBJECT_NAME
> (stream->x264enc),
>                 GST_OBJECT_NAME (next));
>
>             gst_element_set_state (stream->x264enc, GST_STATE_NULL);
>
>             /* remove unlinks automatically */
>             GST_DEBUG_OBJECT (stream->pipeline, "removing %"
> GST_PTR_FORMAT,
> stream->x264enc);
>             gst_bin_remove (GST_BIN (stream->pipeline), stream->x264enc);
>
>             GST_DEBUG_OBJECT (stream->pipeline, "adding   %"
> GST_PTR_FORMAT,
> next);
>             gst_bin_add (GST_BIN (stream->pipeline), next);
>
>             auto enc265sinkpad = gst_element_get_static_pad(next,"sink");
>             if(!gst_pad_link(stream->decodebinPad,enc265sinkpad))
>               std::cout << "Linked src and sink pad success " << std::endl;
>
>             GST_DEBUG_OBJECT (stream->pipeline, "linking..");
>
>             gst_element_link_many (next, stream->mpegtsmux1, NULL);
>             gst_element_sync_state_with_parent(next);
>             GST_DEBUG_OBJECT (stream->pipeline, "done");
>
>             auto elem =
> gst_bin_get_by_name(GST_BIN(stream->pipeline),"x265enc_elem");
>             if(elem)
>                 std::cout <<" ***** Element name : " <<
> GST_OBJECT_NAME(elem) << " *****" << std::endl;
>             else
>             {
>                 auto elem2 =
> gst_bin_get_by_name(GST_BIN(stream->pipeline),"x264enc_elem");
>                 std::cout <<" ***** Element name : " <<
> GST_OBJECT_NAME(elem2) << " *****" << std::endl;
>             }
>
>           return GST_PAD_PROBE_DROP;
>         }
>
>
>         static GstPadProbeReturn
>         pad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer
> user_data)
>         {
>           GstPad *srcpad, *sinkpad;
>           auto stream = reinterpret_cast<GstreamerStream*>(user_data);
>
>           GST_DEBUG_OBJECT (pad, "pad is blocked now");
>
>           /* remove the probe first */
>           gst_pad_remove_probe (pad, GST_PAD_PROBE_INFO_ID (info));
>           auto filesrcPad =
> gst_element_get_static_pad(stream->filesrc,"src");
>
>           /* install new probe for EOS */
>           srcpad = gst_element_get_static_pad (stream->x264enc, "src");
>
>           gst_pad_add_probe (srcpad,
> static_cast<GstPadProbeType>(GST_PAD_PROBE_TYPE_BLOCK |
>               GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM), event_probe_cb,
> user_data, NULL);
>           gst_object_unref (srcpad);
>
>           /* push EOS into the element, the probe will be fired when the
>            * EOS leaves the effect and it has thus drained all of its data
> */
>           sinkpad = gst_element_get_static_pad (stream->x264enc, "sink");
>           gst_pad_send_event (sinkpad, gst_event_new_eos ());
>
>           gst_object_unref (sinkpad);
>
>           return GST_PAD_PROBE_OK;
>         }
>
>         static gboolean
>         timeout_cb (gpointer user_data)
>         {
>             auto stream = reinterpret_cast<GstreamerStream*>(user_data);
>             auto blockPad = stream->decodebinPad;
>
>             std::cout  << "Pad name : " << (GST_DEBUG_PAD_NAME(blockPad))
> <<
> std::endl;
>
>           gst_pad_add_probe (blockPad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
>               pad_probe_cb, user_data, NULL);
>
>
>           return TRUE;
>         }
>
>         int main()
>         {
>
>             gst_init(NULL,NULL);
>
>             static GstreamerStream stream;
>             stream.pipeline =
> gst_element_factory_make("pipeline","pipeline_elem");
>             stream.filesrc =
> gst_element_factory_make("filesrc","filesrc_elem");
>             stream.capsfilter =
> gst_element_factory_make("capsfilter","capsfilter_elem");
>             stream.decodebin =
> gst_element_factory_make("decodebin","decodebin_elem");
>
>             stream.x264enc =
> gst_element_factory_make("x264enc","x264enc_elem");
>             stream.x265enc =
> gst_element_factory_make("x265enc","x265enc_elem");
>             stream.mpegtsmux1 =
> gst_element_factory_make("mpegtsmux","mpegtsmux_element");
>             stream.udpsink1 =
> gst_element_factory_make("udpsink","udpsink_element");
>
>             if(!stream.pipeline, !stream.filesrc || !stream.capsfilter ||
> !stream.decodebin  || !stream.x264enc || !stream.mpegtsmux1 ||
> !stream.udpsink1)
>             {
>                 g_error("Element create error");
>             }
>
>
>
> g_object_set(stream.filesrc,"location","/home/mbkrc/Desktop/ElephantsDream.mp4",NULL);
>
>
>             g_object_set(stream.mpegtsmux1,"alignment",7,NULL);
>
> g_object_set(stream.udpsink1,"host","127.0.0.1","port",9000,"sync", FALSE,
> "async", FALSE,NULL);
>             g_object_set (G_OBJECT (stream.x264enc), "bitrate", 1000,
> NULL);
>
>
>
>
> gst_bin_add_many(GST_BIN(stream.pipeline),stream.filesrc,stream.capsfilter,stream.decodebin,stream.x264enc,
>                              stream.mpegtsmux1,stream.udpsink1,NULL);
>
>
>            auto newCaps = gst_caps_new_simple("video/x-raw",
>                    "width", G_TYPE_INT, 1920,
>                    "height", G_TYPE_INT, 1080,
>                    "framerate", GST_TYPE_FRACTION, 60, 1, NULL);
>
>            g_object_set(stream.capsfilter,"caps",newCaps,NULL);
>
>
>
> gst_element_link_many(stream.filesrc,stream.capsfilter,stream.decodebin,NULL);
>
>
>
> if(!gst_element_link_many(stream.x264enc,stream.mpegtsmux1,stream.udpsink1,NULL))
>                 std::cerr << "Link Failed" << std::endl;
>
>
>
> g_signal_connect(stream.decodebin,"pad-added",(GCallback)signal_cb,&stream);
>
>             stream.bus = gst_pipeline_get_bus (GST_PIPELINE
> (stream.pipeline));
>             auto bus_watch_id = gst_bus_add_watch (stream.bus,
> my_bus_callback, stream.loop);
>             gst_object_unref (stream.bus);
>
>
>             gst_element_set_state(stream.pipeline,GST_STATE_PLAYING);
>
>             std::thread th{[&]()
>                            {
>                             sleep(5);
>                             timeout_cb(&stream);
>                            }};
>
>             stream.loop = g_main_loop_new (NULL, FALSE);
>             g_main_loop_run (stream.loop);
>
>             /* clean up */
>             gst_element_set_state (stream.pipeline, GST_STATE_NULL);
>             gst_object_unref (stream.pipeline);
>             g_source_remove (bus_watch_id);
>             g_main_loop_unref (stream.loop);
>
>             return 0;
>         }
>
>         static gboolean
>         my_bus_callback (GstBus * bus, GstMessage * message, gpointer data)
>         {
>           g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message));
>           auto loop = reinterpret_cast<GMainLoop*>(data);
>
>           switch (GST_MESSAGE_TYPE (message)) {
>             case GST_MESSAGE_ERROR:{
>               GError *err;
>               gchar *debug;
>
>               gst_message_parse_error (message, &err, &debug);
>               g_print ("Error: %s\n", err->message);
>               g_error_free (err);
>               g_free (debug);
>
>               g_main_loop_quit (loop);
>               break;
>             }
>           case GST_MESSAGE_ASYNC_DONE:
>           {
>               std::cout << "Asyn Done : " << std::endl;
>               break;
>           }
>             case GST_MESSAGE_EOS:
>               /* end-of-stream */
>               g_main_loop_quit (loop);
>               break;
>             default:
>               /* unhandled message */
>               break;
>           }
>         }
>         `
>
>
>
>
>
>
> --
> Sent from: http://gstreamer-devel.966125.n4.nabble.com/
> _______________________________________________
> gstreamer-devel mailing list
> gstreamer-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/gstreamer-devel/attachments/20201207/e5f437dc/attachment-0001.htm>


More information about the gstreamer-devel mailing list