I am trying to pragmatically create the following chain with gstreamer-0.10.
gst-launch filesrc location=<file>.mkv ! decodebin ! ffenc_mpeg4 bitrate=5000000 ! rtpmp4vpay mtu=1400 pt=96 ssrc=0 timestamp-offset=0 seqnum-offset=0 send-config=true ! udpsink host=127.0.0.1 port=5000
Here is the code:
#include <gst/gst.h>
int
main (int argc,
char *argv[])
{
GstElement* pipeline;
GstElement* source;
GstElement* decodebin;
GstElement* encoder;
GstElement* rtp;
GstElement* udpsink;
/* init */
gst_init (&argc, &argv);
/* create pipeline */
pipeline = gst_pipeline_new ("my-pipeline");
/* create elements */
source = gst_element_factory_make ("filesrc", "source");
g_object_set (G_OBJECT (source), "location", argv[1], NULL);
decodebin = gst_element_factory_make ("decodebin", "decoder");
encoder = gst_element_factory_make ("ffenc_mpeg4", "encoder");
g_object_set (G_OBJECT (encoder), "bitrate", "5000000", NULL);
rtp = gst_element_factory_make ("rtpmp4vpay", "rtp");
g_object_set (G_OBJECT (rtp), "mtu", "1400", NULL);
g_object_set (G_OBJECT (rtp), "pt", 96, NULL);
g_object_set (G_OBJECT (rtp), "ssrc", "0", NULL);
g_object_set (G_OBJECT (rtp), "timestamp-offset", "0", NULL);
g_object_set (G_OBJECT (rtp), "seqnum-offset", 0, NULL);
g_object_set (G_OBJECT (rtp), "send-config", true, NULL);
udpsink = gst_element_factory_make ("udpsink", "udp");
g_object_set (G_OBJECT (udpsink), "host", "127.0.0.1", NULL);
g_object_set (G_OBJECT (udpsink), "port", 5000, NULL);
// /* must add elements to pipeline before linking them */
gst_bin_add_many (GST_BIN (pipeline), source, decodebin, encoder, rtp, udpsink, NULL);
/* link */
if (!gst_element_link_many (source, decodebin, encoder, rtp, udpsink, NULL)) {
g_warning ("Failed to link elements!");
}
}
Although this matches the gst-launch chain exactly, I get the following error in gst_element_link_many call.
0:00:03.025847872 28265 0x611400 INFO GST_PLUGIN_LOADING gstplugin.c:859:gst_plugin_load_file: plugin "/usr/lib64/gstreamer-0.10/libgstudp.so" loaded
0:00:03.025912744 28265 0x611400 INFO GST_ELEMENT_FACTORY gstelementfactory.c:374:gst_element_factory_create: creating element "udpsink" named "udp"
0:00:03.026163748 28265 0x611400 INFO GST_ELEMENT_PADS gstelement.c:728:gst_element_add_pad:<GstBaseSink#0x82b9e0> adding pad 'sink'
0:00:04.824498407 28265 0x611400 INFO GST_ELEMENT_PADS gstutils.c:1698:gst_element_link_pads_full: trying to link element source:(any) to element decoder:(any)
0:00:04.824604374 28265 0x611400 INFO GST_PADS gstutils.c:1032:gst_pad_check_link: trying to link source:src and decoder:sink
0:00:04.824676367 28265 0x611400 INFO GST_PADS gstutils.c:1596:prepare_link_maybe_ghosting: source and decoder in same bin, no need for ghost pads
0:00:04.824725877 28265 0x611400 INFO GST_PADS gstpad.c:1978:gst_pad_link_prepare: trying to link source:src and decoder:sink
0:00:04.824786544 28265 0x611400 INFO GST_PADS gstpad.c:2161:gst_pad_link_full: linked source:src and decoder:sink, successful
0:00:04.824863468 28265 0x611400 INFO GST_ELEMENT_PADS gstutils.c:1698:gst_element_link_pads_full: trying to link element decoder:(any) to element encoder:(any)
0:00:04.824989178 28265 0x611400 INFO GST_ELEMENT_PADS gstelement.c:972:gst_element_get_static_pad: no such pad 'src%d' in element "decoder"
0:00:04.825051308 28265 0x611400 INFO GST_ELEMENT_PADS gstutils.c:1216:gst_element_get_compatible_pad:<decoder> Could not find a compatible pad to link to encoder:sink
What am I doing wrong? Can't I use the decode bin like this programatically?
bin documentation and found that src of decoder is not always pad and is sometimes pad.The same can be observed by the log present.
Related
I encountered different behavior with a gstreamer pipelines when implemented in C++ compared to gst-launch-1.0 execution in command line - the problem is with the bitrate property.
Same problem as described bellow in both implementations (C++ & command line execution) occurs with omxh264enc encoder as well with control-rate property set to 2 (CBR mode).
The pipeline which used in command line was:
gst-launch-1.0 ximagesrc ! autovideoconvert ! x264enc bitrate=800 pass=0 ! video/x-h264, stream-format=byte-stream ! h264parse ! mpegtsmux ! udpsink host=127.0.0.1 port=1234 sync=false
The C++ implementation is:
GstElement* pipeline;
GstElement* appsrc;
GstElement* videoConvert;
GstElement* encoder;
GstElement* encoderCapsFilter;
GstElement* parser;
GstElement* tsmux;
GstElement* udpsink;
pipeline = gst_pipeline_new ("pipeline");
appsrc = gst_element_factory_make ("appsrc", "source");
videoConvert = gst_element_factory_make ("autovideoconvert", "my_video_convertor");
encoder = gst_element_factory_make ("x264enc", "my_encoder");
encoderCapsFilter = gst_element_factory_make("capsfilter", "my_caps");
parser = gst_element_factory_make ("h264parse", "my_parser");
tsmux = gst_element_factory_make ("mpegtsmux", "my_muxer");
udpsink = gst_element_factory_make ("udpsink", "my_udpsink");
/*Configure appsrc*/
g_object_set (G_OBJECT (appsrc), "caps", gst_caps_new_simple ("video/x-raw",
"format", G_TYPE_STRING, "I420",
"width", G_TYPE_INT, width,
"height", G_TYPE_INT, height,
"framerate", GST_TYPE_FRACTION, 25, 1, NULL), NULL);
g_object_set(G_OBJECT(appsrc), "is-live" , true, NULL);
/*Configure videoConvert*/
/*Configure encoder*/
g_object_set(G_OBJECT(encoder), "bitrate" , 800, NULL);
g_object_set(G_OBJECT(encoder), "pass" , 0, NULL);
/*Configure encoder caps*/
g_object_set(G_OBJECT (encoderCapsFilter), "caps", gst_caps_from_string("video/x-h264, stream-format=byte-stream"), NULL);
/*Configure h264parse*/
/*Configure mpegtsmux*/
/*Configure udpsink*/
g_object_set(G_OBJECT(udpsink), "host" , "127.0.0.1", NULL);
g_object_set(G_OBJECT(udpsink), "port" , 1234, NULL);
g_object_set(G_OBJECT(udpsink), "sync" , false, NULL);
// add
gst_bin_add_many(GST_BIN(pipeline),
appsrc,
videoConvert,
encoder,
encoderCapsFilter,
parser,
tsmux,
udpsink,
NULL);
// link
if (!gst_element_link_many(appsrc,
videoConvert,
encoder,
encoderCapsFilter,
parser,
tsmux,
udpsink,
NULL))
{
g_printerr("Elements could not be linked");
}
bitrate is set to 800kbps and when testing this pipeline from command line with Wireshark the baudrate results around 800-850kbps which is good,
when tested the same pipeline in C++ (to use appsrc instead of ximagesrc) the baudrate results in different and higher bitrate (around 1200-1300kbps).
What is missing to reach the same bitrate result when executed through command line?
Is there more configuration to be done into the gst elements when implemented in C++?
I have a gstreamer media pipeline as shown below which I am trying to convert into a c code. The command line works fine.
gst-launch-1.0 v4l2src device=/dev/video1 ! capsfilter caps=video/x-raw,width=1280,height=720,format=UYVY ! queue ! videoconvert ! queue ! capsfilter caps=video/x-raw,format=NV12,width=1280,height=720,pixel-aspect-ratio=1/1 ! v4l2h264enc extra-controls="controls,h264_level=12,h264_profile=1" ! h264parse ! autovideosink
I have written the code and compilation is successful. When, I execute the code, the videosrc element is unable to link to capsfilter. I have surfed through the internet and was unsuccessful in rectifying the problem. Can someone help in correcting me what, I am doing wrong.
The code snippet is below:
/* Create the gstreamer elements */
source = gst_element_factory_make ("v4l2src", "source");
capsfilter = gst_element_factory_make ("capsfilter", "Caps-Filter");
capsfilter2 = gst_element_factory_make ("capsfilter", "caps-filter2");
video_convert = gst_element_factory_make ("videoconvert", "Video Convert");
queue1 = gst_element_factory_make ("queue", "Encoded Video Queue 1");
queue2 = gst_element_factory_make ("queue", "Encoded Video Queue 2");
encoder = gst_element_factory_make ("v4l2h264enc", "HW Accelerated Encoder");
H264_pay = gst_element_factory_make ("h264parse", "Payload-encode H264 video into RTP packets");
sink = gst_element_factory_make("autovideosink", "sink");
/* Create the empty pipeline */
pipeline = gst_pipeline_new ("test-pipeline");
if(!source || !capsfilter || ! capsfilter2 || !video_convert || !queue1 || !queue2 || !encoder || !H264_pay || !sink)
/* Set Source element properties */
g_object_set (G_OBJECT(source), "device", "/dev/video1", NULL);
GstCaps* filtercaps = gst_caps_from_string("video/x-raw,width=1280,height=720,format=(string)UYUY");
GstCaps* vconvertfilter = gst_caps_from_string("video/x-raw,width=1280,height=720,format=(string)NV12,pixel-aspect-ratio=1/1");
GstStructure *test = gst_structure_new_from_string("controls,h264_level=12,h264_profile=1");
g_object_set(G_OBJECT(capsfilter), "caps", filtercaps,NULL);
g_object_set(G_OBJECT(capsfilter2), "caps", vconvertfilter, NULL);
g_object_set (G_OBJECT(encoder), "extra-controls", test, NULL);
gst_caps_unref(filtercaps);
gst_caps_unref(vconvertfilter);
/* Link all elements that can be automatically linked because they have "Always" pads */
gst_bin_add_many (GST_BIN (pipeline),
source, capsfilter,
queue1, video_convert, queue2,
capsfilter2, encoder,
H264_pay, sink, NULL);
if(!gst_element_link(source, capsfilter))
{
g_printerr("Unable to link Source to filter. check your caps. \n");
gst_object_unref (pipeline);
}
if (gst_element_link_many (capsfilter, queue1, video_convert, NULL) != TRUE)
{
g_printerr("Capsfilter could not be linked to queue1. \n");
gst_object_unref (pipeline);
}
if (gst_element_link_many (video_convert, queue2, capsfilter2, encoder, H264_pay, NULL) != TRUE)
{
g_printerr("video_convert could not be linked to queue2. \n");
gst_object_unref (pipeline);
}
if(gst_element_link_many (H264_pay, sink, NULL) != TRUE)
{
g_printerr("parse could not link to sink.\n");
gst_object_unref (pipeline);
}
I get the error as below;
Unable to link Source to filter. check your caps.
Can somebody help me correct the mistake?
I am trying to connect to a ubiquiti camera and successfully with the following command with gstreamer.
gst-launch-1.0 --gst-debug=4 rtspsrc location="rtsp://:554/live/ch00_0" ! rtph264depay ! h264parse ! openh264dec ! d3dvideosink
I look at the debug and it says could not link pads rtspsrc to rtph264depay.
Picture
but it gets the stream alright and can see the video. when I put this into a c project it says cannot link source to rtph264parse. I looked around it says to use a dynamic pad with the following code
static void on_pad_added (GstElement *element, GstPad *pad, gpointer data)
{
GstPad *sinkpad;
GstElement *decoder = (GstElement *) data;
/* We can now link this pad with the rtsp-decoder sink pad */
g_print ("Dynamic pad created, linking source/demuxer\n");
sinkpad = gst_element_get_static_pad (decoder, "sink");
gst_pad_link (pad, sinkpad);
gst_object_unref (sinkpad);
}
int main(int argc, char *argv[])
{
/* Initialize GStreamer */
gst_init(&argc,&argv);
/* Build Pipeline */
pipel.pipeline = gst_pipeline_new("My pipeline");
pipel.source = gst_element_factory_make ("rtspsrc","source");
g_object_set (G_OBJECT (pipel.source), "latency",2000,NULL);
pipel.rtppay = gst_element_factory_make( "rtph264depay", "depayl");
pipel.parse = gst_element_factory_make("h264parse","parse");
pipel.filter1 = gst_element_factory_make("capsfilter","filter");
pipel.decodebin = gst_element_factory_make ("openh264dec","decode");
pipel.sink = gst_element_factory_make("d3dvideosink","sink");
g_object_set (G_OBJECT (pipel.sink), "sync",FALSE,NULL);
//create_uri(url,url_size,ip_address,port);
g_object_set(GST_OBJECT(pipel.source),"location","rtsp://<IP>:554/live/ch00_0",NULL);
filtercaps = gst_caps_from_string("application/x-rtp");
g_object_set (G_OBJECT (pipel.filter1), "caps",filtercaps,NULL);
gst_caps_unref(filtercaps);
gst_bin_add_many (GST_BIN (pipel.pipeline),pipel.source
,pipel.rtppay
,pipel.parse
,pipel.decodebin
,pipel.sink
,NULL);
if(!gst_element_link(pipel.source,pipel.rtppay))
printf("\nFailed source to rtppay\n");
if(!gst_element_link_many(pipel.parse,pipel.decodebin,pipel.sink,NULL))
printf("\nFailed to link parse to sink");
g_signal_connect(pipel.rtppay, "pad-added", G_CALLBACK(on_pad_added), pipel.parse);
}
static void cb_new_rtspsrc_pad(GstElement *element,GstPad*pad,gpointer data)
{
gchar *name;
GstCaps * p_caps;
gchar * description;
GstElement *p_rtph264depay;
name = gst_pad_get_name(pad);
g_print("A new pad %s was created\n", name);
// here, you would setup a new pad link for the newly created pad
// sooo, now find that rtph264depay is needed and link them?
p_caps = gst_pad_get_pad_template_caps (pad);
description = gst_caps_to_string(p_caps);
printf("%s\n",p_caps,", ",description,"\n");
g_free(description);
p_rtph264depay = GST_ELEMENT(data);
// try to link the pads then ...
if(!gst_element_link_pads(element, name, p_rtph264depay, "sink"))
{
printf("Failed to link elements 3\n");
}
g_free(name);
}
/* ---------- Main --------------- */
int main(int argc, char *argv[])
{
/* Initialize GStreamer */
gst_init(&argc,&argv);
/* Build Pipeline */
pipel.pipeline = gst_pipeline_new("My pipeline");
creating_pipeline(ip_address,port);
pipel.source = gst_element_factory_make ("rtspsrc","source");
g_object_set (G_OBJECT (pipel.source), "latency",2000,NULL);
pipel.rtppay = gst_element_factory_make( "rtph264depay", "depayl");
pipel.parse = gst_element_factory_make("h264parse","parse");
pipel.filter1 = gst_element_factory_make("capsfilter","filter");
pipel.decodebin = gst_element_factory_make ("openh264dec","decode");
pipel.sink = gst_element_factory_make("d3dvideosink","sink");
g_object_set (G_OBJECT (pipel.sink), "sync",FALSE,NULL);
//create_uri(url,url_size,ip_address,port);
g_object_set(GST_OBJECT(pipel.source),"location","rtsp://<ip>:554/live/ch00_0",NULL);
filtercaps = gst_caps_from_string("application/x-rtp");
g_object_set (G_OBJECT (pipel.filter1), "caps",filtercaps,NULL);
gst_caps_unref(filtercaps);
gst_bin_add_many (GST_BIN (pipel.pipeline),pipel.source
,pipel.rtppay
,NULL);
// listen for newly created pads
g_signal_connect(pipel.source, "pad-added", G_CALLBACK(cb_new_rtspsrc_pad),pipel.rtppay);
gst_bin_add_many (GST_BIN (pipel.pipeline),pipel.parse,NULL);
if(!gst_element_link(pipel.rtppay,pipel.parse))
printf("\nNOPE\n");
gst_bin_add_many (GST_BIN (pipel.pipeline),pipel.decodebin
,pipel.sink
,NULL);
if(!gst_element_link_many(pipel.parse,pipel.decodebin,pipel.sink,NULL))
printf("\nFailed to link parse to sink");
g_signal_connect(pipel.rtppay, "pad-added", G_CALLBACK(on_pad_added), pipel.parse);
}
Works Now!
use cb_new_rtspsrc_pad to add the pad dynamically
add the parse to bin
link up between rtppay and parse
add the necessary elements the rest of the string to make it work.
I want to play two local video file using gstreamer,but I got an error: Segmentation fault It from libgstvideomixer.so.What's wrong with my code? The videomixer element is needed to play two videos.Should I use videobox for that?
gst-launch --no-fault filesrc location=/mnt/upan/source.264 ! queue ! typefind ! ffdec_h264 ! videomixer name=mix ! xvimagesink sync=false filesrc location=/mnt/upan/source.264 ! queue ! typefind ! ffdec_h264! mix.
static void p_gst_init(void)
{
App *app = &s_app;
GError *error = NULL;
GstBus *bus;
GstElement *parse, *decoder, *queue;
GstElement *parse2, *decoder2, *queue2;
gst_init (NULL, NULL);
/* create a mainloop to get messages */
app->loop = g_main_loop_new (NULL, TRUE);
app->playbin = gst_pipeline_new ("pipeline");
app->appsrc = gst_element_factory_make ("filesrc", "disk_source");
g_object_set (G_OBJECT (app->appsrc), "location", "/mnt/upan/test.264", NULL);
queue = gst_element_factory_make ("queue", "queue");
parse = gst_element_factory_make ("typefind", "parse");
decoder = gst_element_factory_make ("ffdec_h264", "decoder");
GstElement *filesrc2;
filesrc2 = gst_element_factory_make ("filesrc", "disk_source2");
g_object_set (G_OBJECT (appsrc2), "location", "/mnt/upan/source.264", NULL);
queue2 = gst_element_factory_make ("queue", "queue2");
parse2 = gst_element_factory_make ("typefind", "parse2");
decoder2 = gst_element_factory_make ("ffdec_h264", "decoder2");
/*
GstElement * videobox;
videobox = gst_element_factory_make("videobox", NULL);
g_object_set (videobox, "alpha", 0, "border-alpha", 0, "bottom", 100, "left", 100, "right", 100, "top", 100, NULL);
*/
GstElement * videomixer;
videomixer = gst_element_factory_make("videomixer","videomixer");
app->xvimagesink = gst_element_factory_make ("xvimagesink", "play_video");
g_object_set (G_OBJECT (app->xvimagesink), "synchronous", FALSE, NULL);
gst_bin_add_many (GST_BIN (app->playbin), app->appsrc, queue, parse, decoder, videomixer, app->xvimagesink, filesrc2, queue2, parse2, decoder2, NULL);
if(gst_element_link_many (app->appsrc, queue, parse, decoder, videomixer, NULL))
{
printf("---------link element success-----------------\n");
}
else
printf("---------link element failed-----------------\n");
gst_element_link_many (filesrc2, queue2, parse2, decoder2, videomixer, NULL);
gst_element_link_many(videomixer, app->xvimagesink, NULL);
bus = gst_pipeline_get_bus (GST_PIPELINE (app->playbin));
gst_bus_add_watch (bus, (GstBusFunc) bus_message, app);
gst_bus_set_sync_handler(bus, (GstBusSyncHandler)create_window, app);
g_signal_connect (app->appsrc, "need-data", G_CALLBACK (feed_data), app);
return ;
}
I am using gst library to play multiple audio files and I have a problem:
Error: Internal data flow error
This is my code (without other demuxer and sink init):
GstElement *elm1, *elm2;
elm1 = gst_element_factory_make ("filesrc", "file1.ogg");
elm2 = gst_element_factory_make ("filesrc", "file2.ogg");
g_object_set (G_OBJECT (elm1), "location", "file1.ogg", NULL);
g_object_set (G_OBJECT (elm2), "location", "file2.ogg", NULL);
GstBus *bus;
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref (bus);
gst_bin_add_many (GST_BIN (pipeline), elm1, elm2, demuxer, sink, NULL);
gst_element_link_many (elm1, elm2, demuxer);
g_signal_connect (demuxer, "pad-added", G_CALLBACK (on_pad_added), sink);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
Did I make something wrong?
you need to listen for EOS for file-1 and then change the filesrc to file-2.
the following answer should help you -
'GStreamer dynamically change the filesrc location of a pipeline- No sound'