| /* |
| * GStreamer |
| * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #define CLUTTER_VERSION_MIN_REQUIRED CLUTTER_VERSION_1_8 |
| |
| #include <X11/Xlib.h> |
| #include <X11/extensions/Xcomposite.h> |
| #include <clutter/clutter.h> |
| #include <clutter/x11/clutter-x11.h> |
| #include <clutter/glx/clutter-glx.h> |
| #include <gst/gst.h> |
| #include <gst/video/videooverlay.h> |
| |
| #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; |
| ClutterAnimation *animation = NULL; |
| |
| actor->texture = g_object_new (CLUTTER_X11_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); */ |
| animation = |
| clutter_actor_animate (actor->texture, CLUTTER_LINEAR, 2400, |
| "x", 100.0, "y", 100.0, "opacity", 0, NULL); |
| |
| /* 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 (animation); |
| //g_object_unref (timeline); |
| |
| return FALSE; |
| } |
| |
| static GstBusSyncReply |
| create_window (GstBus * bus, GstMessage * message, gpointer data) |
| { |
| GstGLClutterActor *actor = (GstGLClutterActor *) data; |
| // ignore anything but 'prepare-window-handle' element messages |
| if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) |
| return GST_BUS_PASS; |
| |
| if (!gst_is_video_overlay_prepare_window_handle_message (message)) |
| return GST_BUS_PASS; |
| |
| g_debug ("CREATING WINDOW"); |
| |
| gst_video_overlay_set_window_handle (GST_VIDEO_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; |
| ClutterInitError clutter_err = CLUTTER_INIT_ERROR_UNKNOWN; |
| |
| clutter_err = clutter_init (&argc, &argv); |
| if (clutter_err != CLUTTER_INIT_SUCCESS) |
| g_warning ("Failed to initalize clutter: %d\n", clutter_err); |
| |
| 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, width=320, height=240, framerate=(fraction)30/1 ! " |
| "gleffects effect=twirl ! glimagesink", NULL)); |
| |
| bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); |
| |
| gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, actor, |
| NULL); |
| gst_object_unref (bus); |
| |
| 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); |
| gst_object_unref (pipeline); |
| |
| return 0; |
| } |