gst-launch and multiple lines of text - gstreamer

how do i set multiple lines of text in the textoverlay pipe in gst-launch?
I want to set up a pipeline and want to have multiple lines of text both vertically and horizontally centered. I'm able to do 1 line.
I'm not sure how to specify a newline.
gst-launch-1.0 videotestsrc pattern=0 horizontal-speed=0 is-live=1 \
! textoverlay text="PLEASE <b>STAND</b> <span foreground=\"blue\" size=\"x-large\">\nBY</span>Next <u>under-line</u>" valignment=center halignment=center font-desc="Sans, 24" \ ... other pipes ...
I would like to basically have 2+ lines. both be vertically and horizontally aligned with respect to each other and the overall screen.

I don't know how to pass newline character inside a parameter in gst-launch, but you can achieve the same thing using C code. Below is the example:
#include <glib.h>
#include <gst/gst.h>
int main(int argc, char* argv[])
{
GMainLoop* loop;
GstElement *pipeline, *source, *overlay, *sink;
gst_init(&argc, &argv);
loop = g_main_loop_new(NULL, FALSE);
// initialize elements
pipeline = gst_pipeline_new("audio-player");
source = gst_element_factory_make("videotestsrc", "source");
overlay = gst_element_factory_make("textoverlay", "overlay");
sink = gst_element_factory_make("autovideosink", "sink");
if (!pipeline || !source || !overlay || !sink) {
g_printerr("One element could not be created. Exiting.\n");
return -1;
}
g_object_set(G_OBJECT(overlay), "text", "blebleble\nble", NULL);
g_object_set(G_OBJECT(overlay), "font-desc", "Sans, 24", NULL);
g_object_set(G_OBJECT(overlay), "halignment", 1, NULL);
g_object_set(G_OBJECT(overlay), "valignment", 1, NULL);
// add elements to pipeline
gst_bin_add_many(GST_BIN(pipeline), source, overlay, sink, NULL);
// link elements
gst_element_link(source, overlay);
gst_element_link_many(overlay, sink, NULL);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
g_main_loop_run(loop);
// cleanup
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(pipeline));
g_main_loop_unref(loop);
return 0;
}

Related

How to change gstreamer Element property

I want to make the gstreamer app full screen.
Waylandsink property has fullscreen, how do I change it?
Or is there a way to go full screen without changing the Waylandsink property?
When setting by command
$ gst-launch-1.0 filesrc location=/home/root/testpi.h264 ! decodebin ! vspmfilter ! waylandsink fullscreen=TRUE
When writing in code
`#define INPUT_FILE "/home/root/testpi.h264"
GstElement *pipeline, *source, *parser, *decoder, *filter, *sink;
const gchar *input_file = INPUT_FILE;
gst_init(&argc, &argv);
/* Create gstreamer elements */
pipeline = gst_pipeline_new ("video-play");
source = gst_element_factory_make ("filesrc", "file-source");
parser = gst_element_factory_make ("h264parse", "h264-parser");
decoder = gst_element_factory_make ("omxh264dec", "h264-decoder");
filter = gst_element_factory_make ("vspmfilter", "filter");
sink = gst_element_factory_make ("waylandsink", "video-output");
/* Set input video file for source element */
g_object_set (G_OBJECT (source), "location", input_file, NULL);
/* Set element property */
g_object_set(G_OBJECT(sink),"fullscreen",TRUE,NULL);
/* Add all elements into the pipeline */
/* pipeline---[ file-source + h264-parser + h264-decoder + filter + video-output ] */
gst_bin_add_many (GST_BIN (pipeline), source, parser, decoder, filter, sink, NULL);
/* Link the elements together */
/* file-source -> h264-parser -> h264-decoder -> filter -> video-output */
if (gst_element_link_many (source, parser, decoder, filter, sink, NULL) != TRUE) {
g_printerr ("Elements could not be linked.\n");
gst_object_unref (pipeline);
return -1;
}
/* Set the pipeline to "playing" state */
g_print ("Now playing: %s\n", input_file);
if (gst_element_set_state (pipeline,
GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
g_printerr ("Unable to set the pipeline to the playing state.\n");
gst_object_unref (pipeline);
return -1;
}
g_print ("Running...\n");
while(1)
{
;
}
`

How to run multiple pipelines with appsrc in Gstreamer?

