Friday, September 26, 2008

Fullscreen video in gstreamer with gtk+

UPDATE: Source files are now up on gitorious.

In a similar vein to my previous entry, I'd like to explain how to get full screen video with gstreamer and gtk. Here again I'm using the latest CVS head of gstreamer, as well as the gtk+ and gdk development files.

I was very impressed with gtk's well documented API and in-depth tutorial. Also, since both gstreamer and gtk depend on GObject, combining functionality from both frameworks is quite seamless.

The source file fullscreen.c and accompanying Makefile are used for this example.

To test that your build environment is properly setup, I would recommend making a simple C file with the following:

#include <gst/gst.h>
#include <gtk/gtk.h>
#include <gst/interfaces/xoverlay.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>

gint main(gint argc, gchar *argv[])
gst_init(&argc, &argv);
gtk_init(&argc, &argv);
return 0;

and try compiling. Make sure that you have all the necessary development files installed and that your environment can find them. The gst_init and gtk_init calls must always be called once, by any program using gstreamer and gtk. Note that if for some reason they are called more than once, the calls have no effect.

To be able to process key-events and to keep the pipeline rolling, we need to use glib's mainloop. It may be possible to achieve the same results with some other event loop mechanism, this is just the one most often used in gtk and gstreamer applications.

loop = g_main_loop_new (NULL, FALSE);

The simple pipeline here consists of a videotestsrc going to an xvimagesink. We set the "force-aspect-ratio" property of the xvimagesink to TRUE so that when the size is changed, the image's proportions are not distorted.

We build our gtk window:
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(window), "expose-event", G_CALLBACK(expose_cb), sink);

and attach the "expose-event" to the expose callback function. This function will be called when our window is brought to the foreground. The expose callback overlays xvimagesink's video on our gtk window.

A common feature in video-players is to assign a hot key to switch from windowed to full screen viewing. This is possible using:

gtk_widget_set_events(window, GDK_KEY_PRESS_MASK);
g_signal_connect(G_OBJECT(window), "key-press-event", G_CALLBACK(key_press_event_cb), sink);

which connects are key_press_event_cb function to the "key-press-event" signal emitted by the gtk window. The call to gtk_widget_set_events makes sure that the key-press event is propagated all the way up to our top-level window. This is important for determining which level of a window hierarchy is intended to handle such an event.

Lastly, we need to make the window black initially, as otherwise the background will sometimes be white when switching from fullscreen to windowed mode.
We call gtk_widget_show_all() on our window to "recursively show a widget, and any child widgets (if the widget is a container)". The pipeline is then set to playing, and the mainloop is run.

gstreamer test video