I’m trying to setup an application in C++ with gstreamer to read a .mov file encoded in h264 format.
I’ve try the following pipelines with success:
gst-launch-1.0 filesrc location=big_buck_bunny_720p_h264.mov ! qtdemux name=demux ! h264parse ! decodebin ! videoconvert ! videoscale ! autovideosink
gst-launch-1.0 filesrc location=big_buck_bunny_720p_h264.mov ! qtdemux name=demux ! h264parse ! qsvh264dec ! videoconvert ! videoscale ! autovideosink
gst-launch-1.0 filesrc location=big_buck_bunny_720p_h264.mov ! qtdemux name=demux ! h264parse ! d3d11h264dec ! videoconvert ! videoscale ! autovideosink
gst-launch-1.0 filesrc location=big_buck_bunny_720p_h264.mov ! qtdemux name=demux ! h264parse ! d3d11h264device1dec ! videoconvert ! videoscale ! autovideosink
gst-launch-1.0 filesrc location=big_buck_bunny_720p_h264.mov ! qtdemux name=demux ! h264parse ! openh264dec ! videoconvert ! videoscale ! autovideosink
gst-launch-1.0 filesrc location=big_buck_bunny_720p_h264.mov ! qtdemux name=demux ! h264parse ! nvh264dec ! videoconvert ! videoscale ! autovideosink
gst-launch-1.0 filesrc location=big_buck_bunny_720p_h264.mov ! qtdemux name=demux ! h264parse ! nvh264sldec ! videoconvert ! videoscale ! autovideosink
My code is as follow:
void Foo::init()
{
gst_init(0, NULL);
_pipelineEments.pipeline = gst_pipeline_new("video-player");
_pipelineEments._videoSrc = gst_element_factory_make("filesrc", "video_src");
_pipelineEments._qtdemux = gst_element_factory_make("qtdemux", "qtdemux_src");
_pipelineEments._h264parse = gst_element_factory_make("h264parse", "h264parse_src");
_pipelineEments._decodeBin = gst_element_factory_make("decodebin", "video_decode");
_pipelineEments._videoConvert = gst_element_factory_make("videoconvert", "video_convert");
_pipelineEments._videoScale = gst_element_factory_make("videoscale", "video_scale");
_pipelineEments._sink = GST_APP_SINK(gst_element_factory_make("appsink", "video_sink"));
VERIFY_GST_NULL(_pipelineEments.pipeline)
VERIFY_GST_NULL(_pipelineEments._videoSrc)
VERIFY_GST_NULL(_pipelineEments._qtdemux)
VERIFY_GST_NULL(_pipelineEments._h264parse)
VERIFY_GST_NULL(_pipelineEments._decodeBin)
VERIFY_GST_NULL(_pipelineEments._videoConvert)
VERIFY_GST_NULL(_pipelineEments._videoScale)
VERIFY_GST_NULL(_pipelineEments._sink)
gst_bin_add_many(GST_BIN (_pipelineEments.pipeline),
_pipelineEments._videoSrc,
_pipelineEments._qtdemux,
_pipelineEments._h264parse,
_pipelineEments._decodeBin,
_pipelineEments._videoConvert,
_pipelineEments._videoScale,
_pipelineEments._sink,
NULL);
gst_element_link_many(_pipelineEments._videoSrc,
_pipelineEments._qtdemux,
_pipelineEments._h264parse,
_pipelineEments._decodeBin,
_pipelineEments._videoConvert,
_pipelineEments._videoScale,
_pipelineEments._sink,
NULL);
gst_app_sink_set_emit_signals(_pipelineEments._sink, true);
gst_app_sink_set_drop(_pipelineEments._sink, true);
gst_app_sink_set_max_buffers(_pipelineEments._sink, 1);
gst_app_sink_set_caps(_pipelineEments._sink, gst_caps_new_simple("video/x-raw",
"format", G_TYPE_STRING, "BGRA",
"width", G_TYPE_INT, _videoWidth,
"height", G_TYPE_INT, _videoHeight,
NULL));
g_object_set (_pipelineEments._videoSrc, "location", file.c_str(), NULL);
g_signal_connect (_pipelineEments._qtdemux, "pad-added", G_CALLBACK (Foo::pad_added_handler), &_pipelineEments);
gst_element_set_state(_pipelineEments.pipeline, GST_STATE_PLAYING);
}
void Foo::pad_added_handler(GstElement *src, GstPad *newPad, PipelineElements *data)
{
auto padName = GST_PAD_NAME(newPad);
auto elementName = GST_ELEMENT_NAME(src);
LOG_STATIC(Logger::Level::Info, "Received new pad: " << padName << " from: " << elementName)
auto sink_pad = gst_element_get_static_pad(data->_h264parse, "sink");
if (gst_pad_is_linked(sink_pad))
{
LOG_STATIC(Logger::Level::Info, "Sink pad of qtdemux already linked")
return;
}
/* Check the new pad's type */
auto new_pad_caps = gst_pad_get_current_caps (newPad);
auto new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
auto new_pad_type = gst_structure_get_name (new_pad_struct);
if (!g_str_has_prefix (new_pad_type, "video/x-h264"))
{
LOG_STATIC(Logger::Level::Info, "New pad: '" << new_pad_type << "' is not video! Descarting it")
return;
}
/* Attempt the link */
auto ret = gst_pad_link (newPad, sink_pad);
if (GST_PAD_LINK_FAILED (ret))
{
LOG_STATIC(Logger::Level::Error, "Type is '" << new_pad_type << "' but link failed!")
}
else
{
LOG_STATIC(Logger::Level::Info, "Link succeeded. Type: " << new_pad_type)
}
}
I’ve been playing around in this pipeline and just changing the _pipelineElements._decodeBin and loading different decoders.
For the following decoders I always got: “Internal data stream error.” , I also can see the link being created beetween the qtdemux and h264parse.
- nvh264sldec
- nvh264dec
- openh264dec
- decodebin
So it seems that there’s something wrong on my pipeline, but I can’t figure out what it will be.
Any help will be very much appreciated.
Thank you