How to play avi video using GStreamer - c++

I am trying to play my first video in GSTreamer, by using GstElement, without pre-configured things like gst_parse_launch etc
I dont understand why my pipeline cant be linked and I get an error "unable to set the pipeline to playing state" ?
How can I fix it? What is missed?
#include <iostream>
#include <gst/gst.h>
int main(int argc, char *argv[])
{
GstElement *pipeline;
GstElement *source, *sink;
gst_init(&argc, &argv); //! Initialize GStreamer
pipeline = gst_pipeline_new("my-pipeline"); //! Creating pipeline
source = gst_element_factory_make("filesrc", "file-source"); //! Creating source
g_object_set(G_OBJECT(source), "location", "file:///D:/workspace/rocket.mp4", NULL);
sink = gst_element_factory_make("autovideosink", "sink"); //! Creating sink
if (sink == NULL)
{
g_error("Could not create neither 'autovideosink' element");
}
gst_bin_add_many(GST_BIN(pipeline), source, sink, NULL); //! Adding elements to pipeline container
if (!gst_element_link_many(source, sink, NULL)) //! Linking all elements together
{
g_warning("Unable to link elements!");
}
auto ret = gst_element_set_state(pipeline, GST_STATE_PLAYING); //! Turning pipeline in PLAYING STATE
if (ret == GST_STATE_CHANGE_FAILURE)
{
g_printerr("unable to set the pipeline to playing state");
gst_object_unref(pipeline);
return -1;
}
return 0;
}
Thanks in advance!

Try to change "file:///D:/workspace/rocket.mp4" to "D:/workspace/rocket.mp4".
And also maybe you need to change gst_element_link_many(source, sink, NULL) to gst_element_link(source, sink).

Here is an answer
First of all, here is github link to my solution with comments.
Explanation:
If you want to play video file, without predefined pipelines, like playbin, gst_parse_launch etc, you have two options
Dynamically link uridecodebin with 2 pipeline sleeves (one for audio and second for video)
Dynamically link by using avidemux and make it on 'atomic' level. Its very complicated, and there is no working help in net. Maybe I will update this branch later with working solution.
In my github link, you will find first solution with 2 pipelines and uridecodebin

Related

Gstreamer Elements could not be linked

I'm new to GStreamer, I followed the Basic tutorial 2 on GStreamer website and try to make it work with local mp4 file.
My problem is that I can't link "uridecodebin" and "autovideosink", here is my related code :
GstElement *pipeline, *source, *sink;
GstBus *bus;
GstMessage *msg;
GstStateChangeReturn ret;
/* Initialize GStreamer */
gst_init (&argc, &argv);
/* Create the elements */
source = gst_element_factory_make ("uridecodebin", "source");
sink = gst_element_factory_make ("autovideosink", "sink");
/* Create the empty pipeline */
pipeline = gst_pipeline_new ("pipeline");
if (!pipeline || !source || !sink) {
g_printerr ("Not all elements could be created.\n");
return -1;
}
/* Build the pipeline */
gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
if (gst_element_link (source, sink) != TRUE) {
g_printerr ("Elements could not be linked.\n");
gst_object_unref (pipeline);
return -1;
}
It always return false with gst_element_link (source, sink), but it worked well if I simply use gst-launch-1.0 uridecodebin uri=file://MyPathToVideo/test.mp4 ! autovideosink command, what am I doing wrong?
Lots of thanks.
Try using gst_parse_launch() and giving it your pipeline. It is shorter this way. And I believe it takes care of some particularities in your case.
The main issue your approach is not working is that uridecodebin does not expose any pads because at that point in time it does not know anything about your MP4 file. So it can contain audio, video, both - or whatever. The correct approach is to implement delayed linking.
So instead of linking it directly you implement the pad-added signal on uridecodebin:
https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html?gi-language=c#GstElement::pad-added
Then you start the pipeline with the elements disconnected.
This pad-added signal is triggered when uridecodebin has scanned your media file and exposes pads which can be linked. In case it is your video pad you can connect it to the autovideosink.
gst_parse_launch() if I'm not mistaken will take of this automatically for you (at least that is what gst-lauch-1.0 is doing - not sure if that specific functionality moved to that API as well).
P.S. You jumped the gun. Tutorial 2 does not use uridecodebin but more basic elements. Tutorial 3 will cover dynamic pipelines.