I've got running already a working gstreamer pipeline in an embedded C linux application. The pipeline looks like this:
appsrc-> queue - > h264encode -> queue -> h264parse -> mp4mux -> filesink
The source is a video memory buffer which is pushed into a appscr element using the "need-data" standard method.
The code is similar to the gstreamer examples and looks like this:
static void
cb_need_data (GstElement *appsrc,
guint unused_size,
gpointer user_data)
{
static gboolean white = FALSE;
static GstClockTime timestamp = 0;
GstBuffer *buffer;
guint size;
GstFlowReturn ret;
size = 1024 * 768 * 2;
buffer = gst_buffer_new_and_alloc (size);
/* this makes the image black/white */
memset (buffer->data, white ? 0x55 : 0xaa, size);
white = !white;
GST_BUFFER_TIMESTAMP (buffer) = timestamp;
GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int (1, GST_SECOND, 2);
timestamp += GST_BUFFER_DURATION (buffer);
g_print("push-buffer\n");
//g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
ret = gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer);
if (ret != GST_FLOW_OK) {
/* something wrong, stop pushing */
g_print("ret fail\n");
g_main_loop_quit (loop);
}
}
gint
main (gint argc,
gchar *argv[])
{
GstElement *pipeline, *appsrc;
/* init GStreamer */
gst_init (&argc, &argv);
loop = g_main_loop_new (NULL, FALSE);
/* setup pipeline */
pipeline = gst_parse_launch("appsrc name=mysource ! fakesink silent=0", NULL);
appsrc = gst_bin_get_by_name_recurse_up (GST_BIN (element), "source");
GstCaps *caps = gst_video_format_new_caps(GST_VIDEO_FORMAT_UYVY, 1024, 768, 0, 1, 4, 3);
gst_app_src_set_caps(GST_APP_SRC(appsrc), caps);
/* setup appsrc */
g_object_set (G_OBJECT (appsrc),
"stream-type", 0,
"format", GST_FORMAT_TIME, NULL);
g_signal_connect (appsrc, "need-data", G_CALLBACK (cb_need_data), NULL);
/* play */
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_print("PLAY\n");
g_main_loop_run (loop);
/* clean up */
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (pipeline));
g_main_loop_unref (loop);
return 0;
}
Now I need to run multiple identical pipelines in parallel. Since the pipeline elements will be identical, I'm planning to create a data structure containing all necessary gstreamer elements, like that I should be able to create different instances of the same pipeline type:
appsrc1-> ...... -> filesink1
appsrc2-> ...... -> filesink2
appsrc3-> ...... -> filesink3
.....
The question:
The problem is that I don't know how to instantiate the cb_need_data callback function for each the different appsrc elements, would it be possible to instantiate this function? Or do I need to create a copy for each pipeline? (cb_need_data1, cb_need_data2,...etc )

gstreamer 1.0 rtspsrc to rtph264depay cannot link

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.

why is gstreamer caps is blocking pipeline

I am trying a basic pipeline below. If I run the pipeline without the caps function it passes straight through (assuming same I/O format). Once I add the caps the pre-roll starts but the video does not continue through to the sink output.
Am I coding this wrong?
thx
Art
#include <gst/gst.h>
#include <glib.h>
static void
on_pad_added (GstElement *element,
GstPad *pad,
gpointer data)
{
GstPad *sinkpad;
GstElement *decoder = (GstElement *) data;
g_print ("Dynamic pad created, linking out/in \n");
sinkpad = gst_element_get_static_pad (decoder, "sink");
gst_pad_link (pad, sinkpad);
gst_object_unref (sinkpad);
}
int
main (int argc,
char *argv[])
{
GMainLoop *loop;
gboolean link_ok;
GstElement *pipeline, *source, *decoder, *ffcs, *vidsc, *capsfout, *sink;
GstBus *bus;
GstCaps *caps;
/* Initialisation */
gst_init (&argc, &argv);
loop = g_main_loop_new (NULL, FALSE);
/* Create gstreamer elements */
pipeline = gst_pipeline_new ("video-player");
source = gst_element_factory_make ("filesrc", "file-source");
decoder = gst_element_factory_make ("decodebin2", "dec-bin2");
ffcs = gst_element_factory_make ("ffmpegcolorspace", "ffcs");
vidsc = gst_element_factory_make ("videoscale", "vidsc");
capsfout = gst_element_factory_make ("capsfilter", "capsfout");
sink = gst_element_factory_make ("filesink", "vidout");
if (!pipeline || !source || !decoder || !ffcs || !vidsc || !capsfout || !sink) {
g_printerr ("One element could not be created. Exiting.\n");
return -1;
}
/* we set the input/output filename to the source element */
g_object_set (G_OBJECT (source), "location", argv[1], NULL);
g_object_set (G_OBJECT (sink), "location", argv[2], NULL);
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_bin_add_many (GST_BIN (pipeline),
source, decoder, ffcs, vidsc, capsfout, sink, NULL);
/* we link the elements together */
gst_element_link (source, decoder);
gst_element_link (decoder, ffcs);
gst_element_link (ffcs, vidsc);
caps = gst_caps_new_simple("video/x-raw-yuv",
"format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
"width", G_TYPE_INT, 384,
"height", G_TYPE_INT, 216,
"framerate", GST_TYPE_FRACTION, 25, 1,
NULL);
link_ok = gst_element_link_filtered(vidsc,sink,caps);
gst_caps_unref (caps);
if (!link_ok) {
g_warning ("Failed to link vidsc to sink!");
}else{
g_print("seems ok, no error reported?\n");
}
/* Set the pipeline to "playing" state*/
g_print ("Now playing: %s\n", argv[1]);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
/* Iterate */
g_print ("Running...\n");
g_main_loop_run (loop);
/* Out of the main loop, clean up nicely */
g_print ("Returned, stopping playback\n");
gst_element_set_state (pipeline, GST_STATE_NULL);
g_print ("Deleting pipeline\n");
gst_object_unref (GST_OBJECT (pipeline));
return 0;
}
It may be late to answer but you maybe forgot to do the dynamic pad link between some elements and you never call the on_pad_added function. I had the same problem.
Have you tried to add it since then? For example this line to dynamically link two elements instead of the gst_element_link:
g_signal_connect (decoder, "pad-added", G_CALLBACK (on_pad_added), ffcs);
For what reasons do you need the capsfilter? Only constrain the properties you need. E.g. you set a framerate, but don't have a videorate element before the capsfilter. If you don't care about the framerate (e.g. just want to force a size) remove the framerate from the caps you set on capsfilter..

