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

17 comments:

ange said...

Hi Tristan, the test.c file is no anymore available on your svn repo :/ BTW, did you successfully integrated the gstreamer sink INSIDE a gtk+ widget? I'm still newbie on this issue and I still have some trouble on win32 / gst_x_overlay_set_xwindow_id.

Best!

Tristan Matthews said...

Sorry about the link, I just updated them. In the example the xvimagesink's video is overlayed in the gtk_window widget. I have only tested this in ubuntu, I'm not sure what there is in terms of support for the Xvideo extension in windows. You might try this program:
http://bellet.info/XVideo/testxv.c

Nick said...

Hi Tristan, thanks for this - it has been invaluable for for me learning how to overlay Gstreamer video onto a GTK+ DrawingArea widget! One question though...every time I exit your test program I get an "X Window System Error". It says "The error was a 'BadWindow (invalid Window parameter)'". As I have based my program on yours I get this error too. Have you any idea why this might be caused? I assume it is something to do with the way the g_main_loop is being exited? Any help would be greatly appreciated!
Many thanks,
Nick

Tristan Matthews said...

Hi Nick,

I responded on the gstreamer mailing list but I'd post here in case anyone else reads this.
I've since changed how we use xoverlay in our application (http://svn.sat.qc.ca/trac/miville). Instead of handling the expose-event, I listen on the pipeline's bus for the "prepare-xwindow-id" message and then call
gst_x_overlay_set_xwindow_id on the window. Additionally, I added a callback for the window's destroy-event which quits the GMainLoop.

The updated example lives at:
http://svn.sat.qc.ca/trac/miville/changeset/4318/inhouse/prototypes/gstreamer/cpp/fullscreen/test.c

Anonymous said...

Hi Tristan,I try to compiler test.c,but get somemessage:
test.c:(.text+0x6f): undefined reference to `gst_x_overlay_get_type'
test.c:(.text+0xa0): undefined reference to `gst_x_overlay_set_xwindow_id'
,can u help me?thanks!!

Anonymous said...

Hi Tristan,I try to compiler test.c,but get somemessage:
test.c:(.text+0x6f): undefined reference to `gst_x_overlay_get_type'
test.c:(.text+0xa0): undefined reference to `gst_x_overlay_set_xwindow_id'
,can u help me?thanks!!

Tristan Matthews said...

Anonymous:
Could you post the output of the command:

gst-inspect xvimagesink | grep Version

Anonymous said...

Hi Tristan,
xvimagesink Version:0.10.22

Anonymous said...

Hi Tristan,
My xvimagesink version:0.10.22

Anonymous said...

Hi Tristan,

I have the same problem:

/tmp/ccQth4BD.o: In function `handleBusMsg':
helloworld.c:(.text+0x6b): undefined reference to `gst_x_overlay_get_type'
helloworld.c:(.text+0x9c): undefined reference to `gst_x_overlay_set_xwindow_id'



gst-inspect xvimagesink | grep Version
Version: 0.10.25

sytsem: Ubuntu 9.10

Gerd

Tristan Matthews said...

Hey guys,
I redid the Makefile to use pkg-config, let me know if it still doesn't work and thanks for testing.

Best,
Tristan

Marek said...

Hi,

thanks for your posting, but the links to the files are not working atm. I specifically would like to know how to get the black background.
Could you make the files available again or contact me via marek@jawurek.net ?

Thanks, Marek

Anonymous said...

this article helped me a lot. thank you very much

please update the link to the source code

http://code.sat.qc.ca/miville/inhouse/prototypes/gstreamer/cpp/fullscreen/

Tristan Matthews said...

The files for this article are now on gitorious:
https://gitorious.org/blog-examples/blog-examples/trees/master/fullscreen_video_with_gst_gtk
Now I just have to get around to the other articles here...who knows, maybe I'll even be able to write a new one at some point.

ange said...

hi tristan!
it's me again... surfing my 'past' to check what it's still online about me and i've discovered that:
1-this post it's still alive after more than three years!! you rock! internet rocks!
2-i've never said you thank you for the 'tutorial' that help me a lot, let me say, for these past more than 3 years!! on windows (blah), it's time to move to linux (yeah!)

ange said...
This comment has been removed by a blog administrator.
Tristan Matthews said...

Hi Angelo,

I'm glad the article was helpful! It's great that you're switching to GNU/Linux, it's a joyful move as a developer :)