9.1 KiB
Basic tutorial 15: Clutter integration
Goal
“Clutter is an open source software
library for creating fast, compelling, portable, and dynamic graphical
user interfaces”. GStreamer can be integrated into Clutter through the
cluttersink
element, allowing video to be used as a texture. This
tutorial shows:
- How to use the video output of a GStreamer pipeline as a texture in Clutter.
Introduction
The process to link GStreamer with Clutter is actually very simple. A cluttersink
element must be instantiated (or, better,
autocluttersink
, if available) and used as the video sink. Through the
texture
property this element accepts a Clutter texture, which is
automatically updated by GStreamer.
A 3D media player
Copy this code into a text file named basic-tutorial-15.c
..
This tutorial is included in the SDK since release 2012.9. If you cannot find it in the downloaded code, please install the latest release of the GStreamer SDK. |
basic-tutorial-15.c
#include <clutter-gst/clutter-gst.h>
/* Setup the video texture once its size is known */
void size_change (ClutterActor *texture, gint width, gint height, gpointer user_data) {
ClutterActor *stage;
gfloat new_x, new_y, new_width, new_height;
gfloat stage_width, stage_height;
ClutterAnimation *animation = NULL;
stage = clutter_actor_get_stage (texture);
if (stage == NULL)
return;
clutter_actor_get_size (stage, &stage_width, &stage_height);
/* Center video on window and calculate new size preserving aspect ratio */
new_height = (height * stage_width) / width;
if (new_height <= stage_height) {
new_width = stage_width;
new_x = 0;
new_y = (stage_height - new_height) / 2;
} else {
new_width = (width * stage_height) / height;
new_height = stage_height;
new_x = (stage_width - new_width) / 2;
new_y = 0;
}
clutter_actor_set_position (texture, new_x, new_y);
clutter_actor_set_size (texture, new_width, new_height);
clutter_actor_set_rotation (texture, CLUTTER_Y_AXIS, 0.0, stage_width / 2, 0, 0);
/* Animate it */
animation = clutter_actor_animate (texture, CLUTTER_LINEAR, 10000, "rotation-angle-y", 360.0, NULL);
clutter_animation_set_loop (animation, TRUE);
}
int main(int argc, char *argv[]) {
GstElement *pipeline, *sink;
ClutterTimeline *timeline;
ClutterActor *stage, *texture;
/* clutter-gst takes care of initializing Clutter and GStreamer */
if (clutter_gst_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) {
g_error ("Failed to initialize clutter\n");
return -1;
}
stage = clutter_stage_get_default ();
/* Make a timeline */
timeline = clutter_timeline_new (1000);
g_object_set(timeline, "loop", TRUE, NULL);
/* Create new texture and disable slicing so the video is properly mapped onto it */
texture = CLUTTER_ACTOR (g_object_new (CLUTTER_TYPE_TEXTURE, "disable-slicing", TRUE, NULL));
g_signal_connect (texture, "size-change", G_CALLBACK (size_change), NULL);
/* Build the GStreamer pipeline */
pipeline = gst_parse_launch ("playbin uri=http://docs.gstreamer.com/media/sintel_trailer-480p.webm", NULL);
/* Instantiate the Clutter sink */
sink = gst_element_factory_make ("autocluttersink", NULL);
if (sink == NULL) {
/* Revert to the older cluttersink, in case autocluttersink was not found */
sink = gst_element_factory_make ("cluttersink", NULL);
}
if (sink == NULL) {
g_printerr ("Unable to find a Clutter sink.\n");
return -1;
}
/* Link GStreamer with Clutter by passing the Clutter texture to the Clutter sink*/
g_object_set (sink, "texture", texture, NULL);
/* Add the Clutter sink to the pipeline */
g_object_set (pipeline, "video-sink", sink, NULL);
/* Start playing */
gst_element_set_state (pipeline, GST_STATE_PLAYING);
/* start the timeline */
clutter_timeline_start (timeline);
/* Add texture to the stage, and show it */
clutter_group_add (CLUTTER_GROUP (stage), texture);
clutter_actor_show_all (stage);
clutter_main();
/* Free resources */
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
return 0;
}
Need help? (Click to expand)
If you need help to compile this code, refer to the Building the tutorials section for your platform: Linux, Mac OS X or Windows, or use this specific command on Linux:
If you need help to run this code, refer to the Running the tutorials section for your platform: Linux, Mac OS X or Windows This tutorial opens a window and displays a movie on a revolving plane, with accompanying audio. The media is fetched from the Internet, so the window might take a few seconds to appear, depending on your connection speed. Required libraries: |
Walkthrough
It is not the purpose of this tutorial to teach how to use Clutter, but how to integrate GStreamer with it. This is accomplished through the clutter-gst library, so its header must be included (and the program must link against it):
#include <clutter-gst/clutter-gst.h>
The first thing this library does is initialize both GStreamer and
Clutter, so you must call clutter-gst-init()
instead of initializing
these libraries yourself.
/* clutter-gst takes care of initializing Clutter and GStreamer */
if (clutter_gst_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) {
g_error ("Failed to initialize clutter\n");
return -1;
}
The GStreamer video is to be played on a Clutter texture, so, we need to create a texture. Just remember to disable texture slicing to allow for proper integration:
/* Create new texture and disable slicing so the video is properly mapped onto it */
texture = CLUTTER_ACTOR (g_object_new (CLUTTER_TYPE_TEXTURE, "disable-slicing", TRUE, NULL));
g_signal_connect (texture, "size-change", G_CALLBACK (size_change), NULL);
We connect to the size-change signal so we can perform final setup once the video size is known.
/* Instantiate the Clutter sink */
sink = gst_element_factory_make ("autocluttersink", NULL);
if (sink == NULL) {
/* Revert to the older cluttersink, in case autocluttersink was not found */
sink = gst_element_factory_make ("cluttersink", NULL);
}
if (sink == NULL) {
g_printerr ("Unable to find a Clutter sink.\n");
return -1;
}
The proper Clutter sink element to instantiate for GStreamer is
autocluttersink
, which works more or less like autovideosink
, trying
to find the best Clutter sink available. However, autocluttersink
(for
which there is no documentation yet) is only available since the 2012.7
release of the SDK, so, if it cannot be found, the
simpler cluttersink
element is created
instead.
/* Link GStreamer with Clutter by passing the Clutter texture to the Clutter sink*/
g_object_set (sink, "texture", texture, NULL);
This texture is everything GStreamer needs to know about Clutter.
/* Add the Clutter sink to the pipeline */
g_object_set (pipeline, "video-sink", sink, NULL);
Finally, tell playbin
to use the sink we created instead of the
default one.
Then the GStreamer pipeline and the Clutter timeline are started and the
ball starts rolling. Once the pipeline has received enough information
to know the video size (width and height), the Clutter texture gets
updated and we receive a notification, handled in the
size_change
callback. This method sets the texture to the proper
size, centers it on the output window and starts a revolving animation,
just for demonstration purposes. But this has nothing to do with
GStreamer.
Conclusion
This tutorial has shown:
- How to use the video output of a GStreamer pipeline as a Clutter
texture using the
cluttersink
orautocluttersink
elements. - How to link GStreamer and Clutter through the
texture
property ofcluttersink
orautocluttersink
.
It has been a pleasure having you here, and see you soon!