Hello,
I am new to gstreamer, but I really like the flexibility what you can all do.
But now I have an issue that I don’t understand. Hopefully somebody can guide me into the right direction.
I am playing a video with ‘playbin’ and I am adding (at least) 2 text overlay over the video. Because I am switching between videos when something occurs I am putting the sink video in a GTK widget for smooth switching between the videos.
When I use ‘gtksink’ as my ‘sinkVideo’, the two overlay texts are displayed and it is all working fine. But I am wondering why it doesn’t work with the following code when I am using ‘glsinkbin’. I only see the first text, the second text is not shown.
How can I let both the texts shown? Do I need something like a compositor?
#include <gst/gst.h>
#include <gtk/gtk.h>
typedef struct _CustomData {
GstElement *playbin;
GstElement *binVideo;
GstElement *sinkVideo;
GstElement *text1;
GstElement *text2;
GtkWidget *sinkWidget;
} CustomData;
static gboolean handle_message(GstBus *bus, GstMessage *msg, CustomData *data) {
GError *err;
gchar *debug_info;
gboolean ret;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_ERROR:
gst_message_parse_error(msg, &err, &debug_info);
g_printerr("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);
g_printerr("Debugging information: %s\n", debug_info ? debug_info : "none");
g_clear_error(&err);
g_free(debug_info);
break;
case GST_MESSAGE_EOS:
g_print("End-Of-Stream reached.\n");
ret = gst_element_seek(data->playbin, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
if (!ret) {
g_print("Seek failed!\n");
}
break;
case GST_MESSAGE_STATE_CHANGED:
{
if (GST_MESSAGE_SRC(msg) == GST_OBJECT(data->playbin)) {
GstState old_state, new_state, pending_state;
gst_message_parse_state_changed(msg, &old_state, &new_state, &pending_state);
g_print("Pipeline state changed from %s to %s:\n", gst_element_state_get_name(old_state), gst_element_state_get_name(new_state));
}
}
break;
default:
break;
}
return TRUE;
}
static void delete_event_cb(GtkWidget *widget, GdkEvent *event, CustomData *data) {
gtk_main_quit();
}
static void create_ui(CustomData *data) {
GtkWidget *main_window;
GtkWidget *main_box;
GtkWidget *main_hbox;
main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(main_window), "delete-event", G_CALLBACK(delete_event_cb), data);
main_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start(GTK_BOX(main_hbox), data->sinkWidget, TRUE, TRUE, 0);
main_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start(GTK_BOX(main_box), main_hbox, TRUE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(main_window), main_box);
gtk_window_fullscreen(GTK_WINDOW(main_window));
gtk_widget_show_all(main_window);
}
int main(int argc, char *argv[]) {
CustomData data;
gst_init(&argc, &argv);
gtk_init(&argc, &argv);
data.playbin = gst_element_factory_make("playbin", "source");
data.binVideo = gst_bin_new("binVideo");
data.sinkVideo = gst_element_factory_make("glsinkbin", "sinkVideo");
data.text1 = gst_element_factory_make("textoverlay", "text1");
data.text2 = gst_element_factory_make("textoverlay", "text2");
GstElement *gtkglsink = gst_element_factory_make("gtkglsink", "gtkglsink");
if (gtkglsink != NULL && data.sinkVideo != NULL) {
g_object_set(data.sinkVideo, "sink", gtkglsink, NULL);
g_object_get(gtkglsink, "widget", &data.sinkWidget, NULL);
} else {
data.sinkVideo = gst_element_factory_make("gtksink", "gtksink");
g_object_get(data.sinkVideo, "widget", &data.sinkWidget, NULL);
}
if (!data.playbin || !data.binVideo || !data.text1 || !data.text2 || !data.sinkVideo ) {
g_printerr("Not all elements could be created\n");
return -1;
}
gst_bin_add_many(GST_BIN(data.binVideo), data.text1, data.text2, data.sinkVideo, NULL);
if (!gst_element_link_many(data.text1, data.text2, data.sinkVideo, NULL)) {
g_printerr("Elements could not be linked\n");
return -1;
}
g_object_set(data.text1, "text", "TEST-1", NULL);
g_object_set(data.text1, "valignment", 2, NULL);
g_object_set(data.text1, "halignment", 1, NULL);
g_object_set(data.text1, "font-desc", "Sans, 20", NULL);
g_object_set(data.text2, "text", "TEST-2", NULL);
g_object_set(data.text2, "valignment", 1, NULL);
g_object_set(data.text2, "halignment", 1, NULL);
g_object_set(data.text2, "font-desc", "Sans, 20", NULL);
GstPad *sink_pad = gst_element_get_static_pad(data.text1, "video_sink");
GstPad *ghost_pad = gst_ghost_pad_new("sink", sink_pad);
gst_element_add_pad(data.binVideo, ghost_pad);
gst_object_unref(sink_pad);
g_object_set(data.playbin, "video-sink", data.binVideo, NULL);
// Listen to the bus
GstBus *bus = gst_element_get_bus(data.playbin);
gst_bus_add_watch(bus, (GstBusFunc)handle_message, &data);
create_ui(&data);
g_object_set(data.playbin, "uri", "https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm", NULL);
gst_element_set_state(data.playbin, GST_STATE_PLAYING);
gtk_main();
gst_object_unref(bus);
gst_element_set_state(data.playbin, GST_STATE_NULL);
gst_object_unref(data.playbin);
return 0;
}