Change pipeline encoder h264 to h265 at runtime

MustafaBkrc mustafa.bkrc93 at gmail.com
Sun Dec 6 20:56:45 UTC 2020


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/


More information about the gstreamer-devel mailing list