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