I have a small C project which uses GStreamer. I want to load a video and display it together with a subtitle (textoverlay) and elapsed time (timeoverlay).
My idea looks like this:
- create a textoverlay and set a sample subtitle
- create a timeoverlay
- create a videosink
- put the three elements in a new bin and link them:
textoverlay -> timeoverlay -> videosink
- use playbin2 for playback and send the video from playbin2 to the new bin
Here is my testing standalone application:
// Save as "test.c". Compile with:
// gcc -o test `pkg-config --cflags --libs gtk+-2.0 gstreamer-0.10 gstreamer-interfaces-0.10` test.c
#include <gst/gst.h>
#include <gtk/gtk.h>
int main(int argc, char **argv) {
// Init - GTK is only used here as a GUI hook
gtk_init (&argc, &argv);
gst_init(0, NULL);
// Path to file - juts a simple demo file
char uri[2048];
sprintf(&uri[0], "file:///tmp/1.mpg");
// Playbin and URI
GstElement *playbin2 = gst_element_factory_make ("playbin2", "playbin2");
g_object_set (G_OBJECT (playbin2), "uri", &uri[0], NULL);
// Elements - videosink, textoverlay, timeoverlay
GstElement *videosink = gst_element_factory_make ("sdlvideosink", "videosink");
GstElement *textoverlay = gst_element_factory_make("textoverlay", "textoverlay");
GstElement *timeoverlay = gst_element_factory_make("timeoverlay", "timeoverlay");
// Set sample text in textoverlay
g_object_set(G_OBJECT(textoverlay), "text", "Test Subtitle", NULL);
// Create bin, add elements
GstElement *mybin = gst_bin_new("mybin");
gst_bin_add (GST_BIN (mybin), videosink);
gst_bin_add (GST_BIN (mybin), textoverlay);
gst_bin_add (GST_BIN (mybin), timeoverlay);
// Get sink pad for textoverlay and make it a ghostpad for bin
GstPad *pad_textoverlay_sink = gst_element_get_pad(textoverlay, "video_sink");
gst_element_add_pad(mybin, gst_ghost_pad_new("sink", pad_textoverlay_sink));
// Link elements: textoverlay -> timeoverlay -> videosink
gst_element_link_pads(textoverlay, "src", timeoverlay, "sink");
gst_element_link_pads(timeoverlay, "src", videosink, "sink");
// Conect the bin to the playbin
g_object_set (G_OBJECT (playbin2), "video-sink", mybin, NULL);
// Play video
gst_element_set_state (playbin2, GST_STATE_PLAYING);
// GTK Main loop
gtk_main ();
}
If I link the src pad of textoverlay to the sink pad of the videosink (thus skipping timeoverlay), I get a video and a subtitle – just as expected.
If I change the code and make the sink pad of timeoverlay a ghostpad for mybin, then link the src pad of timeoverlay to videosink (thus skipping textoverlay) – I get a video with elapsed time, just as expected.
However, when I try to cascade textoverlay and timeoverlay, there’s no video. It does not depend on videosink – same with xvimagesink and ximagesink. No error is shown. With gstreamer-launch it works fine, so obviously I’m doing something wrong in C – I just can’t figure out what.
Any help will be appreciated.
What solves the problem is using a pipeline instead of bin.
Why it does, however, is still unclear to me. GStreamer docs say that pipeline is just a top-level bin; I found no restriction in the docs on how many elements can reside in a bin or on what can they do. On the other hand, playbin2 is internally a pipeline, therefore mybin can be a regular bin (and it works fine as a regular bin as long as only textoverlay or timeoverlay is used).