I'm trying to play audio with Gstreamer in C.
I'm using Laptop, Ubuntu 16.
To play I use this pipeline and it's working:
gst-launch-1.0 filesrc location=lambo-engine.mp3 ! decodebin ! audioconvert ! autoaudiosink
But when I convert it to C:
GstElement *pipeline, *source, *decode, *audioconvert, *sink;
GMainLoop *loop;
GstBus *bus;
GstMessage *msg;
int main(int argc, char *argv[]) {
/* Initialize GStreamer */
gst_init (&argc, &argv);
/* Create the elements */
source = gst_element_factory_make("filesrc", NULL);
decode = gst_element_factory_make("decodebin", NULL);
audioconvert = gst_element_factory_make("audioconvert", NULL);
sink = gst_element_factory_make("autoaudiosink", NULL);
// Set parameters for some elements
g_object_set(G_OBJECT(source), "location", "lambo-engine.mp3", NULL);
/* Create the empty pipeline */
pipeline = gst_pipeline_new ("pipeline");
/* Build the pipeline */
gst_bin_add_many (GST_BIN (pipeline), source, decode, audioconvert, sink, NULL);
if (gst_element_link_many(source, decode, audioconvert, sink, NULL) != TRUE){
g_error("Failed to link save elements!");
gst_object_unref (pipeline);
return -1;
}
/* Start playing */
gst_element_set_state (pipeline, GST_STATE_PLAYING);
bus = gst_element_get_bus (pipeline);
gst_object_unref (bus);
/* now run */
g_main_loop_run (loop);
/* Free pipeline */
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT(pipeline));
return 0;
}
I can built it success. But when I run it, it return error can't link elements:
** (example:2516): ERROR **: 22:59:42.310: Failed to link save elements!
Trace/breakpoint trap (core dumped)
Someone helps me to figure out error, please.
Thank you so much
Gstreamer is centered around pipelines that are lists of elements. Elements have pads to exchange data on. In your example, decodebin has an output pad and audioconvert has an input pad. At the start of the pipeline, the pads need to be linked.
This is when pads agree on the format of data, as well as some other information, such as who's in charge of timing and maybe some more format specifics.
Your problem arises from the fact that decodebin is not actually a real element. At runtime, when filesrc starts up, it tells decodebin what pad it has, and decodebin internally creates elements to handle that file.
For example:
filesrc location=test.mp4 ! decodebin would run in this order:
delay linking because types are unknown
start filesrc
filesrc says "trying to link, I have a pad of format MP4(h264)
decodebin sees this request, and in turn, creates on the fly a h264 parse element that can handle the mp4 file
decodebin now has enough information to describe it's pads, and it links the rest of the pipeline
video starts playing
Because you are using c to do this, you link the pipeline before filesrc loads the file. This means that decodebin doesn't know the format of it's pads at startup, and therefore fails to link.
To fix this, you have two options:
1.) Swap out decodebin for something that supports only one type. If you know your videos will always be mp4s with h264, for example, you can use h264parse instead of decodebin. Because h264parse only works with one type of format, it knows it's pad formats at the start, and will be able to link without issue.
2.) Reimplement the smart delaying linking. You can read the docs for more info, but you can delay linking of the pipeline, and install callbacks to complete the linking when there's enough information. This is what gst-launch-1.0 is doing under the hood. This has the benefit of being more flexible: anything support by decodebin will work. The downside is that it's much more complex, involves a nontrivial amount of work on your end, and is more fragile. If you can get away with it, try fix 1
Related
My Goal
I'm trying to embed subtitles into an mp4 file using the mp4mux gstreamer element.
What I've tried
The pipeline I would like to use is:
GST_DEBUG=3 gst-launch-1.0 filesrc location=sample-nosub-avc.mp4 ! qtdemux ! queue ! video/x-h264 ! mp4mux name=mux reserved-moov-update-period=1000 ! filesink location=output.mp4 filesrc location=english.srt ! subparse ! queue ! text/x-raw,format=utf8 ! mux.subtitle_0
It just demuxes a sample mp4 file for the h.264 stream and then muxes it together with an srt subtitle file.
The error I get is:
Setting pipeline to PAUSED ...
0:00:00.009958915 1324869 0x5624a8c7a0a0 WARN basesrc gstbasesrc.c:3600:gst_base_src_start_complete:<filesrc0> pad not activated yet
Pipeline is PREROLLING ...
0:00:00.010128080 1324869 0x5624a8c53de0 WARN basesrc gstbasesrc.c:3072:gst_base_src_loop:<filesrc1> error: Internal data stream error.
0:00:00.010129102 1324869 0x5624a8c53e40 WARN qtdemux qtdemux_types.c:239:qtdemux_type_get: unknown QuickTime node type pasp
0:00:00.010140810 1324869 0x5624a8c53de0 WARN basesrc gstbasesrc.c:3072:gst_base_src_loop:<filesrc1> error: streaming stopped, reason not-negotiated (-4)
0:00:00.010172990 1324869 0x5624a8c53e40 WARN qtdemux qtdemux.c:3237:qtdemux_parse_trex:<qtdemux0> failed to find fragment defaults for stream 1
ERROR: from element /GstPipeline:pipeline0/GstFileSrc:filesrc1: Internal data stream error.
Additional debug info:
gstbasesrc.c(3072): gst_base_src_loop (): /GstPipeline:pipeline0/GstFileSrc:filesrc1:
streaming stopped, reason not-negotiated (-4)
ERROR: pipeline doesn't want to preroll.
Setting pipeline to NULL ...
Freeing pipeline ...
My Thoughts
I believe the issue is not related to the above warning but rather mp4mux's incompatibility with srt subtitles.
The reason I belive this is because, other debug logs hint at it, but also stealing the subititles from another mp4 file and muxing it back together does work.
gst-launch-1.0 filesrc location=sample-nosub-avc.mp4 ! qtdemux ! mp4mux name=mux ! filesink location=output.mp4 filesrc location=sample-with-subs.mp4 ! qtdemux name=demux demux.subtitle_1 ! text/x-raw,format=utf8 ! queue ! mux.subtitle_0
A major catch 22 I am having is that mp4 files don't typically support srt subtitles, but gstreamer's subparse element doesn't support parsing mp4 subtitle formats (tx3g, ttxt, etc.) so I'm not sure how I'm meant to put it all together.
I'm very sorry for the lengthy question but I've tried many things so it was difficult to condense it. Any hints or help is appreciated. Thank you.
I have a problem in my Gstreamer pipeline that causes the sprop-parameter-sets to (i think) overflow its buffer. I am doing this in a iMX6 board and my pipeline is appsrc format=3 ! imxvpuenc_h264 ! rtph264pay and I use an RTSP server for accessing the pipeline. The pipeline works if a static image is sent, but in the case of a video it stops working by calculating the wrong pps.
I have tried using a static sprop-parameter-sets for rtph264pay by setting its property, but in this case the same thing happens in rtph264depay that calculates a new sprop-parameter-set. The output from the caps creation can be seen below:
0:01:15.970217009 578 0xa482ad50 INFO GST_EVENT gstevent.c:809:gst_event_new_caps: creating caps event application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, packetization-mode=(string)1, sprop-parameter-sets=(string)"Z0JAIKaAUAIGQAA\=\,aM48gP94AAIS4AAg2AACAudABxMbtz5ZqJ6U4vk7wAAQMgABAOgA5R6ZQkwQNaTPhfwAQAAgjAACD54YHcvx9FXG9ON62mcABAAFAAEAYbX2rm8Qe4mSKvXrwAAQBgACNJAZdcgDiEnNE5djN4GAAIJhoAKAEnAmvb0KVFQMwyGTwAAi4AIgBINIKIds1udUngAAgcAACAWS1IEgBehG7wDL75/W5JRBIi0WrX8gABAsAAEA0DVsAnpAKiCjVLNdK8AAEJ4AEAc/YVCfjDJO+t73KSd4AAII4AAgpAACAWwBo6CGMh3HueozX+Z4AAIJgAAgOgD2gYFqlGlGBjWn1MULXgAAg5AACAkEA8JLN5OJHLJcZmDo+eAACC8AAIDoAMAGGzM8zzGmJZwKeFL8AAQAAgKhbICDBChH5BKlw+PuMscAACACAAcACA3uGjeSK7gZZzT+NH/ewABDWAAEEQsALG1gYcE5FEbXp1hW8DAcAAQBQAnNfkbKQ/Pc/I9SGjgAwABAXAGdyJu7gpKxj9M5ERP/eAA6MAAIBgopwP8Sbdqzl4CjgAAQMwABAAAHALgpUcLtczR+Yjocj/eBgACC0YACtjKAXenmNmgRczT4AAIF4AAgDgAEASJqHnyzxQfCXUdO3gAAgoAACBgaSADVwoxVTFA7X0vaZsnexAU7CW/gAAgvAAQoABAXFGq3qUtmUv9VYp8AACCaEAIA7Bmj1M+lA7...
and this continues on for about a hundred or more lines and the device crashes if the pipeline isn't stopped. This should have only a few more characters after the first comma. Can someone tell why this would happen and provide a solution?
I am learning about gstreamer and I have a simple program where I want to end a stream gracefully after pressing CTRL+C in Linux. For this, I've read the source code for gst-launch and saw that g_unix_signal_add() is used for adding the signals. In my code I've added the line:
signal_watch_intr_id = g_unix_signal_add (SIGINT,
(GSourceFunc) intr_handler, data.pipeline);
where data is a structure containing the pipeline. My handling function is:
static gboolean
intr_handler (gpointer user_data)
{
printf("handling interrupt.\n");
GstElement *pipeline = (GstElement *) user_data;
/* post an application specific message */
gst_element_post_message (GST_ELEMENT (pipeline),
gst_message_new_application (GST_OBJECT (pipeline),
gst_structure_new ("GstLaunchInterrupt",
"message", G_TYPE_STRING, "Pipeline interrupted", NULL)));
/* remove signal handler */
signal_watch_intr_id = 0;
return G_SOURCE_REMOVE;
}
I expect it to print "handling interrupt." to the console, make the pipeline send a GST_MESSAGE_APPLICATION type message which then will be handled to stop the pipeline. However, the application simply does nothing after a SIGINT now. Because it does NOTHING, I know it changes the default handle, but I don't understand why it does not call the handling function. Can someone help me do this handling?
As Philip's comments suggested, the problem was that I wasn't running a main loop and using gst_bus_timed_pop() to get the messages from the bus. By using a GMainLoop and adding a bus watcher(using gst_bus_add_watch) with a bus callback function, I managed to catch the interrupt as I wanted to.
I'm currently facing a problem that I'm not able to resovle yet, but I hope I can do it with your help.
I currently developp an application with gstreamer to playback different kind of files : video and photo (avi and jpg respectively). The user has to have the possibility to switch between those different files. I have achieved this but by creating a new pipeline if the file format is different. There, screen randomly blinks between two files loading.
Now, I've played with valve just for jpg files and it works like a charm. But, I'm stuck at the step to implement video files, I don't know how to swith between two video files : the code below doesn't work for video files, it freezes:
gst-launch-1.0 filesrc name=photosrc ! jpegdec ! valve name=playvalve drop=false ! imxg2dvideosink
Then further in my code, I drop the valve, set differents elements to ready state, change location of filesrc and return to playing state.
I take a look a input-selector but it appears that non-read file still playing when one switches to the other (cf doc). Is it possible to set an input as ready to avoid this behavior ?
Thanks a lot for helping
Take a look at https://github.com/RidgeRun/gst-interpipe plugin.
You can create 2 different source mini pipelines ending with interpipesink, and in runtime change which will connect to interpipesrc. Make sure to have the same format on both ends. Or use renegotiation capability, however, I have not tried it yet.
Check wiki for dynamic switching details:
/* Create pipelines */
GstElement *pipe1 = gst_parse_launch ("videotestsrc ! interpipesink name=camera1", NULL);
GstElement *pipe2 = gst_parse_launch ("videotestsrc ! interpipesink name=camera2", NULL);
GstElement *pipe3 = gst_parse_launch ("interpipesrc name=src listen-to=camera1 ! fakesink", NULL);
/* Grab a reference to the interpipesrc */
GstElement *src = gst_bin_get_by_name(pipe3, "src");
/* Perform the switch */
g_object_set (src, "listen-to", "camera2", NULL);
It seems a little bit tricky for me to compile this plugin for imx6 target...
Is it possible to change pipeline like this :
- ----. .----------. .---- - .---- -
filesrc | avidemux | | vpudec | imxg2dsink
src -> sink src -> sink src -> sink
- ----' '----------' '---- - '---- -
to
- ----. .----------. .---- -
filesrc | jpedec | | imxg2dsink
src -> sink src -> sink
- ----' '----------' '---- -
Without set all pipeline to null ?
I've tried to create a new pipeline at each time I change the location of filesrc, it works but sometimes the framebuffer blinks ....
When I change location of filesrc in case of jpeg file, it works. In case I change location of avi file, pipeline doesn't restart correctly :
avidemux gstavidemux.c:5678:gst_avi_demux_loop:<demux> error: Internal data stream error.
avidemux gstavidemux.c:5678:gst_avi_demux_loop:<demux> error: streaming stopped, reason not-linked
Thank you.
GstH264NalParser *parser = NULL;
GstH264NalUnit nal_unit = { 0 };
parser = gst_h264_nal_parser_new();
GstH264ParserResult parser_result = gst_h264_parser_identify_nalu(parser,
buffer_map.data,
0,
buffer_map.size,
&nal_unit); /* This returns GST_H264_PARSER_NO_NAL */
Why is that? Unless data is not supposed to come from a GstMapInfo* but some other data structure. A GstStructure pointer from a GstSample, perhaps?
Context
Writing a small program that parses h.264 encoded video from Gstreamer's videotestsrc and appsink plug-ins. So far, so good.
Using the (bad) x264enc plug-in in my pipeline to convert the stream before feeding it into an h264parse, then into appsink. Pretty sure the h264parse is an unnecessary step, but I get the same results with and without.
Convinced that am using incorrect struct to read data into NALU parse function.
If you believe your incoming data is good, odds are you need to do a small conversion because in h264 streams there are a few different modes of encoding.
I'm not sure why that is, but you sometimes need to do a small conversion. That is what the h264parse element is for.
Pad Templates:
SRC template: 'src'
Availability: Always
Capabilities:
video/x-h264
parsed: true
stream-format: { avc, avc3, byte-stream }
alignment: { au, nal }
So in your pipeline you might try permutations on the stream-format and alignmnet options, such as:
gst-launch videotestsrc ! ... ! h264parse ! video/x-h264,stream-format=byte-stream,alignment=nal ! appsink