Unable to play .wav file using gstreamer apis

Following code is written to play a .wav file but it doesn't seem to work.
I would like to know if i am missing something in it.
Code:
#include <gst/gst.h>
#include <glib.h>
int main(int argc , char *argv[])
{
GMainLoop *loop;
GstElement *source,*audioparser,*sink,*pipeline;
GstBus *bus;
gst_init(&argc,&argv);
// create a pipeline
loop = g_main_loop_new (NULL, FALSE);
pipeline = gst_pipeline_new ("wav-player");
source = gst_element_factory_make("filesrc","file-source");
audioparser = gst_element_factory_make("wavparse","wav-parser");
sink = gst_element_factory_make("alsasink","sink1");
g_object_set (G_OBJECT (source), "location", argv[1], NULL);
gst_element_set_state (pipeline, GST_STATE_NULL);
// set location to current sourceg_object_set(G_OBJECT(source),"location",argv[1],NULL);
// add elements to bin
gst_bin_add_many(GST_BIN(pipeline),source,audioparser,sink,NULL);
gst_element_link_many(source,audioparser,sink,NULL);
// create bus
bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref (bus);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
g_main_loop_run (loop);
return 1;
}
Please compile this using following command:
gcc -Wall $(pkg-config --cflags --libs gstreamer-0.10) wav.c -o wavparser
Thanks in advance
Just use playbin2 instead of a hand-crafted pipeline
that is, replace everything from "pipeline = gst_pipeline_new()" to "gst_element_link_many" by:
pipeline = gst_element_factory_make("playbin2", NULL);
g_object_set(pipeline, "uri", "file:///the/file/I/want.wav", NULL);
maybe playbin2 is exactly what you need, but answerring question: wavparse does not have static src-pad, so you must handle "pad-added" signal from this element on runtime. something like the code:
gst_bin_add_many (GST_BIN (pipeline), wavsrc, wavparse,audioconvert, audiosink, NULL);
g_object_set (G_OBJECT (wavsrc), "location", "sound.wav", NULL);
gst_element_link(wavsrc, wavparse);
gst_element_link(audioconvert, audiosink);
g_signal_connect (wavparse, "pad-added", G_CALLBACK (on_pad_added), audioconvert);
where: wavsrc is filesrc, wavparse is wavparse, audioconvert is audioconvert, audiosink is alsasink (i'm not sure alsasink works for you, so you can choose another)
void on_pad_added (GstElement *src_element, GstPad *src_pad, gpointer data)
{
g_print ("Linking dynamic pad...\n");
GstElement *sink_element = (GstElement *) data; // is audioconvert
GstPad *sink_pad = gst_element_get_static_pad (sink_element, "sink");
gst_pad_link (src_pad, sink_pad);
gst_object_unref (sink_pad);
src_element = NULL; // yup, i don't want "unused" warning here
}