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
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)
{
;
}
`
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 )
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 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..
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
}