Is it possible to set initial index of splitmuxsink?

I have setup gstreamer with few pipes (with help of RidgRun GSTd & gst-interpipe).
First pipe realize snapshots with multifilesink with max-files and could setup starting index=start_index.
Second pipe realize record with splitmuxsink and max-files & max-size-time
GStreamer 1.10.4
gstd v.0.7.0
multifilesink name=snapshot_sink index=${start_index} max-files=20 location=pic_%04d.jpg
splitmuxsink name=rec_file_sink location=rec_%03d.mpg max-size-time=60000000000 send-keyframe-requests=true max-files=5 muxer=mpegtsmux
The problem is that if I restart gstreamer (respectively gstd) the indexes are reset.
If I start recording in second pipe index begins from 000.
I could setup starting index in multifilesink pipe I couldn't find same for splitmuxsink.
Any ideas ?
How about the start-index property
https://gstreamer.freedesktop.org/documentation/multifile/splitmuxsink.html?gi-language=c#splitmuxsink:start-index
I just ran into this issue myself and I am afraid there is no way to do that using command line parameters only.
However, for those who are not afraid of diving into the API and create a gstreamer application, it is achievable using the 'format-location' signal (see the splitmuxsink documentation).
In C/C++, you may define the signal handler as follows:
static gchar* cb_FormatLocation(GstElement* splitmux, guint fragment_id, const int* offset)
{
char* location;
g_object_get(splitmux, "location", &location, nullptr);
gchar* fileName = g_strdup_printf(location, fragment_id + *offset);
g_free(location);
return fileName;
}
and, in the pipeline definition, all you need to do is to compute an offset and pass it to g_signal_connect:
#include <filesystem>
...
GstElement* sink = gst_element_factory_make("splitmuxsink", "sink");
...
std::filesystem::path fileTemplate = "/path/to/folder/%04d.mp4";
int offset = 0;
while (std::filesystem::exists(g_strdup_printf(fileTemplate.c_str(), offset))) offset++;
g_object_set(sink, "location", fileTemplate.c_str(), nullptr);
g_signal_connect (sink, "format-location", G_CALLBACK(cb_FormatLocation), &offset);
Side note: make sure the offset variable is not destroyed before the application terminates.
It should be possible to achieve the same behaviour with the Python API.

gstreamer filesrc is not working with error "sink-actual-sink-d3dvideo", but gst-launch is working correctly on windows

I want to read a file and playback. very simple.
*windows10, visual studio 2017 community.
in command prompt, this is working correctly.
gst-launch-1.0 filesrc location="C:/test.webm" ! decodebin ! autovideosink
but my code is not working, this.
int main(int argc, char *argv[]) {
..... declare variable
/* Initialize GStreamer */
gst_init (&argc, &argv);
/* Create the elements */
source = gst_element_factory_make ("filesrc", "source");
decode = gst_element_factory_make("decodebin", "decode");
sink = gst_element_factory_make ("autovideosink", "sink");
pipeline = gst_pipeline_new ("test-pipeline");
gst_bin_add_many (GST_BIN (pipeline), source, decode, sink, NULL);
g_object_set (G_OBJECT(source), "location", "C:/test.webm", NULL);
bus = gst_element_get_bus (pipeline);
... error processing
}
and my error is this
Error received from element sink-actual-sink-d3dvideo: Output window was closed
Debugging information: ../sys/d3dvideosink/d3dhelpers.c(1911): d3d_render_buffer (): /GstPipeline:test-pipeline/GstAutoVideoSink:sink/GstD3DVideoSink:sink-actual-sink-d3dvideo
please help me what is my problem.
my code is almost same to official tutorial. I just changed videotestsrc to filesrc, add the decodebin between source and sink, set the property for giving media file location

