#include #include #include #include #include #include #include #define W 320 #define H 240 struct GstGLClutterActor_ { Window win; Window root; ClutterActor *texture; ClutterActor *stage; }; typedef struct GstGLClutterActor_ GstGLClutterActor; static gboolean create_actor (GstGLClutterActor *actor) { ClutterKnot knot[2]; ClutterTimeline *timeline; ClutterEffectTemplate *effect_template; actor->texture = g_object_new (CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, "window", actor->win, "automatic-updates", TRUE, NULL); clutter_container_add_actor (CLUTTER_CONTAINER (actor->stage), actor->texture); clutter_actor_set_scale (actor->texture, 0.2 , 0.2); clutter_actor_set_opacity (actor->texture, 0); clutter_actor_show (actor->texture); timeline = clutter_timeline_new(120 /* frames */, 50 /* frames per second. */); clutter_timeline_set_loop(timeline, TRUE); clutter_timeline_start(timeline); /* Instead of our custom callback, * we could use a standard callback. For instance, CLUTTER_ALPHA_SINE_INC. */ effect_template = clutter_effect_template_new (timeline, CLUTTER_ALPHA_SINE_INC); knot[0].x = -10; knot[0].y = -10; knot[1].x= 160; knot[1].y= 120; // Move the actor along the path: clutter_effect_path (effect_template, actor->texture, knot, sizeof(knot) / sizeof(ClutterKnot), NULL, NULL); clutter_effect_scale (effect_template, actor->texture, 1.0, 1.0, NULL, NULL); clutter_effect_rotate (effect_template, actor->texture, CLUTTER_Z_AXIS, 360.0, W/2.0, H/2.0, 0.0, CLUTTER_ROTATE_CW, NULL, NULL); clutter_effect_rotate (effect_template, actor->texture, CLUTTER_X_AXIS, 360.0, 0.0, W/4.0, 0.0, CLUTTER_ROTATE_CW, NULL, NULL); // Also change the actor's opacity while moving it along the path: // (You would probably want to use a different ClutterEffectTemplate, // so you could use a different alpha callback for this.) clutter_effect_fade (effect_template, actor->texture, 255, NULL, NULL); g_object_unref (effect_template); g_object_unref (timeline); return FALSE; } static GstBusSyncReply create_window (GstBus * bus, GstMessage * message, gpointer data) { GstGLClutterActor *actor = (GstGLClutterActor *) data; // ignore anything but 'prepare-xwindow-id' element messages if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) return GST_BUS_PASS; if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) return GST_BUS_PASS; g_debug ("CREATING WINDOW"); gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), actor->win); clutter_threads_add_idle ((GSourceFunc) create_actor, actor); gst_message_unref (message); return GST_BUS_DROP; } int main (int argc, char *argv[]) { GstPipeline *pipeline; GstBus *bus; ClutterActor *stage; GstGLClutterActor *actor; Display *disp; Window stage_win; clutter_init (&argc, &argv); gst_init (&argc, &argv); disp = clutter_x11_get_default_display (); if(!clutter_x11_has_composite_extension ()) { g_error ("XComposite extension missing"); } stage = clutter_stage_get_default (); // clutter_actor_set_size (CLUTTER_ACTOR (stage), W*3+2, H); stage_win = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); actor = g_new0 (GstGLClutterActor, 1); actor->stage = stage; actor->win = XCreateSimpleWindow (disp, stage_win, 0, 0, W, H, 0, 0, 0); XCompositeRedirectWindow (disp, actor->win, CompositeRedirectManual); XMapRaised (disp, actor->win); XSync (disp, FALSE); pipeline = GST_PIPELINE (gst_parse_launch ("videotestsrc ! video/x-raw-rgb, width=320, height=240, framerate=(fraction)30/1 ! " "glupload ! gleffects effect=twirl ! glimagesink", NULL)); bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, actor); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); clutter_actor_show_all (stage); clutter_main(); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); g_object_unref (pipeline); return 0; }