How to set a GstPlayer pipeline?

I have constructed a custom GStreamer pipeline that I will use to play RTSP streams. At the same time I'd like to create a new GstPlayer to use this pipeline. The problem is that there isn't a way that I can see to set a GstPlayer's pipeline (the only related method is gst_player_get_pipeline(). I don't understand how there is no way to customize a pipeline for a GstPlayer. This seems like basic functionality, so I must be missing something.
My pipeline:
GstElement *pipeline, *source, *filter, *sink;
// Create pipeline elements
pipeline = gst_pipeline_new ("vdi-pipeline");
source = gst_element_factory_make ("rtspsrc", "vdi-source");
filter = gst_element_factory_make ("decodebin", "vdi-filter");
sink = gst_element_factory_make ("appsink", "vdi-sink");
if (!source || !filter || !sink)
{
__android_log_print (ANDROID_LOG_ERROR, "Error", "A GstElement could not be created. Exiting.");
return;
}
// Add elements to pipeline
gst_bin_add_many (GST_BIN (pipeline), source, filter, sink, NULL);
// Link elements together
if (!gst_element_link_many (source, filter, sink, NULL)) {
__android_log_print (ANDROID_LOG_ERROR, "Warning", "Failed to link elements!");
}
But you can play rtsp via GstPlayer out of the box.. why do you want custom pipeline?
The player is using playbin which accept any kind of url.. and it will create pipeline dynamically according to what is being played..
What about patching the player itself, if you really cannot use playbin? I dont think it is intended for custom pipelines.. but you can hack it here.
You will then have hook the newpads and other callback on the rtspsrc instead of playbin.. and other stuff - I guess you do not want this.
The other way is - when the playbin constructs pipeline it uses rtspsrc inside - you can get this element from pipeline object and change some parameters.. but be carefull as changing parameters during playback is very tricky..
UPDATE:
Hm I think I overlook the appsink somehow.. well I think you can set playbin property audio-sink or video-sink to override it to use appsink.
But still you will have to somehow get the playbin element out of GstPlayer or set the playbin parameter upon initialization (I dont know how) - in this case I would ask on IRC (freenode, #gstreamer) if you are going the right direction.
Maybe better way would be to create your own application using decodebin and or even playbin and pass there the appsink element.. why do you want to use GstPlayer if you are not playing but processing buffers?
HTH

pad not being added to uridecodebin

I'm currently working on a gstreamer pipeline that begins with a uridecodebin that opens a png file and that I hope to eventually link to an imagefreeze element (although in the future I may want to link it to any arbitrary element). I've connected to the "pad-added" signal, but it appears that uridecodebin doesn't ever actually create the pad.
After looking closely at the logs, it appears that it successfully opens the png file and links the filesrc to the decodebin, but there doesn't appear to be any pad created (the callback is never called, and when I iterate over the src pads of the uridecodebin after the file is opened, there are none). Does anyone know why this might be the case?
Unfortunately it's part of a much larger codebase so I can't share the full code but I can give excerpts of the relevant samples:
GstElement *uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
GstElement *imagefreeze = gst_element_factory_make ("imagefreeze", NULL);
GstElement *sink = gst_element_factory_make ("fakesink", NULL);
g_object_set (G_OBJECT (uridecodebin), "uri"
"file:///test.png", NULL);
g_signal_connect (uridecodebin, "pad-added",
G_CALLBACK (uri_pad_added_cb), NULL);
gst_bin_add_many (GST_BIN (bin), uridecodebin, imagefreeze, sink, NULL);
gst_element_link (imagefreeze, sink);
And then, the callback (at this point, just a stub):
static void
uri_pad_added_cb (GstElement * element, GstPad * pad, gpointer data)
{
GST_WARNING ("uri_pad_added_cb");
}