summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clutter-gst/Makefile.am23
-rw-r--r--clutter-gst/clutter-gst-actor.c804
-rw-r--r--clutter-gst/clutter-gst-actor.h57
-rw-r--r--clutter-gst/clutter-gst-camera-actor.h216
-rw-r--r--clutter-gst/clutter-gst-camera.c (renamed from clutter-gst/clutter-gst-camera-actor.c)1186
-rw-r--r--clutter-gst/clutter-gst-camera.h208
-rw-r--r--clutter-gst/clutter-gst-playback.c2799
-rw-r--r--clutter-gst/clutter-gst-playback.h116
-rw-r--r--clutter-gst/clutter-gst-player.c3165
-rw-r--r--clutter-gst/clutter-gst-player.h181
-rw-r--r--clutter-gst/clutter-gst-private.h7
-rw-r--r--clutter-gst/clutter-gst-types.c75
-rw-r--r--clutter-gst/clutter-gst-types.h21
-rw-r--r--clutter-gst/clutter-gst-util.c29
-rw-r--r--clutter-gst/clutter-gst-video-actor.c184
-rw-r--r--clutter-gst/clutter-gst-video-actor.h113
-rw-r--r--clutter-gst/clutter-gst-video-sink.c494
-rw-r--r--clutter-gst/clutter-gst-video-sink.h2
-rw-r--r--clutter-gst/clutter-gst.h5
-rw-r--r--configure.ac2
-rw-r--r--examples/camera-player.c94
-rw-r--r--examples/video-player.c66
-rw-r--r--examples/video-sink.c47
-rw-r--r--tests/test-start-stop.c45
-rw-r--r--tests/test-video-actor-new-unref-loop.c2
25 files changed, 4610 insertions, 5331 deletions
diff --git a/clutter-gst/Makefile.am b/clutter-gst/Makefile.am
index 49f1763..2feae3d 100644
--- a/clutter-gst/Makefile.am
+++ b/clutter-gst/Makefile.am
@@ -25,11 +25,10 @@ source_h = \
$(srcdir)/clutter-gst-types.h \
$(srcdir)/clutter-gst-util.h \
$(srcdir)/clutter-gst-version.h \
- $(srcdir)/clutter-gst-actor.h \
- $(srcdir)/clutter-gst-video-sink.h \
- $(srcdir)/clutter-gst-video-actor.h \
- $(srcdir)/clutter-gst-camera-actor.h \
+ $(srcdir)/clutter-gst-actor.h \
+ $(srcdir)/clutter-gst-camera.h \
$(srcdir)/clutter-gst-camera-device.h \
+ $(srcdir)/clutter-gst-playback.h \
$(srcdir)/clutter-gst-player.h \
$(NULL)
@@ -41,13 +40,13 @@ source_priv_h = \
source_c = \
$(srcdir)/clutter-gst-debug.c \
+ $(srcdir)/clutter-gst-types.c \
$(srcdir)/clutter-gst-marshal.c \
$(srcdir)/clutter-gst-player.c \
$(srcdir)/clutter-gst-actor.c \
- $(srcdir)/clutter-gst-video-sink.c \
- $(srcdir)/clutter-gst-video-actor.c \
- $(srcdir)/clutter-gst-camera-actor.c \
+ $(srcdir)/clutter-gst-camera.c \
$(srcdir)/clutter-gst-camera-device.c \
+ $(srcdir)/clutter-gst-playback.c \
$(srcdir)/clutter-gst-util.c \
$(glib_enum_c) \
$(NULL)
@@ -102,8 +101,7 @@ cluttergstheaders_HEADERS = $(source_h) $(glib_enum_h)
#
plugin_source_c = \
- $(srcdir)/clutter-gst-plugin.c \
- $(srcdir)/clutter-gst-video-sink.c \
+ $(srcdir)/clutter-gst-plugin.c \
$(srcdir)/clutter-gst-auto-video-sink.c \
$(srcdir)/clutter-gst-auto-video-sink.h \
$(NULL)
@@ -139,7 +137,9 @@ ClutterGst-@CLUTTER_GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libclutter-gs
--add-include-path=$(srcdir) --add-include=path=. \
--c-include="clutter-gst/clutter-gst.h" \
--include=GObject-2.0 \
+ --include=Cogl-1.0 \
--include=Clutter-1.0 \
+ --include=GdkPixbuf-2.0 \
--add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-1.0` \
--include=Gst-1.0 \
--add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-base-1.0` \
@@ -148,12 +148,16 @@ ClutterGst-@CLUTTER_GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libclutter-gs
--include=GstVideo-1.0 \
--add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-audio-1.0` \
--include=GstAudio-1.0 \
+ --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-pbutils-1.0` \
+ --include=GstPbutils-1.0 \
--add-init-section="clutter_gst_init(0,NULL);" \
--library=libclutter-gst-@CLUTTER_GST_API_VERSION@.la \
--libtool="$(top_builddir)/libtool" \
--output $@ \
--pkg gobject-2.0 \
+ --pkg cogl-1.0 \
--pkg clutter-1.0 \
+ --pkg gdk-pixbuf-2.0 \
--pkg gstreamer-1.0 \
--pkg gstreamer-base-1.0 \
--pkg-export clutter-gst-@CLUTTER_GST_API_VERSION@ \
@@ -178,6 +182,7 @@ typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib)
--includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-base-1.0` \
--includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-video-1.0` \
--includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-audio-1.0` \
+ --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-pbutils-1.0` \
$(INTROSPECTION_COMPILER_OPTS) $< -o $(builddir)/$(@F)
CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA)
diff --git a/clutter-gst/clutter-gst-actor.c b/clutter-gst/clutter-gst-actor.c
index b36c01a..c33fe35 100644
--- a/clutter-gst/clutter-gst-actor.c
+++ b/clutter-gst/clutter-gst-actor.c
@@ -11,7 +11,7 @@
* Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk>
*
* Copyright (C) 2006 OpenedHand
- * Copyright (C) 2010, 2011 Intel Corporation
+ * Copyright (C) 2010-2013 Intel Corporation
* Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
*
* This library is free software; you can redistribute it and/or
@@ -56,365 +56,73 @@
struct _ClutterGstActorPrivate
{
- CoglPipeline *pipeline;
-
- /* width / height (in pixels) of the frame data before applying the pixel
- * aspect ratio */
- gint buffer_width;
- gint buffer_height;
-
- /* Pixel aspect ration is par_n / par_d. this is set by the sink */
- guint par_n, par_d;
-
- /* natural width / height (in pixels) of the actor (after par applied) */
- guint texture_width;
- guint texture_height;
-
- CoglHandle idle_material;
- CoglColor idle_color_unpre;
+ ClutterGstPlayer *player;
+ ClutterGstFrame *frame;
};
static CoglPipeline *texture_template_pipeline = NULL;
enum {
PROP_0,
- PROP_TEXTURE,
- PROP_MATERIAL,
- PROP_IDLE,
- PROP_IDLE_MATERIAL,
- PROP_PAR
-};
-enum
-{
- SIZE_CHANGE,
- LAST_SIGNAL
+ PROP_PLAYER
};
-static int actor_signals[LAST_SIGNAL] = { 0 };
-
G_DEFINE_TYPE (ClutterGstActor, clutter_gst_actor, CLUTTER_TYPE_ACTOR)
-/* Clutter 1.4 has this symbol, we don't want to depend on 1.4 just for that
- * just yet */
-static void
-_cogl_color_unpremultiply (CoglColor *color)
-{
- gfloat alpha;
-
- alpha = cogl_color_get_alpha (color);
-
- if (alpha != 0)
- {
- gfloat red, green, blue;
-
- red = cogl_color_get_red (color);
- green = cogl_color_get_green (color);
- blue = cogl_color_get_blue (color);
-
- red = red / alpha;
- green = green / alpha;
- blue = blue / alpha;
-
- cogl_color_set_from_4f (color, red, green, blue, alpha);
- }
-}
-
-/* Clutter 1.4 has this symbol, we don't want to depend on 1.4 just for that
- * just yet */
-static void
-_cogl_color_set_alpha_byte (CoglColor *color,
- unsigned char alpha)
-{
- unsigned char red, green, blue;
-
- red = cogl_color_get_red_byte (color);
- green = cogl_color_get_green_byte (color);
- blue = cogl_color_get_blue_byte (color);
-
- cogl_color_set_from_4ub (color, red, green, blue, alpha);
-}
-
static void
-texture_free_gl_resources (ClutterGstActor *actor)
+clutter_gst_actor_paint_frame (ClutterGstActor *self,
+ ClutterGstFrame *frame)
{
- ClutterGstActorPrivate *priv = actor->priv;
-
- if (priv->pipeline != NULL)
- {
- /* We want to keep the layer so that the filter settings will
- remain but we want to free its resources so we clear the
- texture handle */
- cogl_pipeline_set_layer_texture (priv->pipeline, 0, NULL);
- }
-}
-
-static void
-gen_texcoords_and_draw_cogl_rectangle (ClutterActor *actor)
-{
- ClutterActorBox box;
-
- clutter_actor_get_allocation_box (actor, &box);
-
- cogl_rectangle_with_texture_coords (0, 0,
- box.x2 - box.x1,
- box.y2 - box.y1,
- 0, 0, 1.0, 1.0);
-}
-
-static void
-create_black_idle_material (ClutterGstActor *actor)
-{
- ClutterGstActorPrivate *priv = actor->priv;
-
- priv->idle_material = cogl_material_new ();
- cogl_color_set_from_4ub (&priv->idle_color_unpre, 0, 0, 0, 0xff);
- cogl_material_set_color (priv->idle_material, &priv->idle_color_unpre);
-}
-
-/*
- * ClutterActor implementation
- */
-
-static gboolean
-clutter_gst_actor_get_paint_volume (ClutterActor *actor,
- ClutterPaintVolume *volume)
-{
- ClutterGstActorPrivate *priv = CLUTTER_GST_ACTOR (actor)->priv;
+ ClutterGstActorPrivate *priv = self->priv;
ClutterActorBox box;
-
- if (priv->pipeline == NULL)
- return FALSE;
-
- if (priv->buffer_width == 0 || priv->buffer_height == 0)
- return FALSE;
-
- /* calling clutter_actor_get_allocation_* can potentially be very
- * expensive, as it can result in a synchronous full stage relayout
- * and redraw
- */
- if (!clutter_actor_has_allocation (actor))
- return FALSE;
-
- clutter_actor_get_allocation_box (actor, &box);
-
- /* we only set the width and height, as the paint volume is defined
- * to be relative to the actor's modelview, which means that the
- * allocation's origin has already been applied
- */
- clutter_paint_volume_set_width (volume, box.x2 - box.x1);
- clutter_paint_volume_set_height (volume, box.y2 - box.y1);
-
- return TRUE;
-}
-
-static void
-clutter_gst_actor_get_natural_size (ClutterGstActor *actor,
- gfloat *width,
- gfloat *height)
-{
- ClutterGstActorPrivate *priv = actor->priv;
- guint dar_n, dar_d;
- gboolean ret;
-
- /* we cache texture_width and texture_height */
-
- if (G_UNLIKELY (priv->buffer_width == 0 || priv->buffer_height == 0))
- {
- /* we don't know the size of the frames yet default to 0,0 */
- priv->texture_width = 0;
- priv->texture_height = 0;
- }
- else if (G_UNLIKELY (priv->texture_width == 0 || priv->texture_height == 0))
- {
- CLUTTER_GST_NOTE (ASPECT_RATIO, "frame is %dx%d with par %d/%d",
- priv->buffer_width, priv->buffer_height,
- priv->par_n, priv->par_d);
-
- ret = gst_video_calculate_display_ratio (&dar_n, &dar_d,
- priv->buffer_width,
- priv->buffer_height,
- priv->par_n, priv->par_d,
- 1, 1);
- if (ret == FALSE)
- dar_n = dar_d = 1;
-
- if (priv->buffer_height % dar_d == 0)
- {
- priv->texture_width = gst_util_uint64_scale (priv->buffer_height,
- dar_n, dar_d);
- priv->texture_height = priv->buffer_height;
- }
- else if (priv->buffer_width % dar_n == 0)
- {
- priv->texture_width = priv->buffer_width;
- priv->texture_height = gst_util_uint64_scale (priv->buffer_width,
- dar_d, dar_n);
-
- }
- else
- {
- priv->texture_width = gst_util_uint64_scale (priv->buffer_height,
- dar_n, dar_d);
- priv->texture_height = priv->buffer_height;
- }
-
- CLUTTER_GST_NOTE (ASPECT_RATIO,
- "final size is %dx%d (calculated par is %d/%d)",
- priv->texture_width, priv->texture_height,
- dar_n, dar_d);
- }
-
- if (width)
- *width = (gfloat)priv->texture_width;
-
- if (height)
- *height = (gfloat)priv->texture_height;
-}
-
-static void
-clutter_gst_actor_get_preferred_width (ClutterActor *self,
- gfloat for_height,
- gfloat *min_width_p,
- gfloat *natural_width_p)
-{
- ClutterGstActor *actor = CLUTTER_GST_ACTOR (self);
- ClutterGstActorPrivate *priv = actor->priv;
- gfloat natural_width, natural_height;
-
- /* Min request is always 0 since we can scale down or clip */
- if (min_width_p)
- *min_width_p = 0;
-
- if (natural_width_p)
- {
- clutter_gst_actor_get_natural_size (actor,
- &natural_width,
- &natural_height);
-
- if (for_height < 0 ||
- priv->buffer_height <= 0)
- {
- *natural_width_p = natural_width;
- }
- else
- {
- gfloat ratio = natural_width / natural_height;
-
- *natural_width_p = ratio * for_height;
- }
- }
-}
-
-static void
-clutter_gst_actor_get_preferred_height (ClutterActor *self,
- gfloat for_width,
- gfloat *min_height_p,
- gfloat *natural_height_p)
-{
- ClutterGstActor *actor = CLUTTER_GST_ACTOR (self);
- ClutterGstActorPrivate *priv = actor->priv;
- gfloat natural_width, natural_height;
-
- /* Min request is always 0 since we can scale down or clip */
- if (min_height_p)
- *min_height_p = 0;
-
- if (natural_height_p)
- {
- clutter_gst_actor_get_natural_size (actor,
- &natural_width,
- &natural_height);
-
- if (for_width < 0 ||
- priv->buffer_width <= 0)
- {
- *natural_height_p = natural_height;
- }
- else
- {
- gfloat ratio = natural_height / natural_width;
-
- *natural_height_p = ratio * for_width;
- }
- }
+ guint8 paint_opacity;
+
+ clutter_actor_get_allocation_box (CLUTTER_ACTOR (self), &box);
+ paint_opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (self));
+ cogl_pipeline_set_color4ub (priv->frame->pipeline,
+ paint_opacity,
+ paint_opacity,
+ paint_opacity,
+ paint_opacity);
+ cogl_set_source (frame->pipeline);
+
+ cogl_rectangle (0, 0, box.x2 - box.x1, box.y2 - box.y1);
}
static void
clutter_gst_actor_paint (ClutterActor *actor)
{
- ClutterGstActorPrivate *priv = CLUTTER_GST_ACTOR (actor)->priv;
- gboolean is_idle;
+ ClutterGstActor *self = CLUTTER_GST_ACTOR (actor);
+ ClutterGstActorPrivate *priv = self->priv;
- is_idle = clutter_gst_actor_is_idle (CLUTTER_GST_ACTOR (actor));
- if (G_UNLIKELY (is_idle) || !priv->pipeline)
+ if (priv->player)
{
- CoglColor *color;
- gfloat alpha;
+ ClutterGstFrame *frame = clutter_gst_player_get_frame (priv->player);
- /* blend the alpha of the idle material with the actor's opacity */
- color = cogl_color_copy (&priv->idle_color_unpre);
- alpha = clutter_actor_get_paint_opacity (actor) *
- cogl_color_get_alpha_byte (color) / 0xff;
- _cogl_color_set_alpha_byte (color, alpha);
- cogl_color_premultiply (color);
- cogl_material_set_color (priv->idle_material, color);
-
- cogl_set_source (priv->idle_material);
-
- /* draw */
- gen_texcoords_and_draw_cogl_rectangle (actor);
- }
- else
- {
- guint8 paint_opacity;
-
- paint_opacity = clutter_actor_get_paint_opacity (actor);
- cogl_pipeline_set_color4ub (priv->pipeline,
- paint_opacity,
- paint_opacity,
- paint_opacity,
- paint_opacity);
- cogl_set_source (priv->pipeline);
-
- gen_texcoords_and_draw_cogl_rectangle (actor);
+ if (frame)
+ CLUTTER_GST_ACTOR_GET_CLASS (self)->paint_frame (self, frame);
}
}
/*
- * ClutterGstActor implementation
- */
-
-static gboolean
-clutter_gst_actor_is_idle_impl (ClutterGstActor *actor)
-{
- ClutterGstActorPrivate *priv = actor->priv;
-
- return !priv->pipeline;
-}
-
-/*
* GObject implementation
*/
static void
-clutter_gst_actor_finalize (GObject *object)
+clutter_gst_actor_dispose (GObject *object)
{
- ClutterGstActor *actor = CLUTTER_GST_ACTOR (object);
- ClutterGstActorPrivate *priv = actor->priv;
+ ClutterGstActorPrivate *priv = CLUTTER_GST_ACTOR (object)->priv;
- texture_free_gl_resources (actor);
+ g_clear_object (&priv->player);
- if (priv->pipeline != NULL)
+ if (priv->frame)
{
- cogl_object_unref (priv->pipeline);
- priv->pipeline = NULL;
+ g_boxed_free (CLUTTER_GST_TYPE_FRAME, priv->frame);
+ priv->frame = NULL;
}
- if (priv->idle_material != COGL_INVALID_HANDLE)
- cogl_handle_unref (priv->idle_material);
-
- G_OBJECT_CLASS (clutter_gst_actor_parent_class)->finalize (object);
+ G_OBJECT_CLASS (clutter_gst_actor_parent_class)->dispose (object);
}
static void
@@ -428,20 +136,11 @@ clutter_gst_actor_get_property (GObject *object,
switch (property_id)
{
- case PROP_TEXTURE:
- g_value_set_boxed (value, clutter_gst_actor_get_cogl_texture (actor));
- break;
- case PROP_MATERIAL:
- g_value_set_boxed (value, clutter_gst_actor_get_cogl_material (actor));
- break;
- case PROP_IDLE:
- g_value_set_boolean (value, clutter_gst_actor_is_idle (actor));
- break;
- case PROP_IDLE_MATERIAL:
- g_value_set_boxed (value, priv->idle_material);
- break;
- case PROP_PAR:
- gst_value_set_fraction (value, priv->par_n, priv->par_d);
+ /* case PROP_PAR: */
+ /* gst_value_set_fraction (value, priv->par_n, priv->par_d); */
+ /* break; */
+ case PROP_PLAYER:
+ g_value_set_object (value, priv->player);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -459,18 +158,13 @@ clutter_gst_actor_set_property (GObject *object,
switch (property_id)
{
- case PROP_TEXTURE:
- clutter_gst_actor_set_cogl_texture (actor, g_value_get_boxed (value));
- break;
- case PROP_MATERIAL:
- clutter_gst_actor_set_cogl_material (actor, g_value_get_boxed (value));
- break;
- case PROP_IDLE_MATERIAL:
- clutter_gst_actor_set_idle_material (actor, g_value_get_boxed (value));
- break;
- case PROP_PAR:
- priv->par_n = gst_value_get_fraction_numerator (value);
- priv->par_d = gst_value_get_fraction_denominator (value);
+ /* case PROP_PAR: */
+ /* priv->par_n = gst_value_get_fraction_numerator (value); */
+ /* priv->par_d = gst_value_get_fraction_denominator (value); */
+ /* break; */
+ case PROP_PLAYER:
+ g_clear_object (&priv->player);
+ priv->player = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -486,92 +180,27 @@ clutter_gst_actor_class_init (ClutterGstActorClass *klass)
g_type_class_add_private (klass, sizeof (ClutterGstActorPrivate));
- klass->is_idle = clutter_gst_actor_is_idle_impl;
-
- object_class->finalize = clutter_gst_actor_finalize;
+ object_class->dispose = clutter_gst_actor_dispose;
object_class->set_property = clutter_gst_actor_set_property;
object_class->get_property = clutter_gst_actor_get_property;
- actor_class->get_paint_volume = clutter_gst_actor_get_paint_volume;
- actor_class->get_preferred_width = clutter_gst_actor_get_preferred_width;
- actor_class->get_preferred_height = clutter_gst_actor_get_preferred_height;
actor_class->paint = clutter_gst_actor_paint;
- /**
- * ClutterGstActor:idle:
- *
- * Whether the #ClutterGstActor is in idle mode.
- */
- pspec = g_param_spec_boolean ("idle",
- "Idle",
- "Idle state of the actor",
- TRUE,
- CLUTTER_GST_PARAM_READABLE);
- g_object_class_install_property (object_class, PROP_IDLE, pspec);
-
- /**
- * ClutterGstActor:texture:
- *
- * Texture to use for drawing when not in idle.
- */
- pspec = g_param_spec_boxed ("texture",
- "Texture",
- "Texture to use for drawing when not in idle",
- COGL_TYPE_HANDLE,
- CLUTTER_GST_PARAM_READWRITE);
- g_object_class_install_property (object_class, PROP_TEXTURE, pspec);
-
- /**
- * ClutterGstActor:material:
- *
- * Material to use for drawing when not in idle.
- */
- pspec = g_param_spec_boxed ("material",
- "Material",
- "Material to use for drawing when not in idle",
- COGL_TYPE_HANDLE,
- CLUTTER_GST_PARAM_READWRITE);
- g_object_class_install_property (object_class, PROP_MATERIAL, pspec);
-
- /**
- * ClutterGstActor:idle-material:
- *
- * Material to use for drawing when in idle.
- */
- pspec = g_param_spec_boxed ("idle-material",
- "Idle material",
- "Material to use for drawing when in idle",
- COGL_TYPE_HANDLE,
- CLUTTER_GST_PARAM_READWRITE);
- g_object_class_install_property (object_class, PROP_IDLE_MATERIAL, pspec);
-
- pspec = gst_param_spec_fraction ("pixel-aspect-ratio",
- "Pixel Aspect Ratio",
- "Pixel aspect ratio of incoming frames",
- 1, 100, 100, 1, 1, 1,
- CLUTTER_GST_PARAM_READWRITE);
- g_object_class_install_property (object_class, PROP_PAR, pspec);
-
- /**
- * ClutterGstActor::size-change:
- * @actor: the actor which received the signal
- * @width: the width of the new actor
- * @height: the height of the new actor
- *
- * The ::size-change signal is emitted each time the size of the
- * pixbuf used by @actor changes. The new size is given as
- * argument to the callback.
- */
- actor_signals[SIZE_CHANGE] =
- g_signal_new ("size-change",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterGstActorClass, size_change),
- NULL, NULL,
- _clutter_gst_marshal_VOID__INT_INT,
- G_TYPE_NONE, 2,
- G_TYPE_INT,
- G_TYPE_INT);
+ klass->paint_frame = clutter_gst_actor_paint_frame;
+
+ /* pspec = gst_param_spec_fraction ("pixel-aspect-ratio", */
+ /* "Pixel Aspect Ratio", */
+ /* "Pixel aspect ratio of incoming frames", */
+ /* 1, 100, 100, 1, 1, 1, */
+ /* CLUTTER_GST_PARAM_READWRITE); */
+ /* g_object_class_install_property (object_class, PROP_PAR, pspec); */
+
+ pspec = g_param_spec_object ("player",
+ "Player",
+ "Player",
+ G_TYPE_OBJECT,
+ CLUTTER_GST_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_PLAYER, pspec);
}
static void
@@ -586,65 +215,23 @@ idle_cb (ClutterGstActor *actor,
static void
clutter_gst_actor_init (ClutterGstActor *actor)
{
- ClutterGstActorPrivate *priv;
-
- actor->priv = priv =
- G_TYPE_INSTANCE_GET_PRIVATE (actor,
- CLUTTER_GST_TYPE_ACTOR,
- ClutterGstActorPrivate);
-
- create_black_idle_material (actor);
-
- if (G_UNLIKELY (texture_template_pipeline == NULL))
- {
- CoglPipeline *pipeline;
- CoglContext *ctx =
- clutter_backend_get_cogl_context (clutter_get_default_backend ());
-
- texture_template_pipeline = cogl_pipeline_new (ctx);
- pipeline = COGL_PIPELINE (texture_template_pipeline);
- cogl_pipeline_set_layer_null_texture (pipeline,
- 0, /* layer_index */
- COGL_TEXTURE_TYPE_2D);
- }
-
- g_assert (texture_template_pipeline != NULL);
- priv->pipeline = cogl_pipeline_copy (texture_template_pipeline);
-
- priv->par_n = priv->par_d = 1;
-
- g_signal_connect (actor, "notify::idle",
- G_CALLBACK (idle_cb),
- NULL);
+ actor->priv = G_TYPE_INSTANCE_GET_PRIVATE (actor,
+ CLUTTER_GST_TYPE_ACTOR,
+ ClutterGstActorPrivate);
}
-typedef struct _GetLayerState
-{
- gboolean has_layer;
- int first_layer;
-} GetLayerState;
-
-static gboolean
-layer_cb (CoglPipeline *pipeline, int layer, void *user_data)
+static void
+_player_new_frame (ClutterGstPlayer *player,
+ ClutterGstFrame *frame,
+ ClutterGstActor *self)
{
- GetLayerState *state = user_data;
-
- state->has_layer = TRUE;
- state->first_layer = layer;
-
- /* We only care about the first layer. */
- return FALSE;
-}
+ ClutterGstActorPrivate *priv = self->priv;
-static gboolean
-get_first_layer_index (CoglPipeline *pipeline, int *layer_index)
-{
- GetLayerState state = { FALSE };
- cogl_pipeline_foreach_layer (pipeline, layer_cb, &state);
- if (state.has_layer)
- *layer_index = state.first_layer;
+ if (priv->frame)
+ g_boxed_free (CLUTTER_GST_TYPE_FRAME, priv->frame);
+ priv->frame = g_boxed_copy (CLUTTER_GST_TYPE_FRAME, frame);
- return state.has_layer;
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
/*
@@ -652,238 +239,67 @@ get_first_layer_index (CoglPipeline *pipeline, int *layer_index)
*/
/**
- * clutter_gst_actor_get_cogl_texture:
- * @actor: A #ClutterActor
+ * clutter_gst_actor_get_player:
+ * @self: a #ClutterGstActor
*
- * Retrieves the handle to the underlying COGL texture used for drawing
- * the actor. No extra reference is taken so if you need to keep the
- * handle then you should call cogl_handle_ref() on it.
+ * Retrieves the #ClutterGstPlayer used by the @self.
*
- * The texture handle returned is the first layer of the material
- * handle used by the #ClutterActor. If you need to access the other
- * layers you should use clutter_gst_actor_get_cogl_material() instead
- * and use the #CoglMaterial API.
+ * Return value: (transfer none): the #ClutterGstPlayer element used by the actor
*
- * Return value: (transfer none): a #CoglHandle for the texture. The returned
- * handle is owned by the #ClutterActor and it should not be unreferenced
+ * Since: 3.0
*/
-CoglHandle
-clutter_gst_actor_get_cogl_texture (ClutterGstActor *actor)
+ClutterGstPlayer *
+clutter_gst_actor_get_player (ClutterGstActor *self)
{
ClutterGstActorPrivate *priv;
- int layer_index;
-
- g_return_val_if_fail (CLUTTER_GST_IS_ACTOR (actor), NULL);
-
- priv = actor->priv;
-
- if (get_first_layer_index (priv->pipeline, &layer_index))
- return cogl_pipeline_get_layer_texture (priv->pipeline, layer_index);
-
- return NULL;
-}
-
-/**
- * clutter_gst_actor_set_cogl_texture:
- * @actor: A #ClutterActor
- * @cogl_tex: A CoglHandle for a texture
- *
- * Replaces the underlying COGL texture drawn by this actor with
- * @cogl_tex. A reference to the texture is taken so if the handle is
- * no longer needed it should be deref'd with cogl_handle_unref.
- */
-void
-clutter_gst_actor_set_cogl_texture (ClutterGstActor *actor,
- CoglHandle cogl_tex)
-{
- ClutterGstActorPrivate *priv;
- gboolean size_changed;
- guint width, height;
-
- g_return_if_fail (CLUTTER_GST_IS_ACTOR (actor));
- g_return_if_fail (cogl_is_texture (cogl_tex));
-
- /* This function can set the texture without the actor being
- realized. This is ok because Clutter requires that the GL context
- always be current so there is no point in waiting to realization
- to set the texture. */
-
- priv = actor->priv;
-
- width = cogl_texture_get_width (cogl_tex);
- height = cogl_texture_get_height (cogl_tex);
-
- /* Reference the new texture now in case it is the same one we are
- already using */
- cogl_object_ref (cogl_tex);
-
- /* Remove old texture */
- texture_free_gl_resources (actor);
-
- /* Use the new texture */
- if (priv->pipeline == NULL)
- priv->pipeline = cogl_pipeline_copy (texture_template_pipeline);
-
- g_assert (priv->pipeline != NULL);
- cogl_pipeline_set_layer_texture (priv->pipeline, 0, cogl_tex);
- /* The pipeline now holds a reference to the texture so we can
- safely release the reference we claimed above */
- cogl_object_unref (cogl_tex);
+ g_return_val_if_fail (CLUTTER_GST_IS_ACTOR (self), NULL);
- size_changed = (width != (guint) priv->buffer_width || height != (guint) priv->buffer_height);
- priv->buffer_width = width;
- priv->buffer_height = height;
+ priv = self->priv;
- if (size_changed)
- {
- priv->texture_width = priv->texture_height = 0;
-
- /* queue a relayout to ask containers/layout manager to ask for
- * the preferred size again */
- clutter_actor_queue_relayout (CLUTTER_ACTOR (actor));
-
- g_signal_emit (actor, actor_signals[SIZE_CHANGE], 0,
- priv->buffer_width,
- priv->buffer_height);
- }
-
- /* If resized actor may need resizing but paint() will do this */
- clutter_actor_queue_redraw (CLUTTER_ACTOR (actor));
-
- g_object_notify (G_OBJECT (actor), "texture");
+ return priv->player;
}
/**
- * clutter_gst_actor_get_cogl_material:
- * @actor: A #ClutterActor
+ * clutter_gst_actor_get_player:
+ * @self: a #ClutterGstActor
*
- * Returns a handle to the underlying COGL material used for drawing
- * the actor.
+ * Retrieves the #ClutterGstPlayer used by the @self.
*
- * Return value: (transfer none): a handle for a #CoglMaterial. The
- * material is owned by the #ClutterActor and it should not be
- * unreferenced
- */
-CoglHandle
-clutter_gst_actor_get_cogl_material (ClutterGstActor *actor)
-{
- g_return_val_if_fail (CLUTTER_GST_IS_ACTOR (actor), NULL);
-
- return actor->priv->pipeline;
-}
-
-/**
- * clutter_gst_actor_set_cogl_material:
- * @actor: A #ClutterActor
- * @cogl_material: A CoglHandle for a material
+ * Return value: (transfer none): the #ClutterGstPlayer element used by the actor
*
- * Replaces the underlying Cogl material drawn by this actor with
- * @cogl_material. A reference to the material is taken so if the
- * handle is no longer needed it should be deref'd with
- * cogl_handle_unref. Texture data is attached to the material so
- * calling this function also replaces the Cogl
- * texture. #ClutterActor requires that the material have a texture
- * layer so you should set one on the material before calling this
- * function.
+ * Since: 3.0
*/
void
-clutter_gst_actor_set_cogl_material (ClutterGstActor *actor,
- CoglHandle cogl_material)
-{
- CoglPipeline *cogl_pipeline = cogl_material;
- CoglHandle cogl_texture;
-
- g_return_if_fail (CLUTTER_GST_IS_ACTOR (actor));
-
- cogl_object_ref (cogl_pipeline);
-
- if (actor->priv->pipeline)
- cogl_object_unref (actor->priv->pipeline);
-
- actor->priv->pipeline = cogl_pipeline;
-
- /* XXX: We are re-asserting the first layer of the new pipeline to ensure the
- * priv state is in sync with the contents of the pipeline. */
- cogl_texture = clutter_gst_actor_get_cogl_texture (actor);
- clutter_gst_actor_set_cogl_texture (actor, cogl_texture);
- /* XXX: If we add support for more pipeline layers, this will need
- * extending */
-
- g_object_notify (G_OBJECT (actor), "material");
-}
-
-/**
- * clutter_gst_actor_is_idle:
- * @actor: a #ClutterGstActor
- *
- * Get the idle state of actor.
- *
- * Return value: TRUE if the actor is in idle, FALSE otherwise.
- */
-gboolean
-clutter_gst_actor_is_idle (ClutterGstActor *actor)
+clutter_gst_actor_set_player (ClutterGstActor *self,
+ ClutterGstPlayer *player)
{
- ClutterGstActorClass *klass;
-
- g_return_val_if_fail (CLUTTER_GST_IS_ACTOR (actor), TRUE);
-
- klass = CLUTTER_GST_ACTOR_GET_CLASS (actor);
-
- return klass->is_idle (actor);
-}
+ ClutterGstActorPrivate *priv;
-/**
- * clutter_gst_actor_get_idle_material:
- * @actor: a #ClutterGstActor
- *
- * Retrieves the material used to draw when the actor is idle.
- *
- * Return value: (transfer none): the #CoglHandle of the idle material
- */
-CoglHandle
-clutter_gst_actor_get_idle_material (ClutterGstActor *actor)
-{
- g_return_val_if_fail (CLUTTER_GST_IS_ACTOR (actor),
- COGL_INVALID_HANDLE);
+ g_return_if_fail (CLUTTER_GST_IS_ACTOR (self));
+ g_return_if_fail (CLUTTER_GST_IS_PLAYER (player) || player == NULL);
- return actor->priv->idle_material;
-}
+ priv = self->priv;
-/**
- * clutter_gst_actor_set_idle_material:
- * @actor: a #ClutterGstActor
- * @cogl_material: the handle of a Cogl material
- *
- * Sets a material to use to draw when the actor is idle. The
- * #ClutterGstActor holds a reference of the @material.
- *
- * The default idle material will paint the #ClutterGstActor in black.
- * If %COGL_INVALID_HANDLE is given as @cogl_material to this function, this
- * default idle material will be used.
- */
-void
-clutter_gst_actor_set_idle_material (ClutterGstActor *actor,
- CoglHandle cogl_material)
-{
- ClutterGstActorPrivate *priv;
+ if (priv->player) {
+ g_boxed_free (CLUTTER_GST_TYPE_FRAME, priv->frame);
+ priv->frame = NULL;
+ g_signal_handlers_disconnect_by_func (priv->player,
+ _player_new_frame,
+ self);
- g_return_if_fail (CLUTTER_GST_IS_ACTOR (actor));
+ g_clear_object (&priv->player);
+ }
- priv = actor->priv;
- /* priv->idle_material always has a valid material */
- cogl_handle_unref (priv->idle_material);
+ if (player != NULL) {
+ priv->player = g_object_ref_sink (player);
+ priv->frame = g_boxed_copy (CLUTTER_GST_TYPE_FRAME,
+ clutter_gst_player_get_frame (player));
- if (cogl_material != COGL_INVALID_HANDLE)
- {
- priv->idle_material = cogl_handle_ref (cogl_material);
- cogl_material_get_color (cogl_material, &priv->idle_color_unpre);
- _cogl_color_unpremultiply (&priv->idle_color_unpre);
- }
- else
- {
- create_black_idle_material (actor);
- }
+ g_signal_connect (priv->player, "new-frame",
+ G_CALLBACK (_player_new_frame), self);
+ }
- g_object_notify (G_OBJECT (actor), "idle-material");
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+ g_object_notify (G_OBJECT (self), "player");
}
diff --git a/clutter-gst/clutter-gst-actor.h b/clutter-gst/clutter-gst-actor.h
index ab21550..baf4b8b 100644
--- a/clutter-gst/clutter-gst-actor.h
+++ b/clutter-gst/clutter-gst-actor.h
@@ -6,8 +6,10 @@
* clutter-gst-actor.h - ClutterActor using GStreamer
*
* Authored By Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk>
+ * Lionel Landwerlin <lionel.g.landwerlin@linux.intel.com>
*
* Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2013 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -34,33 +36,36 @@
#include <glib-object.h>
#include <clutter/clutter.h>
-#include <gst/gstelement.h>
#include <clutter-gst/clutter-gst-types.h>
+#include <clutter-gst/clutter-gst-player.h>
G_BEGIN_DECLS
#define CLUTTER_GST_TYPE_ACTOR clutter_gst_actor_get_type()
#define CLUTTER_GST_ACTOR(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
- CLUTTER_GST_TYPE_ACTOR, ClutterGstActor))
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ CLUTTER_GST_TYPE_ACTOR, \
+ ClutterGstActor))
-#define CLUTTER_GST_ACTOR_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST ((klass), \
- CLUTTER_GST_TYPE_ACTOR, ClutterGstActorClass))
+#define CLUTTER_GST_ACTOR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ CLUTTER_GST_TYPE_ACTOR, \
+ ClutterGstActorClass))
-#define CLUTTER_GST_IS_ACTOR(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
- CLUTTER_GST_TYPE_ACTOR))
+#define CLUTTER_GST_IS_ACTOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ CLUTTER_GST_TYPE_ACTOR))
-#define CLUTTER_GST_IS_ACTOR_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((klass), \
- CLUTTER_GST_TYPE_ACTOR))
+#define CLUTTER_GST_IS_ACTOR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ CLUTTER_GST_TYPE_ACTOR))
-#define CLUTTER_GST_ACTOR_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), \
- CLUTTER_GST_TYPE_ACTOR, ClutterGstActorClass))
+#define CLUTTER_GST_ACTOR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ CLUTTER_GST_TYPE_ACTOR, \
+ ClutterGstActorClass))
typedef struct _ClutterGstActor ClutterGstActor;
typedef struct _ClutterGstActorClass ClutterGstActorClass;
@@ -90,33 +95,23 @@ struct _ClutterGstActorClass
ClutterActorClass parent_class;
/*< public >*/
- void (* size_change) (ClutterGstActor *actor,
- gint width,
- gint height);
- gboolean (* is_idle) (ClutterGstActor *actor);
+ void (* paint_frame) (ClutterGstActor *actor, ClutterGstFrame *frame);
/* Future padding */
- void (* _clutter_reserved1) (void);
void (* _clutter_reserved2) (void);
void (* _clutter_reserved3) (void);
void (* _clutter_reserved4) (void);
void (* _clutter_reserved5) (void);
void (* _clutter_reserved6) (void);
+ void (* _clutter_reserved7) (void);
+ void (* _clutter_reserved8) (void);
};
GType clutter_gst_actor_get_type (void) G_GNUC_CONST;
-CoglHandle clutter_gst_actor_get_cogl_texture (ClutterGstActor *actor);
-void clutter_gst_actor_set_cogl_texture (ClutterGstActor *actor,
- CoglHandle cogl_tex);
-CoglHandle clutter_gst_actor_get_cogl_material (ClutterGstActor *actor);
-void clutter_gst_actor_set_cogl_material (ClutterGstActor *actor,
- CoglHandle cogl_material);
-
-gboolean clutter_gst_actor_is_idle (ClutterGstActor *actor);
-CoglHandle clutter_gst_actor_get_idle_material (ClutterGstActor *actor);
-void clutter_gst_actor_set_idle_material (ClutterGstActor *actor,
- CoglHandle cogl_material);
+ClutterGstPlayer *clutter_gst_actor_get_player (ClutterGstActor *self);
+void clutter_gst_actor_set_player (ClutterGstActor *self,
+ ClutterGstPlayer *player);
G_END_DECLS
diff --git a/clutter-gst/clutter-gst-camera-actor.h b/clutter-gst/clutter-gst-camera-actor.h
deleted file mode 100644
index bbbafbd..0000000
--- a/clutter-gst/clutter-gst-camera-actor.h
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Clutter-GStreamer.
- *
- * GStreamer integration library for Clutter.
- *
- * clutter-gst-camera-actor.h - ClutterActor using GStreamer to display/manipulate a
- * camera stream.
- *
- * Authored By Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk>
- *
- * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#if !defined(__CLUTTER_GST_H_INSIDE__) && !defined(CLUTTER_GST_COMPILATION)
-#error "Only <clutter-gst/clutter-gst.h> can be included directly."
-#endif
-
-#ifndef __CLUTTER_GST_CAMERA_ACTOR_H__
-#define __CLUTTER_GST_CAMERA_ACTOR_H__
-
-#include <clutter/clutter.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <glib-object.h>
-#include <gst/gstelement.h>
-#include <gst/pbutils/encoding-profile.h>
-
-#include <clutter-gst/clutter-gst-actor.h>
-#include <clutter-gst/clutter-gst-camera-device.h>
-#include <clutter-gst/clutter-gst-types.h>
-
-G_BEGIN_DECLS
-
-#define CLUTTER_GST_TYPE_CAMERA_ACTOR clutter_gst_camera_actor_get_type()
-
-#define CLUTTER_GST_CAMERA_ACTOR(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
- CLUTTER_GST_TYPE_CAMERA_ACTOR, ClutterGstCameraActor))
-
-#define CLUTTER_GST_CAMERA_ACTOR_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST ((klass), \
- CLUTTER_GST_TYPE_CAMERA_ACTOR, ClutterGstCameraActorClass))
-
-#define CLUTTER_GST_IS_CAMERA_ACTOR(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
- CLUTTER_GST_TYPE_CAMERA_ACTOR))
-
-#define CLUTTER_GST_IS_CAMERA_ACTOR_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((klass), \
- CLUTTER_GST_TYPE_CAMERA_ACTOR))
-
-#define CLUTTER_GST_CAMERA_ACTOR_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), \
- CLUTTER_GST_TYPE_CAMERA_ACTOR, ClutterGstCameraActorClass))
-
-typedef struct _ClutterGstCameraActor ClutterGstCameraActor;
-typedef struct _ClutterGstCameraActorClass ClutterGstCameraActorClass;
-typedef struct _ClutterGstCameraActorPrivate ClutterGstCameraActorPrivate;
-
-/**
- * ClutterGstCameraActor:
- *
- * Subclass of #ClutterGstActor that displays camera streams using GStreamer.
- *
- * The #ClutterGstCameraActor structure contains only private data and
- * should not be accessed directly.
- */
-struct _ClutterGstCameraActor
-{
- /*< private >*/
- ClutterGstActor parent;
- ClutterGstCameraActorPrivate *priv;
-};
-
-/**
- * ClutterGstCameraActorClass:
- *
- * Base class for #ClutterGstCameraActor.
- */
-struct _ClutterGstCameraActorClass
-{
- /*< private >*/
- ClutterGstActorClass parent_class;
-
- void (* ready_for_capture) (ClutterGstCameraActor *camera_actor,
- gboolean ready);
- void (* photo_saved) (ClutterGstCameraActor *camera_actor);
- void (* photo_taken) (ClutterGstCameraActor *camera_actor,
- GdkPixbuf *pixbuf);
- void (* video_saved) (ClutterGstCameraActor *camera_actor);
-
- /* Future padding */
- void (* _clutter_reserved1) (void);
- void (* _clutter_reserved2) (void);
- void (* _clutter_reserved3) (void);
- void (* _clutter_reserved4) (void);
- void (* _clutter_reserved5) (void);
- void (* _clutter_reserved6) (void);
-};
-
-GType clutter_gst_camera_actor_get_type (void) G_GNUC_CONST;
-
-ClutterActor * clutter_gst_camera_actor_new (void);
-
-GstElement * clutter_gst_camera_actor_get_pipeline (ClutterGstCameraActor *camera_actor);
-GstElement * clutter_gst_camera_actor_get_camerabin (ClutterGstCameraActor *camera_actor);
-
-const GPtrArray *
- clutter_gst_camera_actor_get_camera_devices (ClutterGstCameraActor *camera_actor);
-ClutterGstCameraDevice *
- clutter_gst_camera_actor_get_camera_device (ClutterGstCameraActor *camera_actor);
-gboolean clutter_gst_camera_actor_set_camera_device
- (ClutterGstCameraActor *camera_actor,
- ClutterGstCameraDevice *camera_device);
-
-gboolean clutter_gst_camera_actor_supports_gamma_correction
- (ClutterGstCameraActor *camera_actor);
-gboolean clutter_gst_camera_actor_get_gamma_range (ClutterGstCameraActor *camera_actor,
- gdouble *min_value,
- gdouble *max_value,
- gdouble *default_value);
-gboolean clutter_gst_camera_actor_get_gamma (ClutterGstCameraActor *camera_actor,
- gdouble *cur_value);
-gboolean clutter_gst_camera_actor_set_gamma (ClutterGstCameraActor *camera_actor,
- gdouble value);
-
-gboolean clutter_gst_camera_actor_supports_color_balance
- (ClutterGstCameraActor *camera_actor);
-gboolean clutter_gst_camera_actor_get_color_balance_property_range
- (ClutterGstCameraActor *camera_actor,
- const gchar *property,
- gdouble *min_value,
- gdouble *max_value,
- gdouble *default_value);
-gboolean clutter_gst_camera_actor_get_color_balance_property
- (ClutterGstCameraActor *camera_actor,
- const gchar *property,
- gdouble *cur_value);
-gboolean clutter_gst_camera_actor_set_color_balance_property
- (ClutterGstCameraActor *camera_actor,
- const gchar *property,
- gdouble value);
-gboolean clutter_gst_camera_actor_get_brightness_range (ClutterGstCameraActor *camera_actor,
- gdouble *min_value,
- gdouble *max_value,
- gdouble *default_value);
-gboolean clutter_gst_camera_actor_get_brightness (ClutterGstCameraActor *camera_actor,
- gdouble *cur_value);
-gboolean clutter_gst_camera_actor_set_brightness (ClutterGstCameraActor *camera_actor,
- gdouble value);
-gboolean clutter_gst_camera_actor_get_contrast_range (ClutterGstCameraActor *camera_actor,
- gdouble *min_value,
- gdouble *max_value,
- gdouble *default_value);
-gboolean clutter_gst_camera_actor_get_contrast (ClutterGstCameraActor *camera_actor,
- gdouble *cur_value);
-gboolean clutter_gst_camera_actor_set_contrast (ClutterGstCameraActor *camera_actor,
- gdouble value);
-gboolean clutter_gst_camera_actor_get_saturation_range (ClutterGstCameraActor *camera_actor,
- gdouble *min_value,
- gdouble *max_value,
- gdouble *default_value);
-gboolean clutter_gst_camera_actor_get_saturation (ClutterGstCameraActor *camera_actor,
- gdouble *cur_value);
-gboolean clutter_gst_camera_actor_set_saturation (ClutterGstCameraActor *camera_actor,
- gdouble value);
-gboolean clutter_gst_camera_actor_get_hue_range (ClutterGstCameraActor *camera_actor,
- gdouble *min_value,
- gdouble *max_value,
- gdouble *default_value);
-gboolean clutter_gst_camera_actor_get_hue (ClutterGstCameraActor *camera_actor,
- gdouble *cur_value);
-gboolean clutter_gst_camera_actor_set_hue (ClutterGstCameraActor *camera_actor,
- gdouble value);
-
-GstElement * clutter_gst_camera_actor_get_filter (ClutterGstCameraActor *camera_actor);
-gboolean clutter_gst_camera_actor_set_filter (ClutterGstCameraActor *camera_actor,
- GstElement *filter);
-gboolean clutter_gst_camera_actor_remove_filter (ClutterGstCameraActor *camera_actor);
-
-gboolean clutter_gst_camera_actor_is_playing (ClutterGstCameraActor *camera_actor);
-void clutter_gst_camera_actor_set_playing (ClutterGstCameraActor *camera_actor,
- gboolean playing);
-
-gboolean clutter_gst_camera_actor_is_ready_for_capture (ClutterGstCameraActor *camera_actor);
-
-void clutter_gst_camera_actor_set_video_profile (ClutterGstCameraActor *camera_actor,
- GstEncodingProfile *profile);
-gboolean clutter_gst_camera_actor_is_recording_video (ClutterGstCameraActor *camera_actor);
-gboolean clutter_gst_camera_actor_start_video_recording (ClutterGstCameraActor *camera_actor,
- const gchar *filename);
-void clutter_gst_camera_actor_stop_video_recording (ClutterGstCameraActor *camera_actor);
-
-void clutter_gst_camera_actor_set_photo_profile (ClutterGstCameraActor *camera_actor,
- GstEncodingProfile *profile);
-gboolean clutter_gst_camera_actor_take_photo (ClutterGstCameraActor *camera_actor,
- const gchar *filename);
-gboolean clutter_gst_camera_actor_take_photo_pixbuf (ClutterGstCameraActor *camera);
-
-G_END_DECLS
-
-#endif /* __CLUTTER_GST_CAMERA_ACTOR_H__ */
diff --git a/clutter-gst/clutter-gst-camera-actor.c b/clutter-gst/clutter-gst-camera.c
index 4d87657..43a95f2 100644
--- a/clutter-gst/clutter-gst-camera-actor.c
+++ b/clutter-gst/clutter-gst-camera.c
@@ -3,8 +3,8 @@
*
* GStreamer integration library for Clutter.
*
- * clutter-gst-camera-actor.c - ClutterActor using GStreamer to display/manipulate a
- * camera stream.
+ * clutter-gst-camera.c - a GStreamer pipeline to display/manipulate a
+ * camera stream.
*
* Authored By Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk>
*
@@ -27,10 +27,11 @@
*/
/**
- * SECTION:clutter-gst-camera-actor
- * @short_description: Actor for playback of camera streams.
+ * SECTION:clutter-gst-camera
+ * @short_description: A player of camera streams.
*
- * #ClutterGstCameraActor is a #ClutterActor that plays camera streams.
+ * #ClutterGstCamera implements the #ClutterGstPlayer interface and
+ * plays camera streams.
*/
#ifdef HAVE_CONFIG_H
@@ -47,10 +48,11 @@
#include <gudev/gudev.h>
#endif
-#include "clutter-gst-camera-actor.h"
+#include "clutter-gst-camera.h"
#include "clutter-gst-debug.h"
#include "clutter-gst-enum-types.h"
#include "clutter-gst-marshal.h"
+#include "clutter-gst-player.h"
#include "clutter-gst-private.h"
static const gchar *supported_media_types[] = {
@@ -58,7 +60,7 @@ static const gchar *supported_media_types[] = {
NULL
};
-struct _ClutterGstCameraActorPrivate
+struct _ClutterGstCameraPrivate
{
GPtrArray *camera_devices;
ClutterGstCameraDevice *camera_device;
@@ -90,6 +92,15 @@ enum
enum
{
+ PROP_0,
+
+ PROP_IDLE,
+ PROP_PLAYING,
+ PROP_AUDIO_VOLUME
+};
+
+enum
+{
READY_FOR_CAPTURE,
PHOTO_SAVED,
PHOTO_TAKEN,
@@ -97,33 +108,154 @@ enum
LAST_SIGNAL
};
-static int camera_actor_signals[LAST_SIGNAL] = { 0 };
+static int camera_signals[LAST_SIGNAL] = { 0 };
+
+static void player_iface_init (ClutterGstPlayerIface *iface);
-G_DEFINE_TYPE (ClutterGstCameraActor,
- clutter_gst_camera_actor,
- CLUTTER_GST_TYPE_ACTOR);
+G_DEFINE_TYPE_WITH_CODE (ClutterGstCamera, clutter_gst_camera, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (CLUTTER_GST_TYPE_PLAYER, player_iface_init));
/*
- * ClutterGstActor implementation
+ * ClutterGstPlayer implementation
*/
+static GstElement *
+clutter_gst_camera_get_pipeline (ClutterGstPlayer *player)
+{
+ ClutterGstCameraPrivate *priv = CLUTTER_GST_CAMERA (player)->priv;
+
+ return priv->camerabin;
+}
+
static gboolean
-clutter_gst_camera_actor_is_idle (ClutterGstActor *actor)
+clutter_gst_camera_get_idle (ClutterGstPlayer *player)
{
- ClutterGstCameraActorPrivate *priv = CLUTTER_GST_CAMERA_ACTOR (actor)->priv;
+ ClutterGstCameraPrivate *priv = CLUTTER_GST_CAMERA (player)->priv;
return priv->is_idle;
}
+static gdouble
+clutter_gst_camera_get_audio_volume (ClutterGstPlayer *player)
+{
+ return 0;
+}
+
+
+static void
+clutter_gst_camera_set_audio_volume (ClutterGstPlayer *player,
+ gdouble volume)
+{
+}
+
+static gboolean
+clutter_gst_camera_get_playing (ClutterGstPlayer *player)
+{
+ ClutterGstCameraPrivate *priv = CLUTTER_GST_CAMERA (player)->priv;
+ GstState state, pending;
+ gboolean playing;
+
+ if (!priv->camerabin)
+ return FALSE;
+
+ gst_element_get_state (priv->camerabin, &state, &pending, 0);
+
+ if (pending)
+ playing = (pending == GST_STATE_PLAYING);
+ else
+ playing = (state == GST_STATE_PLAYING);
+
+ return playing;
+}
+
+static void
+clutter_gst_camera_set_playing (ClutterGstPlayer *player,
+ gboolean playing)
+{
+ ClutterGstCameraPrivate *priv = CLUTTER_GST_CAMERA (player)->priv;
+ GstState target_state;
+
+ if (!priv->camerabin)
+ return;
+
+ target_state = playing ? GST_STATE_PLAYING : GST_STATE_NULL;
+
+ gst_element_set_state (priv->camerabin, target_state);
+}
+
+static void
+player_iface_init (ClutterGstPlayerIface *iface)
+{
+ iface->get_pipeline = clutter_gst_camera_get_pipeline;
+ iface->get_idle = clutter_gst_camera_get_idle;
+
+ iface->get_audio_volume = clutter_gst_camera_get_audio_volume;
+ iface->set_audio_volume = clutter_gst_camera_set_audio_volume;
+
+ iface->get_playing = clutter_gst_camera_get_playing;
+ iface->set_playing = clutter_gst_camera_set_playing;
+}
+
/*
* GObject implementation
*/
static void
-clutter_gst_camera_actor_dispose (GObject *object)
+clutter_gst_camera_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id)
+ {
+ case PROP_IDLE:
+ g_value_set_boolean (value,
+ clutter_gst_camera_get_idle (CLUTTER_GST_PLAYER (object)));
+ break;
+
+ case PROP_PLAYING:
+ g_value_set_boolean (value,
+ clutter_gst_camera_get_playing (CLUTTER_GST_PLAYER (object)));
+ break;
+
+ case PROP_AUDIO_VOLUME:
+ g_value_set_double (value,
+ clutter_gst_camera_get_audio_volume (CLUTTER_GST_PLAYER (object)));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+clutter_gst_camera_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id)
+ {
+ case PROP_PLAYING:
+ clutter_gst_camera_set_playing (CLUTTER_GST_PLAYER (object),
+ g_value_get_boolean (value));
+ break;
+
+ case PROP_AUDIO_VOLUME:
+ clutter_gst_camera_set_audio_volume (CLUTTER_GST_PLAYER (object),
+ g_value_get_double (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+clutter_gst_camera_dispose (GObject *object)
{
- ClutterGstCameraActor *camera_actor = CLUTTER_GST_CAMERA_ACTOR (object);
- ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+ ClutterGstCamera *self = CLUTTER_GST_CAMERA (object);
+ ClutterGstCameraPrivate *priv = self->priv;
g_free (priv->photo_filename);
priv->photo_filename = NULL;
@@ -147,102 +279,111 @@ clutter_gst_camera_actor_dispose (GObject *object)
priv->camerabin = NULL;
}
- G_OBJECT_CLASS (clutter_gst_camera_actor_parent_class)->dispose (object);
+ G_OBJECT_CLASS (clutter_gst_camera_parent_class)->dispose (object);
}
static void
-clutter_gst_camera_actor_class_init (ClutterGstCameraActorClass *klass)
+clutter_gst_camera_class_init (ClutterGstCameraClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterGstActorClass *gst_actor_class = CLUTTER_GST_ACTOR_CLASS (klass);
- g_type_class_add_private (klass, sizeof (ClutterGstCameraActorPrivate));
+ g_type_class_add_private (klass, sizeof (ClutterGstCameraPrivate));
+
+ object_class->get_property = clutter_gst_camera_get_property;
+ object_class->set_property = clutter_gst_camera_set_property;
+ object_class->dispose = clutter_gst_camera_dispose;
- object_class->dispose = clutter_gst_camera_actor_dispose;
+ g_object_class_override_property (object_class,
+ PROP_IDLE, "idle");
+ g_object_class_override_property (object_class,
+ PROP_PLAYING, "playing");
+ g_object_class_override_property (object_class,
+ PROP_AUDIO_VOLUME, "audio-volume");
- gst_actor_class->is_idle = clutter_gst_camera_actor_is_idle;
+ /* Signals */
/**
- * ClutterGstCameraActor::ready-for-capture:
- * @camera_actor: the actor which received the signal
- * @ready: whether the @camera_actor is ready for a new capture
+ * ClutterGstCamera::ready-for-capture:
+ * @self: the actor which received the signal
+ * @ready: whether the @self is ready for a new capture
*
* The ::ready-for-capture signal is emitted whenever the value of
- * clutter_gst_camera_actor_is_ready_for_capture changes.
+ * clutter_gst_camera_is_ready_for_capture changes.
*/
- camera_actor_signals[READY_FOR_CAPTURE] =
+ camera_signals[READY_FOR_CAPTURE] =
g_signal_new ("ready-for-capture",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterGstCameraActorClass, ready_for_capture),
+ G_STRUCT_OFFSET (ClutterGstCameraClass, ready_for_capture),
NULL, NULL,
g_cclosure_marshal_VOID__BOOLEAN,
G_TYPE_NONE, 1,
G_TYPE_BOOLEAN);
/**
- * ClutterGstCameraActor::photo-saved:
- * @camera_actor: the actor which received the signal
+ * ClutterGstCamera::photo-saved:
+ * @self: the actor which received the signal
*
* The ::photo-saved signal is emitted when a photo was saved to disk.
*/
- camera_actor_signals[PHOTO_SAVED] =
- g_signal_new ("photo-saved",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (ClutterGstCameraActorClass, photo_saved),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
+ camera_signals[PHOTO_SAVED] =
+ g_signal_new ("photo-saved",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (ClutterGstCameraClass, photo_saved),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
/**
- * ClutterGstCameraActor::photo-taken:
- * @camera_actor: the actor which received the signal
+ * ClutterGstCamera::photo-taken:
+ * @self: the actor which received the signal
* @pixbuf: the photo taken as a #GdkPixbuf
*
* The ::photo-taken signal is emitted when a photo was taken.
*/
- camera_actor_signals[PHOTO_TAKEN] =
- g_signal_new ("photo-taken",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (ClutterGstCameraActorClass, photo_taken),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 1, GDK_TYPE_PIXBUF);
+ camera_signals[PHOTO_TAKEN] =
+ g_signal_new ("photo-taken",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (ClutterGstCameraClass, photo_taken),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, GDK_TYPE_PIXBUF);
/**
- * ClutterGstCameraActor::video-saved:
- * @camera_actor: the actor which received the signal
+ * ClutterGstCamera::video-saved:
+ * @self: the actor which received the signal
*
* The ::video-saved signal is emitted when a video was saved to disk.
*/
- camera_actor_signals[VIDEO_SAVED] =
- g_signal_new ("video-saved",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (ClutterGstCameraActorClass, video_saved),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
+ camera_signals[VIDEO_SAVED] =
+ g_signal_new ("video-saved",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (ClutterGstCameraClass, video_saved),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
}
static void
notify_ready_for_capture (GObject *object,
GParamSpec *pspec,
- ClutterGstCameraActor *camera_actor)
+ ClutterGstCamera *self)
{
- ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+ ClutterGstCameraPrivate *priv = self->priv;
gboolean ready_for_capture;
g_object_get (priv->camera_source, "ready-for-capture",
&ready_for_capture, NULL);
- g_signal_emit (camera_actor, camera_actor_signals[READY_FOR_CAPTURE],
+ g_signal_emit (self, camera_signals[READY_FOR_CAPTURE],
0, ready_for_capture);
}
static void
-parse_photo_data (ClutterGstCameraActor *camera_actor,
- GstSample *sample)
+parse_photo_data (ClutterGstCamera *self,
+ GstSample *sample)
{
- ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+ ClutterGstCameraPrivate *priv = self->priv;
GstBuffer *buffer;
GstCaps *caps;
const GstStructure *structure;
@@ -270,106 +411,106 @@ parse_photo_data (ClutterGstCameraActor *camera_actor,
data ? (GdkPixbufDestroyNotify) g_free : NULL, NULL);
g_object_set (G_OBJECT (priv->camerabin), "post-previews", FALSE, NULL);
- g_signal_emit (camera_actor, camera_actor_signals[PHOTO_TAKEN], 0, pixbuf);
+ g_signal_emit (self, camera_signals[PHOTO_TAKEN], 0, pixbuf);
g_object_unref (pixbuf);
}
static void
-bus_message_cb (GstBus *bus,
- GstMessage *message,
- ClutterGstCameraActor *camera_actor)
+bus_message_cb (GstBus *bus,
+ GstMessage *message,
+ ClutterGstCamera *self)
{
- ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+ ClutterGstCameraPrivate *priv = self->priv;
switch (GST_MESSAGE_TYPE (message))
{
- case GST_MESSAGE_ERROR:
- {
- GError *err = NULL;
- gchar *debug = NULL;
-
- gst_message_parse_error (message, &err, &debug);
- if (err && err->message)
- g_warning ("%s", err->message);
- else
- g_warning ("Unparsable GST_MESSAGE_ERROR message.");
-
- if (err)
- g_error_free (err);
- g_free (debug);
-
- priv->is_idle = TRUE;
- g_object_notify (G_OBJECT (camera_actor), "idle");
- break;
- }
-
- case GST_MESSAGE_STATE_CHANGED:
- {
- if (strcmp (GST_MESSAGE_SRC_NAME (message), "camerabin") == 0)
- {
- GstState new;
-
- gst_message_parse_state_changed (message, NULL, &new, NULL);
- if (new == GST_STATE_PLAYING)
- priv->is_idle = FALSE;
- else
- priv->is_idle = TRUE;
- g_object_notify (G_OBJECT (camera_actor), "idle");
- }
- break;
- }
-
- case GST_MESSAGE_ELEMENT:
- {
- const GstStructure *structure;
- const GValue *image;
-
- if (strcmp (GST_MESSAGE_SRC_NAME (message), "camera_source") == 0)
- {
- structure = gst_message_get_structure (message);
- if (strcmp (gst_structure_get_name (structure), "preview-image") == 0)
- {
- if (gst_structure_has_field_typed (structure, "sample", GST_TYPE_SAMPLE))
- {
- image = gst_structure_get_value (structure, "sample");
- if (image)
- {
- GstSample *sample;
-
- sample = gst_value_get_sample (image);
- parse_photo_data (camera_actor, sample);
- }
- else
- g_warning ("Could not get buffer from bus message");
- }
- }
- }
- else if (strcmp (GST_MESSAGE_SRC_NAME (message), "camerabin") == 0)
- {
- structure = gst_message_get_structure (message);
- if (strcmp (gst_structure_get_name (structure), "image-done") == 0)
- {
- const gchar *filename = gst_structure_get_string (structure, "filename");
- if (priv->photo_filename != NULL && filename != NULL &&
- (strcmp (priv->photo_filename, filename) == 0))
- g_signal_emit (camera_actor, camera_actor_signals[PHOTO_SAVED], 0);
- }
- else if (strcmp (gst_structure_get_name (structure), "video-done") == 0)
- {
- g_signal_emit (camera_actor, camera_actor_signals[VIDEO_SAVED], 0);
- priv->is_recording = FALSE;
- }
- }
- break;
- }
+ case GST_MESSAGE_ERROR:
+ {
+ GError *err = NULL;
+ gchar *debug = NULL;
+
+ gst_message_parse_error (message, &err, &debug);
+ if (err && err->message)
+ g_warning ("%s", err->message);
+ else
+ g_warning ("Unparsable GST_MESSAGE_ERROR message.");
+
+ if (err)
+ g_error_free (err);
+ g_free (debug);
+
+ priv->is_idle = TRUE;
+ g_object_notify (G_OBJECT (self), "idle");
+ break;
+ }
+
+ case GST_MESSAGE_STATE_CHANGED:
+ {
+ if (strcmp (GST_MESSAGE_SRC_NAME (message), "camerabin") == 0)
+ {
+ GstState new;
+
+ gst_message_parse_state_changed (message, NULL, &new, NULL);
+ if (new == GST_STATE_PLAYING)
+ priv->is_idle = FALSE;
+ else
+ priv->is_idle = TRUE;
+ g_object_notify (G_OBJECT (self), "idle");
+ }
+ break;
+ }
+
+ case GST_MESSAGE_ELEMENT:
+ {
+ const GstStructure *structure;
+ const GValue *image;
+
+ if (strcmp (GST_MESSAGE_SRC_NAME (message), "camera_source") == 0)
+ {
+ structure = gst_message_get_structure (message);
+ if (strcmp (gst_structure_get_name (structure), "preview-image") == 0)
+ {
+ if (gst_structure_has_field_typed (structure, "sample", GST_TYPE_SAMPLE))
+ {
+ image = gst_structure_get_value (structure, "sample");
+ if (image)
+ {
+ GstSample *sample;
+
+ sample = gst_value_get_sample (image);
+ parse_photo_data (self, sample);
+ }
+ else
+ g_warning ("Could not get buffer from bus message");
+ }
+ }
+ }
+ else if (strcmp (GST_MESSAGE_SRC_NAME (message), "camerabin") == 0)
+ {
+ structure = gst_message_get_structure (message);
+ if (strcmp (gst_structure_get_name (structure), "image-done") == 0)
+ {
+ const gchar *filename = gst_structure_get_string (structure, "filename");
+ if (priv->photo_filename != NULL && filename != NULL &&
+ (strcmp (priv->photo_filename, filename) == 0))
+ g_signal_emit (self, camera_signals[PHOTO_SAVED], 0);
+ }
+ else if (strcmp (gst_structure_get_name (structure), "video-done") == 0)
+ {
+ g_signal_emit (self, camera_signals[VIDEO_SAVED], 0);
+ priv->is_recording = FALSE;
+ }
+ }
+ break;
+ }
default:
- break;
- }
+ break;
+ }
}
static void
-set_video_profile (ClutterGstCameraActor *camera_actor)
+set_video_profile (ClutterGstCamera *self)
{
GstEncodingContainerProfile *prof;
GstEncodingAudioProfile *audio_prof;
@@ -378,8 +519,8 @@ set_video_profile (ClutterGstCameraActor *camera_actor)
caps = gst_caps_from_string ("application/ogg");
prof = gst_encoding_container_profile_new ("Ogg audio/video",
- "Standard Ogg/Theora/Vorbis",
- caps, NULL);
+ "Standard Ogg/Theora/Vorbis",
+ caps, NULL);
gst_caps_unref (caps);
caps = gst_caps_from_string ("video/x-theora");
@@ -392,16 +533,16 @@ set_video_profile (ClutterGstCameraActor *camera_actor)
gst_encoding_container_profile_add_profile (prof, (GstEncodingProfile*) audio_prof);
gst_caps_unref (caps);
- clutter_gst_camera_actor_set_video_profile (camera_actor,
- (GstEncodingProfile *) prof);
+ clutter_gst_camera_set_video_profile (self,
+ (GstEncodingProfile *) prof);
gst_encoding_profile_unref (prof);
}
static GstElement *
-setup_video_filter_bin (ClutterGstCameraActor *camera_actor)
+setup_video_filter_bin (ClutterGstCamera *self)
{
- ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+ ClutterGstCameraPrivate *priv = self->priv;
GstElement *bin;
GstPad *pad;
@@ -438,7 +579,7 @@ setup_video_filter_bin (ClutterGstCameraActor *camera_actor)
gst_object_unref (pad);
return bin;
-error:
+ error:
if (priv->identity)
gst_object_unref (priv->identity);
if (priv->valve)
@@ -453,14 +594,14 @@ error:
gst_object_unref (priv->post_colorspace);
return NULL;
-error_not_linked:
+ error_not_linked:
gst_object_unref (bin);
return NULL;
}
static GstCaps *
-create_caps_for_formats (gint width,
- gint height)
+create_caps_for_formats (gint width,
+ gint height)
{
GstCaps *ret = NULL;
guint length;
@@ -487,9 +628,9 @@ static void
device_capture_resolution_changed (ClutterGstCameraDevice *camera_device,
gint width,
gint height,
- ClutterGstCameraActor *camera_actor)
+ ClutterGstCamera *self)
{
- ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+ ClutterGstCameraPrivate *priv = self->priv;
GstCaps *caps;
if (priv->camera_device != camera_device)
@@ -503,45 +644,45 @@ device_capture_resolution_changed (ClutterGstCameraDevice *camera_device,
}
static void
-set_device_resolutions (ClutterGstCameraActor *camera_actor,
- ClutterGstCameraDevice *camera_device)
+set_device_resolutions (ClutterGstCamera *self,
+ ClutterGstCameraDevice *device)
{
gint width;
gint height;
- clutter_gst_camera_device_get_capture_resolution (camera_device, &width, &height);
- device_capture_resolution_changed (camera_device, width, height, camera_actor);
+ clutter_gst_camera_device_get_capture_resolution (device, &width, &height);
+ device_capture_resolution_changed (device, width, height, self);
}
static void
-add_device (ClutterGstCameraActor *camera_actor,
- GstElementFactory *element_factory,
- const gchar *device_node,
- const gchar *device_name)
+add_device (ClutterGstCamera *self,
+ GstElementFactory *element_factory,
+ const gchar *device_node,
+ const gchar *device_name)
{
- ClutterGstCameraActorPrivate *priv = camera_actor->priv;
- ClutterGstCameraDevice *camera_device;
+ ClutterGstCameraPrivate *priv = self->priv;
+ ClutterGstCameraDevice *device;
if (!priv->camera_devices)
priv->camera_devices =
- g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
-
- camera_device = g_object_new (CLUTTER_GST_TYPE_CAMERA_DEVICE,
- "element-factory", element_factory,
- "node", device_node,
- "name", device_name,
- NULL);
- g_signal_connect (camera_device, "capture-resolution-changed",
+ g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+
+ device = g_object_new (CLUTTER_GST_TYPE_CAMERA_DEVICE,
+ "element-factory", element_factory,
+ "node", device_node,
+ "name", device_name,
+ NULL);
+ g_signal_connect (device, "capture-resolution-changed",
G_CALLBACK (device_capture_resolution_changed),
- camera_actor);
- g_ptr_array_add (priv->camera_devices, camera_device);
+ self);
+ g_ptr_array_add (priv->camera_devices, device);
}
static gboolean
-probe_camera_devices (ClutterGstCameraActor *camera_actor)
+probe_camera_devices (ClutterGstCamera *self)
{
- ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+ ClutterGstCameraPrivate *priv = self->priv;
GstElement *videosrc;
GstElementFactory *element_factory;
GParamSpec *pspec;
@@ -562,7 +703,7 @@ probe_camera_devices (ClutterGstCameraActor *camera_actor)
}
pspec = g_object_class_find_property (
- G_OBJECT_GET_CLASS (G_OBJECT (videosrc)), "device");
+ G_OBJECT_GET_CLASS (G_OBJECT (videosrc)), "device");
if (!G_IS_PARAM_SPEC_STRING (pspec))
{
g_warning ("Unable to get available camera devices, "
@@ -592,7 +733,7 @@ probe_camera_devices (ClutterGstCameraActor *camera_actor)
device_node = (gchar *) g_udev_device_get_device_file (udevice);
device_name = (gchar *) g_udev_device_get_property (udevice, "ID_V4L_PRODUCT");
- add_device (camera_actor, element_factory, device_node, device_name);
+ add_device (self, element_factory, device_node, device_name);
}
g_object_unref (udevice);
@@ -604,21 +745,21 @@ probe_camera_devices (ClutterGstCameraActor *camera_actor)
* device as only known device */
g_object_get (videosrc, "device", &device_node, NULL);
g_object_get (videosrc, "device-name", &device_name, NULL);
- add_device (camera_actor, element_factory, device_node, device_name);
+ add_device (self, element_factory, device_node, device_name);
g_free (device_node);
g_free (device_name);
#endif
-out:
+ out:
gst_object_unref (videosrc);
return (priv->camera_devices != NULL);
}
static gboolean
-setup_camera_source (ClutterGstCameraActor *camera_actor)
+setup_camera_source (ClutterGstCamera *self)
{
- ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+ ClutterGstCameraPrivate *priv = self->priv;
GstElement *camera_source;
GstElement *old_camera_source = NULL;
@@ -637,7 +778,7 @@ setup_camera_source (ClutterGstCameraActor *camera_actor)
g_signal_connect (camera_source, "notify::ready-for-capture",
G_CALLBACK (notify_ready_for_capture),
- camera_actor);
+ self);
if (priv->video_filter_bin)
{
@@ -650,12 +791,12 @@ setup_camera_source (ClutterGstCameraActor *camera_actor)
}
static gboolean
-setup_pipeline (ClutterGstCameraActor *camera_actor)
+setup_pipeline (ClutterGstCamera *self)
{
- ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+ ClutterGstCameraPrivate *priv = self->priv;
GstElement *camera_sink;
- if (!probe_camera_devices (camera_actor))
+ if (!probe_camera_devices (self))
{
g_critical ("Unable to find any suitable capture device");
return FALSE;
@@ -668,11 +809,11 @@ setup_pipeline (ClutterGstCameraActor *camera_actor)
return FALSE;
}
- priv->video_filter_bin = setup_video_filter_bin (camera_actor);
+ priv->video_filter_bin = setup_video_filter_bin (self);
if (!priv->video_filter_bin)
g_warning ("Unable to setup video filter, some features will be disabled");
- if (G_UNLIKELY (!setup_camera_source (camera_actor)))
+ if (G_UNLIKELY (!setup_camera_source (self)))
{
g_critical ("Unable to create camera source element");
gst_object_unref (priv->camerabin);
@@ -680,8 +821,8 @@ setup_pipeline (ClutterGstCameraActor *camera_actor)
return FALSE;
}
- if (!clutter_gst_camera_actor_set_camera_device (camera_actor,
- g_ptr_array_index (priv->camera_devices, 0)))
+ if (!clutter_gst_camera_set_camera_device (self,
+ g_ptr_array_index (priv->camera_devices, 0)))
{
g_critical ("Unable to select capture device");
gst_object_unref (priv->camerabin);
@@ -689,36 +830,33 @@ setup_pipeline (ClutterGstCameraActor *camera_actor)
return FALSE;
}
- camera_sink = gst_element_factory_make ("cluttersink", NULL);
- g_object_set (camera_sink,
- "actor", CLUTTER_GST_ACTOR (camera_actor),
- NULL);
+ camera_sink = gst_element_factory_make ("coglsink", NULL);
g_object_set (priv->camerabin,
"viewfinder-sink", camera_sink,
NULL);
- set_video_profile (camera_actor);
+ set_video_profile (self);
priv->bus = gst_element_get_bus (priv->camerabin);
gst_bus_add_signal_watch (priv->bus);
g_signal_connect (G_OBJECT (priv->bus), "message",
- G_CALLBACK (bus_message_cb), camera_actor);
+ G_CALLBACK (bus_message_cb), self);
return TRUE;
}
static void
-clutter_gst_camera_actor_init (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_init (ClutterGstCamera *self)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
- camera_actor->priv = priv =
- G_TYPE_INSTANCE_GET_PRIVATE (camera_actor,
- CLUTTER_GST_TYPE_CAMERA_ACTOR,
- ClutterGstCameraActorPrivate);
+ self->priv = priv =
+ G_TYPE_INSTANCE_GET_PRIVATE (self,
+ CLUTTER_GST_TYPE_CAMERA,
+ ClutterGstCameraPrivate);
- if (!setup_pipeline (camera_actor))
+ if (!setup_pipeline (self))
{
g_warning ("Failed to initiate suitable elements for pipeline.");
return;
@@ -732,7 +870,7 @@ clutter_gst_camera_actor_init (ClutterGstCameraActor *camera_actor)
*/
/**
- * clutter_gst_camera_actor_new:
+ * clutter_gst_camera_new:
*
* Create a camera actor.
*
@@ -743,50 +881,50 @@ clutter_gst_camera_actor_init (ClutterGstCameraActor *camera_actor)
*
* Return value: the newly created camera actor
*/
-ClutterActor*
-clutter_gst_camera_actor_new (void)
+ClutterGstCamera *
+clutter_gst_camera_new (void)
{
- return g_object_new (CLUTTER_GST_TYPE_CAMERA_ACTOR,
+ return g_object_new (CLUTTER_GST_TYPE_CAMERA,
NULL);
}
-/**
- * clutter_gst_camera_actor_get_pipeline:
- * @camera_actor: a #ClutterGstCameraActor
- *
- * Retrieve the #GstPipeline used by the @camera_actor, for direct use with
- * GStreamer API.
- *
- * Return value: (transfer none): the pipeline element used by the camera actor
- */
-GstElement *
-clutter_gst_camera_actor_get_pipeline (ClutterGstCameraActor *camera_actor)
-{
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), NULL);
-
- return camera_actor->priv->camerabin;
-}
-
-/**
- * clutter_gst_camera_actor_get_camerabin:
- * @camera_actor: a #ClutterGstCameraActor
- *
- * Retrieve the camerabin element used by the @camera_actor, for direct use with
- * GStreamer API.
- *
- * Return value: (transfer none): the pipeline element used by the camera actor
- */
-GstElement *
-clutter_gst_camera_actor_get_camerabin (ClutterGstCameraActor *camera_actor)
-{
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), NULL);
-
- return camera_actor->priv->camerabin;
-}
+/* /\** */
+/* * clutter_gst_camera_get_pipeline: */
+/* * @self: a #ClutterGstCamera */
+/* * */
+/* * Retrieve the #GstPipeline used by the @self, for direct use with */
+/* * GStreamer API. */
+/* * */
+/* * Return value: (transfer none): the pipeline element used by the camera actor */
+/* *\/ */
+/* GstElement * */
+/* clutter_gst_camera_get_pipeline (ClutterGstCamera *self) */
+/* { */
+/* g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), NULL); */
+
+/* return self->priv->camerabin; */
+/* } */
+
+/* /\** */
+/* * clutter_gst_camera_get_camerabin: */
+/* * @self: a #ClutterGstCamera */
+/* * */
+/* * Retrieve the camerabin element used by the @self, for direct use with */
+/* * GStreamer API. */
+/* * */
+/* * Return value: (transfer none): the pipeline element used by the camera actor */
+/* *\/ */
+/* GstElement * */
+/* clutter_gst_camera_get_camerabin (ClutterGstCamera *self) */
+/* { */
+/* g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), NULL); */
+
+/* return self->priv->camerabin; */
+/* } */
/**
- * clutter_gst_camera_actor_get_camera_devices:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_get_camera_devices:
+ * @self: a #ClutterGstCamera
*
* Retrieve an array of supported camera devices.
*
@@ -794,66 +932,66 @@ clutter_gst_camera_actor_get_camerabin (ClutterGstCameraActor *camera_actor)
* the supported camera devices
*/
const GPtrArray *
-clutter_gst_camera_actor_get_camera_devices (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_get_camera_devices (ClutterGstCamera *self)
{
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), NULL);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), NULL);
- return camera_actor->priv->camera_devices;
+ return self->priv->camera_devices;
}
/**
- * clutter_gst_camera_actor_get_camera_device:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_get_camera_device:
+ * @self: a #ClutterGstCamera
*
* Retrieve the current selected camera device.
*
* Return value: (transfer none): The currently selected camera device
*/
ClutterGstCameraDevice *
-clutter_gst_camera_actor_get_camera_device (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_get_camera_device (ClutterGstCamera *self)
{
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), NULL);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), NULL);
- return camera_actor->priv->camera_device;
+ return self->priv->camera_device;
}
/**
- * clutter_gst_camera_actor_set_camera_device:
- * @camera_actor: a #ClutterGstCameraActor
- * @camera_device: a #ClutterGstCameraDevice
+ * clutter_gst_camera_set_camera_device:
+ * @self: a #ClutterGstCamera
+ * @device: a #ClutterGstCameraDevice
*
* Set the new active camera device.
*
* Return value: %TRUE on success, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_set_camera_device (ClutterGstCameraActor *camera_actor,
- ClutterGstCameraDevice *camera_device)
+clutter_gst_camera_set_camera_device (ClutterGstCamera *self,
+ ClutterGstCameraDevice *device)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
GstElementFactory *element_factory;
GstElement *src;
gchar *node;
gboolean was_playing = FALSE;
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
- g_return_val_if_fail (camera_device != NULL, FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
+ g_return_val_if_fail (device != NULL, FALSE);
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->camerabin)
return FALSE;
if (priv->is_recording)
- clutter_gst_camera_actor_stop_video_recording (camera_actor);
+ clutter_gst_camera_stop_video_recording (self);
- if (clutter_gst_camera_actor_is_playing (camera_actor))
+ if (clutter_gst_camera_is_playing (self))
{
gst_element_set_state (priv->camerabin, GST_STATE_NULL);
was_playing = TRUE;
}
- g_object_get (camera_device,
+ g_object_get (device,
"element-factory", &element_factory,
"node", &node,
NULL);
@@ -875,13 +1013,13 @@ clutter_gst_camera_actor_set_camera_device (ClutterGstCameraActor *camera_actor
gst_object_unref (element_factory);
- priv->camera_device = camera_device;
+ priv->camera_device = device;
g_object_set (G_OBJECT (src), "device", node, NULL);
g_free (node);
g_object_set (G_OBJECT (priv->camera_source), "video-source", src, NULL);
- set_device_resolutions (camera_actor, camera_device);
+ set_device_resolutions (self, device);
if (was_playing)
gst_element_set_state (priv->camerabin, GST_STATE_PLAYING);
@@ -890,24 +1028,24 @@ clutter_gst_camera_actor_set_camera_device (ClutterGstCameraActor *camera_actor
}
/**
- * clutter_gst_camera_actor_supports_gamma_correction:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_supports_gamma_correction:
+ * @self: a #ClutterGstCamera
*
- * Check whether the @camera_actor supports gamma correction.
+ * Check whether the @self supports gamma correction.
*
- * Return value: %TRUE if @camera_actor supports gamma correction, %FALSE otherwise
+ * Return value: %TRUE if @self supports gamma correction, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_supports_gamma_correction (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_supports_gamma_correction (ClutterGstCamera *self)
{
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
- return (camera_actor->priv->gamma != NULL);
+ return (self->priv->gamma != NULL);
}
/**
- * clutter_gst_camera_actor_get_gamma_range:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_get_gamma_range:
+ * @self: a #ClutterGstCamera
* @min_value: Pointer to store the minimum gamma value, or %NULL
* @max_value: Pointer to store the maximum gamma value, or %NULL
* @default_value: Pointer to store the default gamma value, or %NULL
@@ -915,29 +1053,29 @@ clutter_gst_camera_actor_supports_gamma_correction (ClutterGstCameraActor *camer
* Retrieve the minimum, maximum and default gamma values.
*
* This method will return FALSE if gamma correction is not
- * supported on @camera_actor.
- * See clutter_gst_camera_actor_supports_gamma_correction().
+ * supported on @self.
+ * See clutter_gst_camera_supports_gamma_correction().
*
* Return value: %TRUE if successful, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_get_gamma_range (ClutterGstCameraActor *camera_actor,
- gdouble *min_value,
- gdouble *max_value,
- gdouble *default_value)
+clutter_gst_camera_get_gamma_range (ClutterGstCamera *self,
+ gdouble *min_value,
+ gdouble *max_value,
+ gdouble *default_value)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
GParamSpec *pspec;
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->gamma)
return FALSE;
pspec = g_object_class_find_property (
- G_OBJECT_GET_CLASS (G_OBJECT (priv->gamma)), "gamma");
+ G_OBJECT_GET_CLASS (G_OBJECT (priv->gamma)), "gamma");
/* shouldn't happen */
g_return_val_if_fail (G_IS_PARAM_SPEC_DOUBLE (pspec), FALSE);
@@ -951,28 +1089,28 @@ clutter_gst_camera_actor_get_gamma_range (ClutterGstCameraActor *camera_actor,
}
/**
- * clutter_gst_camera_actor_get_gamma:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_get_gamma:
+ * @self: a #ClutterGstCamera
* @cur_value: Pointer to store the current gamma value
*
* Retrieve the current gamma value.
*
* This method will return FALSE if gamma correction is not
- * supported on @camera_actor.
- * See clutter_gst_camera_actor_supports_gamma_correction().
+ * supported on @self.
+ * See clutter_gst_camera_supports_gamma_correction().
*
* Return value: %TRUE if successful, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_get_gamma (ClutterGstCameraActor *camera_actor,
- gdouble *cur_value)
+clutter_gst_camera_get_gamma (ClutterGstCamera *self,
+ gdouble *cur_value)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
g_return_val_if_fail (cur_value != NULL, FALSE);
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->gamma)
return FALSE;
@@ -982,29 +1120,29 @@ clutter_gst_camera_actor_get_gamma (ClutterGstCameraActor *camera_actor,
}
/**
- * clutter_gst_camera_actor_set_gamma:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_set_gamma:
+ * @self: a #ClutterGstCamera
* @value: The value to set
*
* Set the gamma value.
* Allowed values can be retrieved with
- * clutter_gst_camera_actor_get_gamma_range().
+ * clutter_gst_camera_get_gamma_range().
*
* This method will return FALSE if gamma correction is not
- * supported on @camera_actor.
- * See clutter_gst_camera_actor_supports_gamma_correction().
+ * supported on @self.
+ * See clutter_gst_camera_supports_gamma_correction().
*
* Return value: %TRUE if successful, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_set_gamma (ClutterGstCameraActor *camera_actor,
- gdouble value)
+clutter_gst_camera_set_gamma (ClutterGstCamera *self,
+ gdouble value)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->gamma)
return FALSE;
@@ -1014,24 +1152,24 @@ clutter_gst_camera_actor_set_gamma (ClutterGstCameraActor *camera_actor,
}
/**
- * clutter_gst_camera_actor_supports_color_balance:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_supports_color_balance:
+ * @self: a #ClutterGstCamera
*
- * Check whether the @camera_actor supports color balance.
+ * Check whether the @self supports color balance.
*
- * Return value: %TRUE if @camera_actor supports color balance, %FALSE otherwise
+ * Return value: %TRUE if @self supports color balance, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_supports_color_balance (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_supports_color_balance (ClutterGstCamera *self)
{
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
- return (camera_actor->priv->color_balance != NULL);
+ return (self->priv->color_balance != NULL);
}
/**
- * clutter_gst_camera_actor_get_color_balance_property_range:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_get_color_balance_property_range:
+ * @self: a #ClutterGstCamera
* @property: Property name
* @min_value: Pointer to store the minimum value of @property, or %NULL
* @max_value: Pointer to store the maximum value of @property, or %NULL
@@ -1040,30 +1178,30 @@ clutter_gst_camera_actor_supports_color_balance (ClutterGstCameraActor *camera_a
* Retrieve the minimum, maximum and default values for the color balance property @property,
*
* This method will return FALSE if @property does not exist or color balance is not
- * supported on @camera_actor.
- * See clutter_gst_camera_actor_supports_color_balance().
+ * supported on @self.
+ * See clutter_gst_camera_supports_color_balance().
*
* Return value: %TRUE if successful, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_get_color_balance_property_range (ClutterGstCameraActor *camera_actor,
- const gchar *property,
- gdouble *min_value,
- gdouble *max_value,
- gdouble *default_value)
+clutter_gst_camera_get_color_balance_property_range (ClutterGstCamera *self,
+ const gchar *property,
+ gdouble *min_value,
+ gdouble *max_value,
+ gdouble *default_value)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
GParamSpec *pspec;
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->color_balance)
return FALSE;
pspec = g_object_class_find_property (
- G_OBJECT_GET_CLASS (G_OBJECT (priv->color_balance)), property);
+ G_OBJECT_GET_CLASS (G_OBJECT (priv->color_balance)), property);
g_return_val_if_fail (G_IS_PARAM_SPEC_DOUBLE (pspec), FALSE);
if (min_value)
@@ -1076,37 +1214,37 @@ clutter_gst_camera_actor_get_color_balance_property_range (ClutterGstCameraActor
}
/**
- * clutter_gst_camera_actor_get_color_balance_property:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_get_color_balance_property:
+ * @self: a #ClutterGstCamera
* @property: Property name
* @cur_value: Pointer to store the current value of @property
*
* Retrieve the current value for the color balance property @property,
*
* This method will return FALSE if @property does not exist or color balance is not
- * supported on @camera_actor.
- * See clutter_gst_camera_actor_supports_color_balance().
+ * supported on @self.
+ * See clutter_gst_camera_supports_color_balance().
*
* Return value: %TRUE if successful, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_get_color_balance_property (ClutterGstCameraActor *camera_actor,
- const gchar *property,
- gdouble *cur_value)
+clutter_gst_camera_get_color_balance_property (ClutterGstCamera *self,
+ const gchar *property,
+ gdouble *cur_value)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
GParamSpec *pspec;
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
g_return_val_if_fail (cur_value != NULL, FALSE);
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->color_balance)
return FALSE;
pspec = g_object_class_find_property (
- G_OBJECT_GET_CLASS (G_OBJECT (priv->color_balance)), property);
+ G_OBJECT_GET_CLASS (G_OBJECT (priv->color_balance)), property);
g_return_val_if_fail (G_IS_PARAM_SPEC_DOUBLE (pspec), FALSE);
g_object_get (G_OBJECT (priv->color_balance), property, cur_value, NULL);
@@ -1114,38 +1252,38 @@ clutter_gst_camera_actor_get_color_balance_property (ClutterGstCameraActor *came
}
/**
- * clutter_gst_camera_actor_set_color_balance_property:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_set_color_balance_property:
+ * @self: a #ClutterGstCamera
* @property: Property name
* @value: The value to set
*
* Set the value for the color balance property @property to @value.
* Allowed values can be retrieved with
- * clutter_gst_camera_actor_get_color_balance_property_range().
+ * clutter_gst_camera_get_color_balance_property_range().
*
* This method will return FALSE if @property does not exist or color balance is not
- * supported on @camera_actor.
- * See clutter_gst_camera_actor_supports_color_balance().
+ * supported on @self.
+ * See clutter_gst_camera_supports_color_balance().
*
* Return value: %TRUE if successful, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_set_color_balance_property (ClutterGstCameraActor *camera_actor,
- const gchar *property,
- gdouble value)
+clutter_gst_camera_set_color_balance_property (ClutterGstCamera *self,
+ const gchar *property,
+ gdouble value)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
GParamSpec *pspec;
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->color_balance)
return FALSE;
pspec = g_object_class_find_property (
- G_OBJECT_GET_CLASS (G_OBJECT (priv->color_balance)), property);
+ G_OBJECT_GET_CLASS (G_OBJECT (priv->color_balance)), property);
g_return_val_if_fail (G_IS_PARAM_SPEC_DOUBLE (pspec), FALSE);
g_object_set (G_OBJECT (priv->color_balance), property, value, NULL);
@@ -1153,123 +1291,123 @@ clutter_gst_camera_actor_set_color_balance_property (ClutterGstCameraActor *came
}
gboolean
-clutter_gst_camera_actor_get_brightness_range (ClutterGstCameraActor *camera_actor,
- gdouble *min_value,
- gdouble *max_value,
- gdouble *default_value)
+clutter_gst_camera_get_brightness_range (ClutterGstCamera *self,
+ gdouble *min_value,
+ gdouble *max_value,
+ gdouble *default_value)
{
- return clutter_gst_camera_actor_get_color_balance_property_range (camera_actor,
- "brightness", min_value, max_value, default_value);
+ return clutter_gst_camera_get_color_balance_property_range (self,
+ "brightness", min_value, max_value, default_value);
}
gboolean
-clutter_gst_camera_actor_get_brightness (ClutterGstCameraActor *camera_actor,
- gdouble *cur_value)
+clutter_gst_camera_get_brightness (ClutterGstCamera *self,
+ gdouble *cur_value)
{
- return clutter_gst_camera_actor_get_color_balance_property (camera_actor,
- "brightness", cur_value);
+ return clutter_gst_camera_get_color_balance_property (self,
+ "brightness", cur_value);
}
gboolean
-clutter_gst_camera_actor_set_brightness (ClutterGstCameraActor *camera_actor,
- gdouble value)
+clutter_gst_camera_set_brightness (ClutterGstCamera *self,
+ gdouble value)
{
- return clutter_gst_camera_actor_set_color_balance_property (camera_actor,
- "brightness", value);
+ return clutter_gst_camera_set_color_balance_property (self,
+ "brightness", value);
}
gboolean
-clutter_gst_camera_actor_get_contrast_range (ClutterGstCameraActor *camera_actor,
- gdouble *min_value,
- gdouble *max_value,
- gdouble *default_value)
+clutter_gst_camera_get_contrast_range (ClutterGstCamera *self,
+ gdouble *min_value,
+ gdouble *max_value,
+ gdouble *default_value)
{
- return clutter_gst_camera_actor_get_color_balance_property_range (camera_actor,
- "contrast", min_value, max_value, default_value);
+ return clutter_gst_camera_get_color_balance_property_range (self,
+ "contrast", min_value, max_value, default_value);
}
gboolean
-clutter_gst_camera_actor_get_contrast (ClutterGstCameraActor *camera_actor,
- gdouble *cur_value)
+clutter_gst_camera_get_contrast (ClutterGstCamera *self,
+ gdouble *cur_value)
{
- return clutter_gst_camera_actor_get_color_balance_property (camera_actor,
- "contrast", cur_value);
+ return clutter_gst_camera_get_color_balance_property (self,
+ "contrast", cur_value);
}
gboolean
-clutter_gst_camera_actor_set_contrast (ClutterGstCameraActor *camera_actor,
- gdouble value)
+clutter_gst_camera_set_contrast (ClutterGstCamera *self,
+ gdouble value)
{
- return clutter_gst_camera_actor_set_color_balance_property (camera_actor,
- "contrast", value);
+ return clutter_gst_camera_set_color_balance_property (self,
+ "contrast", value);
}
gboolean
-clutter_gst_camera_actor_get_saturation_range (ClutterGstCameraActor *camera_actor,
- gdouble *min_value,
- gdouble *max_value,
- gdouble *default_value)
+clutter_gst_camera_get_saturation_range (ClutterGstCamera *self,
+ gdouble *min_value,
+ gdouble *max_value,
+ gdouble *default_value)
{
- return clutter_gst_camera_actor_get_color_balance_property_range (camera_actor,
- "saturation", min_value, max_value, default_value);
+ return clutter_gst_camera_get_color_balance_property_range (self,
+ "saturation", min_value, max_value, default_value);
}
gboolean
-clutter_gst_camera_actor_get_saturation (ClutterGstCameraActor *camera_actor,
- gdouble *cur_value)
+clutter_gst_camera_get_saturation (ClutterGstCamera *self,
+ gdouble *cur_value)
{
- return clutter_gst_camera_actor_get_color_balance_property (camera_actor,
- "saturation", cur_value);
+ return clutter_gst_camera_get_color_balance_property (self,
+ "saturation", cur_value);
}
gboolean
-clutter_gst_camera_actor_set_saturation (ClutterGstCameraActor *camera_actor,
- gdouble value)
+clutter_gst_camera_set_saturation (ClutterGstCamera *self,
+ gdouble value)
{
- return clutter_gst_camera_actor_set_color_balance_property (camera_actor,
- "saturation", value);
+ return clutter_gst_camera_set_color_balance_property (self,
+ "saturation", value);
}
gboolean
-clutter_gst_camera_actor_get_hue_range (ClutterGstCameraActor *camera_actor,
- gdouble *min_value,
- gdouble *max_value,
- gdouble *default_value)
+clutter_gst_camera_get_hue_range (ClutterGstCamera *self,
+ gdouble *min_value,
+ gdouble *max_value,
+ gdouble *default_value)
{
- return clutter_gst_camera_actor_get_color_balance_property_range (camera_actor,
- "hue", min_value, max_value, default_value);
+ return clutter_gst_camera_get_color_balance_property_range (self,
+ "hue", min_value, max_value, default_value);
}
gboolean
-clutter_gst_camera_actor_get_hue (ClutterGstCameraActor *camera_actor,
- gdouble *cur_value)
+clutter_gst_camera_get_hue (ClutterGstCamera *self,
+ gdouble *cur_value)
{
- return clutter_gst_camera_actor_get_color_balance_property (camera_actor,
- "hue", cur_value);
+ return clutter_gst_camera_get_color_balance_property (self,
+ "hue", cur_value);
}
gboolean
-clutter_gst_camera_actor_set_hue (ClutterGstCameraActor *camera_actor,
- gdouble value)
+clutter_gst_camera_set_hue (ClutterGstCamera *self,
+ gdouble value)
{
- return clutter_gst_camera_actor_set_color_balance_property (camera_actor,
- "hue", value);
+ return clutter_gst_camera_set_color_balance_property (self,
+ "hue", value);
}
/**
- * clutter_gst_camera_actor_get_filter:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_get_filter:
+ * @self: a #ClutterGstCamera
*
* Retrieve the current filter being used.
*
* Return value: (transfer none): The current filter or %NULL if none is set
*/
GstElement *
-clutter_gst_camera_actor_get_filter (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_get_filter (ClutterGstCamera *self)
{
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
- return camera_actor->priv->custom_filter;
+ return self->priv->custom_filter;
}
static GstElement *
@@ -1300,25 +1438,25 @@ create_filter_bin (GstElement *filter)
gst_element_add_pad (filter_bin, gst_ghost_pad_new ("src", pad));
gst_object_unref (GST_OBJECT (pad));
-out:
+ out:
return filter_bin;
-err:
+ err:
if (pre_filter_colorspace)
gst_object_unref (pre_filter_colorspace);
if (post_filter_colorspace)
gst_object_unref (post_filter_colorspace);
goto out;
-err_not_linked:
+ err_not_linked:
gst_object_unref (filter_bin);
filter_bin = NULL;
goto out;
}
/**
- * clutter_gst_camera_actor_set_filter:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_set_filter:
+ * @self: a #ClutterGstCamera
* @filter: a #GstElement for the filter
*
* Set the filter element to be used.
@@ -1327,15 +1465,15 @@ err_not_linked:
* Return value: %TRUE on success, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_set_filter (ClutterGstCameraActor *camera_actor,
- GstElement *filter)
+clutter_gst_camera_set_filter (ClutterGstCamera *self,
+ GstElement *filter)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
gboolean ret = FALSE;
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->custom_filter && !filter)
{
@@ -1381,7 +1519,7 @@ clutter_gst_camera_actor_set_filter (ClutterGstCameraActor *camera_actor,
goto err_restore;
}
- if (clutter_gst_camera_actor_is_playing (camera_actor))
+ if (clutter_gst_camera_is_playing (self))
gst_element_set_state (priv->custom_filter, GST_STATE_PLAYING);
}
else
@@ -1389,11 +1527,11 @@ clutter_gst_camera_actor_set_filter (ClutterGstCameraActor *camera_actor,
ret = TRUE;
-out:
+ out:
g_object_set (G_OBJECT (priv->valve), "drop", FALSE, NULL);
return ret;
-err_restore:
+ err_restore:
ret = FALSE;
/* restore default pipeline, should always work */
gst_element_link (priv->valve, priv->gamma);
@@ -1401,37 +1539,37 @@ err_restore:
}
/**
- * clutter_gst_camera_actor_remove_filter:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_remove_filter:
+ * @self: a #ClutterGstCamera
*
* Remove the current filter, if any.
*
* Return value: %TRUE on success, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_remove_filter (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_remove_filter (ClutterGstCamera *self)
{
- return clutter_gst_camera_actor_set_filter (camera_actor, NULL);
+ return clutter_gst_camera_set_filter (self, NULL);
}
/**
- * clutter_gst_camera_actor_is_playing:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_is_playing:
+ * @self: a #ClutterGstCamera
*
- * Retrieve whether the @camera_actor is playing.
+ * Retrieve whether the @self is playing.
*
* Return value: %TRUE if playing, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_is_playing (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_is_playing (ClutterGstCamera *self)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
GstState state, pending;
gboolean playing;
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->camerabin)
return FALSE;
@@ -1446,48 +1584,22 @@ clutter_gst_camera_actor_is_playing (ClutterGstCameraActor *camera_actor)
}
/**
- * clutter_gst_camera_actor_set_playing:
- * @camera_actor: a #ClutterGstCameraActor
- * @playing: %TRUE to start playback
- *
- * Starts or stops playback.
- */
-void
-clutter_gst_camera_actor_set_playing (ClutterGstCameraActor *camera_actor,
- gboolean playing)
-{
- ClutterGstCameraActorPrivate *priv;
- GstState target_state;
-
- g_return_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor));
-
- priv = camera_actor->priv;
-
- if (!priv->camerabin)
- return;
-
- target_state = playing ? GST_STATE_PLAYING : GST_STATE_NULL;
-
- gst_element_set_state (priv->camerabin, target_state);
-}
-
-/**
- * clutter_gst_camera_actor_is_ready_for_capture:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_is_ready_for_capture:
+ * @self: a #ClutterGstCamera
*
- * Check whether the @camera_actor is ready for video/photo capture.
+ * Check whether the @self is ready for video/photo capture.
*
- * Return value: %TRUE if @camera_actor is ready for capture, %FALSE otherwise
+ * Return value: %TRUE if @self is ready for capture, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_is_ready_for_capture (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_is_ready_for_capture (ClutterGstCamera *self)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
gboolean ready_for_capture;
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
- priv = camera_actor->priv;
+ priv = self->priv;
g_object_get (priv->camera_source, "ready-for-capture", &ready_for_capture, NULL);
@@ -1495,42 +1607,42 @@ clutter_gst_camera_actor_is_ready_for_capture (ClutterGstCameraActor *camera_act
}
/**
- * clutter_gst_camera_actor_is_recording_video:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_is_recording_video:
+ * @self: a #ClutterGstCamera
*
- * Check whether the @camera_actor is recording video.
+ * Check whether the @self is recording video.
*
- * Return value: %TRUE if @camera_actor is recording video, %FALSE otherwise
+ * Return value: %TRUE if @self is recording video, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_is_recording_video (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_is_recording_video (ClutterGstCamera *self)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
- priv = camera_actor->priv;
+ priv = self->priv;
return priv->is_recording;
}
/**
- * clutter_gst_camera_actor_set_video_profile:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_set_video_profile:
+ * @self: a #ClutterGstCamera
* @profile: A #GstEncodingProfile to be used for video recording.
*
* Set the encoding profile to be used for video recording.
* The default profile saves videos as Ogg/Theora videos.
*/
void
-clutter_gst_camera_actor_set_video_profile (ClutterGstCameraActor *camera_actor,
- GstEncodingProfile *profile)
+clutter_gst_camera_set_video_profile (ClutterGstCamera *self,
+ GstEncodingProfile *profile)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
- g_return_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor));
+ g_return_if_fail (CLUTTER_GST_IS_CAMERA (self));
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->camerabin)
return;
@@ -1539,27 +1651,27 @@ clutter_gst_camera_actor_set_video_profile (ClutterGstCameraActor *camera_actor,
}
/**
- * clutter_gst_camera_actor_start_video_recording:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_start_video_recording:
+ * @self: a #ClutterGstCamera
* @filename: (type filename): the name of the video file to where the
* recording will be saved
*
- * Start a video recording with the @camera_actor and save it to @filename.
- * This method requires that @camera_actor is playing and ready for capture.
+ * Start a video recording with the @self and save it to @filename.
+ * This method requires that @self is playing and ready for capture.
*
* The ::video-saved signal will be emitted when the video is saved.
*
* Return value: %TRUE if the video recording was successfully started, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_start_video_recording (ClutterGstCameraActor *camera_actor,
- const gchar *filename)
+clutter_gst_camera_start_video_recording (ClutterGstCamera *self,
+ const gchar *filename)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->camerabin)
return FALSE;
@@ -1567,34 +1679,34 @@ clutter_gst_camera_actor_start_video_recording (ClutterGstCameraActor *camera_ac
if (priv->is_recording)
return TRUE;
- if (!clutter_gst_camera_actor_is_playing (camera_actor))
+ if (!clutter_gst_camera_is_playing (self))
return FALSE;
- if (!clutter_gst_camera_actor_is_ready_for_capture (camera_actor))
+ if (!clutter_gst_camera_is_ready_for_capture (self))
return FALSE;
g_object_set (priv->camerabin, "mode", CAPTURE_MODE_VIDEO, NULL);
g_object_set (priv->camerabin, "location", filename, NULL);
- g_signal_emit_by_name (priv->camerabin, "start-capture", 0);
+ g_signal_emit_by_name (priv->camerabin, "start-capture");
priv->is_recording = TRUE;
return TRUE;
}
/**
* clutter_gst_camera_stop_video_recording:
- * @camera_actor: a #ClutterGstCameraActor
+ * @self: a #ClutterGstCamera
*
- * Stop recording video on the @camera_actor.
+ * Stop recording video on the @self.
*/
void
-clutter_gst_camera_actor_stop_video_recording (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_stop_video_recording (ClutterGstCamera *self)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
GstState state;
- g_return_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor));
+ g_return_if_fail (CLUTTER_GST_IS_CAMERA (self));
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->camerabin)
return;
@@ -1602,13 +1714,13 @@ clutter_gst_camera_actor_stop_video_recording (ClutterGstCameraActor *camera_act
if (!priv->is_recording)
return;
- if (!clutter_gst_camera_actor_is_playing (camera_actor))
+ if (!clutter_gst_camera_is_playing (self))
return;
gst_element_get_state (priv->camerabin, &state, NULL, 0);
if (state == GST_STATE_PLAYING)
- g_signal_emit_by_name (priv->camerabin, "stop-capture", 0);
+ g_signal_emit_by_name (priv->camerabin, "stop-capture");
else if (priv->is_recording)
{
g_warning ("Cannot cleanly shutdown recording pipeline, forcing");
@@ -1620,22 +1732,22 @@ clutter_gst_camera_actor_stop_video_recording (ClutterGstCameraActor *camera_act
}
/**
- * clutter_gst_camera_actor_set_photo_profile:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_set_photo_profile:
+ * @self: a #ClutterGstCamera
* @profile: A #GstEncodingProfile to be used for photo captures.
*
* Set the encoding profile to be used for photo captures.
* The default profile saves photos as JPEG images.
*/
void
-clutter_gst_camera_actor_set_photo_profile (ClutterGstCameraActor *camera_actor,
- GstEncodingProfile *profile)
+clutter_gst_camera_set_photo_profile (ClutterGstCamera *self,
+ GstEncodingProfile *profile)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
- g_return_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor));
+ g_return_if_fail (CLUTTER_GST_IS_CAMERA (self));
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->camerabin)
return;
@@ -1644,36 +1756,36 @@ clutter_gst_camera_actor_set_photo_profile (ClutterGstCameraActor *camera_actor,
}
/**
- * clutter_gst_camera_actor_take_photo:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_take_photo:
+ * @self: a #ClutterGstCamera
* @filename: (type filename): the name of the file to where the
* photo will be saved
*
- * Take a photo with the @camera_actor and save it to @filename.
- * This method requires that @camera_actor is playing and ready for capture.
+ * Take a photo with the @self and save it to @filename.
+ * This method requires that @self is playing and ready for capture.
*
* The ::photo-saved signal will be emitted when the video is saved.
*
* Return value: %TRUE if the photo was successfully captured, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_take_photo (ClutterGstCameraActor *camera_actor,
- const gchar *filename)
+clutter_gst_camera_take_photo (ClutterGstCamera *self,
+ const gchar *filename)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->camerabin)
return FALSE;
- if (!clutter_gst_camera_actor_is_playing (camera_actor))
+ if (!clutter_gst_camera_is_playing (self))
return FALSE;
- if (!clutter_gst_camera_actor_is_ready_for_capture (camera_actor))
+ if (!clutter_gst_camera_is_ready_for_capture (self))
return FALSE;
g_free (priv->photo_filename);
@@ -1682,37 +1794,37 @@ clutter_gst_camera_actor_take_photo (ClutterGstCameraActor *camera_actor,
/* Take the photo */
g_object_set (priv->camerabin, "location", filename, NULL);
g_object_set (priv->camerabin, "mode", CAPTURE_MODE_IMAGE, NULL);
- g_signal_emit_by_name (priv->camerabin, "start-capture", 0);
+ g_signal_emit_by_name (priv->camerabin, "start-capture");
return TRUE;
}
/**
* clutter_gst_camera_take_photo_pixbuf:
- * @camera_actor: a #ClutterGstCameraActor
+ * @self: a #ClutterGstCamera
*
- * Take a photo with the @camera_actor and emit it in the ::photo-taken signal as a
+ * Take a photo with the @self and emit it in the ::photo-taken signal as a
* #GdkPixbuf.
- * This method requires that @camera_actor is playing and ready for capture.
+ * This method requires that @self is playing and ready for capture.
*
* Return value: %TRUE if the photo was successfully captured, %FALSE otherwise
*/
gboolean
-clutter_gst_camera_actor_take_photo_pixbuf (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_take_photo_pixbuf (ClutterGstCamera *self)
{
- ClutterGstCameraActorPrivate *priv;
+ ClutterGstCameraPrivate *priv;
GstCaps *caps;
- g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
- priv = camera_actor->priv;
+ priv = self->priv;
if (!priv->camerabin)
return FALSE;
- if (!clutter_gst_camera_actor_is_playing (camera_actor))
+ if (!clutter_gst_camera_is_playing (self))
return FALSE;
- if (!clutter_gst_camera_actor_is_ready_for_capture (camera_actor))
+ if (!clutter_gst_camera_is_ready_for_capture (self))
return FALSE;
caps = gst_caps_new_simple ("video/x-raw",
@@ -1729,6 +1841,6 @@ clutter_gst_camera_actor_take_photo_pixbuf (ClutterGstCameraActor *camera_actor)
/* Take the photo */
g_object_set (priv->camerabin, "location", NULL, NULL);
g_object_set (priv->camerabin, "mode", CAPTURE_MODE_IMAGE, NULL);
- g_signal_emit_by_name (priv->camerabin, "start-capture", 0);
+ g_signal_emit_by_name (priv->camerabin, "start-capture");
return TRUE;
}
diff --git a/clutter-gst/clutter-gst-camera.h b/clutter-gst/clutter-gst-camera.h
new file mode 100644
index 0000000..f348ab0
--- /dev/null
+++ b/clutter-gst/clutter-gst-camera.h
@@ -0,0 +1,208 @@
+/*
+ * Clutter-GStreamer.
+ *
+ * GStreamer integration library for Clutter.
+ *
+ * clutter-gst-camera-actor.h - ClutterActor using GStreamer to display/manipulate a
+ * camera stream.
+ *
+ * Authored By Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk>
+ *
+ * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined(__CLUTTER_GST_H_INSIDE__) && !defined(CLUTTER_GST_COMPILATION)
+#error "Only <clutter-gst/clutter-gst.h> can be included directly."
+#endif
+
+#ifndef __CLUTTER_GST_CAMERA_H__
+#define __CLUTTER_GST_CAMERA_H__
+
+#include <clutter/clutter.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <glib-object.h>
+#include <gst/gstelement.h>
+#include <gst/pbutils/encoding-profile.h>
+
+#include <clutter-gst/clutter-gst-actor.h>
+#include <clutter-gst/clutter-gst-camera-device.h>
+#include <clutter-gst/clutter-gst-types.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_GST_TYPE_CAMERA clutter_gst_camera_get_type()
+
+#define CLUTTER_GST_CAMERA(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ CLUTTER_GST_TYPE_CAMERA, ClutterGstCamera))
+
+#define CLUTTER_GST_CAMERA_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ CLUTTER_GST_TYPE_CAMERA, ClutterGstCameraClass))
+
+#define CLUTTER_GST_IS_CAMERA(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ CLUTTER_GST_TYPE_CAMERA))
+
+#define CLUTTER_GST_IS_CAMERA_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ CLUTTER_GST_TYPE_CAMERA))
+
+#define CLUTTER_GST_CAMERA_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ CLUTTER_GST_TYPE_CAMERA, ClutterGstCameraClass))
+
+typedef struct _ClutterGstCamera ClutterGstCamera;
+typedef struct _ClutterGstCameraClass ClutterGstCameraClass;
+typedef struct _ClutterGstCameraPrivate ClutterGstCameraPrivate;
+
+/**
+ * ClutterGstCamera:
+ *
+ * Subclass of #ClutterGstActor that displays camera streams using GStreamer.
+ *
+ * The #ClutterGstCamera structure contains only private data and
+ * should not be accessed directly.
+ */
+struct _ClutterGstCamera
+{
+ /*< private >*/
+ ClutterGstActor parent;
+ ClutterGstCameraPrivate *priv;
+};
+
+/**
+ * ClutterGstCameraClass:
+ *
+ * Base class for #ClutterGstCamera.
+ */
+struct _ClutterGstCameraClass
+{
+ /*< private >*/
+ ClutterGstActorClass parent_class;
+
+ void (* ready_for_capture) (ClutterGstCamera *self,
+ gboolean ready);
+ void (* photo_saved) (ClutterGstCamera *self);
+ void (* photo_taken) (ClutterGstCamera *self,
+ GdkPixbuf *pixbuf);
+ void (* video_saved) (ClutterGstCamera *self);
+
+ /* Future padding */
+ void (* _clutter_reserved1) (void);
+ void (* _clutter_reserved2) (void);
+ void (* _clutter_reserved3) (void);
+ void (* _clutter_reserved4) (void);
+ void (* _clutter_reserved5) (void);
+ void (* _clutter_reserved6) (void);
+};
+
+GType clutter_gst_camera_get_type (void) G_GNUC_CONST;
+
+ClutterGstCamera * clutter_gst_camera_new (void);
+
+const GPtrArray *
+ clutter_gst_camera_get_camera_devices (ClutterGstCamera *self);
+ClutterGstCameraDevice *
+ clutter_gst_camera_get_camera_device (ClutterGstCamera *self);
+gboolean clutter_gst_camera_set_camera_device (ClutterGstCamera *self,
+ ClutterGstCameraDevice *device);
+
+gboolean clutter_gst_camera_supports_gamma_correction
+ (ClutterGstCamera *self);
+gboolean clutter_gst_camera_get_gamma_range (ClutterGstCamera *self,
+ gdouble *min_value,
+ gdouble *max_value,
+ gdouble *default_value);
+gboolean clutter_gst_camera_get_gamma (ClutterGstCamera *self,
+ gdouble *cur_value);
+gboolean clutter_gst_camera_set_gamma (ClutterGstCamera *self,
+ gdouble value);
+
+gboolean clutter_gst_camera_supports_color_balance
+ (ClutterGstCamera *self);
+gboolean clutter_gst_camera_get_color_balance_property_range
+ (ClutterGstCamera *self,
+ const gchar *property,
+ gdouble *min_value,
+ gdouble *max_value,
+ gdouble *default_value);
+gboolean clutter_gst_camera_get_color_balance_property
+ (ClutterGstCamera *self,
+ const gchar *property,
+ gdouble *cur_value);
+gboolean clutter_gst_camera_set_color_balance_property
+ (ClutterGstCamera *self,
+ const gchar *property,
+ gdouble value);
+gboolean clutter_gst_camera_get_brightness_range (ClutterGstCamera *self,
+ gdouble *min_value,
+ gdouble *max_value,
+ gdouble *default_value);
+gboolean clutter_gst_camera_get_brightness (ClutterGstCamera *self,
+ gdouble *cur_value);
+gboolean clutter_gst_camera_set_brightness (ClutterGstCamera *self,
+ gdouble value);
+gboolean clutter_gst_camera_get_contrast_range (ClutterGstCamera *self,
+ gdouble *min_value,
+ gdouble *max_value,
+ gdouble *default_value);
+gboolean clutter_gst_camera_get_contrast (ClutterGstCamera *self,
+ gdouble *cur_value);
+gboolean clutter_gst_camera_set_contrast (ClutterGstCamera *self,
+ gdouble value);
+gboolean clutter_gst_camera_get_saturation_range (ClutterGstCamera *self,
+ gdouble *min_value,
+ gdouble *max_value,
+ gdouble *default_value);
+gboolean clutter_gst_camera_get_saturation (ClutterGstCamera *self,
+ gdouble *cur_value);
+gboolean clutter_gst_camera_set_saturation (ClutterGstCamera *self,
+ gdouble value);
+gboolean clutter_gst_camera_get_hue_range (ClutterGstCamera *self,
+ gdouble *min_value,
+ gdouble *max_value,
+ gdouble *default_value);
+gboolean clutter_gst_camera_get_hue (ClutterGstCamera *self,
+ gdouble *cur_value);
+gboolean clutter_gst_camera_set_hue (ClutterGstCamera *self,
+ gdouble value);
+
+GstElement * clutter_gst_camera_get_filter (ClutterGstCamera *self);
+gboolean clutter_gst_camera_set_filter (ClutterGstCamera *self,
+ GstElement *filter);
+gboolean clutter_gst_camera_remove_filter (ClutterGstCamera *self);
+
+gboolean clutter_gst_camera_is_ready_for_capture (ClutterGstCamera *self);
+
+void clutter_gst_camera_set_video_profile (ClutterGstCamera *self,
+ GstEncodingProfile *profile);
+gboolean clutter_gst_camera_is_recording_video (ClutterGstCamera *self);
+gboolean clutter_gst_camera_start_video_recording (ClutterGstCamera *self,
+ const gchar *filename);
+void clutter_gst_camera_stop_video_recording (ClutterGstCamera *self);
+
+void clutter_gst_camera_set_photo_profile (ClutterGstCamera *self,
+ GstEncodingProfile *profile);
+gboolean clutter_gst_camera_take_photo (ClutterGstCamera *self,
+ const gchar *filename);
+gboolean clutter_gst_camera_take_photo_pixbuf (ClutterGstCamera *self);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_GST_CAMERA_H__ */
diff --git a/clutter-gst/clutter-gst-playback.c b/clutter-gst/clutter-gst-playback.c
new file mode 100644
index 0000000..2152547
--- /dev/null
+++ b/clutter-gst/clutter-gst-playback.c
@@ -0,0 +1,2799 @@
+/*
+ * Clutter-GStreamer.
+ *
+ * GStreamer integration library for Clutter.
+ *
+ * clutter-gst-player.c - Wrap some convenience functions around playbin
+ *
+ * Authored By Damien Lespiau <damien.lespiau@intel.com>
+ * Lionel Landwerlin <lionel.g.landwerlin@linux.intel.com>
+ * Matthew Allum <mallum@openedhand.com>
+ * Emmanuele Bassi <ebassi@linux.intel.com>
+ * Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk>
+ *
+ * Copyright (C) 2006 OpenedHand
+ * Copyright (C) 2009-2013 Intel Corporation
+ * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter-gst-debug.h"
+#include "clutter-gst-enum-types.h"
+#include "clutter-gst-marshal.h"
+#include "clutter-gst-playback.h"
+#include "clutter-gst-player.h"
+#include "clutter-gst-private.h"
+
+#include <string.h>
+
+#include <gio/gio.h>
+#include <cogl-gst/cogl-gst.h>
+#include <gst/video/video.h>
+#include <gst/tag/tag.h>
+#include <gst/audio/streamvolume.h>
+
+#if defined (CLUTTER_WINDOWING_X11) && defined (HAVE_HW_DECODER_SUPPORT)
+#define GST_USE_UNSTABLE_API 1
+#include <gst/video/videocontext.h>
+#include <clutter/x11/clutter-x11.h>
+#endif
+
+static void player_iface_init (ClutterGstPlayerIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ClutterGstPlayback, clutter_gst_playback, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (CLUTTER_GST_TYPE_PLAYER, player_iface_init))
+
+#define GST_PLAYBACK_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), CLUTTER_GST_TYPE_PLAYBACK, ClutterGstPlaybackPrivate))
+
+/* idle timeouts (in ms) */
+#define TICK_TIMEOUT 500
+#define BUFFERING_TIMEOUT 250
+
+enum
+{
+ PROP_0,
+
+ PROP_URI,
+ PROP_PLAYING,
+ PROP_PROGRESS,
+ PROP_SUBTITLE_URI,
+ PROP_SUBTITLE_FONT_NAME,
+ PROP_AUDIO_VOLUME,
+ PROP_CAN_SEEK,
+ PROP_BUFFER_FILL,
+ PROP_DURATION,
+ PROP_IDLE,
+ PROP_USER_AGENT,
+ PROP_SEEK_FLAGS,
+ PROP_AUDIO_STREAMS,
+ PROP_AUDIO_STREAM,
+ PROP_SUBTITLE_TRACKS,
+ PROP_SUBTITLE_TRACK,
+ PROP_IN_SEEK
+};
+
+enum
+{
+ DOWNLOAD_BUFFERING_SIGNAL,
+
+ LAST_SIGNAL
+};
+
+/* Elements don't expose header files */
+typedef enum {
+ GST_PLAY_FLAG_VIDEO = (1 << 0),
+ GST_PLAY_FLAG_AUDIO = (1 << 1),
+ GST_PLAY_FLAG_TEXT = (1 << 2),
+ GST_PLAY_FLAG_VIS = (1 << 3),
+ GST_PLAY_FLAG_SOFT_VOLUME = (1 << 4),
+ GST_PLAY_FLAG_NATIVE_AUDIO = (1 << 5),
+ GST_PLAY_FLAG_NATIVE_VIDEO = (1 << 6),
+ GST_PLAY_FLAG_DOWNLOAD = (1 << 7),
+ GST_PLAY_FLAG_BUFFERING = (1 << 8),
+ GST_PLAY_FLAG_DEINTERLACE = (1 << 9)
+} GstPlayFlags;
+
+struct _ClutterGstPlaybackPrivate
+{
+ GstElement *pipeline;
+ GstBus *bus;
+
+ ClutterGstFrame *current_frame;
+
+ gchar *uri;
+
+ guint is_idle : 1;
+ guint is_live : 1;
+ guint can_seek : 1;
+ guint in_seek : 1;
+ guint is_changing_uri : 1;
+ guint in_error : 1;
+ guint in_eos : 1;
+ guint in_download_buffering : 1;
+ /* when in progressive download, we use the buffer-fill property to signal
+ * that we have enough data to play the stream. This flag allows to send
+ * the notify that buffer-fill is 1.0 only once */
+ guint virtual_stream_buffer_signalled : 1;
+
+ gdouble stacked_progress;
+
+ gdouble target_progress;
+ GstState target_state;
+
+ guint tick_timeout_id;
+ guint buffering_timeout_id;
+
+ /* This is a cubic volume, suitable for use in a UI cf. StreamVolume doc */
+ gdouble volume;
+
+ gdouble buffer_fill;
+ gdouble duration;
+ gchar *font_name;
+ gchar *user_agent;
+
+ GstSeekFlags seek_flags; /* flags for the seek in set_progress(); */
+
+ GstElement *download_buffering_element;
+
+ GList *audio_streams;
+ GList *subtitle_tracks;
+};
+
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+static gboolean player_buffering_timeout (gpointer data);
+
+/* Logic */
+
+#ifdef CLUTTER_GST_ENABLE_DEBUG
+static gchar *
+get_stream_description (GstTagList *tags,
+ gint track_num)
+{
+ gchar *description = NULL;
+
+ if (tags)
+ {
+
+ gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &description);
+
+ if (description)
+ {
+ const gchar *language = gst_tag_get_language_name (description);
+
+ if (language)
+ {
+ g_free (description);
+ description = g_strdup (language);
+ }
+ }
+
+ if (!description)
+ gst_tag_list_get_string (tags, GST_TAG_CODEC, &description);
+ }
+
+ if (!description)
+ description = g_strdup_printf ("Track %d", track_num);
+
+ return description;
+}
+
+gchar *
+list_to_string (GList *list)
+{
+ GstTagList *tags;
+ gchar *description;
+ GString *string;
+ GList *l;
+ gint n, i;
+
+ if (!list)
+ return g_strdup ("<empty list>");
+
+ string = g_string_new (NULL);
+ n = g_list_length (list);
+ for (i = 0, l = list; i < n - 1; i++, l = g_list_next (l))
+ {
+ tags = l->data;
+ description = get_stream_description (tags, i);
+ g_string_append_printf (string, "%s, ", description);
+ g_free (description);
+ }
+
+ tags = l->data;
+ description = get_stream_description (tags, i);
+ g_string_append_printf (string, "%s", (gchar *) description);
+ g_free (description);
+
+ return g_string_free (string, FALSE);
+}
+#endif
+
+static const gchar *
+gst_state_to_string (GstState state)
+{
+ switch (state)
+ {
+ case GST_STATE_VOID_PENDING:
+ return "pending";
+ case GST_STATE_NULL:
+ return "null";
+ case GST_STATE_READY:
+ return "ready";
+ case GST_STATE_PAUSED:
+ return "paused";
+ case GST_STATE_PLAYING:
+ return "playing";
+ }
+
+ return "Unknown state";
+}
+
+static void
+free_tags_list (GList **listp)
+{
+ GList *l;
+
+ l = *listp;
+ while (l)
+ {
+ if (l->data)
+ gst_tag_list_unref (l->data);
+ l = g_list_delete_link (l, l);
+ }
+
+ *listp = NULL;
+}
+
+static gboolean
+tick_timeout (gpointer data)
+{
+ GObject *player = data;
+
+ g_object_notify (player, "progress");
+
+ return TRUE;
+}
+
+static void
+player_set_user_agent (ClutterGstPlayback *self,
+ const gchar *user_agent)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ GstElement *source;
+ GParamSpec *pspec;
+
+ if (user_agent == NULL)
+ return;
+
+ g_object_get (priv->pipeline, "source", &source, NULL);
+ if (source == NULL)
+ return;
+
+ pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (source),
+ "user-agent");
+ if (pspec == NULL)
+ return;
+
+ CLUTTER_GST_NOTE (MEDIA, "setting user agent: %s", user_agent);
+
+ g_object_set (source, "user-agent", user_agent, NULL);
+}
+
+static void
+autoload_subtitle (ClutterGstPlayback *self,
+ const gchar *uri)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ gchar *path, *dot, *subtitle_path;
+ GFile *video;
+ guint i;
+
+ static const char subtitles_extensions[][4] =
+ {
+ "sub", "SUB",
+ "srt", "SRT",
+ "smi", "SMI",
+ "ssa", "SSA",
+ "ass", "ASS",
+ "asc", "ASC"
+ };
+
+ /* do not try to look for subtitle files if the video file is not mounted
+ * locally */
+ if (!g_str_has_prefix (uri, "file://"))
+ return;
+
+ /* Retrieve the absolute path of the video file */
+ video = g_file_new_for_uri (uri);
+ path = g_file_get_path (video);
+ g_object_unref (video);
+ if (path == NULL)
+ return;
+
+ /* Put a '\0' after the dot of the extension */
+ dot = strrchr (path, '.');
+ if (dot == NULL) {
+ g_free (path);
+ return;
+ }
+ *++dot = '\0';
+
+ /* we can't use path as the temporary buffer for the paths of the potential
+ * subtitle files as we may not have enough room there */
+ subtitle_path = g_malloc (strlen (path) + 1 + 4);
+ strcpy (subtitle_path, path);
+
+ /* reuse dot to point to the first byte of the extension of subtitle_path */
+ dot = subtitle_path + (dot - path);
+
+ for (i = 0; i < G_N_ELEMENTS (subtitles_extensions); i++)
+ {
+ GFile *candidate;
+
+ memcpy (dot, subtitles_extensions[i], 4);
+ candidate = g_file_new_for_path (subtitle_path);
+ if (g_file_query_exists (candidate, NULL))
+ {
+ gchar *suburi;
+
+ suburi = g_file_get_uri (candidate);
+
+ CLUTTER_GST_NOTE (MEDIA, "found subtitle: %s", suburi);
+
+ g_object_set (priv->pipeline, "suburi", suburi, NULL);
+ g_free (suburi);
+
+ g_object_unref (candidate);
+ break;
+ }
+
+ g_object_unref (candidate);
+ }
+
+ g_free (path);
+ g_free (subtitle_path);
+}
+
+static void
+set_subtitle_uri (ClutterGstPlayback *self,
+ const gchar *uri)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ GstPlayFlags flags;
+
+ if (!priv->pipeline)
+ return;
+
+ CLUTTER_GST_NOTE (MEDIA, "setting subtitle URI: %s", uri);
+
+ g_object_get (priv->pipeline, "flags", &flags, NULL);
+
+ g_object_set (priv->pipeline, "suburi", uri, NULL);
+
+ g_object_set (priv->pipeline, "flags", flags, NULL);
+}
+
+static void
+player_configure_buffering_timeout (ClutterGstPlayback *self,
+ guint ms)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+
+ if (priv->buffering_timeout_id)
+ {
+ g_source_remove (priv->buffering_timeout_id);
+ priv->buffering_timeout_id = 0;
+ }
+
+ if (ms)
+ {
+ priv->buffering_timeout_id =
+ g_timeout_add (ms, player_buffering_timeout, self);
+ }
+}
+
+static void
+player_clear_download_buffering (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+
+ if (priv->download_buffering_element)
+ {
+ g_object_unref (priv->download_buffering_element);
+ priv->download_buffering_element = NULL;
+ }
+ player_configure_buffering_timeout (self, 0);
+ priv->in_download_buffering = FALSE;
+ priv->virtual_stream_buffer_signalled = 0;
+}
+
+static gboolean
+is_live_pipeline (GstElement *pipeline)
+{
+ GstState state, pending;
+ GstStateChangeReturn state_change_res;
+ gboolean is_live = FALSE;
+
+ /* get pipeline current state, we need to change the pipeline state to PAUSED to
+ * see if we are dealing with a live source and we want to restore the pipeline
+ * state afterwards */
+ gst_element_get_state (pipeline, &state, &pending, 0);
+
+ /* a pipeline with live source should return NO_PREROLL in PAUSE */
+ state_change_res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+ is_live = (state_change_res == GST_STATE_CHANGE_NO_PREROLL);
+
+ /* restore pipeline previous state */
+ if (pending == GST_STATE_VOID_PENDING)
+ gst_element_set_state (pipeline, state);
+ else
+ gst_element_set_state (pipeline, pending);
+
+ return is_live;
+}
+
+static void
+set_uri (ClutterGstPlayback *self,
+ const gchar *uri)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ GstState state, pending;
+
+ CLUTTER_GST_NOTE (MEDIA, "setting uri %s", uri);
+
+ if (!priv->pipeline)
+ return;
+
+ g_free (priv->uri);
+
+ priv->in_eos = FALSE;
+ priv->in_error = FALSE;
+
+ if (uri)
+ {
+ priv->uri = g_strdup (uri);
+
+ /* Ensure the tick timeout is installed.
+ *
+ * We also have it installed in PAUSED state, because
+ * seeks etc may have a delayed effect on the position.
+ */
+ if (priv->tick_timeout_id == 0)
+ {
+ priv->tick_timeout_id =
+ g_timeout_add (TICK_TIMEOUT, tick_timeout, self);
+ }
+
+ /* try to load subtitles based on the uri of the file */
+ set_subtitle_uri (self, NULL);
+
+ /* reset the states of download buffering */
+ player_clear_download_buffering (self);
+ }
+ else
+ {
+ priv->uri = NULL;
+
+ if (priv->tick_timeout_id)
+ {
+ g_source_remove (priv->tick_timeout_id);
+ priv->tick_timeout_id = 0;
+ }
+
+ if (priv->buffering_timeout_id)
+ {
+ g_source_remove (priv->buffering_timeout_id);
+ priv->buffering_timeout_id = 0;
+ }
+
+ if (priv->download_buffering_element)
+ {
+ g_object_unref (priv->download_buffering_element);
+ priv->download_buffering_element = NULL;
+ }
+
+ }
+
+ priv->can_seek = FALSE;
+ priv->duration = 0.0;
+ priv->stacked_progress = 0.0;
+ priv->target_progress = 0.0;
+
+ CLUTTER_GST_NOTE (MEDIA, "setting URI: %s", uri);
+
+ if (uri)
+ {
+ gst_element_get_state (priv->pipeline, &state, &pending, 0);
+ if (pending)
+ state = pending;
+
+ gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+
+ g_object_set (priv->pipeline, "uri", uri, NULL);
+
+ priv->is_live = is_live_pipeline (priv->pipeline);
+
+ set_subtitle_uri (self, NULL);
+ autoload_subtitle (self, uri);
+
+ gst_element_set_state (priv->pipeline, state);
+
+ priv->is_changing_uri = TRUE;
+ }
+ else
+ {
+ priv->is_idle = TRUE;
+ priv->is_live = FALSE;
+ set_subtitle_uri (self, NULL);
+ gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+ g_object_notify (G_OBJECT (self), "idle");
+ }
+
+ /*
+ * Emit notifications for all these to make sure UI is not showing
+ * any properties of the old URI.
+ */
+ g_object_notify (G_OBJECT (self), "uri");
+ g_object_notify (G_OBJECT (self), "can-seek");
+ g_object_notify (G_OBJECT (self), "duration");
+ g_object_notify (G_OBJECT (self), "progress");
+
+ free_tags_list (&priv->audio_streams);
+ CLUTTER_GST_NOTE (AUDIO_STREAM, "audio-streams changed");
+ g_object_notify (G_OBJECT (self), "audio-streams");
+
+ free_tags_list (&priv->subtitle_tracks);
+ CLUTTER_GST_NOTE (SUBTITLES, "subtitle-tracks changed");
+ g_object_notify (G_OBJECT (self), "subtitle-tracks");
+}
+
+static gdouble
+get_audio_volume (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+
+ if (!priv->pipeline)
+ return 0.0;
+
+ CLUTTER_GST_NOTE (MEDIA, "get volume: %.02f", priv->volume);
+
+ return priv->volume;
+}
+
+static void
+set_audio_volume (ClutterGstPlayback *self,
+ gdouble volume)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+
+ if (!priv->pipeline)
+ return;
+
+ CLUTTER_GST_NOTE (MEDIA, "set volume: %.02f", volume);
+
+ volume = CLAMP (volume, 0.0, 1.0);
+ gst_stream_volume_set_volume (GST_STREAM_VOLUME (priv->pipeline),
+ GST_STREAM_VOLUME_FORMAT_CUBIC,
+ volume);
+ g_object_notify (G_OBJECT (self), "audio-volume");
+}
+
+static void
+set_in_seek (ClutterGstPlayback *self,
+ gboolean seeking)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+
+ priv->in_seek = seeking;
+ g_object_notify (G_OBJECT (self), "in-seek");
+}
+
+
+static void
+set_playing (ClutterGstPlayback *self,
+ gboolean playing)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+
+ if (!priv->pipeline)
+ return;
+
+ CLUTTER_GST_NOTE (MEDIA, "set playing: %d", playing);
+
+ priv->in_error = FALSE;
+ priv->in_eos = FALSE;
+
+ priv->target_state = playing ? GST_STATE_PLAYING : GST_STATE_PAUSED;
+
+ if (priv->uri)
+ {
+ set_in_seek (self, FALSE);
+
+ gst_element_set_state (priv->pipeline, priv->target_state);
+ }
+ else
+ {
+ if (playing)
+ g_warning ("Unable to start playing: no URI is set");
+ }
+
+ g_object_notify (G_OBJECT (self), "playing");
+ g_object_notify (G_OBJECT (self), "progress");
+}
+
+static gboolean
+get_playing (ClutterGstPlayback *player)
+{
+ ClutterGstPlaybackPrivate *priv = player->priv;
+ GstState state, pending;
+ gboolean playing;
+
+ if (!priv->pipeline)
+ return FALSE;
+
+ gst_element_get_state (priv->pipeline, &state, &pending, 0);
+
+ if (pending)
+ playing = (pending == GST_STATE_PLAYING);
+ else
+ playing = (state == GST_STATE_PLAYING);
+
+ CLUTTER_GST_NOTE (MEDIA, "get playing: %d", playing);
+
+ return playing;
+}
+
+static void
+set_progress (ClutterGstPlayback *self,
+ gdouble progress)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ GstQuery *duration_q;
+ gint64 position;
+
+ if (!priv->pipeline)
+ return;
+
+ CLUTTER_GST_NOTE (MEDIA, "set progress: %.02f", progress);
+
+ priv->in_eos = FALSE;
+ priv->target_progress = progress;
+
+ if (priv->in_download_buffering)
+ {
+ /* we clear the virtual_stream_buffer_signalled flag as it's likely we
+ * need to buffer again */
+ priv->virtual_stream_buffer_signalled = 0;
+ }
+
+ if (priv->in_seek || priv->is_idle || priv->is_changing_uri)
+ {
+ /* We can't seek right now, let's save the position where we
+ want to seek and do that later. */
+ CLUTTER_GST_NOTE (MEDIA,
+ "already seeking/idleing. stacking progress point.");
+ priv->stacked_progress = progress;
+ return;
+ }
+
+ duration_q = gst_query_new_duration (GST_FORMAT_TIME);
+
+ if (gst_element_query (priv->pipeline, duration_q))
+ {
+ gint64 duration = 0;
+
+ gst_query_parse_duration (duration_q, NULL, &duration);
+
+ position = progress * duration;
+ }
+ else
+ position = 0;
+
+ gst_query_unref (duration_q);
+
+ gst_element_seek (priv->pipeline,
+ 1.0,
+ GST_FORMAT_TIME,
+ GST_SEEK_FLAG_FLUSH | priv->seek_flags,
+ GST_SEEK_TYPE_SET,
+ position,
+ GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
+
+ set_in_seek (self, TRUE);
+
+ priv->stacked_progress = 0.0;
+
+ CLUTTER_GST_NOTE (MEDIA, "set progress (seeked): %.02f", progress);
+}
+
+static gdouble
+get_progress (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ GstQuery *position_q, *duration_q;
+ gdouble progress;
+
+ if (!priv->pipeline)
+ return 0.0;
+
+ /* when hitting an error or after an EOS, playbin has some weird values when
+ * querying the duration and progress. We default to 0.0 on error and 1.0 on
+ * EOS */
+ if (priv->in_error)
+ {
+ CLUTTER_GST_NOTE (MEDIA, "get progress (error): 0.0");
+ return 0.0;
+ }
+
+ if (priv->in_eos)
+ {
+ CLUTTER_GST_NOTE (MEDIA, "get progress (eos): 1.0");
+ return 1.0;
+ }
+
+ /* When seeking, the progress returned by playbin is 0.0. We want that to be
+ * the last known position instead as returning 0.0 will have some ugly
+ * effects, say on a progress bar getting updated from the progress tick. */
+ if (priv->in_seek || priv->is_changing_uri)
+ {
+ CLUTTER_GST_NOTE (MEDIA, "get progress (target): %.02f",
+ priv->target_progress);
+ return priv->target_progress;
+ }
+
+ position_q = gst_query_new_position (GST_FORMAT_TIME);
+ duration_q = gst_query_new_duration (GST_FORMAT_TIME);
+
+ if (gst_element_query (priv->pipeline, position_q) &&
+ gst_element_query (priv->pipeline, duration_q))
+ {
+ gint64 position, duration;
+
+ position = duration = 0;
+
+ gst_query_parse_position (position_q, NULL, &position);
+ gst_query_parse_duration (duration_q, NULL, &duration);
+
+ progress = CLAMP ((gdouble) position / (gdouble) duration, 0.0, 1.0);
+ }
+ else
+ progress = 0.0;
+
+ gst_query_unref (position_q);
+ gst_query_unref (duration_q);
+
+ CLUTTER_GST_NOTE (MEDIA, "get progress (pipeline): %.02f", progress);
+
+ return progress;
+}
+
+static void
+set_subtitle_font_name (ClutterGstPlayback *self,
+ const gchar *font_name)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+
+ if (!priv->pipeline)
+ return;
+
+ CLUTTER_GST_NOTE (MEDIA, "setting subtitle font to %s", font_name);
+
+ g_free (priv->font_name);
+ priv->font_name = g_strdup (font_name);
+ g_object_set (priv->pipeline, "subtitle-font-desc", font_name, NULL);
+}
+
+static gboolean
+player_buffering_timeout (gpointer data)
+{
+ ClutterGstPlayback *self = (ClutterGstPlayback *) data;
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ gdouble start_d, stop_d, seconds_buffered;
+ gint64 start, stop, left;
+ gint buffer_percent;
+ GstState current_state;
+ GstElement *element;
+ GstQuery *query;
+ gboolean res;
+
+ element = priv->download_buffering_element;
+ if (element == NULL)
+ element = priv->pipeline;
+
+ /* queue2 only knows about _PERCENT and _BYTES */
+ query = gst_query_new_buffering (GST_FORMAT_PERCENT);
+ res = gst_element_query (element, query);
+
+ if (res == FALSE)
+ {
+ priv->buffering_timeout_id = 0;
+ player_clear_download_buffering (self);
+ return FALSE;
+ }
+
+ /* signal the current range */
+
+ gst_query_parse_buffering_stats (query, NULL, NULL, NULL, &left);
+ gst_query_parse_buffering_range (query, NULL, &start, &stop, NULL);
+
+ CLUTTER_GST_NOTE (BUFFERING,
+ "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT
+ ", buffering left %" G_GINT64_FORMAT, start, stop, left);
+
+ start_d = (gdouble) start / GST_FORMAT_PERCENT_MAX;
+ stop_d = (gdouble) stop / GST_FORMAT_PERCENT_MAX;
+
+ g_signal_emit (self, signals[DOWNLOAD_BUFFERING_SIGNAL], 0, start_d, stop_d);
+
+ /* handle the "virtual stream buffer" and the associated pipeline state.
+ * We pause the pipeline until the content is buffered.
+ */
+ seconds_buffered = priv->duration * (stop_d - start_d);
+ gst_query_parse_buffering_percent (query, NULL, &buffer_percent);
+ priv->buffer_fill = CLAMP ((gdouble) buffer_percent / 100.0, 0.0, 1.0);
+
+ if (priv->buffer_fill != 1.0 || !priv->virtual_stream_buffer_signalled)
+ {
+ CLUTTER_GST_NOTE (BUFFERING, "buffer holds %0.2fs of data, buffer-fill "
+ "is %.02f", seconds_buffered, priv->buffer_fill);
+
+ g_object_notify (G_OBJECT (self), "buffer-fill");
+
+ if (priv->buffer_fill == 1.0)
+ priv->virtual_stream_buffer_signalled = 1;
+ }
+
+ gst_element_get_state (priv->pipeline, &current_state, NULL, 0);
+ if (priv->buffer_fill < 1.0)
+ {
+ if (current_state != GST_STATE_PAUSED)
+ {
+ CLUTTER_GST_NOTE (BUFFERING, "pausing the pipeline");
+ gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
+ }
+ }
+ else
+ {
+ if (current_state != priv->target_state)
+ {
+ CLUTTER_GST_NOTE (BUFFERING, "restoring the pipeline");
+ gst_element_set_state (priv->pipeline, priv->target_state);
+ }
+ }
+
+ /* the file has finished downloading */
+ if (left == G_GINT64_CONSTANT (0))
+ {
+ priv->buffering_timeout_id = 0;
+
+ player_clear_download_buffering (self);
+ gst_query_unref (query);
+ return FALSE;
+ }
+
+ gst_query_unref (query);
+ return TRUE;
+}
+
+static void
+bus_message_error_cb (GstBus *bus,
+ GstMessage *message,
+ ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ GError *error = NULL;
+
+ gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+
+ gst_message_parse_error (message, &error, NULL);
+ g_signal_emit_by_name (self, "error", error);
+ g_error_free (error);
+
+ priv->is_idle = TRUE;
+ g_object_notify (G_OBJECT (self), "idle");
+}
+
+/*
+ * This is what's intented in the EOS callback:
+ * - receive EOS from playbin
+ * - fire the EOS signal, the user can install a signal handler to loop the
+ * video for instance.
+ * - after having emitted the signal, check the state of the pipeline
+ * - if the pipeline has been set back to playing or pause, don't touch the
+ * idle state. This will avoid drawing a frame (or more) with the idle
+ * material when looping
+ */
+static void
+bus_message_eos_cb (GstBus *bus,
+ GstMessage *message,
+ ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ GstState state, pending;
+
+ priv->in_eos = TRUE;
+
+ gst_element_set_state (priv->pipeline, GST_STATE_READY);
+
+ g_signal_emit_by_name (self, "eos");
+ g_object_notify (G_OBJECT (self), "progress");
+
+ gst_element_get_state (priv->pipeline, &state, &pending, 0);
+ if (pending)
+ state = pending;
+
+ if (!(state == GST_STATE_PLAYING || state == GST_STATE_PAUSED))
+ {
+ priv->is_idle = TRUE;
+ g_object_notify (G_OBJECT (self), "idle");
+ }
+}
+
+static void
+bus_message_buffering_cb (GstBus *bus,
+ GstMessage *message,
+ ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ GstBufferingMode mode;
+ GstState current_state;
+ gint buffer_percent;
+
+ gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL);
+
+ if (mode != GST_BUFFERING_DOWNLOAD)
+ priv->in_download_buffering = FALSE;
+
+ switch (mode)
+ {
+ case GST_BUFFERING_LIVE:
+ case GST_BUFFERING_STREAM:
+ gst_message_parse_buffering (message, &buffer_percent);
+ priv->buffer_fill = CLAMP ((gdouble) buffer_percent / 100.0, 0.0, 1.0);
+
+ CLUTTER_GST_NOTE (BUFFERING, "buffer-fill: %.02f", priv->buffer_fill);
+
+ /* no state management needed for live pipelines */
+ if (!priv->is_live)
+ {
+ /* The playbin documentation says that we need to pause the pipeline
+ * when there's not enough data yet. We try to limit the calls to
+ * gst_element_set_state() */
+ gst_element_get_state (priv->pipeline, &current_state, NULL, 0);
+
+ if (priv->buffer_fill < 1.0)
+ {
+ if (current_state != GST_STATE_PAUSED)
+ {
+ CLUTTER_GST_NOTE (BUFFERING, "pausing the pipeline");
+ gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
+ }
+ }
+ else
+ {
+ if (current_state != priv->target_state)
+ {
+ CLUTTER_GST_NOTE (BUFFERING, "restoring the pipeline");
+ gst_element_set_state (priv->pipeline, priv->target_state);
+ }
+ }
+ }
+
+ g_object_notify (G_OBJECT (self), "buffer-fill");
+ break;
+
+ case GST_BUFFERING_DOWNLOAD:
+ /* we rate limit the messages from GStreamer for a usage in a UI (we
+ * don't want *that* many updates). This is done by installing an idle
+ * handler querying the buffer range and sending a signal from there */
+
+ if (priv->in_download_buffering)
+ break;
+
+ /* install the querying idle handler the first time we receive a download
+ * buffering message */
+ player_configure_buffering_timeout (self, BUFFERING_TIMEOUT);
+
+ /* pause the stream. the idle timeout will set the target state when
+ * having received enough data. We'll use buffer_fill as a "virtual
+ * stream buffer" to signal the application we're buffering until we
+ * can play back from the downloaded stream. */
+ gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
+ priv->buffer_fill = 0.0;
+ g_object_notify (G_OBJECT (self), "buffer-fill");
+
+ priv->download_buffering_element = g_object_ref (message->src);
+ priv->in_download_buffering = TRUE;
+ priv->virtual_stream_buffer_signalled = 0;
+ break;
+
+ case GST_BUFFERING_TIMESHIFT:
+ default:
+ g_warning ("Buffering mode %d not handled", mode);
+ break;
+ }
+}
+
+static void
+on_source_changed (GstElement *pipeline,
+ GParamSpec *pspec,
+ ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+
+ player_set_user_agent (self, priv->user_agent);
+}
+
+static void
+query_duration (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ gboolean success;
+ gint64 duration;
+ gdouble new_duration, difference;
+
+ success = gst_element_query_duration (priv->pipeline,
+ GST_FORMAT_TIME,
+ &duration);
+ if (G_UNLIKELY (success != TRUE))
+ return;
+
+ new_duration = (gdouble) duration / GST_SECOND;
+
+ /* while we store the new duration if it sligthly changes, the duration
+ * signal is sent only if the new duration is at least one second different
+ * from the old one (as the duration signal is mainly used to update the
+ * time displayed in a UI */
+ difference = ABS (priv->duration - new_duration);
+ if (difference > 1e-3)
+ {
+ CLUTTER_GST_NOTE (MEDIA, "duration: %.02f", new_duration);
+ priv->duration = new_duration;
+
+ if (difference > 1.0)
+ g_object_notify (G_OBJECT (self), "duration");
+ }
+}
+
+static void
+bus_message_duration_changed_cb (GstBus *bus,
+ GstMessage *message,
+ ClutterGstPlayback *self)
+{
+ /* GstElements send a duration-changed message on the bus to signal
+ * that the duration has changed and should be re-queried */
+ query_duration (self);
+}
+
+static void
+bus_message_state_change_cb (GstBus *bus,
+ GstMessage *message,
+ ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ GstState old_state, new_state;
+ gpointer src;
+
+ src = GST_MESSAGE_SRC (message);
+ if (src != priv->pipeline)
+ return;
+
+ gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
+
+ CLUTTER_GST_NOTE (MEDIA, "state change: %s -> %s",
+ gst_state_to_string (old_state),
+ gst_state_to_string (new_state));
+
+ if (old_state == new_state)
+ return;
+
+ if (old_state == GST_STATE_READY &&
+ new_state == GST_STATE_PAUSED)
+ {
+ GstQuery *query;
+
+ /* Determine whether we can seek */
+ query = gst_query_new_seeking (GST_FORMAT_TIME);
+
+ if (gst_element_query (priv->pipeline, query))
+ {
+ gboolean can_seek = FALSE;
+
+ gst_query_parse_seeking (query, NULL, &can_seek,
+ NULL,
+ NULL);
+
+ priv->can_seek = (can_seek == TRUE) ? TRUE : FALSE;
+ }
+ else
+ {
+ /* could not query for ability to seek by querying the
+ * pipeline; let's crudely try by using the URI
+ */
+ if (priv->uri && g_str_has_prefix (priv->uri, "http://"))
+ priv->can_seek = FALSE;
+ else
+ priv->can_seek = TRUE;
+ }
+
+ gst_query_unref (query);
+
+ CLUTTER_GST_NOTE (MEDIA, "can-seek: %d", priv->can_seek);
+
+ g_object_notify (G_OBJECT (self), "can-seek");
+
+ query_duration (self);
+ }
+
+ /* is_idle controls the drawing with the idle material */
+ if (new_state == GST_STATE_NULL)
+ {
+ priv->is_idle = TRUE;
+ g_object_notify (G_OBJECT (self), "idle");
+ }
+ else if (new_state == GST_STATE_PLAYING)
+ {
+ priv->is_idle = FALSE;
+ priv->is_changing_uri = FALSE;
+ g_object_notify (G_OBJECT (self), "idle");
+ }
+
+ if (!priv->is_idle)
+ {
+ if (priv->stacked_progress)
+ {
+ set_progress (self, priv->stacked_progress);
+ }
+ }
+}
+
+static void
+bus_message_async_done_cb (GstBus *bus,
+ GstMessage *message,
+ ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+
+ if (priv->in_seek)
+ {
+ g_object_notify (G_OBJECT (self), "progress");
+
+ set_in_seek (self, FALSE);
+
+ if (priv->stacked_progress)
+ {
+ set_progress (self, priv->stacked_progress);
+ }
+ }
+}
+
+static gboolean
+on_volume_changed_main_context (gpointer data)
+{
+ ClutterGstPlayback *self = CLUTTER_GST_PLAYBACK (data);
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ gdouble volume;
+
+ volume =
+ gst_stream_volume_get_volume (GST_STREAM_VOLUME (priv->pipeline),
+ GST_STREAM_VOLUME_FORMAT_CUBIC);
+ priv->volume = volume;
+
+ g_object_notify (G_OBJECT (self), "audio-volume");
+
+ g_object_unref (self);
+
+ return FALSE;
+}
+
+/* playbin proxies the volume property change notification directly from
+ * the element having the "volume" property. This means this callback is
+ * called from the thread that runs the element, potentially different from
+ * the main thread */
+static void
+on_volume_changed (GstElement *pipeline,
+ GParamSpec *pspec,
+ ClutterGstPlayback *self)
+{
+ g_idle_add (on_volume_changed_main_context, g_object_ref (self));
+}
+
+static GList *
+get_tags (GstElement *pipeline,
+ const gchar *property_name,
+ const gchar *action_signal)
+{
+ GList *ret = NULL;
+ gint i, n;
+
+ g_object_get (G_OBJECT (pipeline), property_name, &n, NULL);
+ if (n == 0)
+ return NULL;
+
+ for (i = 0; i < n; i++)
+ {
+ GstTagList *tags = NULL;
+
+ g_signal_emit_by_name (G_OBJECT (pipeline), action_signal, i, &tags);
+
+ ret = g_list_prepend (ret, tags);
+ }
+
+ return g_list_reverse (ret);
+}
+
+static gboolean
+on_audio_changed_main_context (gpointer data)
+{
+ ClutterGstPlayback *self = CLUTTER_GST_PLAYBACK (data);
+ ClutterGstPlaybackPrivate *priv = self->priv;
+
+ free_tags_list (&priv->audio_streams);
+ priv->audio_streams = get_tags (priv->pipeline, "n-audio", "get-audio-tags");
+
+ CLUTTER_GST_NOTE (AUDIO_STREAM, "audio-streams changed");
+
+ g_object_notify (G_OBJECT (self), "audio-streams");
+
+ g_object_unref (self);
+
+ return FALSE;
+}
+
+/* same explanation as for notify::volume's usage of g_idle_add() */
+static void
+on_audio_changed (GstElement *pipeline,
+ ClutterGstPlayback *self)
+{
+ g_idle_add (on_audio_changed_main_context, g_object_ref (self));
+}
+
+static void
+on_audio_tags_changed (GstElement *pipeline,
+ gint stream,
+ ClutterGstPlayback *self)
+{
+ gint current_stream;
+
+ g_object_get (G_OBJECT (pipeline), "current-audio", &current_stream, NULL);
+
+ if (current_stream != stream)
+ return;
+
+ g_idle_add (on_audio_changed_main_context, g_object_ref (self));
+}
+
+static gboolean
+on_current_audio_changed_main_context (gpointer data)
+{
+ ClutterGstPlayback *self = CLUTTER_GST_PLAYBACK (data);
+
+ CLUTTER_GST_NOTE (AUDIO_STREAM, "audio stream changed");
+ g_object_notify (G_OBJECT (self), "audio-stream");
+
+ g_object_unref (self);
+
+ return FALSE;
+}
+
+static void
+on_current_audio_changed (GstElement *pipeline,
+ GParamSpec *pspec,
+ ClutterGstPlayback *self)
+{
+ g_idle_add (on_current_audio_changed_main_context, g_object_ref (self));
+}
+
+static gboolean
+on_text_changed_main_context (gpointer data)
+{
+ ClutterGstPlayback *self = CLUTTER_GST_PLAYBACK (data);
+ ClutterGstPlaybackPrivate *priv = self->priv;
+
+ free_tags_list (&priv->subtitle_tracks);
+ priv->subtitle_tracks = get_tags (priv->pipeline, "n-text", "get-text-tags");
+
+ CLUTTER_GST_NOTE (AUDIO_STREAM, "subtitle-tracks changed");
+
+ g_object_notify (G_OBJECT (self), "subtitle-tracks");
+
+ g_object_unref (self);
+
+ return FALSE;
+}
+
+/* same explanation as for notify::volume's usage of g_idle_add() */
+static void
+on_text_changed (GstElement *pipeline,
+ ClutterGstPlayback *self)
+{
+ g_idle_add (on_text_changed_main_context, g_object_ref (self));
+}
+
+static void
+on_text_tags_changed (GstElement *pipeline,
+ gint stream,
+ ClutterGstPlayback *self)
+{
+ g_idle_add (on_text_changed_main_context, g_object_ref (self));
+}
+
+static gboolean
+on_current_text_changed_main_context (gpointer data)
+{
+ ClutterGstPlayback *self = CLUTTER_GST_PLAYBACK (data);
+
+ CLUTTER_GST_NOTE (AUDIO_STREAM, "text stream changed");
+ g_object_notify (G_OBJECT (self), "subtitle-track");
+
+ g_object_unref (self);
+
+ return FALSE;
+}
+
+static void
+on_current_text_changed (GstElement *pipeline,
+ GParamSpec *pspec,
+ ClutterGstPlayback *self)
+{
+ g_idle_add (on_current_text_changed_main_context, g_object_ref (self));
+}
+
+/**/
+
+static ClutterGstFrame *
+clutter_gst_playback_get_frame (ClutterGstPlayer *self)
+{
+ ClutterGstPlaybackPrivate *priv = CLUTTER_GST_PLAYBACK (self)->priv;
+
+ return priv->current_frame;
+}
+
+static GstElement *
+clutter_gst_playback_get_pipeline (ClutterGstPlayer *self)
+{
+ ClutterGstPlaybackPrivate *priv = CLUTTER_GST_PLAYBACK (self)->priv;
+
+ return priv->pipeline;
+}
+
+static gboolean
+clutter_gst_playback_get_idle (ClutterGstPlayer *self)
+{
+ ClutterGstPlaybackPrivate *priv = CLUTTER_GST_PLAYBACK (self)->priv;
+
+ return priv->is_idle;
+}
+
+static gdouble
+clutter_gst_playback_get_audio_volume (ClutterGstPlayer *self)
+{
+ return get_audio_volume (CLUTTER_GST_PLAYBACK (self));
+}
+
+static void
+clutter_gst_playback_set_audio_volume (ClutterGstPlayer *self,
+ gdouble volume)
+{
+ set_audio_volume (CLUTTER_GST_PLAYBACK (self), volume);
+}
+
+static gboolean
+clutter_gst_playback_get_playing (ClutterGstPlayer *self)
+{
+ return get_playing (CLUTTER_GST_PLAYBACK (self));
+}
+
+static void
+clutter_gst_playback_set_playing (ClutterGstPlayer *self,
+ gboolean playing)
+{
+ set_playing (CLUTTER_GST_PLAYBACK (self), playing);
+}
+
+static void
+player_iface_init (ClutterGstPlayerIface *iface)
+{
+ iface->get_frame = clutter_gst_playback_get_frame;
+ iface->get_pipeline = clutter_gst_playback_get_pipeline;
+ iface->get_idle = clutter_gst_playback_get_idle;
+
+ iface->get_audio_volume = clutter_gst_playback_get_audio_volume;
+ iface->set_audio_volume = clutter_gst_playback_set_audio_volume;
+
+ iface->get_playing = clutter_gst_playback_get_playing;
+ iface->set_playing = clutter_gst_playback_set_playing;
+}
+
+/**/
+
+static void
+clutter_gst_playback_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterGstPlayback *self;
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ gchar *str;
+
+ switch (property_id)
+ {
+ case PROP_URI:
+ g_value_set_string (value, priv->uri);
+ break;
+
+ case PROP_PLAYING:
+ g_value_set_boolean (value, get_playing (self));
+ break;
+
+ case PROP_PROGRESS:
+ g_value_set_double (value, get_progress (self));
+ break;
+
+ case PROP_SUBTITLE_URI:
+ g_object_get (priv->pipeline, "suburi", &str, NULL);
+ g_value_take_string (value, str);
+ break;
+
+ case PROP_SUBTITLE_FONT_NAME:
+ g_value_set_string (value, priv->font_name);
+ break;
+
+ case PROP_AUDIO_VOLUME:
+ g_value_set_double (value, get_audio_volume (self));
+ break;
+
+ case PROP_CAN_SEEK:
+ g_value_set_boolean (value, priv->can_seek);
+ break;
+
+ case PROP_BUFFER_FILL:
+ g_value_set_double (value, priv->buffer_fill);
+ break;
+
+ case PROP_DURATION:
+ g_value_set_double (value, priv->duration);
+ break;
+
+ case PROP_IDLE:
+ g_value_set_boolean (value, priv->is_idle);
+ break;
+
+ case PROP_USER_AGENT:
+ {
+ gchar *user_agent;
+
+ user_agent = clutter_gst_playback_get_user_agent (self);
+ g_value_take_string (value, user_agent);
+ }
+ break;
+
+ case PROP_SEEK_FLAGS:
+ {
+ ClutterGstSeekFlags seek_flags;
+
+ seek_flags = clutter_gst_playback_get_seek_flags (self);
+ g_value_set_flags (value, seek_flags);
+ }
+ break;
+
+ case PROP_AUDIO_STREAMS:
+ g_value_set_pointer (value, priv->audio_streams);
+ break;
+
+ case PROP_AUDIO_STREAM:
+ {
+ gint index_;
+
+ index_ = clutter_gst_playback_get_audio_stream (self);
+ g_value_set_int (value, index_);
+ }
+ break;
+
+ case PROP_SUBTITLE_TRACKS:
+ g_value_set_pointer (value, priv->subtitle_tracks);
+ break;
+
+ case PROP_SUBTITLE_TRACK:
+ {
+ gint index_;
+
+ index_ = clutter_gst_playback_get_subtitle_track (self);
+ g_value_set_int (value, index_);
+ }
+ break;
+
+ case PROP_IN_SEEK:
+ g_value_set_boolean (value, priv->in_seek);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+clutter_gst_playback_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterGstPlayback *self = CLUTTER_GST_PLAYBACK (object);
+
+ switch (property_id)
+ {
+ case PROP_URI:
+ set_uri (self, g_value_get_string (value));
+ break;
+
+ case PROP_PLAYING:
+ set_playing (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_PROGRESS:
+ set_progress (self, g_value_get_double (value));
+ break;
+
+ case PROP_SUBTITLE_URI:
+ set_subtitle_uri (self, g_value_get_string (value));
+ break;
+
+ case PROP_SUBTITLE_FONT_NAME:
+ set_subtitle_font_name (self, g_value_get_string (value));
+ break;
+
+ case PROP_AUDIO_VOLUME:
+ set_audio_volume (self, g_value_get_double (value));
+ break;
+
+ case PROP_USER_AGENT:
+ clutter_gst_playback_set_user_agent (self,
+ g_value_get_string (value));
+ break;
+
+ case PROP_SEEK_FLAGS:
+ clutter_gst_playback_set_seek_flags (self,
+ g_value_get_flags (value));
+ break;
+
+ case PROP_AUDIO_STREAM:
+ clutter_gst_playback_set_audio_stream (self,
+ g_value_get_int (value));
+ break;
+
+ case PROP_SUBTITLE_TRACK:
+ clutter_gst_playback_set_subtitle_track (self,
+ g_value_get_int (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+clutter_gst_playback_dispose (GObject *object)
+{
+ ClutterGstPlaybackPrivate *priv = CLUTTER_GST_PLAYBACK (object)->priv;
+
+ if (priv->tick_timeout_id)
+ {
+ g_source_remove (priv->tick_timeout_id);
+ priv->tick_timeout_id = 0;
+ }
+
+ if (priv->buffering_timeout_id)
+ {
+ g_source_remove (priv->buffering_timeout_id);
+ priv->buffering_timeout_id = 0;
+ }
+
+ if (priv->download_buffering_element)
+ g_clear_object (&priv->download_buffering_element);
+
+ if (priv->bus)
+ {
+ gst_bus_remove_signal_watch (priv->bus);
+ priv->bus = NULL;
+ }
+
+ if (priv->pipeline)
+ {
+ gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+ g_clear_object (&priv->pipeline);
+ }
+
+ if (priv->current_frame)
+ {
+ g_boxed_free (CLUTTER_GST_TYPE_FRAME, priv->current_frame);
+ priv->current_frame = NULL;
+ }
+
+ g_free (priv->uri);
+ g_free (priv->font_name);
+ g_free (priv->user_agent);
+ priv->uri = priv->font_name = priv->user_agent = NULL;
+ free_tags_list (&priv->audio_streams);
+ free_tags_list (&priv->subtitle_tracks);
+
+ G_OBJECT_CLASS (clutter_gst_playback_parent_class)->dispose (object);
+}
+
+static void
+clutter_gst_playback_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (clutter_gst_playback_parent_class)->finalize (object);
+}
+
+static void
+clutter_gst_playback_class_init (ClutterGstPlaybackClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (ClutterGstPlaybackPrivate));
+
+ object_class->get_property = clutter_gst_playback_get_property;
+ object_class->set_property = clutter_gst_playback_set_property;
+ object_class->dispose = clutter_gst_playback_dispose;
+ object_class->finalize = clutter_gst_playback_finalize;
+
+ /**
+ * ClutterGstPlayback:uri:
+ *
+ * The location of a media file, expressed as a valid URI.
+ */
+ pspec = g_param_spec_string ("uri",
+ "URI",
+ "URI of a media file",
+ NULL,
+ CLUTTER_GST_PARAM_READWRITE |
+ G_PARAM_DEPRECATED);
+ g_object_class_install_property (object_class, PROP_URI, pspec);
+
+ /**
+ * ClutterGstPlayback:progress:
+ *
+ * The current progress of the playback, as a normalized
+ * value between 0.0 and 1.0.
+ */
+ pspec = g_param_spec_double ("progress",
+ "Progress",
+ "Current progress of the playback",
+ 0.0, 1.0, 0.0,
+ CLUTTER_GST_PARAM_READWRITE |
+ G_PARAM_DEPRECATED);
+ g_object_class_install_property (object_class, PROP_PROGRESS, pspec);
+
+ /**
+ * ClutterGstPlayback:subtitle-uri:
+ *
+ * The location of a subtitle file, expressed as a valid URI.
+ */
+ pspec = g_param_spec_string ("subtitle-uri",
+ "Subtitle URI",
+ "URI of a subtitle file",
+ NULL,
+ CLUTTER_GST_PARAM_READWRITE |
+ G_PARAM_DEPRECATED);
+ g_object_class_install_property (object_class, PROP_SUBTITLE_URI, pspec);
+
+ /**
+ * ClutterGstPlayback:subtitle-font-name:
+ *
+ * The font used to display subtitles. The font description has to
+ * follow the same grammar as the one recognized by
+ * pango_font_description_from_string().
+ */
+ pspec = g_param_spec_string ("subtitle-font-name",
+ "Subtitle Font Name",
+ "The font used to display subtitles",
+ NULL,
+ CLUTTER_GST_PARAM_READWRITE |
+ G_PARAM_DEPRECATED);
+ g_object_class_install_property (object_class, PROP_SUBTITLE_FONT_NAME, pspec);
+
+ /**
+ * ClutterGstPlayback:can-seek:
+ *
+ * Whether the current stream is seekable.
+ */
+ pspec = g_param_spec_boolean ("can-seek",
+ "Can Seek",
+ "Whether the current stream is seekable",
+ FALSE,
+ CLUTTER_GST_PARAM_READABLE |
+ G_PARAM_DEPRECATED);
+ g_object_class_install_property (object_class, PROP_CAN_SEEK, pspec);
+
+ /**
+ * ClutterGstPlayback:buffer-fill:
+ *
+ * The fill level of the buffer for the current stream,
+ * as a value between 0.0 and 1.0.
+ */
+ pspec = g_param_spec_double ("buffer-fill",
+ "Buffer Fill",
+ "The fill level of the buffer",
+ 0.0, 1.0, 0.0,
+ CLUTTER_GST_PARAM_READABLE |
+ G_PARAM_DEPRECATED);
+ g_object_class_install_property (object_class, PROP_BUFFER_FILL, pspec);
+
+ /**
+ * ClutterGstPlayback:duration:
+ *
+ * The duration of the current stream, in seconds
+ */
+ pspec = g_param_spec_double ("duration",
+ "Duration",
+ "The duration of the stream, in seconds",
+ 0, G_MAXDOUBLE, 0,
+ CLUTTER_GST_PARAM_READABLE);
+ g_object_class_install_property (object_class, PROP_DURATION, pspec);
+
+ /**
+ * ClutterGstPlayback:user-agent:
+ *
+ * The User Agent used by #ClutterGstPlayback with network protocols.
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_string ("user-agent",
+ "User Agent",
+ "User Agent used with network protocols",
+ NULL,
+ CLUTTER_GST_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_USER_AGENT, pspec);
+
+ /**
+ * ClutterGstPlayback:seek-flags:
+ *
+ * Flags to use when seeking.
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_flags ("seek-flags",
+ "Seek Flags",
+ "Flags to use when seeking",
+ CLUTTER_GST_TYPE_SEEK_FLAGS,
+ CLUTTER_GST_SEEK_FLAG_NONE,
+ CLUTTER_GST_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_SEEK_FLAGS, pspec);
+
+ /**
+ * ClutterGstPlayback:audio-streams:
+ *
+ * List of audio streams available on the current media.
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_pointer ("audio-streams",
+ "Audio Streams",
+ "List of the audio streams of the media",
+ CLUTTER_GST_PARAM_READABLE);
+ g_object_class_install_property (object_class, PROP_AUDIO_STREAMS, pspec);
+
+ /**
+ * ClutterGstPlayback:audio-stream:
+ *
+ * Index of the current audio stream.
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_int ("audio-stream",
+ "Audio Stream",
+ "Index of the current audio stream",
+ -1, G_MAXINT, -1,
+ CLUTTER_GST_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_AUDIO_STREAM, pspec);
+
+ /**
+ * ClutterGstPlayback:subtitle-tracks:
+ *
+ * List of subtitle tracks available.
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_pointer ("subtitle-tracks",
+ "Subtitles Tracks",
+ "List of the subtitles tracks of the media",
+ CLUTTER_GST_PARAM_READABLE);
+ g_object_class_install_property (object_class, PROP_SUBTITLE_TRACKS, pspec);
+
+ /**
+ * ClutterGstPlayback:subtitle-track:
+ *
+ * Current subtitle track being displayed.
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_int ("subtitle-track",
+ "Subtitle Track",
+ "Index of the current subtitles track",
+ -1, G_MAXINT, -1,
+ CLUTTER_GST_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_SUBTITLE_TRACK, pspec);
+
+ /**
+ * ClutterGstPlayback:in-seek:
+ *
+ * Whether or not the stream is being seeked.
+ *
+ * Since: 1.6
+ */
+ pspec = g_param_spec_boolean ("in-seek",
+ "In seek mode",
+ "If currently seeking",
+ FALSE,
+ CLUTTER_GST_PARAM_READABLE);
+ g_object_class_install_property (object_class, PROP_IN_SEEK, pspec);
+
+
+ g_object_class_override_property (object_class,
+ PROP_IDLE, "idle");
+ g_object_class_override_property (object_class,
+ PROP_PLAYING, "playing");
+ g_object_class_override_property (object_class,
+ PROP_AUDIO_VOLUME, "audio-volume");
+
+
+ /* Signals */
+
+ /**
+ * ClutterGstPlayback::download-buffering:
+ * @player: the #ClutterGstPlayback instance that received the signal
+ * @start: start position of the buffering
+ * @stop: start position of the buffering
+ *
+ * The ::download-buffering signal is emitted each time their an
+ * update about the buffering of the current media.
+ *
+ * Since: 1.4
+ */
+ signals[DOWNLOAD_BUFFERING_SIGNAL] =
+ g_signal_new ("download-buffering",
+ CLUTTER_GST_TYPE_PLAYBACK,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ClutterGstPlaybackClass,
+ download_buffering),
+ NULL, NULL,
+ _clutter_gst_marshal_VOID__DOUBLE_DOUBLE,
+ G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+}
+
+static void
+_new_frame_from_pipeline (CoglGstVideoSink *sink, ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+
+ clutter_gst_util_update_frame (CLUTTER_GST_PLAYER (self),
+ &priv->current_frame,
+ cogl_gst_video_sink_get_pipeline (sink));
+}
+
+static void
+_ready_from_pipeline (CoglGstVideoSink *sink, ClutterGstPlayback *self)
+{
+
+ ClutterGstPlaybackPrivate *priv = self->priv;
+
+ g_signal_emit_by_name (self, "ready");
+
+ /* clutter_gst_util_update_frame (CLUTTER_GST_PLAYER (self), */
+ /* &priv->current_frame, */
+ /* cogl_gst_video_sink_get_pipeline (sink)); */
+}
+
+static GstElement *
+get_pipeline (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv = self->priv;
+ GstElement *pipeline, *audio_sink;
+ CoglGstVideoSink *video_sink;
+
+ pipeline = gst_element_factory_make ("playbin", "pipeline");
+ if (!pipeline)
+ {
+ g_critical ("Unable to create playbin element");
+ return NULL;
+ }
+
+ audio_sink = gst_element_factory_make ("gconfaudiosink", "audio-sink");
+ if (!audio_sink)
+ {
+ audio_sink = gst_element_factory_make ("autoaudiosink", "audio-sink");
+ if (!audio_sink)
+ {
+ audio_sink = gst_element_factory_make ("alsasink", "audio-sink");
+ g_warning ("Could not create a GST audio_sink. "
+ "Audio unavailable.");
+
+ /* do we even need to bother? */
+ if (!audio_sink)
+ audio_sink = gst_element_factory_make ("fakesink", "audio-sink");
+ }
+ }
+
+ video_sink = cogl_gst_video_sink_new (clutter_backend_get_cogl_context (clutter_get_default_backend ()));
+ /* gst_element_factory_make ("coglsink", "video-sink"); */
+
+ g_signal_connect (video_sink, "new-frame",
+ G_CALLBACK (_new_frame_from_pipeline), self);
+ g_signal_connect (video_sink, "pipeline-ready",
+ G_CALLBACK (_ready_from_pipeline), self);
+
+ g_object_set (G_OBJECT (pipeline),
+ "audio-sink", audio_sink,
+ "video-sink", video_sink,
+ "subtitle-font-desc", "Sans 16",
+ NULL);
+
+ return pipeline;
+}
+
+static void
+clutter_gst_playback_init (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv;
+
+ self->priv = priv = GST_PLAYBACK_PRIVATE (self);
+
+ priv->is_idle = TRUE;
+ priv->in_seek = FALSE;
+ priv->is_changing_uri = FALSE;
+ priv->in_download_buffering = FALSE;
+
+ priv->pipeline = get_pipeline (self);
+ g_assert (priv->pipeline != NULL);
+
+ g_signal_connect (priv->pipeline, "notify::source",
+ G_CALLBACK (on_source_changed), self);
+
+ /* We default to not playing until someone calls set_playing(TRUE) */
+ priv->target_state = GST_STATE_PAUSED;
+
+ /* Default to a fast seek, ie. same effect than set_seek_flags (NONE); */
+ priv->seek_flags = GST_SEEK_FLAG_KEY_UNIT;
+
+ priv->bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
+
+ gst_bus_add_signal_watch (priv->bus);
+
+ g_signal_connect_object (priv->bus, "message::error",
+ G_CALLBACK (bus_message_error_cb),
+ self, 0);
+ g_signal_connect_object (priv->bus, "message::eos",
+ G_CALLBACK (bus_message_eos_cb),
+ self, 0);
+ g_signal_connect_object (priv->bus, "message::buffering",
+ G_CALLBACK (bus_message_buffering_cb),
+ self, 0);
+ g_signal_connect_object (priv->bus, "message::duration-changed",
+ G_CALLBACK (bus_message_duration_changed_cb),
+ self, 0);
+ g_signal_connect_object (priv->bus, "message::state-changed",
+ G_CALLBACK (bus_message_state_change_cb),
+ self, 0);
+ g_signal_connect_object (priv->bus, "message::async-done",
+ G_CALLBACK (bus_message_async_done_cb),
+ self, 0);
+
+ g_signal_connect (priv->pipeline, "notify::volume",
+ G_CALLBACK (on_volume_changed),
+ self);
+
+ g_signal_connect (priv->pipeline, "audio-changed",
+ G_CALLBACK (on_audio_changed),
+ self);
+ g_signal_connect (priv->pipeline, "audio-tags-changed",
+ G_CALLBACK (on_audio_tags_changed),
+ self);
+ g_signal_connect (priv->pipeline, "notify::current-audio",
+ G_CALLBACK (on_current_audio_changed),
+ self);
+
+ g_signal_connect (priv->pipeline, "text-changed",
+ G_CALLBACK (on_text_changed),
+ self);
+ g_signal_connect (priv->pipeline, "text-tags-changed",
+ G_CALLBACK (on_text_tags_changed),
+ self);
+ g_signal_connect (priv->pipeline, "notify::current-text",
+ G_CALLBACK (on_current_text_changed),
+ self);
+
+#if defined(CLUTTER_WINDOWING_X11) && defined (HAVE_HW_DECODER_SUPPORT)
+ gst_bus_set_sync_handler (priv->bus, on_sync_message,
+ clutter_x11_get_default_display (), NULL);
+#endif
+
+ gst_object_unref (GST_OBJECT (priv->bus));
+}
+
+ClutterGstPlayback *
+clutter_gst_playback_new (void)
+{
+ return g_object_new (CLUTTER_GST_TYPE_PLAYBACK, NULL);
+}
+
+/**
+ * clutter_gst_playback_set_uri:
+ * @self: a #ClutterGstPlayback
+ * @uri: the URI of the media stream
+ *
+ * Sets the URI of @self to @uri.
+ */
+void
+clutter_gst_playback_set_uri (ClutterGstPlayback *self,
+ const gchar *uri)
+{
+ g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+ g_object_set (G_OBJECT (self), "uri", uri, NULL);
+}
+
+/**
+ * clutter_gst_playback_get_uri:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the URI from @self.
+ *
+ * Return value: the URI of the media stream. Use g_free()
+ * to free the returned string
+ */
+gchar *
+clutter_gst_playback_get_uri (ClutterGstPlayback *self)
+{
+ gchar *retval = NULL;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), NULL);
+
+ g_object_get (G_OBJECT (self), "uri", &retval, NULL);
+
+ return retval;
+}
+
+/**
+ * clutter_gst_playback_set_filename:
+ * @self: a #ClutterGstPlayback
+ * @filename: A filename
+ *
+ * Sets the source of @self using a file path.
+ */
+void
+clutter_gst_playback_set_filename (ClutterGstPlayback *self,
+ const gchar *filename)
+{
+ gchar *uri;
+ GError *uri_error = NULL;
+
+ if (!g_path_is_absolute (filename))
+ {
+ gchar *abs_path;
+
+ abs_path = g_build_filename (g_get_current_dir (), filename, NULL);
+ uri = g_filename_to_uri (abs_path, NULL, &uri_error);
+ g_free (abs_path);
+ }
+ else
+ uri = g_filename_to_uri (filename, NULL, &uri_error);
+
+ if (uri_error)
+ {
+ g_signal_emit_by_name (self, "error", uri_error);
+ g_error_free (uri_error);
+ return;
+ }
+
+ clutter_gst_playback_set_uri (self, uri);
+
+ g_free (uri);
+}
+
+/**
+ * clutter_gst_playback_get_user_agent:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the user agent used when streaming.
+ *
+ * Return value: the user agent used. The returned string has to be freed with
+ * g_free()
+ *
+ * Since: 1.4
+ */
+gchar *
+clutter_gst_playback_get_user_agent (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv;
+ GstElement *source;
+ GParamSpec *pspec;
+ gchar *user_agent;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), NULL);
+
+ priv = self->priv;
+
+ /* If the user has set a custom user agent, we just return it even if it is
+ * not used by the current source element of the pipeline */
+ if (priv->user_agent)
+ return g_strdup (priv->user_agent);
+
+ /* If not, we try to retrieve the user agent used by the current source */
+ g_object_get (priv->pipeline, "source", &source, NULL);
+ if (source == NULL)
+ return NULL;
+
+ pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (source),
+ "user-agent");
+ if (pspec == NULL)
+ return NULL;
+
+ g_object_get (source, "user-agent", &user_agent, NULL);
+
+ return user_agent;
+}
+
+/**
+ * clutter_gst_playback_set_user_agent:
+ * @self: a #ClutterGstPlayback
+ * @user_agent: the user agent
+ *
+ * Sets the user agent to use when streaming.
+ *
+ * When streaming content, you might want to set a custom user agent, eg. to
+ * promote your software, make it appear in statistics or because the server
+ * requires a special user agent you want to impersonate.
+ *
+ * Since: 1.4
+ */
+void
+clutter_gst_playback_set_user_agent (ClutterGstPlayback *self,
+ const gchar *user_agent)
+{
+ ClutterGstPlaybackPrivate *priv;
+
+ g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+ priv = self->priv;
+
+ g_free (priv->user_agent);
+ if (user_agent)
+ priv->user_agent = g_strdup (user_agent);
+ else
+ priv->user_agent = NULL;
+
+ player_set_user_agent (self, user_agent);
+}
+
+/**
+ * clutter_gst_playback_get_seek_flags:
+ * @self: a #ClutterGstPlayback
+ *
+ * Get the current value of the seek-flags property.
+ *
+ * Return value: a combination of #ClutterGstSeekFlags
+ *
+ * Since: 1.4
+ */
+ClutterGstSeekFlags
+clutter_gst_playback_get_seek_flags (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self),
+ CLUTTER_GST_SEEK_FLAG_NONE);
+
+ priv = self->priv;
+
+ if (priv->seek_flags == GST_SEEK_FLAG_ACCURATE)
+ return CLUTTER_GST_SEEK_FLAG_ACCURATE;
+ else
+ return CLUTTER_GST_SEEK_FLAG_NONE;
+}
+
+/**
+ * clutter_gst_playback_set_seek_flags:
+ * @self: a #ClutterGstPlayback
+ * @flags: a combination of #ClutterGstSeekFlags
+ *
+ * Seeking can be done with several trade-offs. Clutter-gst defaults
+ * to %CLUTTER_GST_SEEK_FLAG_NONE.
+ *
+ * Since: 1.4
+ */
+void
+clutter_gst_playback_set_seek_flags (ClutterGstPlayback *self,
+ ClutterGstSeekFlags flags)
+{
+ ClutterGstPlaybackPrivate *priv;
+
+ g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+ priv = self->priv;
+
+ if (flags == CLUTTER_GST_SEEK_FLAG_NONE)
+ priv->seek_flags = GST_SEEK_FLAG_KEY_UNIT;
+ else if (flags & CLUTTER_GST_SEEK_FLAG_ACCURATE)
+ priv->seek_flags = GST_SEEK_FLAG_ACCURATE;
+}
+
+/**
+ * clutter_gst_playback_get_buffering_mode:
+ * @self: a #ClutterGstPlayback
+ *
+ * Return value: a #ClutterGstBufferingMode
+ *
+ * Since: 1.4
+ */
+ClutterGstBufferingMode
+clutter_gst_playback_get_buffering_mode (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv;
+ GstPlayFlags flags;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self),
+ CLUTTER_GST_BUFFERING_MODE_STREAM);
+
+ priv = self->priv;
+
+ g_object_get (G_OBJECT (priv->pipeline), "flags", &flags, NULL);
+
+ if (flags & GST_PLAY_FLAG_DOWNLOAD)
+ return CLUTTER_GST_BUFFERING_MODE_DOWNLOAD;
+
+ return CLUTTER_GST_BUFFERING_MODE_STREAM;
+}
+
+/**
+ * clutter_gst_playback_set_buffering_mode:
+ * @self: a #ClutterGstPlayback
+ * @mode: a #ClutterGstBufferingMode
+ *
+ * Since: 1.4
+ */
+void
+clutter_gst_playback_set_buffering_mode (ClutterGstPlayback *self,
+ ClutterGstBufferingMode mode)
+{
+ ClutterGstPlaybackPrivate *priv;
+ GstPlayFlags flags;
+
+ g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+ priv = self->priv;
+
+ g_object_get (G_OBJECT (priv->pipeline), "flags", &flags, NULL);
+
+ switch (mode)
+ {
+ case CLUTTER_GST_BUFFERING_MODE_STREAM:
+ flags &= ~GST_PLAY_FLAG_DOWNLOAD;
+ break;
+
+ case CLUTTER_GST_BUFFERING_MODE_DOWNLOAD:
+ flags |= GST_PLAY_FLAG_DOWNLOAD;
+ break;
+
+ default:
+ g_warning ("Unexpected buffering mode %d", mode);
+ break;
+ }
+
+ g_object_set (G_OBJECT (priv->pipeline), "flags", flags, NULL);
+}
+
+/**
+ * clutter_gst_playback_get_buffer_fill:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the amount of the stream that is buffered.
+ *
+ * Return value: the fill level, between 0.0 and 1.0
+ */
+gdouble
+clutter_gst_playback_get_buffer_fill (ClutterGstPlayback *self)
+{
+ gdouble retval = 0.0;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), 0);
+
+ g_object_get (G_OBJECT (self), "buffer-fill", &retval, NULL);
+
+ return retval;
+}
+
+/**
+ * clutter_gst_playback_get_buffer_size:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the buffer size when buffering network streams.
+ *
+ * Return value: The buffer size
+ */
+gint
+clutter_gst_playback_get_buffer_size (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv;
+ gint size;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), 0);
+
+ priv = self->priv;
+
+ g_object_get (G_OBJECT (priv->pipeline), "buffer-size", &size, NULL);
+
+ return size;
+}
+
+/**
+ * clutter_gst_playback_set_buffer_size:
+ * @self: a #ClutterGstPlayback
+ * @size: The new size
+ *
+ * Sets the buffer size to be used when buffering network streams.
+ */
+void
+clutter_gst_playback_set_buffer_size (ClutterGstPlayback *self,
+ gint size)
+{
+ ClutterGstPlaybackPrivate *priv;
+
+ g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+ priv = self->priv;
+
+ g_object_set (G_OBJECT (priv->pipeline), "buffer-size", size, NULL);
+}
+
+/**
+ * clutter_gst_playback_get_buffer_duration:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the buffer duration when buffering network streams.
+ *
+ * Return value: The buffer duration
+ */
+gint64
+clutter_gst_playback_get_buffer_duration (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv;
+ gint64 duration;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), 0);
+
+ priv = self->priv;
+
+ g_object_get (G_OBJECT (priv->pipeline), "buffer-duration", &duration, NULL);
+
+ return duration;
+}
+
+/**
+ * clutter_gst_playback_set_buffer_duration:
+ * @self: a #ClutterGstPlayback
+ * @duration: The new duration
+ *
+ * Sets the buffer duration to be used when buffering network streams.
+ */
+void
+clutter_gst_playback_set_buffer_duration (ClutterGstPlayback *self,
+ gint64 duration)
+{
+ ClutterGstPlaybackPrivate *priv;
+
+ g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+ priv = self->priv;
+
+ g_object_set (G_OBJECT (priv->pipeline), "buffer-duration", duration, NULL);
+}
+
+/**
+ * clutter_gst_playback_get_audio_streams:
+ * @self: a #ClutterGstPlayback
+ *
+ * Get the list of audio streams of the current media.
+ *
+ * Return value: (transfer none) (element-type utf8): a list of
+ * strings describing the available audio streams
+ *
+ * Since: 1.4
+ */
+GList *
+clutter_gst_playback_get_audio_streams (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), NULL);
+
+ priv = self->priv;
+
+ if (CLUTTER_GST_DEBUG_ENABLED (AUDIO_STREAM))
+ {
+ gchar *streams;
+
+ streams = list_to_string (priv->audio_streams);
+ CLUTTER_GST_NOTE (AUDIO_STREAM, "audio streams: %s", streams);
+ g_free (streams);
+ }
+
+ return priv->audio_streams;
+}
+
+/**
+ * clutter_gst_playback_get_audio_stream:
+ * @self: a #ClutterGstPlayback
+ *
+ * Get the current audio stream. The number returned in the index of the
+ * audio stream playing in the list returned by
+ * clutter_gst_playback_get_audio_streams().
+ *
+ * Return value: the index of the current audio stream, -1 if the media has no
+ * audio stream
+ *
+ * Since: 1.4
+ */
+gint
+clutter_gst_playback_get_audio_stream (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv;
+ gint index_ = -1;
+
+ g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+ priv = self->priv;
+
+ g_object_get (G_OBJECT (priv->pipeline),
+ "current-audio", &index_,
+ NULL);
+
+ CLUTTER_GST_NOTE (AUDIO_STREAM, "audio stream is #%d", index_);
+
+ return index_;
+}
+
+/**
+ * clutter_gst_playback_set_audio_stream:
+ * @self: a #ClutterGstPlayback
+ * @index_: the index of the audio stream
+ *
+ * Set the audio stream to play. @index_ is the index of the stream
+ * in the list returned by clutter_gst_playback_get_audio_streams().
+ *
+ * Since: 1.4
+ */
+void
+clutter_gst_playback_set_audio_stream (ClutterGstPlayback *self,
+ gint index_)
+{
+ ClutterGstPlaybackPrivate *priv;
+
+ g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+ priv = self->priv;
+
+ g_return_if_fail (index_ >= 0 &&
+ index_ < (gint) g_list_length (priv->audio_streams));
+
+ CLUTTER_GST_NOTE (AUDIO_STREAM, "set audio audio stream to #%d", index_);
+
+ g_object_set (G_OBJECT (priv->pipeline),
+ "current-audio", index_,
+ NULL);
+}
+
+/**
+ * clutter_gst_playback_set_subtitle_uri:
+ * @self: a #ClutterGstPlayback
+ * @uri: the URI of a subtitle file
+ *
+ * Sets the location of a subtitle file to display while playing @self.
+ */
+void
+clutter_gst_playback_set_subtitle_uri (ClutterGstPlayback *self,
+ const char *uri)
+{
+ g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+ g_object_set (G_OBJECT (self), "subtitle-uri", uri, NULL);
+}
+
+/**
+ * clutter_gst_playback_get_subtitle_uri:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the URI of the subtitle file in use.
+ *
+ * Return value: the URI of the subtitle file. Use g_free()
+ * to free the returned string
+ */
+gchar *
+clutter_gst_playback_get_subtitle_uri (ClutterGstPlayback *self)
+{
+ gchar *retval = NULL;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), NULL);
+
+ g_object_get (G_OBJECT (self), "subtitle-uri", &retval, NULL);
+
+ return retval;
+}
+
+/**
+ * clutter_gst_playback_set_subtitle_font_name:
+ * @self: a #ClutterGstPlayback
+ * @font_name: a font name, or %NULL to set the default font name
+ *
+ * Sets the font used by the subtitle renderer. The @font_name string must be
+ * either %NULL, which means that the default font name of the underlying
+ * implementation will be used; or must follow the grammar recognized by
+ * pango_font_description_from_string() like:
+ *
+ * |[
+ * clutter_gst_playback_set_subtitle_font_name (player, "Sans 24pt");
+ * ]|
+ */
+void
+clutter_gst_playback_set_subtitle_font_name (ClutterGstPlayback *self,
+ const char *font_name)
+{
+ g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+ g_object_set (G_OBJECT (self), "subtitle-font-name", font_name, NULL);
+}
+
+/**
+ * clutter_gst_playback_get_subtitle_font_name:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the font name currently used.
+ *
+ * Return value: a string containing the font name. Use g_free()
+ * to free the returned string
+ */
+gchar *
+clutter_gst_playback_get_subtitle_font_name (ClutterGstPlayback *self)
+{
+ gchar *retval = NULL;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), NULL);
+
+ g_object_get (G_OBJECT (self), "subtitle-font-name", &retval, NULL);
+
+ return retval;
+}
+
+/**
+ * clutter_gst_playback_get_subtitle_tracks:
+ * @self: a #ClutterGstPlayback
+ *
+ * Get the list of subtitles tracks of the current media.
+ *
+ * Return value: (transfer none) (element-type utf8): a list of
+ * strings describing the available subtitles tracks
+ *
+ * Since: 1.4
+ */
+GList *
+clutter_gst_playback_get_subtitle_tracks (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), NULL);
+
+ priv = self->priv;
+
+ if (CLUTTER_GST_DEBUG_ENABLED (SUBTITLES))
+ {
+ gchar *tracks;
+
+ tracks = list_to_string (priv->subtitle_tracks);
+ CLUTTER_GST_NOTE (SUBTITLES, "subtitle tracks: %s", tracks);
+ g_free (tracks);
+ }
+
+ return priv->subtitle_tracks;
+}
+
+/**
+ * clutter_gst_playback_get_subtitle_track:
+ * @self: a #ClutterGstPlayback
+ *
+ * Get the current subtitles track. The number returned is the index of the
+ * subtiles track in the list returned by
+ * clutter_gst_playback_get_subtitle_tracks().
+ *
+ * Return value: the index of the current subtitlest track, -1 if the media has
+ * no subtitles track or if the subtitles have been turned off
+ *
+ * Since: 1.4
+ */
+gint
+clutter_gst_playback_get_subtitle_track (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv;
+ gint index_ = -1;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), -1);
+
+ priv = self->priv;
+
+ g_object_get (G_OBJECT (priv->pipeline),
+ "current-text", &index_,
+ NULL);
+
+ CLUTTER_GST_NOTE (SUBTITLES, "text track is #%d", index_);
+
+ return index_;
+}
+
+/**
+ * clutter_gst_playback_set_subtitle_track:
+ * @self: a #ClutterGstPlayback
+ * @index_: the index of the subtitles track
+ *
+ * Set the subtitles track to play. @index_ is the index of the stream
+ * in the list returned by clutter_gst_playback_get_subtitle_tracks().
+ *
+ * If @index_ is -1, the subtitles are turned off.
+ *
+ * Since: 1.4
+ */
+void
+clutter_gst_playback_set_subtitle_track (ClutterGstPlayback *self,
+ gint index_)
+{
+ ClutterGstPlaybackPrivate *priv;
+ GstPlayFlags flags;
+
+ g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+ priv = self->priv;
+
+ g_return_if_fail (index_ >= -1 &&
+ index_ < (gint) g_list_length (priv->subtitle_tracks));
+
+ CLUTTER_GST_NOTE (SUBTITLES, "set subtitle track to #%d", index_);
+
+ g_object_get (priv->pipeline, "flags", &flags, NULL);
+ flags &= ~GST_PLAY_FLAG_TEXT;
+ g_object_set (priv->pipeline, "flags", flags, NULL);
+
+ if (index_ >= 0)
+ {
+ g_object_set (G_OBJECT (priv->pipeline),
+ "current-text", index_,
+ NULL);
+
+ flags |= GST_PLAY_FLAG_TEXT;
+ g_object_set (priv->pipeline, "flags", flags, NULL);
+ }
+}
+
+/**
+ * clutter_gst_playback_get_in_seek:
+ * @self: a #ClutterGstPlayback
+ *
+ * Whether the player is seeking.
+ *
+ * Return value: TRUE if the player is seeking, FALSE otherwise.
+ *
+ * Since: 1.6
+ */
+gboolean
+clutter_gst_playback_get_in_seek (ClutterGstPlayback *self)
+{
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), FALSE);
+
+ return self->priv->in_seek;
+}
+
+/**
+ * clutter_gst_playback_get_can_seek:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves whether @self is seekable or not.
+ *
+ * Return value: %TRUE if @self can seek, %FALSE otherwise.
+ */
+gboolean
+clutter_gst_playback_get_can_seek (ClutterGstPlayback *self)
+{
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), FALSE);
+
+ return self->priv->can_seek;
+}
+
+/**
+ * clutter_gst_playback_set_progress:
+ * @self: a #ClutterGstPlayback
+ * @progress: the progress of the playback, between 0.0 and 1.0
+ *
+ * Sets the playback progress of @self. The @progress is
+ * a normalized value between 0.0 (begin) and 1.0 (end).
+ */
+void
+clutter_gst_playback_set_progress (ClutterGstPlayback *self,
+ gdouble progress)
+{
+ g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+ set_progress (self, progress);
+}
+
+/**
+ * clutter_gst_playback_get_progress:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the playback progress of @self.
+ *
+ * Return value: the playback progress, between 0.0 and 1.0
+ */
+gdouble
+clutter_gst_playback_get_progress (ClutterGstPlayback *self)
+{
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), 0);
+
+ return get_progress (self);
+}
+
+/**
+ * clutter_gst_playback_get_duration:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the duration of the media stream that @self represents.
+ *
+ * Return value: the duration of the media stream, in seconds
+ */
+gdouble
+clutter_gst_playback_get_duration (ClutterGstPlayback *self)
+{
+ gdouble retval = 0;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), 0);
+
+ g_object_get (G_OBJECT (self), "duration", &retval, NULL);
+
+ return retval;
+}
+
+/**
+ * clutter_gst_playback_is_live_media:
+ * @self: a #ClutterGstPlayback
+ *
+ * Whether the player is using a live media.
+ *
+ * Return value: TRUE if the player is using a live media, FALSE otherwise.
+ */
+gboolean
+clutter_gst_playback_is_live_media (ClutterGstPlayback *self)
+{
+ ClutterGstPlaybackPrivate *priv;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), FALSE);
+
+ return self->priv->is_live;
+}
diff --git a/clutter-gst/clutter-gst-playback.h b/clutter-gst/clutter-gst-playback.h
new file mode 100644
index 0000000..1be5084
--- /dev/null
+++ b/clutter-gst/clutter-gst-playback.h
@@ -0,0 +1,116 @@
+/* clutter-gst-playback.h */
+
+#ifndef __CLUTTER_GST_PLAYBACK_H__
+#define __CLUTTER_GST_PLAYBACK_H__
+
+#include <glib-object.h>
+
+#include <clutter-gst/clutter-gst-types.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_GST_TYPE_PLAYBACK clutter_gst_playback_get_type()
+
+#define CLUTTER_GST_PLAYBACK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ CLUTTER_GST_TYPE_PLAYBACK, \
+ ClutterGstPlayback))
+
+#define CLUTTER_GST_PLAYBACK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ CLUTTER_GST_TYPE_PLAYBACK, \
+ ClutterGstPlaybackClass))
+
+#define CLUTTER_GST_IS_PLAYBACK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ CLUTTER_GST_TYPE_PLAYBACK))
+
+#define CLUTTER_GST_IS_PLAYBACK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ CLUTTER_GST_TYPE_PLAYBACK))
+
+#define CLUTTER_GST_PLAYBACK_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ CLUTTER_GST_TYPE_PLAYBACK, \
+ ClutterGstPlaybackClass))
+
+typedef struct _ClutterGstPlayback ClutterGstPlayback;
+typedef struct _ClutterGstPlaybackClass ClutterGstPlaybackClass;
+typedef struct _ClutterGstPlaybackPrivate ClutterGstPlaybackPrivate;
+
+struct _ClutterGstPlayback
+{
+ GObject parent;
+
+ ClutterGstPlaybackPrivate *priv;
+};
+
+struct _ClutterGstPlaybackClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (* download_buffering) (ClutterGstPlayback *self,
+ gdouble start,
+ gdouble stop);
+};
+
+GType clutter_gst_playback_get_type (void) G_GNUC_CONST;
+
+ClutterGstPlayback * clutter_gst_playback_new (void);
+
+void clutter_gst_playback_set_uri (ClutterGstPlayback *self,
+ const gchar *uri);
+gchar * clutter_gst_playback_get_uri (ClutterGstPlayback *self);
+void clutter_gst_playback_set_filename (ClutterGstPlayback *self,
+ const gchar *filename);
+
+gchar * clutter_gst_playback_get_user_agent (ClutterGstPlayback *self);
+void clutter_gst_playback_set_user_agent (ClutterGstPlayback *self,
+ const gchar *user_agent);
+
+ClutterGstSeekFlags clutter_gst_playback_get_seek_flags (ClutterGstPlayback *self);
+void clutter_gst_playback_set_seek_flags (ClutterGstPlayback *self,
+ ClutterGstSeekFlags flags);
+
+ClutterGstBufferingMode clutter_gst_playback_get_buffering_mode (ClutterGstPlayback *self);
+void clutter_gst_playback_set_buffering_mode (ClutterGstPlayback *self,
+ ClutterGstBufferingMode mode);
+gdouble clutter_gst_playback_get_buffer_fill (ClutterGstPlayback *self);
+gint clutter_gst_playback_get_buffer_size (ClutterGstPlayback *self);
+void clutter_gst_playback_set_buffer_size (ClutterGstPlayback *self,
+ gint size);
+gint64 clutter_gst_playback_get_buffer_duration (ClutterGstPlayback *self);
+void clutter_gst_playback_set_buffer_duration (ClutterGstPlayback *self,
+ gint64 duration);
+
+GList * clutter_gst_playback_get_audio_streams (ClutterGstPlayback *self);
+gint clutter_gst_playback_get_audio_stream (ClutterGstPlayback *self);
+void clutter_gst_playback_set_audio_stream (ClutterGstPlayback *self,
+ gint index_);
+
+void clutter_gst_playback_set_subtitle_uri (ClutterGstPlayback *self,
+ const gchar *uri);
+gchar * clutter_gst_playback_get_subtitle_uri (ClutterGstPlayback *self);
+void clutter_gst_playback_set_subtitle_font_name
+ (ClutterGstPlayback *self,
+ const char *font_name);
+gchar * clutter_gst_playback_get_subtitle_font_name
+ (ClutterGstPlayback *self);
+GList * clutter_gst_playback_get_subtitle_tracks (ClutterGstPlayback *self);
+gint clutter_gst_playback_get_subtitle_track (ClutterGstPlayback *self);
+void clutter_gst_playback_set_subtitle_track (ClutterGstPlayback *self,
+ gint index_);
+
+gboolean clutter_gst_playback_get_in_seek (ClutterGstPlayback *self);
+
+void clutter_gst_playback_set_progress (ClutterGstPlayback *self,
+ gdouble progress);
+gdouble clutter_gst_playback_get_progress (ClutterGstPlayback *self);
+gdouble clutter_gst_playback_get_duration (ClutterGstPlayback *self);
+
+gboolean clutter_gst_playback_is_live_media (ClutterGstPlayback *self);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_GST_PLAYBACK_H__ */
diff --git a/clutter-gst/clutter-gst-player.c b/clutter-gst/clutter-gst-player.c
index 0b5dc81..25f8db5 100644
--- a/clutter-gst/clutter-gst-player.c
+++ b/clutter-gst/clutter-gst-player.c
@@ -12,7 +12,7 @@
* Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk>
*
* Copyright (C) 2006 OpenedHand
- * Copyright (C) 2009-2011 Intel Corporation
+ * Copyright (C) 2009-2013 Intel Corporation
* Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
*
* This library is free software; you can redistribute it and/or
@@ -45,2213 +45,34 @@
#include "config.h"
#endif
-#include <string.h>
-
-#include <gst/video/video.h>
-#include <gst/tag/tag.h>
-#include <gst/audio/streamvolume.h>
-
-#include "clutter-gst-debug.h"
#include "clutter-gst-enum-types.h"
#include "clutter-gst-marshal.h"
#include "clutter-gst-player.h"
#include "clutter-gst-private.h"
-#if defined (CLUTTER_WINDOWING_X11) && defined (HAVE_HW_DECODER_SUPPORT)
-#define GST_USE_UNSTABLE_API 1
-#include <gst/video/videocontext.h>
-#include <clutter/x11/clutter-x11.h>
-#endif
-
-
-typedef ClutterGstPlayerIface ClutterGstPlayerInterface;
+typedef ClutterGstPlayerIface ClutterGstPlayerInterface;
G_DEFINE_INTERFACE (ClutterGstPlayer, clutter_gst_player, G_TYPE_OBJECT)
-#define PLAYER_GET_PRIVATE(player) \
- (g_object_get_qdata (G_OBJECT (player), \
- clutter_gst_player_private_quark))
-#define PLAYER_SET_PRIVATE(player,private) \
- (g_object_set_qdata (G_OBJECT (player), \
- clutter_gst_player_private_quark, \
- private))
-
-#define PLAYER_GET_CLASS_PRIVATE(player) \
- (g_type_get_qdata (G_OBJECT_TYPE (player), \
- clutter_gst_player_class_quark))
-
-/* idle timeouts (in ms) */
-#define TICK_TIMEOUT 500
-#define BUFFERING_TIMEOUT 250
-
enum
{
+ NEW_FRAME,
+ READY_SIGNAL,
EOS_SIGNAL,
+ SIZE_CHANGE,
ERROR_SIGNAL, /* can't be called 'ERROR' otherwise it clashes with wingdi.h */
- DOWNLOAD_BUFFERING_SIGNAL,
LAST_SIGNAL
};
-enum
-{
- PROP_0,
-
- /* ClutterGstPlayer properties */
- PROP_URI,
- PROP_PLAYING,
- PROP_PROGRESS,
- PROP_SUBTITLE_URI,
- PROP_SUBTITLE_FONT_NAME,
- PROP_AUDIO_VOLUME,
- PROP_CAN_SEEK,
- PROP_BUFFER_FILL,
- PROP_DURATION,
- PROP_IDLE,
- PROP_USER_AGENT,
- PROP_SEEK_FLAGS,
- PROP_AUDIO_STREAMS,
- PROP_AUDIO_STREAM,
- PROP_SUBTITLE_TRACKS,
- PROP_SUBTITLE_TRACK,
- PROP_IN_SEEK
-};
-
-struct _ClutterGstPlayerIfacePrivate
-{
- void (*set_property) (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec);
- void (*get_property) (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec);
-};
-
-typedef struct _ClutterGstPlayerPrivate ClutterGstPlayerPrivate;
-
-/* Elements don't expose header files */
-typedef enum {
- GST_PLAY_FLAG_VIDEO = (1 << 0),
- GST_PLAY_FLAG_AUDIO = (1 << 1),
- GST_PLAY_FLAG_TEXT = (1 << 2),
- GST_PLAY_FLAG_VIS = (1 << 3),
- GST_PLAY_FLAG_SOFT_VOLUME = (1 << 4),
- GST_PLAY_FLAG_NATIVE_AUDIO = (1 << 5),
- GST_PLAY_FLAG_NATIVE_VIDEO = (1 << 6),
- GST_PLAY_FLAG_DOWNLOAD = (1 << 7),
- GST_PLAY_FLAG_BUFFERING = (1 << 8),
- GST_PLAY_FLAG_DEINTERLACE = (1 << 9)
-} GstPlayFlags;
-
-struct _ClutterGstPlayerPrivate
-{
- GObject parent;
-
- GstElement *pipeline;
- GstBus *bus;
-
- gchar *uri;
-
- guint is_idle : 1;
- guint is_live : 1;
- guint can_seek : 1;
- guint in_seek : 1;
- guint is_changing_uri : 1;
- guint in_error : 1;
- guint in_eos : 1;
- guint in_download_buffering : 1;
- /* when in progressive download, we use the buffer-fill property to signal
- * that we have enough data to play the stream. This flag allows to send
- * the notify that buffer-fill is 1.0 only once */
- guint virtual_stream_buffer_signalled : 1;
-
- gdouble stacked_progress;
-
- gdouble target_progress;
- GstState target_state;
-
- guint tick_timeout_id;
- guint buffering_timeout_id;
-
- /* This is a cubic volume, suitable for use in a UI cf. StreamVolume doc */
- gdouble volume;
-
- gdouble buffer_fill;
- gdouble duration;
- gchar *font_name;
- gchar *user_agent;
-
- GstSeekFlags seek_flags; /* flags for the seek in set_progress(); */
-
- GstElement *download_buffering_element;
-
- GList *audio_streams;
- GList *subtitle_tracks;
-};
-
-static GQuark clutter_gst_player_private_quark = 0;
-static GQuark clutter_gst_player_class_quark = 0;
-
static guint signals[LAST_SIGNAL] = { 0, };
-static gboolean player_buffering_timeout (gpointer data);
-
-/* Logic */
-
-#ifdef CLUTTER_GST_ENABLE_DEBUG
-static gchar *
-get_stream_description (GstTagList *tags,
- gint track_num)
-{
- gchar *description = NULL;
-
- if (tags)
- {
-
- gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &description);
-
- if (description)
- {
- const gchar *language = gst_tag_get_language_name (description);
-
- if (language)
- {
- g_free (description);
- description = g_strdup (language);
- }
- }
-
- if (!description)
- gst_tag_list_get_string (tags, GST_TAG_CODEC, &description);
- }
-
- if (!description)
- description = g_strdup_printf ("Track %d", track_num);
-
- return description;
-}
-
-gchar *
-list_to_string (GList *list)
-{
- GstTagList *tags;
- gchar *description;
- GString *string;
- GList *l;
- gint n, i;
-
- if (!list)
- return g_strdup ("<empty list>");
-
- string = g_string_new (NULL);
- n = g_list_length (list);
- for (i = 0, l = list; i < n - 1; i++, l = g_list_next (l))
- {
- tags = l->data;
- description = get_stream_description (tags, i);
- g_string_append_printf (string, "%s, ", description);
- g_free (description);
- }
-
- tags = l->data;
- description = get_stream_description (tags, i);
- g_string_append_printf (string, "%s", (gchar *) description);
- g_free (description);
-
- return g_string_free (string, FALSE);
-}
-#endif
-
-static const gchar *
-gst_state_to_string (GstState state)
-{
- switch (state)
- {
- case GST_STATE_VOID_PENDING:
- return "pending";
- case GST_STATE_NULL:
- return "null";
- case GST_STATE_READY:
- return "ready";
- case GST_STATE_PAUSED:
- return "paused";
- case GST_STATE_PLAYING:
- return "playing";
- }
-
- return "Unknown state";
-}
-
-static void
-free_tags_list (GList **listp)
-{
- GList *l;
-
- l = *listp;
- while (l)
- {
- if (l->data)
- gst_tag_list_unref (l->data);
- l = g_list_delete_link (l, l);
- }
-
- *listp = NULL;
-}
-
-static gboolean
-tick_timeout (gpointer data)
-{
- GObject *player = data;
-
- g_object_notify (player, "progress");
-
- return TRUE;
-}
-
-static void
-player_set_user_agent (ClutterGstPlayer *player,
- const gchar *user_agent)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- GstElement *source;
- GParamSpec *pspec;
-
- if (user_agent == NULL)
- return;
-
- g_object_get (priv->pipeline, "source", &source, NULL);
- if (source == NULL)
- return;
-
- pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (source),
- "user-agent");
- if (pspec == NULL)
- return;
-
- CLUTTER_GST_NOTE (MEDIA, "setting user agent: %s", user_agent);
-
- g_object_set (source, "user-agent", user_agent, NULL);
-}
-
-static void
-autoload_subtitle (ClutterGstPlayer *player,
- const gchar *uri)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- gchar *path, *dot, *subtitle_path;
- GFile *video;
- guint i;
-
- static const char subtitles_extensions[][4] =
- {
- "sub", "SUB",
- "srt", "SRT",
- "smi", "SMI",
- "ssa", "SSA",
- "ass", "ASS",
- "asc", "ASC"
- };
-
- /* do not try to look for subtitle files if the video file is not mounted
- * locally */
- if (!g_str_has_prefix (uri, "file://"))
- return;
-
- /* Retrieve the absolute path of the video file */
- video = g_file_new_for_uri (uri);
- path = g_file_get_path (video);
- g_object_unref (video);
- if (path == NULL)
- return;
-
- /* Put a '\0' after the dot of the extension */
- dot = strrchr (path, '.');
- if (dot == NULL) {
- g_free (path);
- return;
- }
- *++dot = '\0';
-
- /* we can't use path as the temporary buffer for the paths of the potential
- * subtitle files as we may not have enough room there */
- subtitle_path = g_malloc (strlen (path) + 1 + 4);
- strcpy (subtitle_path, path);
-
- /* reuse dot to point to the first byte of the extension of subtitle_path */
- dot = subtitle_path + (dot - path);
-
- for (i = 0; i < G_N_ELEMENTS (subtitles_extensions); i++)
- {
- GFile *candidate;
-
- memcpy (dot, subtitles_extensions[i], 4);
- candidate = g_file_new_for_path (subtitle_path);
- if (g_file_query_exists (candidate, NULL))
- {
- gchar *suburi;
-
- suburi = g_file_get_uri (candidate);
-
- CLUTTER_GST_NOTE (MEDIA, "found subtitle: %s", suburi);
-
- g_object_set (priv->pipeline, "suburi", suburi, NULL);
- g_free (suburi);
-
- g_object_unref (candidate);
- break;
- }
-
- g_object_unref (candidate);
- }
-
- g_free (path);
- g_free (subtitle_path);
-}
-
-static void
-set_subtitle_uri (ClutterGstPlayer *player,
- const gchar *uri)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- GstPlayFlags flags;
-
- if (!priv->pipeline)
- return;
-
- CLUTTER_GST_NOTE (MEDIA, "setting subtitle URI: %s", uri);
-
- g_object_get (priv->pipeline, "flags", &flags, NULL);
-
- g_object_set (priv->pipeline, "suburi", uri, NULL);
-
- g_object_set (priv->pipeline, "flags", flags, NULL);
-}
-
-static void
-player_configure_buffering_timeout (ClutterGstPlayer *player,
- guint ms)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
- if (priv->buffering_timeout_id)
- {
- g_source_remove (priv->buffering_timeout_id);
- priv->buffering_timeout_id = 0;
- }
-
- if (ms)
- {
- priv->buffering_timeout_id =
- g_timeout_add (ms, player_buffering_timeout, player);
- }
-}
-
-static void
-player_clear_download_buffering (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
- if (priv->download_buffering_element)
- {
- g_object_unref (priv->download_buffering_element);
- priv->download_buffering_element = NULL;
- }
- player_configure_buffering_timeout (player, 0);
- priv->in_download_buffering = FALSE;
- priv->virtual_stream_buffer_signalled = 0;
-}
-
-static gboolean
-is_live_pipeline (GstElement *pipeline)
-{
- GstState state, pending;
- GstStateChangeReturn state_change_res;
- gboolean is_live = FALSE;
-
- /* get pipeline current state, we need to change the pipeline state to PAUSED to
- * see if we are dealing with a live source and we want to restore the pipeline
- * state afterwards */
- gst_element_get_state (pipeline, &state, &pending, 0);
-
- /* a pipeline with live source should return NO_PREROLL in PAUSE */
- state_change_res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
- is_live = (state_change_res == GST_STATE_CHANGE_NO_PREROLL);
-
- /* restore pipeline previous state */
- if (pending == GST_STATE_VOID_PENDING)
- gst_element_set_state (pipeline, state);
- else
- gst_element_set_state (pipeline, pending);
-
- return is_live;
-}
-
-static void
-set_uri (ClutterGstPlayer *player,
- const gchar *uri)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- GObject *self = G_OBJECT (player);
- GstState state, pending;
-
- CLUTTER_GST_NOTE (MEDIA, "setting uri %s", uri);
-
- if (!priv->pipeline)
- return;
-
- g_free (priv->uri);
-
- priv->in_eos = FALSE;
- priv->in_error = FALSE;
-
- if (uri)
- {
- priv->uri = g_strdup (uri);
-
- /* Ensure the tick timeout is installed.
- *
- * We also have it installed in PAUSED state, because
- * seeks etc may have a delayed effect on the position.
- */
- if (priv->tick_timeout_id == 0)
- {
- priv->tick_timeout_id =
- g_timeout_add (TICK_TIMEOUT, tick_timeout, self);
- }
-
- /* try to load subtitles based on the uri of the file */
- set_subtitle_uri (player, NULL);
-
- /* reset the states of download buffering */
- player_clear_download_buffering (player);
- }
- else
- {
- priv->uri = NULL;
-
- if (priv->tick_timeout_id)
- {
- g_source_remove (priv->tick_timeout_id);
- priv->tick_timeout_id = 0;
- }
-
- if (priv->buffering_timeout_id)
- {
- g_source_remove (priv->buffering_timeout_id);
- priv->buffering_timeout_id = 0;
- }
-
- if (priv->download_buffering_element)
- {
- g_object_unref (priv->download_buffering_element);
- priv->download_buffering_element = NULL;
- }
-
- }
-
- priv->can_seek = FALSE;
- priv->duration = 0.0;
- priv->stacked_progress = 0.0;
- priv->target_progress = 0.0;
-
- CLUTTER_GST_NOTE (MEDIA, "setting URI: %s", uri);
-
- if (uri)
- {
- gst_element_get_state (priv->pipeline, &state, &pending, 0);
- if (pending)
- state = pending;
-
- gst_element_set_state (priv->pipeline, GST_STATE_NULL);
-
- g_object_set (priv->pipeline, "uri", uri, NULL);
-
- priv->is_live = is_live_pipeline (priv->pipeline);
-
- set_subtitle_uri (player, NULL);
- autoload_subtitle (player, uri);
-
- gst_element_set_state (priv->pipeline, state);
-
- priv->is_changing_uri = TRUE;
- }
- else
- {
- priv->is_idle = TRUE;
- priv->is_live = FALSE;
- set_subtitle_uri (player, NULL);
- gst_element_set_state (priv->pipeline, GST_STATE_NULL);
- g_object_notify (G_OBJECT (player), "idle");
- }
-
- /*
- * Emit notifications for all these to make sure UI is not showing
- * any properties of the old URI.
- */
- g_object_notify (self, "uri");
- g_object_notify (self, "can-seek");
- g_object_notify (self, "duration");
- g_object_notify (self, "progress");
-
- free_tags_list (&priv->audio_streams);
- CLUTTER_GST_NOTE (AUDIO_STREAM, "audio-streams changed");
- g_object_notify (self, "audio-streams");
-
- free_tags_list (&priv->subtitle_tracks);
- CLUTTER_GST_NOTE (SUBTITLES, "subtitle-tracks changed");
- g_object_notify (self, "subtitle-tracks");
-}
-
-static void
-set_in_seek (ClutterGstPlayer *player,
- gboolean seeking)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
- priv->in_seek = seeking;
- g_object_notify (G_OBJECT (player), "in-seek");
-}
-
-
-static void
-set_playing (ClutterGstPlayer *player,
- gboolean playing)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
- if (!priv->pipeline)
- return;
-
- CLUTTER_GST_NOTE (MEDIA, "set playing: %d", playing);
-
- priv->in_error = FALSE;
- priv->in_eos = FALSE;
-
- priv->target_state = playing ? GST_STATE_PLAYING : GST_STATE_PAUSED;
-
- if (priv->uri)
- {
- set_in_seek (player, FALSE);
-
- gst_element_set_state (priv->pipeline, priv->target_state);
- }
- else
- {
- if (playing)
- g_warning ("Unable to start playing: no URI is set");
- }
-
- g_object_notify (G_OBJECT (player), "playing");
- g_object_notify (G_OBJECT (player), "progress");
-}
-
-static gboolean
-get_playing (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- GstState state, pending;
- gboolean playing;
-
- if (!priv->pipeline)
- return FALSE;
-
- gst_element_get_state (priv->pipeline, &state, &pending, 0);
-
- if (pending)
- playing = (pending == GST_STATE_PLAYING);
- else
- playing = (state == GST_STATE_PLAYING);
-
- CLUTTER_GST_NOTE (MEDIA, "get playing: %d", playing);
-
- return playing;
-}
-
-static void
-set_progress (ClutterGstPlayer *player,
- gdouble progress)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- GstQuery *duration_q;
- gint64 position;
-
- if (!priv->pipeline)
- return;
-
- CLUTTER_GST_NOTE (MEDIA, "set progress: %.02f", progress);
-
- priv->in_eos = FALSE;
- priv->target_progress = progress;
-
- if (priv->in_download_buffering)
- {
- /* we clear the virtual_stream_buffer_signalled flag as it's likely we
- * need to buffer again */
- priv->virtual_stream_buffer_signalled = 0;
- }
-
- if (priv->in_seek || priv->is_idle || priv->is_changing_uri)
- {
- /* We can't seek right now, let's save the position where we
- want to seek and do that later. */
- CLUTTER_GST_NOTE (MEDIA,
- "already seeking/idleing. stacking progress point.");
- priv->stacked_progress = progress;
- return;
- }
-
- duration_q = gst_query_new_duration (GST_FORMAT_TIME);
-
- if (gst_element_query (priv->pipeline, duration_q))
- {
- gint64 duration = 0;
-
- gst_query_parse_duration (duration_q, NULL, &duration);
-
- position = progress * duration;
- }
- else
- position = 0;
-
- gst_query_unref (duration_q);
-
- gst_element_seek (priv->pipeline,
- 1.0,
- GST_FORMAT_TIME,
- GST_SEEK_FLAG_FLUSH | priv->seek_flags,
- GST_SEEK_TYPE_SET,
- position,
- GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
-
- set_in_seek (player, TRUE);
-
- priv->stacked_progress = 0.0;
-
- CLUTTER_GST_NOTE (MEDIA, "set progress (seeked): %.02f", progress);
-}
-
-static gdouble
-get_progress (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- GstQuery *position_q, *duration_q;
- gdouble progress;
-
- if (!priv->pipeline)
- return 0.0;
-
- /* when hitting an error or after an EOS, playbin has some weird values when
- * querying the duration and progress. We default to 0.0 on error and 1.0 on
- * EOS */
- if (priv->in_error)
- {
- CLUTTER_GST_NOTE (MEDIA, "get progress (error): 0.0");
- return 0.0;
- }
-
- if (priv->in_eos)
- {
- CLUTTER_GST_NOTE (MEDIA, "get progress (eos): 1.0");
- return 1.0;
- }
-
- /* When seeking, the progress returned by playbin is 0.0. We want that to be
- * the last known position instead as returning 0.0 will have some ugly
- * effects, say on a progress bar getting updated from the progress tick. */
- if (priv->in_seek || priv->is_changing_uri)
- {
- CLUTTER_GST_NOTE (MEDIA, "get progress (target): %.02f",
- priv->target_progress);
- return priv->target_progress;
- }
-
- position_q = gst_query_new_position (GST_FORMAT_TIME);
- duration_q = gst_query_new_duration (GST_FORMAT_TIME);
-
- if (gst_element_query (priv->pipeline, position_q) &&
- gst_element_query (priv->pipeline, duration_q))
- {
- gint64 position, duration;
-
- position = duration = 0;
-
- gst_query_parse_position (position_q, NULL, &position);
- gst_query_parse_duration (duration_q, NULL, &duration);
-
- progress = CLAMP ((gdouble) position / (gdouble) duration, 0.0, 1.0);
- }
- else
- progress = 0.0;
-
- gst_query_unref (position_q);
- gst_query_unref (duration_q);
-
- CLUTTER_GST_NOTE (MEDIA, "get progress (pipeline): %.02f", progress);
-
- return progress;
-}
-
-static void
-set_subtitle_font_name (ClutterGstPlayer *player,
- const gchar *font_name)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
- if (!priv->pipeline)
- return;
-
- CLUTTER_GST_NOTE (MEDIA, "setting subtitle font to %s", font_name);
-
- g_free (priv->font_name);
- priv->font_name = g_strdup (font_name);
- g_object_set (priv->pipeline, "subtitle-font-desc", font_name, NULL);
-}
-
-static void
-set_audio_volume (ClutterGstPlayer *player,
- gdouble volume)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
- if (!priv->pipeline)
- return;
-
- CLUTTER_GST_NOTE (MEDIA, "set volume: %.02f", volume);
-
- volume = CLAMP (volume, 0.0, 1.0);
- gst_stream_volume_set_volume (GST_STREAM_VOLUME (priv->pipeline),
- GST_STREAM_VOLUME_FORMAT_CUBIC,
- volume);
- g_object_notify (G_OBJECT (player), "audio-volume");
-}
-
-static gdouble
-get_audio_volume (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
- if (!priv->pipeline)
- return 0.0;
-
- CLUTTER_GST_NOTE (MEDIA, "get volume: %.02f", priv->volume);
-
- return priv->volume;
-}
-
-static gboolean
-player_buffering_timeout (gpointer data)
-{
- ClutterGstPlayer *player = (ClutterGstPlayer *) data;
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- gdouble start_d, stop_d, seconds_buffered;
- gint64 start, stop, left;
- gint buffer_percent;
- GstState current_state;
- GstElement *element;
- GstQuery *query;
- gboolean res;
-
- element = priv->download_buffering_element;
- if (element == NULL)
- element = priv->pipeline;
-
- /* queue2 only knows about _PERCENT and _BYTES */
- query = gst_query_new_buffering (GST_FORMAT_PERCENT);
- res = gst_element_query (element, query);
-
- if (res == FALSE)
- {
- priv->buffering_timeout_id = 0;
- player_clear_download_buffering (player);
- return FALSE;
- }
-
- /* signal the current range */
-
- gst_query_parse_buffering_stats (query, NULL, NULL, NULL, &left);
- gst_query_parse_buffering_range (query, NULL, &start, &stop, NULL);
-
- CLUTTER_GST_NOTE (BUFFERING,
- "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT
- ", buffering left %" G_GINT64_FORMAT, start, stop, left);
-
- start_d = (gdouble) start / GST_FORMAT_PERCENT_MAX;
- stop_d = (gdouble) stop / GST_FORMAT_PERCENT_MAX;
-
- g_signal_emit (player, signals[DOWNLOAD_BUFFERING_SIGNAL], 0, start_d, stop_d);
-
- /* handle the "virtual stream buffer" and the associated pipeline state.
- * We pause the pipeline until the content is buffered.
- */
- seconds_buffered = priv->duration * (stop_d - start_d);
- gst_query_parse_buffering_percent (query, NULL, &buffer_percent);
- priv->buffer_fill = CLAMP ((gdouble) buffer_percent / 100.0, 0.0, 1.0);
-
- if (priv->buffer_fill != 1.0 || !priv->virtual_stream_buffer_signalled)
- {
- CLUTTER_GST_NOTE (BUFFERING, "buffer holds %0.2fs of data, buffer-fill "
- "is %.02f", seconds_buffered, priv->buffer_fill);
-
- g_object_notify (G_OBJECT (player), "buffer-fill");
-
- if (priv->buffer_fill == 1.0)
- priv->virtual_stream_buffer_signalled = 1;
- }
-
- gst_element_get_state (priv->pipeline, &current_state, NULL, 0);
- if (priv->buffer_fill < 1.0)
- {
- if (current_state != GST_STATE_PAUSED)
- {
- CLUTTER_GST_NOTE (BUFFERING, "pausing the pipeline");
- gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
- }
- }
- else
- {
- if (current_state != priv->target_state)
- {
- CLUTTER_GST_NOTE (BUFFERING, "restoring the pipeline");
- gst_element_set_state (priv->pipeline, priv->target_state);
- }
- }
-
- /* the file has finished downloading */
- if (left == G_GINT64_CONSTANT (0))
- {
- priv->buffering_timeout_id = 0;
-
- player_clear_download_buffering (player);
- gst_query_unref (query);
- return FALSE;
- }
-
- gst_query_unref (query);
- return TRUE;
-}
-
-static void
-bus_message_error_cb (GstBus *bus,
- GstMessage *message,
- ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- GError *error = NULL;
-
- gst_element_set_state (priv->pipeline, GST_STATE_NULL);
-
- gst_message_parse_error (message, &error, NULL);
- g_signal_emit (player, signals[ERROR_SIGNAL], 0, error);
- g_error_free (error);
-
- priv->is_idle = TRUE;
- g_object_notify (G_OBJECT (player), "idle");
-}
-
-/*
- * This is what's intented in the EOS callback:
- * - receive EOS from playbin
- * - fire the EOS signal, the user can install a signal handler to loop the
- * video for instance.
- * - after having emitted the signal, check the state of the pipeline
- * - if the pipeline has been set back to playing or pause, don't touch the
- * idle state. This will avoid drawing a frame (or more) with the idle
- * material when looping
- */
-static void
-bus_message_eos_cb (GstBus *bus,
- GstMessage *message,
- ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- GstState state, pending;
-
- priv->in_eos = TRUE;
-
- gst_element_set_state (priv->pipeline, GST_STATE_READY);
-
- g_signal_emit (player, signals[EOS_SIGNAL], 0);
- g_object_notify (G_OBJECT (player), "progress");
-
- gst_element_get_state (priv->pipeline, &state, &pending, 0);
- if (pending)
- state = pending;
-
- if (!(state == GST_STATE_PLAYING || state == GST_STATE_PAUSED))
- {
- priv->is_idle = TRUE;
- g_object_notify (G_OBJECT (player), "idle");
- }
-}
-
-static void
-bus_message_buffering_cb (GstBus *bus,
- GstMessage *message,
- ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- GstBufferingMode mode;
- GstState current_state;
- gint buffer_percent;
-
- gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL);
-
- if (mode != GST_BUFFERING_DOWNLOAD)
- priv->in_download_buffering = FALSE;
-
- switch (mode)
- {
- case GST_BUFFERING_LIVE:
- case GST_BUFFERING_STREAM:
- gst_message_parse_buffering (message, &buffer_percent);
- priv->buffer_fill = CLAMP ((gdouble) buffer_percent / 100.0, 0.0, 1.0);
-
- CLUTTER_GST_NOTE (BUFFERING, "buffer-fill: %.02f", priv->buffer_fill);
-
- /* no state management needed for live pipelines */
- if (!priv->is_live)
- {
- /* The playbin documentation says that we need to pause the pipeline
- * when there's not enough data yet. We try to limit the calls to
- * gst_element_set_state() */
- gst_element_get_state (priv->pipeline, &current_state, NULL, 0);
-
- if (priv->buffer_fill < 1.0)
- {
- if (current_state != GST_STATE_PAUSED)
- {
- CLUTTER_GST_NOTE (BUFFERING, "pausing the pipeline");
- gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
- }
- }
- else
- {
- if (current_state != priv->target_state)
- {
- CLUTTER_GST_NOTE (BUFFERING, "restoring the pipeline");
- gst_element_set_state (priv->pipeline, priv->target_state);
- }
- }
- }
-
- g_object_notify (G_OBJECT (player), "buffer-fill");
- break;
-
- case GST_BUFFERING_DOWNLOAD:
- /* we rate limit the messages from GStreamer for a usage in a UI (we
- * don't want *that* many updates). This is done by installing an idle
- * handler querying the buffer range and sending a signal from there */
-
- if (priv->in_download_buffering)
- break;
-
- /* install the querying idle handler the first time we receive a download
- * buffering message */
- player_configure_buffering_timeout (player, BUFFERING_TIMEOUT);
-
- /* pause the stream. the idle timeout will set the target state when
- * having received enough data. We'll use buffer_fill as a "virtual
- * stream buffer" to signal the application we're buffering until we
- * can play back from the downloaded stream. */
- gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
- priv->buffer_fill = 0.0;
- g_object_notify (G_OBJECT (player), "buffer-fill");
-
- priv->download_buffering_element = g_object_ref (message->src);
- priv->in_download_buffering = TRUE;
- priv->virtual_stream_buffer_signalled = 0;
- break;
-
- case GST_BUFFERING_TIMESHIFT:
- default:
- g_warning ("Buffering mode %d not handled", mode);
- break;
- }
-}
-
-static void
-on_source_changed (GstElement *pipeline,
- GParamSpec *pspec,
- ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
- player_set_user_agent (player, priv->user_agent);
-}
-
-static void
-query_duration (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- gboolean success;
- gint64 duration;
- gdouble new_duration, difference;
-
- success = gst_element_query_duration (priv->pipeline,
- GST_FORMAT_TIME,
- &duration);
- if (G_UNLIKELY (success != TRUE))
- return;
-
- new_duration = (gdouble) duration / GST_SECOND;
-
- /* while we store the new duration if it sligthly changes, the duration
- * signal is sent only if the new duration is at least one second different
- * from the old one (as the duration signal is mainly used to update the
- * time displayed in a UI */
- difference = ABS (priv->duration - new_duration);
- if (difference > 1e-3)
- {
- CLUTTER_GST_NOTE (MEDIA, "duration: %.02f", new_duration);
- priv->duration = new_duration;
-
- if (difference > 1.0)
- g_object_notify (G_OBJECT (player), "duration");
- }
-}
-
-static void
-bus_message_duration_changed_cb (GstBus *bus,
- GstMessage *message,
- ClutterGstPlayer *player)
-{
- /* GstElements send a duration-changed message on the bus to signal
- * that the duration has changed and should be re-queried */
- query_duration (player);
-}
-
-static void
-bus_message_state_change_cb (GstBus *bus,
- GstMessage *message,
- ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- GstState old_state, new_state;
- gpointer src;
-
- src = GST_MESSAGE_SRC (message);
- if (src != priv->pipeline)
- return;
-
- gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
-
- CLUTTER_GST_NOTE (MEDIA, "state change: %s -> %s",
- gst_state_to_string (old_state),
- gst_state_to_string (new_state));
-
- if (old_state == new_state)
- return;
-
- if (old_state == GST_STATE_READY &&
- new_state == GST_STATE_PAUSED)
- {
- GstQuery *query;
-
- /* Determine whether we can seek */
- query = gst_query_new_seeking (GST_FORMAT_TIME);
-
- if (gst_element_query (priv->pipeline, query))
- {
- gboolean can_seek = FALSE;
-
- gst_query_parse_seeking (query, NULL, &can_seek,
- NULL,
- NULL);
-
- priv->can_seek = (can_seek == TRUE) ? TRUE : FALSE;
- }
- else
- {
- /* could not query for ability to seek by querying the
- * pipeline; let's crudely try by using the URI
- */
- if (priv->uri && g_str_has_prefix (priv->uri, "http://"))
- priv->can_seek = FALSE;
- else
- priv->can_seek = TRUE;
- }
-
- gst_query_unref (query);
-
- CLUTTER_GST_NOTE (MEDIA, "can-seek: %d", priv->can_seek);
-
- g_object_notify (G_OBJECT (player), "can-seek");
-
- query_duration (player);
- }
-
- /* is_idle controls the drawing with the idle material */
- if (new_state == GST_STATE_NULL)
- {
- priv->is_idle = TRUE;
- g_object_notify (G_OBJECT (player), "idle");
- }
- else if (new_state == GST_STATE_PLAYING)
- {
- priv->is_idle = FALSE;
- priv->is_changing_uri = FALSE;
- g_object_notify (G_OBJECT (player), "idle");
- }
-
- if (!priv->is_idle)
- {
- if (priv->stacked_progress)
- {
- set_progress (player, priv->stacked_progress);
- }
- }
-}
-
-static void
-bus_message_async_done_cb (GstBus *bus,
- GstMessage *message,
- ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
- if (priv->in_seek)
- {
- g_object_notify (G_OBJECT (player), "progress");
-
- set_in_seek (player, FALSE);
-
- if (priv->stacked_progress)
- {
- set_progress (player, priv->stacked_progress);
- }
- }
-}
-
-static gboolean
-on_volume_changed_main_context (gpointer data)
-{
- ClutterGstPlayer *player = CLUTTER_GST_PLAYER (data);
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- gdouble volume;
-
- volume =
- gst_stream_volume_get_volume (GST_STREAM_VOLUME (priv->pipeline),
- GST_STREAM_VOLUME_FORMAT_CUBIC);
- priv->volume = volume;
-
- g_object_notify (G_OBJECT (player), "audio-volume");
-
- g_object_unref (player);
-
- return FALSE;
-}
-
-/* playbin proxies the volume property change notification directly from
- * the element having the "volume" property. This means this callback is
- * called from the thread that runs the element, potentially different from
- * the main thread */
-static void
-on_volume_changed (GstElement *pipeline,
- GParamSpec *pspec,
- ClutterGstPlayer *player)
-{
- g_idle_add (on_volume_changed_main_context, g_object_ref (player));
-}
-
-static GList *
-get_tags (GstElement *pipeline,
- const gchar *property_name,
- const gchar *action_signal)
-{
- GList *ret = NULL;
- gint i, n;
-
- g_object_get (G_OBJECT (pipeline), property_name, &n, NULL);
- if (n == 0)
- return NULL;
-
- for (i = 0; i < n; i++)
- {
- GstTagList *tags = NULL;
-
- g_signal_emit_by_name (G_OBJECT (pipeline), action_signal, i, &tags);
-
- ret = g_list_prepend (ret, tags);
- }
-
- return g_list_reverse (ret);
-}
-
-static gboolean
-on_audio_changed_main_context (gpointer data)
-{
- ClutterGstPlayer *player = CLUTTER_GST_PLAYER (data);
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
- free_tags_list (&priv->audio_streams);
- priv->audio_streams = get_tags (priv->pipeline, "n-audio", "get-audio-tags");
-
- CLUTTER_GST_NOTE (AUDIO_STREAM, "audio-streams changed");
-
- g_object_notify (G_OBJECT (player), "audio-streams");
-
- g_object_unref (player);
-
- return FALSE;
-}
-
-/* same explanation as for notify::volume's usage of g_idle_add() */
-static void
-on_audio_changed (GstElement *pipeline,
- ClutterGstPlayer *player)
-{
- g_idle_add (on_audio_changed_main_context, g_object_ref (player));
-}
-
-static void
-on_audio_tags_changed (GstElement *pipeline,
- gint stream,
- ClutterGstPlayer *player)
-{
- gint current_stream;
-
- g_object_get (G_OBJECT (pipeline), "current-audio", &current_stream, NULL);
-
- if (current_stream != stream)
- return;
-
- g_idle_add (on_audio_changed_main_context, g_object_ref (player));
-}
-
-static gboolean
-on_current_audio_changed_main_context (gpointer data)
-{
- ClutterGstPlayer *player = CLUTTER_GST_PLAYER (data);
-
- CLUTTER_GST_NOTE (AUDIO_STREAM, "audio stream changed");
- g_object_notify (G_OBJECT (player), "audio-stream");
-
- g_object_unref (player);
-
- return FALSE;
-}
-
-static void
-on_current_audio_changed (GstElement *pipeline,
- GParamSpec *pspec,
- ClutterGstPlayer *player)
-{
- g_idle_add (on_current_audio_changed_main_context, g_object_ref (player));
-}
-
-static gboolean
-on_text_changed_main_context (gpointer data)
-{
- ClutterGstPlayer *player = CLUTTER_GST_PLAYER (data);
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
- free_tags_list (&priv->subtitle_tracks);
- priv->subtitle_tracks = get_tags (priv->pipeline, "n-text", "get-text-tags");
-
- CLUTTER_GST_NOTE (AUDIO_STREAM, "subtitle-tracks changed");
-
- g_object_notify (G_OBJECT (player), "subtitle-tracks");
-
- g_object_unref (player);
-
- return FALSE;
-}
-
-/* same explanation as for notify::volume's usage of g_idle_add() */
-static void
-on_text_changed (GstElement *pipeline,
- ClutterGstPlayer *player)
-{
- g_idle_add (on_text_changed_main_context, g_object_ref (player));
-}
-
-static void
-on_text_tags_changed (GstElement *pipeline,
- gint stream,
- ClutterGstPlayer *player)
-{
- g_idle_add (on_text_changed_main_context, g_object_ref (player));
-}
-
-static gboolean
-on_current_text_changed_main_context (gpointer data)
-{
- ClutterGstPlayer *player = CLUTTER_GST_PLAYER (data);
-
- CLUTTER_GST_NOTE (AUDIO_STREAM, "text stream changed");
- g_object_notify (G_OBJECT (player), "subtitle-track");
-
- g_object_unref (player);
-
- return FALSE;
-}
-
-static void
-on_current_text_changed (GstElement *pipeline,
- GParamSpec *pspec,
- ClutterGstPlayer *player)
-{
- g_idle_add (on_current_text_changed_main_context, g_object_ref (player));
-}
-
-/* GObject's magic/madness */
-
-static void
-clutter_gst_player_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ClutterGstPlayer *player = CLUTTER_GST_PLAYER (object);
- ClutterGstPlayerIfacePrivate *iface_priv;
-
- switch (property_id)
- {
- case PROP_URI:
- set_uri (player, g_value_get_string (value));
- break;
-
- case PROP_PLAYING:
- set_playing (player, g_value_get_boolean (value));
- break;
-
- case PROP_PROGRESS:
- set_progress (player, g_value_get_double (value));
- break;
-
- case PROP_SUBTITLE_URI:
- set_subtitle_uri (player, g_value_get_string (value));
- break;
-
- case PROP_SUBTITLE_FONT_NAME:
- set_subtitle_font_name (player, g_value_get_string (value));
- break;
-
- case PROP_AUDIO_VOLUME:
- set_audio_volume (player, g_value_get_double (value));
- break;
-
- case PROP_USER_AGENT:
- clutter_gst_player_set_user_agent (player,
- g_value_get_string (value));
- break;
-
- case PROP_SEEK_FLAGS:
- clutter_gst_player_set_seek_flags (player,
- g_value_get_flags (value));
- break;
-
- case PROP_AUDIO_STREAM:
- clutter_gst_player_set_audio_stream (player,
- g_value_get_int (value));
- break;
-
- case PROP_SUBTITLE_TRACK:
- clutter_gst_player_set_subtitle_track (player,
- g_value_get_int (value));
- break;
-
- default:
- iface_priv = PLAYER_GET_CLASS_PRIVATE (object);
- iface_priv->set_property (object, property_id, value, pspec);
- }
-}
-
-
-static void
-clutter_gst_player_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ClutterGstPlayer *player = CLUTTER_GST_PLAYER (object);
- ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
- ClutterGstPlayerIfacePrivate *iface_priv;
- gchar *str;
-
- switch (property_id)
- {
- case PROP_URI:
- g_value_set_string (value, priv->uri);
- break;
-
- case PROP_PLAYING:
- g_value_set_boolean (value, get_playing (player));
- break;
-
- case PROP_PROGRESS:
- g_value_set_double (value, get_progress (player));
- break;
-
- case PROP_SUBTITLE_URI:
- g_object_get (priv->pipeline, "suburi", &str, NULL);
- g_value_take_string (value, str);
- break;
-
- case PROP_SUBTITLE_FONT_NAME:
- g_value_set_string (value, priv->font_name);
- break;
-
- case PROP_AUDIO_VOLUME:
- g_value_set_double (value, get_audio_volume (player));
- break;
-
- case PROP_CAN_SEEK:
- g_value_set_boolean (value, priv->can_seek);
- break;
-
- case PROP_BUFFER_FILL:
- g_value_set_double (value, priv->buffer_fill);
- break;
-
- case PROP_DURATION:
- g_value_set_double (value, priv->duration);
- break;
-
- case PROP_IDLE:
- g_value_set_boolean (value, priv->is_idle);
- break;
-
- case PROP_USER_AGENT:
- {
- gchar *user_agent;
-
- user_agent = clutter_gst_player_get_user_agent (player);
- g_value_take_string (value, user_agent);
- }
- break;
-
- case PROP_SEEK_FLAGS:
- {
- ClutterGstSeekFlags seek_flags;
-
- seek_flags = clutter_gst_player_get_seek_flags (player);
- g_value_set_flags (value, seek_flags);
- }
- break;
-
- case PROP_AUDIO_STREAMS:
- g_value_set_pointer (value, priv->audio_streams);
- break;
-
- case PROP_AUDIO_STREAM:
- {
- gint index_;
-
- index_ = clutter_gst_player_get_audio_stream (player);
- g_value_set_int (value, index_);
- }
- break;
-
- case PROP_SUBTITLE_TRACKS:
- g_value_set_pointer (value, priv->subtitle_tracks);
- break;
-
- case PROP_SUBTITLE_TRACK:
- {
- gint index_;
-
- index_ = clutter_gst_player_get_subtitle_track (player);
- g_value_set_int (value, index_);
- }
- break;
-
- case PROP_IN_SEEK:
- g_value_set_boolean (value, priv->in_seek);
- break;
-
- default:
- iface_priv = PLAYER_GET_CLASS_PRIVATE (object);
- iface_priv->get_property (object, property_id, value, pspec);
- }
-}
-
-/**
- * clutter_gst_player_class_init:
- * @object_class: a #GObjectClass
- *
- * Adds the #ClutterGstPlayer properties to a class and surchages the
- * set/get_property of #GObjectClass. You should call this
- * function at the end of the class_init method of the class
- * implementing #ClutterGstPlayer.
- *
- * Since: 1.4
- */
-void
-clutter_gst_player_class_init (GObjectClass *object_class)
-{
- ClutterGstPlayerIfacePrivate *priv;
-
- priv = g_new0 (ClutterGstPlayerIfacePrivate, 1);
- g_type_set_qdata (G_OBJECT_CLASS_TYPE (object_class),
- clutter_gst_player_class_quark,
- priv);
-
- /* Save object's methods we want to override */
- priv->set_property = object_class->set_property;
- priv->get_property = object_class->get_property;
-
- /* Replace by our methods */
- object_class->set_property = clutter_gst_player_set_property;
- object_class->get_property = clutter_gst_player_get_property;
-
- /* Override ClutterGstPlayer's properties */
- g_object_class_override_property (object_class,
- PROP_URI, "uri");
- g_object_class_override_property (object_class,
- PROP_PLAYING, "playing");
- g_object_class_override_property (object_class,
- PROP_PROGRESS, "progress");
- g_object_class_override_property (object_class,
- PROP_SUBTITLE_URI, "subtitle-uri");
- g_object_class_override_property (object_class,
- PROP_SUBTITLE_FONT_NAME,
- "subtitle-font-name");
- g_object_class_override_property (object_class,
- PROP_AUDIO_VOLUME, "audio-volume");
- g_object_class_override_property (object_class,
- PROP_CAN_SEEK, "can-seek");
- g_object_class_override_property (object_class,
- PROP_DURATION, "duration");
- g_object_class_override_property (object_class,
- PROP_BUFFER_FILL, "buffer-fill");
-
- g_object_class_override_property (object_class,
- PROP_IDLE, "idle");
- g_object_class_override_property (object_class,
- PROP_USER_AGENT, "user-agent");
- g_object_class_override_property (object_class,
- PROP_SEEK_FLAGS, "seek-flags");
-
- g_object_class_override_property (object_class,
- PROP_AUDIO_STREAMS, "audio-streams");
- g_object_class_override_property (object_class,
- PROP_AUDIO_STREAM, "audio-stream");
-
- g_object_class_override_property (object_class,
- PROP_SUBTITLE_TRACKS, "subtitle-tracks");
- g_object_class_override_property (object_class,
- PROP_SUBTITLE_TRACK, "subtitle-track");
- g_object_class_override_property (object_class,
- PROP_IN_SEEK, "in-seek");
-}
-
-static GstElement *
-get_pipeline (void)
-{
- GstElement *pipeline, *audio_sink;
-
- pipeline = gst_element_factory_make ("playbin", "pipeline");
- if (!pipeline)
- {
- g_critical ("Unable to create playbin element");
- return NULL;
- }
-
- audio_sink = gst_element_factory_make ("gconfaudiosink", "audio-sink");
- if (!audio_sink)
- {
- audio_sink = gst_element_factory_make ("autoaudiosink", "audio-sink");
- if (!audio_sink)
- {
- audio_sink = gst_element_factory_make ("alsasink", "audio-sink");
- g_warning ("Could not create a GST audio_sink. "
- "Audio unavailable.");
-
- /* do we even need to bother? */
- if (!audio_sink)
- audio_sink = gst_element_factory_make ("fakesink", "audio-sink");
- }
- }
-
- g_object_set (G_OBJECT (pipeline),
- "audio-sink", audio_sink,
- "subtitle-font-desc", "Sans 16",
- NULL);
-
- return pipeline;
-}
-
-/* ClutterGstPlayerIface implementation */
-
-static GstElement *
-clutter_gst_player_get_pipeline_impl (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- return priv->pipeline;
-}
-
-static gchar *
-clutter_gst_player_get_user_agent_impl (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
- GstElement *source;
- GParamSpec *pspec;
- gchar *user_agent;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- /* If the user has set a custom user agent, we just return it even if it is
- * not used by the current source element of the pipeline */
- if (priv->user_agent)
- return g_strdup (priv->user_agent);
-
- /* If not, we try to retrieve the user agent used by the current source */
- g_object_get (priv->pipeline, "source", &source, NULL);
- if (source == NULL)
- return NULL;
-
- pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (source),
- "user-agent");
- if (pspec == NULL)
- return NULL;
-
- g_object_get (source, "user-agent", &user_agent, NULL);
-
- return user_agent;
-}
-
-static void
-clutter_gst_player_set_user_agent_impl (ClutterGstPlayer *player,
- const gchar *user_agent)
-{
- ClutterGstPlayerPrivate *priv;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- g_free (priv->user_agent);
- if (user_agent)
- priv->user_agent = g_strdup (user_agent);
- else
- priv->user_agent = NULL;
-
- player_set_user_agent (player, user_agent);
-}
-
-static ClutterGstSeekFlags
-clutter_gst_player_get_seek_flags_impl (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- if (priv->seek_flags == GST_SEEK_FLAG_ACCURATE)
- return CLUTTER_GST_SEEK_FLAG_ACCURATE;
- else
- return CLUTTER_GST_SEEK_FLAG_NONE;
-}
-
-static void
-clutter_gst_player_set_seek_flags_impl (ClutterGstPlayer *player,
- ClutterGstSeekFlags flags)
-{
- ClutterGstPlayerPrivate *priv;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- if (flags == CLUTTER_GST_SEEK_FLAG_NONE)
- priv->seek_flags = GST_SEEK_FLAG_KEY_UNIT;
- else if (flags & CLUTTER_GST_SEEK_FLAG_ACCURATE)
- priv->seek_flags = GST_SEEK_FLAG_ACCURATE;
-}
-
-static ClutterGstBufferingMode
-clutter_gst_player_get_buffering_mode_impl (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
- GstPlayFlags flags;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- g_object_get (G_OBJECT (priv->pipeline), "flags", &flags, NULL);
-
- if (flags & GST_PLAY_FLAG_DOWNLOAD)
- return CLUTTER_GST_BUFFERING_MODE_DOWNLOAD;
-
- return CLUTTER_GST_BUFFERING_MODE_STREAM;
-}
-
-static void
-clutter_gst_player_set_buffering_mode_impl (ClutterGstPlayer *player,
- ClutterGstBufferingMode mode)
-{
- ClutterGstPlayerPrivate *priv;
- GstPlayFlags flags;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- g_object_get (G_OBJECT (priv->pipeline), "flags", &flags, NULL);
-
- switch (mode)
- {
- case CLUTTER_GST_BUFFERING_MODE_STREAM:
- flags &= ~GST_PLAY_FLAG_DOWNLOAD;
- break;
-
- case CLUTTER_GST_BUFFERING_MODE_DOWNLOAD:
- flags |= GST_PLAY_FLAG_DOWNLOAD;
- break;
-
- default:
- g_warning ("Unexpected buffering mode %d", mode);
- break;
- }
-
- g_object_set (G_OBJECT (priv->pipeline), "flags", flags, NULL);
-}
-
-static gint
-clutter_gst_player_get_buffer_size_impl (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
- gint size;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- g_object_get (G_OBJECT (priv->pipeline), "buffer-size", &size, NULL);
-
- return size;
-}
-
-static void
-clutter_gst_player_set_buffer_size_impl (ClutterGstPlayer *player,
- gint size)
-{
- ClutterGstPlayerPrivate *priv;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- g_object_set (G_OBJECT (priv->pipeline), "buffer-size", size, NULL);
-}
-
-static gint64
-clutter_gst_player_get_buffer_duration_impl (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
- gint64 duration;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- g_object_get (G_OBJECT (priv->pipeline), "buffer-duration", &duration, NULL);
-
- return duration;
-}
-
-static void
-clutter_gst_player_set_buffer_duration_impl (ClutterGstPlayer *player,
- gint64 duration)
-{
- ClutterGstPlayerPrivate *priv;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- g_object_set (G_OBJECT (priv->pipeline), "buffer-duration", duration, NULL);
-}
-
-static GList *
-clutter_gst_player_get_audio_streams_impl (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- if (CLUTTER_GST_DEBUG_ENABLED (AUDIO_STREAM))
- {
- gchar *streams;
-
- streams = list_to_string (priv->audio_streams);
- CLUTTER_GST_NOTE (AUDIO_STREAM, "audio streams: %s", streams);
- g_free (streams);
- }
-
- return priv->audio_streams;
-}
-
-static gint
-clutter_gst_player_get_audio_stream_impl (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
- gint index_ = -1;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- g_object_get (G_OBJECT (priv->pipeline),
- "current-audio", &index_,
- NULL);
-
- CLUTTER_GST_NOTE (AUDIO_STREAM, "audio stream is #%d", index_);
-
- return index_;
-}
-
-static void
-clutter_gst_player_set_audio_stream_impl (ClutterGstPlayer *player,
- gint index_)
-{
- ClutterGstPlayerPrivate *priv;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- g_return_if_fail (index_ >= 0 &&
- index_ < (gint) g_list_length (priv->audio_streams));
-
- CLUTTER_GST_NOTE (AUDIO_STREAM, "set audio audio stream to #%d", index_);
-
- g_object_set (G_OBJECT (priv->pipeline),
- "current-audio", index_,
- NULL);
-}
-
-static GList *
-clutter_gst_player_get_subtitle_tracks_impl (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- if (CLUTTER_GST_DEBUG_ENABLED (SUBTITLES))
- {
- gchar *tracks;
-
- tracks = list_to_string (priv->subtitle_tracks);
- CLUTTER_GST_NOTE (SUBTITLES, "subtitle tracks: %s", tracks);
- g_free (tracks);
- }
-
- return priv->subtitle_tracks;
-}
-
-static gint
-clutter_gst_player_get_subtitle_track_impl (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
- gint index_ = -1;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- g_object_get (G_OBJECT (priv->pipeline),
- "current-text", &index_,
- NULL);
-
- CLUTTER_GST_NOTE (SUBTITLES, "text track is #%d", index_);
-
- return index_;
-}
-
-static void
-clutter_gst_player_set_subtitle_track_impl (ClutterGstPlayer *player,
- gint index_)
-{
- ClutterGstPlayerPrivate *priv;
- GstPlayFlags flags;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- g_return_if_fail (index_ >= -1 &&
- index_ < (gint) g_list_length (priv->subtitle_tracks));
-
- CLUTTER_GST_NOTE (SUBTITLES, "set subtitle track to #%d", index_);
-
- g_object_get (priv->pipeline, "flags", &flags, NULL);
- flags &= ~GST_PLAY_FLAG_TEXT;
- g_object_set (priv->pipeline, "flags", flags, NULL);
-
- if (index_ >= 0)
- {
- g_object_set (G_OBJECT (priv->pipeline),
- "current-text", index_,
- NULL);
-
- flags |= GST_PLAY_FLAG_TEXT;
- g_object_set (priv->pipeline, "flags", flags, NULL);
- }
-}
-
-static gboolean
-clutter_gst_player_get_idle_impl (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- return priv->is_idle;
-}
-
-static gboolean
-clutter_gst_player_get_in_seek_impl (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- return priv->in_seek;
-}
-
-static gboolean
-clutter_gst_player_is_live_media_impl (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
-
- priv = PLAYER_GET_PRIVATE (player);
-
- return priv->is_live;
-}
-
-/**/
-
-#if defined (CLUTTER_WINDOWING_X11) && defined (HAVE_HW_DECODER_SUPPORT)
-static GstBusSyncReply
-on_sync_message (GstBus * bus, GstMessage * message, gpointer user_data)
-{
- Display *display = user_data;
- GstVideoContext *context;
- const gchar **types;
-
- if (gst_video_context_message_parse_prepare (message, &types, &context)) {
- gint i;
-
- for (i = 0; types[i]; i++) {
-
- if (!strcmp(types[i], "x11-display")) {
- gst_video_context_set_context_pointer (context, "x11-display", display);
- }
- else if (!strcmp(types[i], "x11-display-name")) {
- gst_video_context_set_context_string (context, "x11-display-name",
- DisplayString (display));
- } else {
- continue;
- }
-
- gst_message_unref (message);
- return GST_BUS_DROP;
- }
- }
-
- return GST_BUS_PASS;
-}
-#endif
-
-/**
- * clutter_gst_player_init:
- * @player: a #ClutterGstPlayer
- *
- * Initialize a #ClutterGstPlayer instance. You should call this
- * function at the beginning of the init method of the class
- * implementing #ClutterGstPlayer.
- *
- * When you're finished with the ClutterGstPlayer mixin features (usually in
- * the dispose or finalize vfuncs), call clutter_gst_player_deinit() to
- * desallocate the resources created by clutter_gst_player_init().
- *
- * Return value: TRUE if the initialization was successfull, FALSE otherwise.
- *
- * Since: 1.4
- */
-gboolean
-clutter_gst_player_init (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
- ClutterGstPlayerIface *iface;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), FALSE);
-
- priv = PLAYER_GET_PRIVATE (player);
- if (priv)
- return TRUE;
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- iface->get_pipeline = clutter_gst_player_get_pipeline_impl;
- iface->get_user_agent = clutter_gst_player_get_user_agent_impl;
- iface->set_user_agent = clutter_gst_player_set_user_agent_impl;
- iface->get_seek_flags = clutter_gst_player_get_seek_flags_impl;
- iface->set_seek_flags = clutter_gst_player_set_seek_flags_impl;
- iface->get_buffering_mode = clutter_gst_player_get_buffering_mode_impl;
- iface->set_buffering_mode = clutter_gst_player_set_buffering_mode_impl;
- iface->get_buffer_size = clutter_gst_player_get_buffer_size_impl;
- iface->set_buffer_size = clutter_gst_player_set_buffer_size_impl;
- iface->get_buffer_duration = clutter_gst_player_get_buffer_duration_impl;
- iface->set_buffer_duration = clutter_gst_player_set_buffer_duration_impl;
- iface->get_audio_streams = clutter_gst_player_get_audio_streams_impl;
- iface->get_audio_stream = clutter_gst_player_get_audio_stream_impl;
- iface->set_audio_stream = clutter_gst_player_set_audio_stream_impl;
- iface->get_subtitle_tracks = clutter_gst_player_get_subtitle_tracks_impl;
- iface->get_subtitle_track = clutter_gst_player_get_subtitle_track_impl;
- iface->set_subtitle_track = clutter_gst_player_set_subtitle_track_impl;
- iface->get_idle = clutter_gst_player_get_idle_impl;
- iface->get_in_seek = clutter_gst_player_get_in_seek_impl;
- iface->is_live_media = clutter_gst_player_is_live_media_impl;
-
- priv = g_slice_new0 (ClutterGstPlayerPrivate);
- PLAYER_SET_PRIVATE (player, priv);
-
- priv->is_idle = TRUE;
- priv->in_seek = FALSE;
- priv->is_changing_uri = FALSE;
- priv->in_download_buffering = FALSE;
-
- priv->pipeline = get_pipeline ();
- if (!priv->pipeline)
- {
- g_critical ("Unable to create pipeline");
- return FALSE;
- }
-
- g_signal_connect (priv->pipeline, "notify::source",
- G_CALLBACK (on_source_changed), player);
-
- /* We default to not playing until someone calls set_playing(TRUE) */
- priv->target_state = GST_STATE_PAUSED;
-
- /* Default to a fast seek, ie. same effect than set_seek_flags (NONE); */
- priv->seek_flags = GST_SEEK_FLAG_KEY_UNIT;
-
- priv->bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
-
- gst_bus_add_signal_watch (priv->bus);
-
- g_signal_connect_object (priv->bus, "message::error",
- G_CALLBACK (bus_message_error_cb),
- player, 0);
- g_signal_connect_object (priv->bus, "message::eos",
- G_CALLBACK (bus_message_eos_cb),
- player, 0);
- g_signal_connect_object (priv->bus, "message::buffering",
- G_CALLBACK (bus_message_buffering_cb),
- player, 0);
- g_signal_connect_object (priv->bus, "message::duration-changed",
- G_CALLBACK (bus_message_duration_changed_cb),
- player, 0);
- g_signal_connect_object (priv->bus, "message::state-changed",
- G_CALLBACK (bus_message_state_change_cb),
- player, 0);
- g_signal_connect_object (priv->bus, "message::async-done",
- G_CALLBACK (bus_message_async_done_cb),
- player, 0);
-
- g_signal_connect (priv->pipeline, "notify::volume",
- G_CALLBACK (on_volume_changed),
- player);
-
- g_signal_connect (priv->pipeline, "audio-changed",
- G_CALLBACK (on_audio_changed),
- player);
- g_signal_connect (priv->pipeline, "audio-tags-changed",
- G_CALLBACK (on_audio_tags_changed),
- player);
- g_signal_connect (priv->pipeline, "notify::current-audio",
- G_CALLBACK (on_current_audio_changed),
- player);
-
- g_signal_connect (priv->pipeline, "text-changed",
- G_CALLBACK (on_text_changed),
- player);
- g_signal_connect (priv->pipeline, "text-tags-changed",
- G_CALLBACK (on_text_tags_changed),
- player);
- g_signal_connect (priv->pipeline, "notify::current-text",
- G_CALLBACK (on_current_text_changed),
- player);
-
-#if defined(CLUTTER_WINDOWING_X11) && defined (HAVE_HW_DECODER_SUPPORT)
- gst_bus_set_sync_handler (priv->bus, on_sync_message,
- clutter_x11_get_default_display (), NULL);
-#endif
-
- gst_object_unref (GST_OBJECT (priv->bus));
-
- return TRUE;
-}
-
-/**
- * clutter_gst_player_deinit:
- * @player: a #ClutterGstPlayer
- *
- * Frees the resources created by clutter_gst_player_init(). After
- * clutter_gst_player_deinit() has been called, no other player method can be
- * called on the instance.
- *
- * Since: 1.4
- */
-void
-clutter_gst_player_deinit (ClutterGstPlayer *player)
-{
- ClutterGstPlayerPrivate *priv;
-
- g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
- priv = PLAYER_GET_PRIVATE (player);
-
- if (priv == NULL)
- return;
-
- PLAYER_SET_PRIVATE (player, NULL);
-
- if (priv->tick_timeout_id)
- {
- g_source_remove (priv->tick_timeout_id);
- priv->tick_timeout_id = 0;
- }
-
- if (priv->buffering_timeout_id)
- {
- g_source_remove (priv->buffering_timeout_id);
- priv->buffering_timeout_id = 0;
- }
-
- if (priv->download_buffering_element)
- {
- g_object_unref (priv->download_buffering_element);
- priv->download_buffering_element = NULL;
- }
-
- gst_element_set_state (priv->pipeline, GST_STATE_NULL);
-
- if (priv->bus)
- {
- gst_bus_remove_signal_watch (priv->bus);
- priv->bus = NULL;
- }
-
- if (priv->pipeline)
- {
- gst_object_unref (GST_OBJECT (priv->pipeline));
- priv->pipeline = NULL;
- }
-
- g_free (priv->uri);
- g_free (priv->font_name);
- g_free (priv->user_agent);
- free_tags_list (&priv->audio_streams);
- free_tags_list (&priv->subtitle_tracks);
-
- g_slice_free (ClutterGstPlayerPrivate, priv);
-}
-
static void
clutter_gst_player_default_init (ClutterGstPlayerIface *iface)
{
GParamSpec *pspec;
/**
- * ClutterGstPlayer:uri:
- *
- * The location of a media file, expressed as a valid URI.
- */
- pspec = g_param_spec_string ("uri",
- "URI",
- "URI of a media file",
- NULL,
- CLUTTER_GST_PARAM_READWRITE |
- G_PARAM_DEPRECATED);
- g_object_interface_install_property (iface, pspec);
-
- /**
* ClutterGstPlayer:playing:
*
* Whether the #ClutterGstPlayer actor is playing.
@@ -2265,48 +86,6 @@ clutter_gst_player_default_init (ClutterGstPlayerIface *iface)
g_object_interface_install_property (iface, pspec);
/**
- * ClutterGstPlayer:progress:
- *
- * The current progress of the playback, as a normalized
- * value between 0.0 and 1.0.
- */
- pspec = g_param_spec_double ("progress",
- "Progress",
- "Current progress of the playback",
- 0.0, 1.0, 0.0,
- CLUTTER_GST_PARAM_READWRITE |
- G_PARAM_DEPRECATED);
- g_object_interface_install_property (iface, pspec);
-
- /**
- * ClutterGstPlayer:subtitle-uri:
- *
- * The location of a subtitle file, expressed as a valid URI.
- */
- pspec = g_param_spec_string ("subtitle-uri",
- "Subtitle URI",
- "URI of a subtitle file",
- NULL,
- CLUTTER_GST_PARAM_READWRITE |
- G_PARAM_DEPRECATED);
- g_object_interface_install_property (iface, pspec);
-
- /**
- * ClutterGstPlayer:subtitle-font-name:
- *
- * The font used to display subtitles. The font description has to
- * follow the same grammar as the one recognized by
- * pango_font_description_from_string().
- */
- pspec = g_param_spec_string ("subtitle-font-name",
- "Subtitle Font Name",
- "The font used to display subtitles",
- NULL,
- CLUTTER_GST_PARAM_READWRITE |
- G_PARAM_DEPRECATED);
- g_object_interface_install_property (iface, pspec);
-
- /**
* ClutterGstPlayer:audio-volume:
*
* The volume of the audio, as a normalized value between
@@ -2321,45 +100,6 @@ clutter_gst_player_default_init (ClutterGstPlayerIface *iface)
g_object_interface_install_property (iface, pspec);
/**
- * ClutterGstPlayer:can-seek:
- *
- * Whether the current stream is seekable.
- */
- pspec = g_param_spec_boolean ("can-seek",
- "Can Seek",
- "Whether the current stream is seekable",
- FALSE,
- CLUTTER_GST_PARAM_READABLE |
- G_PARAM_DEPRECATED);
- g_object_interface_install_property (iface, pspec);
-
- /**
- * ClutterGstPlayer:buffer-fill:
- *
- * The fill level of the buffer for the current stream,
- * as a value between 0.0 and 1.0.
- */
- pspec = g_param_spec_double ("buffer-fill",
- "Buffer Fill",
- "The fill level of the buffer",
- 0.0, 1.0, 0.0,
- CLUTTER_GST_PARAM_READABLE |
- G_PARAM_DEPRECATED);
- g_object_interface_install_property (iface, pspec);
-
- /**
- * ClutterGstPlayer:duration:
- *
- * The duration of the current stream, in seconds
- */
- pspec = g_param_spec_double ("duration",
- "Duration",
- "The duration of the stream, in seconds",
- 0, G_MAXDOUBLE, 0,
- CLUTTER_GST_PARAM_READABLE);
- g_object_interface_install_property (iface, pspec);
-
- /**
* ClutterGstPlayer:idle:
*
* Whether the #ClutterGstPlayer is in idle mode.
@@ -2373,96 +113,42 @@ clutter_gst_player_default_init (ClutterGstPlayerIface *iface)
CLUTTER_GST_PARAM_READABLE);
g_object_interface_install_property (iface, pspec);
- /**
- * ClutterGstPlayer:user-agent:
- *
- * The User Agent used by #ClutterGstPlayer with network protocols.
- *
- * Since: 1.4
- */
- pspec = g_param_spec_string ("user-agent",
- "User Agent",
- "User Agent used with network protocols",
- NULL,
- CLUTTER_GST_PARAM_READWRITE);
- g_object_interface_install_property (iface, pspec);
-
- /**
- * ClutterGstPlayer:seek-flags:
- *
- * Flags to use when seeking.
- *
- * Since: 1.4
- */
- pspec = g_param_spec_flags ("seek-flags",
- "Seek Flags",
- "Flags to use when seeking",
- CLUTTER_GST_TYPE_SEEK_FLAGS,
- CLUTTER_GST_SEEK_FLAG_NONE,
- CLUTTER_GST_PARAM_READWRITE);
- g_object_interface_install_property (iface, pspec);
-
- /**
- * ClutterGstPlayer:audio-streams:
- *
- * List of audio streams available on the current media.
- *
- * Since: 1.4
- */
- pspec = g_param_spec_pointer ("audio-streams",
- "Audio Streams",
- "List of the audio streams of the media",
- CLUTTER_GST_PARAM_READABLE);
- g_object_interface_install_property (iface, pspec);
+ /* Signals */
/**
- * ClutterGstPlayer:audio-stream:
- *
- * Index of the current audio stream.
+ * ClutterGstPlayer::new-frame:
+ * @player: the #ClutterGstPlayer instance that received the signal
*
- * Since: 1.4
+ * The ::ready signal is emitted each time the gstreamer pipeline
+ * becomes ready.
*/
- pspec = g_param_spec_int ("audio-stream",
- "Audio Stream",
- "Index of the current audio stream",
- -1, G_MAXINT, -1,
- CLUTTER_GST_PARAM_READWRITE);
- g_object_interface_install_property (iface, pspec);
-
- pspec = g_param_spec_pointer ("subtitle-tracks",
- "Subtitles Tracks",
- "List of the subtitles tracks of the media",
- CLUTTER_GST_PARAM_READABLE);
- g_object_interface_install_property (iface, pspec);
-
- pspec = g_param_spec_int ("subtitle-track",
- "Subtitles Track",
- "Index of the current subtitles track",
- -1, G_MAXINT, -1,
- CLUTTER_GST_PARAM_READWRITE);
- g_object_interface_install_property (iface, pspec);
-
-
+ signals[NEW_FRAME] =
+ g_signal_new ("new-frame",
+ CLUTTER_GST_TYPE_PLAYER,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ClutterGstPlayerIface, new_frame),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE, 1,
+ CLUTTER_GST_TYPE_FRAME);
/**
- * ClutterGstPlayer:in-seek:
- *
- * Whether or not the stream is being seeked.
+ * ClutterGstPlayer::ready:
+ * @player: the #ClutterGstPlayer instance that received the signal
*
- * Since: 1.6
+ * The ::ready signal is emitted each time the gstreamer pipeline
+ * becomes ready.
*/
- pspec = g_param_spec_boolean ("in-seek",
- "In seek mode",
- "If currently seeking",
- FALSE,
- CLUTTER_GST_PARAM_READABLE);
- g_object_interface_install_property (iface, pspec);
-
-
- /* Signals */
-
+ signals[READY_SIGNAL] =
+ g_signal_new ("ready",
+ CLUTTER_GST_TYPE_PLAYER,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ClutterGstPlayerIface, ready),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
/**
* ClutterGstPlayer::eos:
- * @media: the #ClutterGstPlayer instance that received the signal
+ * @player: the #ClutterGstPlayer instance that received the signal
*
* The ::eos signal is emitted each time the media stream ends.
*/
@@ -2476,7 +162,7 @@ clutter_gst_player_default_init (ClutterGstPlayerIface *iface)
G_TYPE_NONE, 0);
/**
* ClutterGstPlayer::error:
- * @media: the #ClutterGstPlayer instance that received the signal
+ * @player: the #ClutterGstPlayer instance that received the signal
* @error: the #GError
*
* The ::error signal is emitted each time an error occurred.
@@ -2492,811 +178,184 @@ clutter_gst_player_default_init (ClutterGstPlayerIface *iface)
G_TYPE_ERROR);
/**
- * ClutterGstPlayer::download-buffering:
+ * ClutterGstPlayer::size-change:
* @player: the #ClutterGstPlayer instance that received the signal
- * @start: start position of the buffering
- * @stop: start position of the buffering
- *
- * The ::download-buffering signal is emitted each time their an
- * update about the buffering of the current media.
+ * @width: new width of the frames
+ * @height: new height of the frames
*
- * Since: 1.4
+ * The ::size-change signal is emitted each time the gstreamer pipeline
+ * becomes ready.
*/
- signals[DOWNLOAD_BUFFERING_SIGNAL] =
- g_signal_new ("download-buffering",
+ signals[SIZE_CHANGE] =
+ g_signal_new ("size-change",
CLUTTER_GST_TYPE_PLAYER,
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterGstPlayerIface,
- download_buffering),
+ G_STRUCT_OFFSET (ClutterGstPlayerIface, size_change),
NULL, NULL,
- _clutter_gst_marshal_VOID__DOUBLE_DOUBLE,
- G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
-
- /* Setup a quark for per instance private data */
- if (!clutter_gst_player_private_quark)
- {
- clutter_gst_player_private_quark =
- g_quark_from_static_string ("clutter-gst-player-private-quark");
- clutter_gst_player_class_quark =
- g_quark_from_static_string ("clutter-gst-player-class-quark");
- }
+ _clutter_gst_marshal_VOID__INT_INT,
+ G_TYPE_NONE, 2,
+ G_TYPE_INT, G_TYPE_INT);
}
/* ClutterGstIface */
/**
- * clutter_gst_player_get_pipeline:
- * @player: a #ClutterGstPlayer
+ * clutter_gst_player_get_frame:
+ * @self: a #ClutterGstPlayer
*
- * Retrieves the #GstPipeline used by the @player, for direct use with
- * GStreamer API.
+ * Retrieves the #CoglHandle of the last frame produced by @self.
*
- * Return value: (transfer none): the #GstPipeline element used by the player
+ * Return value: (transfer none): the #CoglHandle of the last frame.
*
- * Since: 1.4
+ * Since: 3.0
*/
-GstElement *
-clutter_gst_player_get_pipeline (ClutterGstPlayer *player)
+ClutterGstFrame *
+clutter_gst_player_get_frame (ClutterGstPlayer *self)
{
ClutterGstPlayerIface *iface;
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), NULL);
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (self), COGL_INVALID_HANDLE);
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
+ iface = CLUTTER_GST_PLAYER_GET_INTERFACE (self);
- return iface->get_pipeline (player);
+ return iface->get_frame (self);
}
/**
- * clutter_gst_player_set_uri:
- * @player: a #ClutterGstPlayer
- * @uri: the URI of the media stream
+ * clutter_gst_player_get_pipeline:
+ * @self: a #ClutterGstPlayer
*
- * Sets the URI of @player to @uri.
- */
-void
-clutter_gst_player_set_uri (ClutterGstPlayer *player,
- const gchar *uri)
-{
- g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
- g_object_set (G_OBJECT (player), "uri", uri, NULL);
-}
-
-/**
- * clutter_gst_player_get_uri:
- * @player: a #ClutterGstPlayer
+ * Retrieves the #GstPipeline used by the @self, for direct use with
+ * GStreamer API.
*
- * Retrieves the URI from @player.
+ * Return value: (transfer none): the #GstPipeline element used by the player
*
- * Return value: the URI of the media stream. Use g_free()
- * to free the returned string
+ * Since: 3.0
*/
-gchar *
-clutter_gst_player_get_uri (ClutterGstPlayer *player)
+GstElement *
+clutter_gst_player_get_pipeline (ClutterGstPlayer *self)
{
- gchar *retval = NULL;
+ ClutterGstPlayerIface *iface;
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), NULL);
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (self), NULL);
- g_object_get (G_OBJECT (player), "uri", &retval, NULL);
+ iface = CLUTTER_GST_PLAYER_GET_INTERFACE (self);
- return retval;
+ return iface->get_pipeline (self);
}
/**
- * clutter_gst_player_set_filename:
- * @player: a #ClutterGstPlayer
- * @filename: A filename
+ * clutter_gst_player_get_playing:
+ * @self: A #ClutterGstPlayer object
*
- * Sets the source of @player using a file path.
+ * Retrieves the playing status of @self.
+ *
+ * Return value: %TRUE if playing, %FALSE if stopped.
+ *
+ * Since: 3.0
*/
-void
-clutter_gst_player_set_filename (ClutterGstPlayer *player,
- const gchar *filename)
+gboolean
+clutter_gst_player_get_playing (ClutterGstPlayer *self)
{
- gchar *uri;
- GError *uri_error = NULL;
-
- if (!g_path_is_absolute (filename))
- {
- gchar *abs_path;
-
- abs_path = g_build_filename (g_get_current_dir (), filename, NULL);
- uri = g_filename_to_uri (abs_path, NULL, &uri_error);
- g_free (abs_path);
- }
- else
- uri = g_filename_to_uri (filename, NULL, &uri_error);
+ ClutterGstPlayerIface *iface;
- if (uri_error)
- {
- g_signal_emit (player, signals[ERROR_SIGNAL], 0, uri_error);
- g_error_free (uri_error);
- return;
- }
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (self), TRUE);
- clutter_gst_player_set_uri (player, uri);
+ iface = CLUTTER_GST_PLAYER_GET_INTERFACE (self);
- g_free (uri);
+ return iface->get_playing (self);
}
/**
* clutter_gst_player_set_playing:
- * @player: a #ClutterGstPlayer
+ * @self: a #ClutterGstPlayer
* @playing: %TRUE to start playing
*
- * Starts or stops playing of @player.
+ * Starts or stops playing of @self.
*
* The implementation might be asynchronous, so the way to know whether
- * the actual playing state of the @player is to use the #GObject::notify
+ * the actual playing state of the @self is to use the #GObject::notify
* signal on the #ClutterGstPlayer:playing property and then retrieve the
- * current state with clutter_gst_player_is_playing(). ClutterGstVideoActor
+ * current state with clutter_gst_player_get_playing(). ClutterGstVideoActor
* in clutter-gst is an example of such an asynchronous implementation.
- */
-void
-clutter_gst_player_set_playing (ClutterGstPlayer *player,
- gboolean playing)
-{
- g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
- g_object_set (G_OBJECT (player), "playing", playing, NULL);
-}
-
-/**
- * clutter_gst_player_is_playing:
- * @player: A #ClutterGstPlayer object
- *
- * Retrieves the playing status of @player.
- *
- * Return value: %TRUE if playing, %FALSE if stopped.
- */
-gboolean
-clutter_gst_player_is_playing (ClutterGstPlayer *player)
-{
- gboolean is_playing = FALSE;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), FALSE);
-
- g_object_get (G_OBJECT (player), "playing", &is_playing, NULL);
-
- return is_playing;
-}
-
-/**
- * clutter_gst_player_get_user_agent:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the user agent used when streaming.
- *
- * Return value: the user agent used. The returned string has to be freed with
- * g_free()
- *
- * Since: 1.4
- */
-gchar *
-clutter_gst_player_get_user_agent (ClutterGstPlayer *player)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), NULL);
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- return iface->get_user_agent (player);
-}
-
-/**
- * clutter_gst_player_set_user_agent:
- * @player: a #ClutterGstPlayer
- * @user_agent: the user agent
- *
- * Sets the user agent to use when streaming.
- *
- * When streaming content, you might want to set a custom user agent, eg. to
- * promote your software, make it appear in statistics or because the server
- * requires a special user agent you want to impersonate.
- *
- * Since: 1.4
- */
-void
-clutter_gst_player_set_user_agent (ClutterGstPlayer *player,
- const gchar *user_agent)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- iface->set_user_agent (player, user_agent);
-}
-
-/**
- * clutter_gst_player_get_seek_flags:
- * @player: a #ClutterGstPlayer
*
- * Get the current value of the seek-flags property.
- *
- * Return value: a combination of #ClutterGstSeekFlags
- *
- * Since: 1.4
- */
-ClutterGstSeekFlags
-clutter_gst_player_get_seek_flags (ClutterGstPlayer *player)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player),
- CLUTTER_GST_SEEK_FLAG_NONE);
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- return iface->get_seek_flags (player);
-}
-
-/**
- * clutter_gst_player_set_seek_flags:
- * @player: a #ClutterGstPlayer
- * @flags: a combination of #ClutterGstSeekFlags
- *
- * Seeking can be done with several trade-offs. Clutter-gst defaults
- * to %CLUTTER_GST_SEEK_FLAG_NONE.
- *
- * Since: 1.4
+ * Since: 3.0
*/
void
-clutter_gst_player_set_seek_flags (ClutterGstPlayer *player,
- ClutterGstSeekFlags flags)
+clutter_gst_player_set_playing (ClutterGstPlayer *self,
+ gboolean playing)
{
ClutterGstPlayerIface *iface;
- g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
+ g_return_if_fail (CLUTTER_GST_IS_PLAYER (self));
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
+ iface = CLUTTER_GST_PLAYER_GET_INTERFACE (self);
- iface->set_seek_flags (player, flags);
+ iface->set_playing (self, playing);
}
/**
- * clutter_gst_player_get_buffering_mode:
- * @player: a #ClutterGstPlayer
+ * clutter_gst_player_get_audio_volume:
+ * @self: a #ClutterGstPlayer
*
- * Return value: a #ClutterGstBufferingMode
+ * Retrieves the playback volume of @self.
*
- * Since: 1.4
- */
-ClutterGstBufferingMode
-clutter_gst_player_get_buffering_mode (ClutterGstPlayer *player)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player),
- CLUTTER_GST_BUFFERING_MODE_STREAM);
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- return iface->get_buffering_mode (player);
-}
-
-/**
- * clutter_gst_player_set_buffering_mode:
- * @player: a #ClutterGstPlayer
- * @mode: a #ClutterGstBufferingMode
- *
- * Since: 1.4
- */
-void
-clutter_gst_player_set_buffering_mode (ClutterGstPlayer *player,
- ClutterGstBufferingMode mode)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- iface->set_buffering_mode (player, mode);
-}
-
-/**
- * clutter_gst_player_get_buffer_fill:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the amount of the stream that is buffered.
+ * Return value: The playback volume between 0.0 and 1.0
*
- * Return value: the fill level, between 0.0 and 1.0
+ * Since: 3.0
*/
gdouble
-clutter_gst_player_get_buffer_fill (ClutterGstPlayer *player)
-{
- gdouble retval = 0.0;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), 0);
-
- g_object_get (G_OBJECT (player), "buffer-fill", &retval, NULL);
-
- return retval;
-}
-
-/*
- * clutter_gst_player_get_buffer_size:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the buffer size when buffering network streams.
- *
- * Return value: The buffer size
- */
-gint
-clutter_gst_player_get_buffer_size (ClutterGstPlayer *player)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), -1);
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- return iface->get_buffer_size (player);
-}
-
-/**
- * clutter_gst_player_set_buffer_size:
- * @player: a #ClutterGstPlayer
- * @size: The new size
- *
- * Sets the buffer size to be used when buffering network streams.
- */
-void
-clutter_gst_player_set_buffer_size (ClutterGstPlayer *player,
- gint size)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- iface->set_buffer_size (player, size);
-}
-
-/**
- * clutter_gst_player_get_buffer_duration:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the buffer duration when buffering network streams.
- *
- * Return value: The buffer duration
- */
-gint64
-clutter_gst_player_get_buffer_duration (ClutterGstPlayer *player)
+clutter_gst_player_get_audio_volume (ClutterGstPlayer *self)
{
ClutterGstPlayerIface *iface;
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), -1);
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (self), TRUE);
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
+ iface = CLUTTER_GST_PLAYER_GET_INTERFACE (self);
- return iface->get_buffer_duration (player);
-}
-
-/**
- * clutter_gst_player_set_buffer_duration:
- * @player: a #ClutterGstPlayer
- * @duration: The new duration
- *
- * Sets the buffer duration to be used when buffering network streams.
- */
-void
-clutter_gst_player_set_buffer_duration (ClutterGstPlayer *player,
- gint64 duration)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- iface->set_buffer_duration (player, duration);
+ return iface->get_audio_volume (self);
}
/**
* clutter_gst_player_set_audio_volume:
- * @player: a #ClutterGstPlayer
+ * @self: a #ClutterGstPlayer
* @volume: the volume as a double between 0.0 and 1.0
*
- * Sets the playback volume of @player to @volume.
- */
-void
-clutter_gst_player_set_audio_volume (ClutterGstPlayer *player,
- gdouble volume)
-{
- g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
- g_object_set (G_OBJECT (player), "audio-volume", volume, NULL);
-}
-
-/**
- * clutter_gst_player_get_audio_volume:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the playback volume of @player.
- *
- * Return value: The playback volume between 0.0 and 1.0
- */
-gdouble
-clutter_gst_player_get_audio_volume (ClutterGstPlayer *player)
-{
- gdouble retval = 0.0;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), 0.0);
-
- g_object_get (G_OBJECT (player), "audio-volume", &retval, NULL);
-
- return retval;
-}
-
-/**
- * clutter_gst_player_get_audio_streams:
- * @player: a #ClutterGstPlayer
- *
- * Get the list of audio streams of the current media.
- *
- * Return value: (transfer none) (element-type utf8): a list of
- * strings describing the available audio streams
- *
- * Since: 1.4
- */
-GList *
-clutter_gst_player_get_audio_streams (ClutterGstPlayer *player)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), NULL);
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- return iface->get_audio_streams (player);
-}
-
-/**
- * clutter_gst_player_get_audio_stream:
- * @player: a #ClutterGstPlayer
- *
- * Get the current audio stream. The number returned in the index of the
- * audio stream playing in the list returned by
- * clutter_gst_player_get_audio_streams().
- *
- * Return value: the index of the current audio stream, -1 if the media has no
- * audio stream
- *
- * Since: 1.4
- */
-gint
-clutter_gst_player_get_audio_stream (ClutterGstPlayer *player)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), -1);
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- return iface->get_audio_stream (player);
-}
-
-/**
- * clutter_gst_player_set_audio_stream:
- * @player: a #ClutterGstPlayer
- * @index_: the index of the audio stream
- *
- * Set the audio stream to play. @index_ is the index of the stream
- * in the list returned by clutter_gst_player_get_audio_streams().
- *
- * Since: 1.4
- */
-void
-clutter_gst_player_set_audio_stream (ClutterGstPlayer *player,
- gint index_)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- iface->set_audio_stream (player, index_);
-}
-
-/**
- * clutter_gst_player_set_subtitle_uri:
- * @player: a #ClutterGstPlayer
- * @uri: the URI of a subtitle file
- *
- * Sets the location of a subtitle file to display while playing @player.
- */
-void
-clutter_gst_player_set_subtitle_uri (ClutterGstPlayer *player,
- const char *uri)
-{
- g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
- g_object_set (G_OBJECT (player), "subtitle-uri", uri, NULL);
-}
-
-/**
- * clutter_gst_player_get_subtitle_uri:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the URI of the subtitle file in use.
- *
- * Return value: the URI of the subtitle file. Use g_free()
- * to free the returned string
- */
-gchar *
-clutter_gst_player_get_subtitle_uri (ClutterGstPlayer *player)
-{
- gchar *retval = NULL;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), NULL);
-
- g_object_get (G_OBJECT (player), "subtitle-uri", &retval, NULL);
-
- return retval;
-}
-
-/**
- * clutter_gst_player_set_subtitle_font_name:
- * @player: a #ClutterGstPlayer
- * @font_name: a font name, or %NULL to set the default font name
- *
- * Sets the font used by the subtitle renderer. The @font_name string must be
- * either %NULL, which means that the default font name of the underlying
- * implementation will be used; or must follow the grammar recognized by
- * pango_font_description_from_string() like:
- *
- * |[
- * clutter_gst_player_set_subtitle_font_name (player, "Sans 24pt");
- * ]|
- */
-void
-clutter_gst_player_set_subtitle_font_name (ClutterGstPlayer *player,
- const char *font_name)
-{
- g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
- g_object_set (G_OBJECT (player), "subtitle-font-name", font_name, NULL);
-}
-
-/**
- * clutter_gst_player_get_subtitle_font_name:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the font name currently used.
- *
- * Return value: a string containing the font name. Use g_free()
- * to free the returned string
- */
-gchar *
-clutter_gst_player_get_subtitle_font_name (ClutterGstPlayer *player)
-{
- gchar *retval = NULL;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), NULL);
-
- g_object_get (G_OBJECT (player), "subtitle-font-name", &retval, NULL);
-
- return retval;
-}
-
-/**
- * clutter_gst_player_get_subtitle_tracks:
- * @player: a #ClutterGstPlayer
- *
- * Get the list of subtitles tracks of the current media.
- *
- * Return value: (transfer none) (element-type utf8): a list of
- * strings describing the available subtitles tracks
- *
- * Since: 1.4
- */
-GList *
-clutter_gst_player_get_subtitle_tracks (ClutterGstPlayer *player)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), NULL);
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- return iface->get_subtitle_tracks (player);
-}
-
-/**
- * clutter_gst_player_get_subtitle_track:
- * @player: a #ClutterGstPlayer
- *
- * Get the current subtitles track. The number returned is the index of the
- * subtiles track in the list returned by
- * clutter_gst_player_get_subtitle_tracks().
- *
- * Return value: the index of the current subtitlest track, -1 if the media has
- * no subtitles track or if the subtitles have been turned off
- *
- * Since: 1.4
- */
-gint
-clutter_gst_player_get_subtitle_track (ClutterGstPlayer *player)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), -1);
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- return iface->get_subtitle_track (player);
-}
-
-/**
- * clutter_gst_player_set_subtitle_track:
- * @player: a #ClutterGstPlayer
- * @index_: the index of the subtitles track
- *
- * Set the subtitles track to play. @index_ is the index of the stream
- * in the list returned by clutter_gst_player_get_subtitle_tracks().
- *
- * If @index_ is -1, the subtitles are turned off.
+ * Sets the playback volume of @self to @volume.
*
- * Since: 1.4
+ * Since: 3.0
*/
void
-clutter_gst_player_set_subtitle_track (ClutterGstPlayer *player,
- gint index_)
+clutter_gst_player_set_audio_volume (ClutterGstPlayer *self,
+ gdouble volume)
{
ClutterGstPlayerIface *iface;
- g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
+ g_return_if_fail (CLUTTER_GST_IS_PLAYER (self));
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
+ iface = CLUTTER_GST_PLAYER_GET_INTERFACE (self);
- iface->set_subtitle_track (player, index_);
+ iface->set_audio_volume (self, volume);
}
/**
* clutter_gst_player_get_idle:
- * @player: a #ClutterGstPlayer
+ * @self: a #ClutterGstPlayer
*
* Get the idle state of the pipeline.
*
* Return value: TRUE if the pipline is in idle mode, FALSE otherwise.
*
- * Since: 1.4
- */
-gboolean
-clutter_gst_player_get_idle (ClutterGstPlayer *player)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), TRUE);
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- return iface->get_idle (player);
-}
-
-/**
- * clutter_gst_player_get_can_seek:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves whether @player is seekable or not.
- *
- * Return value: %TRUE if @player can seek, %FALSE otherwise.
- */
-gboolean
-clutter_gst_player_get_can_seek (ClutterGstPlayer *player)
-{
- gboolean retval = FALSE;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), FALSE);
-
- g_object_get (G_OBJECT (player), "can-seek", &retval, NULL);
-
- return retval;
-}
-
-/**
- * clutter_gst_player_get_in_seek:
- * @player: a #ClutterGstPlayer
- *
- * Whether the player is seeking.
- *
- * Return value: TRUE if the player is seeking, FALSE otherwise.
- *
- * Since: 1.6
- */
-gboolean
-clutter_gst_player_get_in_seek (ClutterGstPlayer *player)
-{
- ClutterGstPlayerIface *iface;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), FALSE);
-
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
- return iface->get_in_seek (player);
-}
-
-/**
- * clutter_gst_player_set_progress:
- * @player: a #ClutterGstPlayer
- * @progress: the progress of the playback, between 0.0 and 1.0
- *
- * Sets the playback progress of @player. The @progress is
- * a normalized value between 0.0 (begin) and 1.0 (end).
- */
-void
-clutter_gst_player_set_progress (ClutterGstPlayer *player,
- gdouble progress)
-{
- g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
- g_object_set (G_OBJECT (player), "progress", progress, NULL);
-}
-
-/**
- * clutter_gst_player_get_progress:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the playback progress of @player.
- *
- * Return value: the playback progress, between 0.0 and 1.0
- */
-gdouble
-clutter_gst_player_get_progress (ClutterGstPlayer *player)
-{
- gdouble retval = 0.0;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), 0);
-
- g_object_get (G_OBJECT (player), "progress", &retval, NULL);
-
- return retval;
-}
-
-/**
- * clutter_gst_player_get_duration:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the duration of the media stream that @player represents.
- *
- * Return value: the duration of the media stream, in seconds
- */
-gdouble
-clutter_gst_player_get_duration (ClutterGstPlayer *player)
-{
- gdouble retval = 0;
-
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), 0);
-
- g_object_get (G_OBJECT (player), "duration", &retval, NULL);
-
- return retval;
-}
-
-/**
- * clutter_gst_player_is_live_media:
- * @player: a #ClutterGstPlayer
- *
- * Whether the player is using a live media.
- *
- * Return value: TRUE if the player is using a live media, FALSE otherwise.
+ * Since: 3.0
*/
gboolean
-clutter_gst_player_is_live_media (ClutterGstPlayer *player)
+clutter_gst_player_get_idle (ClutterGstPlayer *self)
{
ClutterGstPlayerIface *iface;
- g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), FALSE);
+ g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (self), TRUE);
- iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
+ iface = CLUTTER_GST_PLAYER_GET_INTERFACE (self);
- return iface->is_live_media (player);
+ return iface->get_idle (self);
}
diff --git a/clutter-gst/clutter-gst-player.h b/clutter-gst/clutter-gst-player.h
index 3626520..012d2e1 100644
--- a/clutter-gst/clutter-gst-player.h
+++ b/clutter-gst/clutter-gst-player.h
@@ -12,8 +12,7 @@
* Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk>
*
* Copyright (C) 2006 OpenedHand
- * Copyright (C) 2009-2011 Intel Corporation
- * Copyright (C) 2011 Intel Corporation
+ * Copyright (C) 2009-2013 Intel Corporation
* Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
*
* This library is free software; you can redistribute it and/or
@@ -36,8 +35,8 @@
#define __CLUTTER_GST_PLAYER_H__
#include <glib-object.h>
-
-#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+#include <gst/gst.h>
#include <clutter-gst/clutter-gst-types.h>
@@ -88,148 +87,60 @@ struct _ClutterGstPlayerIface
ClutterGstPlayerIfacePrivate *priv;
/*< public >*/
- GstElement * (* get_pipeline) (ClutterGstPlayer *player);
-
- gchar * (* get_user_agent) (ClutterGstPlayer *player);
- void (* set_user_agent) (ClutterGstPlayer *player,
- const gchar *user_agent);
-
- ClutterGstSeekFlags (* get_seek_flags) (ClutterGstPlayer *player);
- void (* set_seek_flags) (ClutterGstPlayer *player,
- ClutterGstSeekFlags flags);
-
- ClutterGstBufferingMode (* get_buffering_mode) (ClutterGstPlayer *player);
- void (* set_buffering_mode) (ClutterGstPlayer *player,
- ClutterGstBufferingMode mode);
-
- GList * (* get_audio_streams) (ClutterGstPlayer *player);
- gint (* get_audio_stream) (ClutterGstPlayer *player);
- void (* set_audio_stream) (ClutterGstPlayer *player,
- gint index_);
-
- GList * (* get_subtitle_tracks) (ClutterGstPlayer *player);
- gint (* get_subtitle_track) (ClutterGstPlayer *player);
- void (* set_subtitle_track) (ClutterGstPlayer *player,
- gint index_);
-
- gboolean (*get_idle) (ClutterGstPlayer *player);
-
- gboolean (*get_in_seek) (ClutterGstPlayer *player);
-
- gint (* get_buffer_size) (ClutterGstPlayer *player);
- void (* set_buffer_size) (ClutterGstPlayer *player,
- gint size);
-
- gint64 (* get_buffer_duration) (ClutterGstPlayer *player);
- void (* set_buffer_duration) (ClutterGstPlayer *player,
- gint64 duration);
-
- gboolean (* is_live_media) (ClutterGstPlayer *player);
-
- void (* _iface_reserved21) (void);
- void (* _iface_reserved22) (void);
- void (* _iface_reserved23) (void);
- void (* _iface_reserved24) (void);
- void (* _iface_reserved25) (void);
- void (* _iface_reserved26) (void);
- void (* _iface_reserved27) (void);
- void (* _iface_reserved28) (void);
- void (* _iface_reserved29) (void);
- void (* _iface_reserved30) (void);
- void (* _iface_reserved31) (void);
- void (* _iface_reserved32) (void);
- void (* _iface_reserved33) (void);
- void (* _iface_reserved34) (void);
- void (* _iface_reserved35) (void);
+ ClutterGstFrame * (* get_frame) (ClutterGstPlayer *self);
+ GstElement * (* get_pipeline) (ClutterGstPlayer *self);
+
+ gboolean (* get_idle) (ClutterGstPlayer *self);
+
+ gdouble (* get_audio_volume) (ClutterGstPlayer *self);
+ void (* set_audio_volume) (ClutterGstPlayer *self,
+ gdouble volume);
+
+ gboolean (* get_playing) (ClutterGstPlayer *self);
+ void (* set_playing) (ClutterGstPlayer *self,
+ gboolean playing);
+
+ void (* _iface_reserved7) (void);
+ void (* _iface_reserved8) (void);
+ void (* _iface_reserved9) (void);
+ void (* _iface_reserved10) (void);
+ void (* _iface_reserved11) (void);
+ void (* _iface_reserved12) (void);
/* signals */
- void (* download_buffering) (ClutterGstPlayer *player,
- gdouble start,
- gdouble stop);
- void (* eos) (ClutterGstPlayer *player);
- void (* error) (ClutterGstPlayer *player,
- const GError *error);
-
- void (* _clutter_reserved4) (void);
- void (* _clutter_reserved5) (void);
+ void (* new_frame) (ClutterGstPlayer *self, ClutterGstFrame *frame);
+ void (* ready) (ClutterGstPlayer *self);
+ void (* eos) (ClutterGstPlayer *self);
+ void (* error) (ClutterGstPlayer *self,
+ const GError *error);
+ void (* size_change) (ClutterGstPlayer *self,
+ gint width,
+ gint height);
+
void (* _clutter_reserved6) (void);
void (* _clutter_reserved7) (void);
void (* _clutter_reserved8) (void);
void (* _clutter_reserved9) (void);
void (* _clutter_reserved10) (void);
+ void (* _clutter_reserved11) (void);
+ void (* _clutter_reserved12) (void);
};
GType clutter_gst_player_get_type (void) G_GNUC_CONST;
-void clutter_gst_player_class_init (GObjectClass *object_class);
-
-gboolean clutter_gst_player_init (ClutterGstPlayer *player);
-void clutter_gst_player_deinit (ClutterGstPlayer *player);
-
-GstElement * clutter_gst_player_get_pipeline (ClutterGstPlayer *player);
-
-void clutter_gst_player_set_uri (ClutterGstPlayer *player,
- const gchar *uri);
-gchar * clutter_gst_player_get_uri (ClutterGstPlayer *player);
-void clutter_gst_player_set_filename (ClutterGstPlayer *player,
- const gchar *filename);
-
-void clutter_gst_player_set_playing (ClutterGstPlayer *player,
- gboolean playing);
-gboolean clutter_gst_player_is_playing (ClutterGstPlayer *player);
-
-
-gchar * clutter_gst_player_get_user_agent (ClutterGstPlayer *player);
-void clutter_gst_player_set_user_agent (ClutterGstPlayer *player,
- const gchar *user_agent);
-
-ClutterGstSeekFlags clutter_gst_player_get_seek_flags (ClutterGstPlayer *player);
-void clutter_gst_player_set_seek_flags (ClutterGstPlayer *player,
- ClutterGstSeekFlags flags);
-
-ClutterGstBufferingMode clutter_gst_player_get_buffering_mode (ClutterGstPlayer *player);
-void clutter_gst_player_set_buffering_mode (ClutterGstPlayer *player,
- ClutterGstBufferingMode mode);
-gdouble clutter_gst_player_get_buffer_fill (ClutterGstPlayer *player);
-gint clutter_gst_player_get_buffer_size (ClutterGstPlayer *player);
-void clutter_gst_player_set_buffer_size (ClutterGstPlayer *player,
- gint size);
-gint64 clutter_gst_player_get_buffer_duration (ClutterGstPlayer *player);
-void clutter_gst_player_set_buffer_duration (ClutterGstPlayer *player,
- gint64 duration);
-
-void clutter_gst_player_set_audio_volume (ClutterGstPlayer *player,
- gdouble volume);
-gdouble clutter_gst_player_get_audio_volume (ClutterGstPlayer *player);
-GList * clutter_gst_player_get_audio_streams (ClutterGstPlayer *player);
-gint clutter_gst_player_get_audio_stream (ClutterGstPlayer *player);
-void clutter_gst_player_set_audio_stream (ClutterGstPlayer *player,
- gint index_);
-
-void clutter_gst_player_set_subtitle_uri (ClutterGstPlayer *player,
- const gchar *uri);
-gchar * clutter_gst_player_get_subtitle_uri (ClutterGstPlayer *player);
-void clutter_gst_player_set_subtitle_font_name
- (ClutterGstPlayer *player,
- const char *font_name);
-gchar * clutter_gst_player_get_subtitle_font_name
- (ClutterGstPlayer *player);
-GList * clutter_gst_player_get_subtitle_tracks (ClutterGstPlayer *player);
-gint clutter_gst_player_get_subtitle_track (ClutterGstPlayer *player);
-void clutter_gst_player_set_subtitle_track (ClutterGstPlayer *player,
- gint index_);
-
-gboolean clutter_gst_player_get_idle (ClutterGstPlayer *player);
-
-gboolean clutter_gst_player_get_can_seek (ClutterGstPlayer *player);
-gboolean clutter_gst_player_get_in_seek (ClutterGstPlayer *player);
-
-void clutter_gst_player_set_progress (ClutterGstPlayer *player,
- gdouble progress);
-gdouble clutter_gst_player_get_progress (ClutterGstPlayer *player);
-gdouble clutter_gst_player_get_duration (ClutterGstPlayer *player);
-
-gboolean clutter_gst_player_is_live_media (ClutterGstPlayer *player);
+ClutterGstFrame * clutter_gst_player_get_frame (ClutterGstPlayer *self);
+
+GstElement * clutter_gst_player_get_pipeline (ClutterGstPlayer *self);
+
+gboolean clutter_gst_player_get_idle (ClutterGstPlayer *self);
+
+gboolean clutter_gst_player_get_playing (ClutterGstPlayer *self);
+void clutter_gst_player_set_playing (ClutterGstPlayer *self,
+ gboolean playing);
+
+gdouble clutter_gst_player_get_audio_volume (ClutterGstPlayer *self);
+void clutter_gst_player_set_audio_volume (ClutterGstPlayer *self,
+ gdouble volume);
G_END_DECLS
diff --git a/clutter-gst/clutter-gst-private.h b/clutter-gst/clutter-gst-private.h
index a7e08e7..18b3c66 100644
--- a/clutter-gst/clutter-gst-private.h
+++ b/clutter-gst/clutter-gst-private.h
@@ -27,6 +27,7 @@
#define __CLUTTER_GST_PRIVATE_H__
#include <glib.h>
+#include "clutter-gst.h"
G_BEGIN_DECLS
@@ -47,6 +48,12 @@ G_BEGIN_DECLS
gboolean
_internal_plugin_init (GstPlugin *plugin);
+ClutterGstFrame *clutter_gst_frame_new (CoglPipeline *pipeline);
+
+void clutter_gst_util_update_frame (ClutterGstPlayer *player,
+ ClutterGstFrame **frame,
+ CoglPipeline *pipeline);
+
G_END_DECLS
#endif /* __CLUTTER_GST_PRIVATE_H__ */
diff --git a/clutter-gst/clutter-gst-types.c b/clutter-gst/clutter-gst-types.c
new file mode 100644
index 0000000..d4f632d
--- /dev/null
+++ b/clutter-gst/clutter-gst-types.c
@@ -0,0 +1,75 @@
+/*
+ * Clutter-GStreamer.
+ *
+ * GStreamer integration library for Clutter.
+ *
+ * clutter-gst-types.c - Some basic types.
+ *
+ * Authored by Lionel Landwerlin <lionel.g.landwerlin@linux.intel.com>
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "clutter-gst-types.h"
+
+ClutterGstFrame *
+clutter_gst_frame_new (CoglPipeline *pipeline)
+{
+ ClutterGstFrame *frame = g_slice_new0 (ClutterGstFrame);
+ CoglTexture *texture;
+
+ frame->pipeline = cogl_object_ref (pipeline);
+ texture = cogl_pipeline_get_layer_texture (pipeline, 0);
+
+ frame->resolution.width = cogl_texture_get_width (texture);
+ frame->resolution.height = cogl_texture_get_width (texture);
+}
+
+static gpointer
+clutter_gst_frame_copy (gpointer data)
+{
+ if (G_LIKELY (data))
+ {
+ ClutterGstFrame *frame = g_slice_dup (ClutterGstFrame, data);
+
+ if (frame->pipeline != COGL_INVALID_HANDLE)
+ frame->pipeline = cogl_handle_ref (frame->pipeline);
+
+ return frame;
+ }
+
+ return NULL;
+}
+
+static void
+clutter_gst_frame_free (gpointer data)
+{
+ if (G_LIKELY (data))
+ {
+ ClutterGstFrame *frame = (ClutterGstFrame *) data;
+
+ if (frame->pipeline != COGL_INVALID_HANDLE)
+ cogl_handle_unref (frame->pipeline);
+ g_slice_free (ClutterGstFrame, frame);
+ }
+}
+
+G_DEFINE_BOXED_TYPE (ClutterGstFrame,
+ clutter_gst_frame,
+ clutter_gst_frame_copy,
+ clutter_gst_frame_free);
diff --git a/clutter-gst/clutter-gst-types.h b/clutter-gst/clutter-gst-types.h
index 60b8d95..ffff545 100644
--- a/clutter-gst/clutter-gst-types.h
+++ b/clutter-gst/clutter-gst-types.h
@@ -29,9 +29,14 @@
#error "Only <clutter-gst/clutter-gst.h> can be included directly."
#endif
+#include <cogl/cogl.h>
+
#ifndef __CLUTTER_GST_TYPES_H__
#define __CLUTTER_GST_TYPES_H__
+#define CLUTTER_GST_TYPE_FRAME (clutter_gst_frame_get_type ())
+
+typedef struct _ClutterGstFrame ClutterGstFrame;
typedef struct _ClutterGstVideoResolution ClutterGstVideoResolution;
/**
@@ -77,4 +82,20 @@ struct _ClutterGstVideoResolution
gint height;
};
+/**
+ * ClutterGstFrame:
+ * @resolution: a #ClutterGstVideoResolution
+ * @frame: a #CoglHandle to the pipeline to paint a frame
+ *
+ * Represents a frame outputted by the #ClutterGstVideoSink.
+ */
+struct _ClutterGstFrame
+{
+ ClutterGstVideoResolution resolution;
+ CoglPipeline *pipeline;
+};
+
+
+GType clutter_gst_frame_get_type (void) G_GNUC_CONST;
+
#endif /* __CLUTTER_GST_TYPES_H__ */
diff --git a/clutter-gst/clutter-gst-util.c b/clutter-gst/clutter-gst-util.c
index d5b5cb6..9d6f80a 100644
--- a/clutter-gst/clutter-gst-util.c
+++ b/clutter-gst/clutter-gst-util.c
@@ -148,7 +148,7 @@ clutter_gst_init (int *argc,
GST_VERSION_MINOR,
"cluttersink",
"Element to render to ClutterGst actors",
- _internal_plugin_init,
+ /* _internal_plugin_init */NULL,
VERSION,
"LGPL", /* license */
"clutter-gst", PACKAGE,
@@ -228,7 +228,7 @@ clutter_gst_init_with_args (int *argc,
GST_VERSION_MINOR,
"cluttersink",
"Element to render to ClutterGst actors",
- _internal_plugin_init,
+ /* _internal_plugin_init */NULL,
VERSION,
"LGPL", /* license */
"clutter-gst", PACKAGE,
@@ -239,3 +239,28 @@ clutter_gst_init_with_args (int *argc,
return CLUTTER_INIT_SUCCESS;
}
+
+void
+clutter_gst_util_update_frame (ClutterGstPlayer *player,
+ ClutterGstFrame **frame,
+ CoglPipeline *pipeline)
+{
+ ClutterGstFrame *old_frame = *frame;
+ ClutterGstFrame *new_frame = clutter_gst_frame_new (pipeline);
+
+ *frame = new_frame;
+
+ if (old_frame == NULL ||
+ new_frame->resolution.width != old_frame->resolution.width ||
+ new_frame->resolution.height != old_frame->resolution.height)
+ {
+ g_signal_emit_by_name (player, "size-change",
+ new_frame->resolution.width,
+ new_frame->resolution.height);
+ }
+
+ if (old_frame)
+ g_boxed_free (CLUTTER_GST_TYPE_FRAME, old_frame);
+
+ g_signal_emit_by_name (player, "new-frame", new_frame);
+}
diff --git a/clutter-gst/clutter-gst-video-actor.c b/clutter-gst/clutter-gst-video-actor.c
deleted file mode 100644
index b865dd4..0000000
--- a/clutter-gst/clutter-gst-video-actor.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Clutter-GStreamer.
- *
- * GStreamer integration library for Clutter.
- *
- * clutter-gst-video-actor.c - ClutterActor using GStreamer to display a
- * video stream.
- *
- * Authored By Matthew Allum <mallum@openedhand.com>
- * Damien Lespiau <damien.lespiau@intel.com>
- * Lionel Landwerlin <lionel.g.landwerlin@linux.intel.com>
- * Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk>
- *
- * Copyright (C) 2006 OpenedHand
- * Copyright (C) 2010, 2011 Intel Corporation
- * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:clutter-gst-actor
- * @short_description: Actor for playback of video files.
- *
- * #ClutterGstVideoActor is a #ClutterActor that plays video files.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-
-#include <glib.h>
-#include <gio/gio.h>
-#include <gst/base/gstbasesink.h>
-#include <gst/video/video.h>
-
-#include "clutter-gst-video-actor.h"
-#include "clutter-gst-debug.h"
-#include "clutter-gst-enum-types.h"
-#include "clutter-gst-marshal.h"
-#include "clutter-gst-player.h"
-#include "clutter-gst-private.h"
-
-struct _ClutterGstVideoActorPrivate
-{
-};
-
-static void clutter_gst_video_actor_player_init (ClutterGstPlayerIface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (ClutterGstVideoActor,
- clutter_gst_video_actor,
- CLUTTER_GST_TYPE_ACTOR,
- G_IMPLEMENT_INTERFACE (CLUTTER_GST_TYPE_PLAYER,
- clutter_gst_video_actor_player_init));
-
-/*
- * ClutterGstPlayer implementation
- */
-
-static void
-clutter_gst_video_actor_player_init (ClutterGstPlayerIface *iface)
-{
-}
-
-/*
- * ClutterGstActor implementation
- */
-
-static gboolean
-clutter_gst_video_actor_is_idle (ClutterGstActor *actor)
-{
- return clutter_gst_player_get_idle (CLUTTER_GST_PLAYER (actor));
-}
-
-/*
- * GObject implementation
- */
-
-static void
-clutter_gst_video_actor_dispose (GObject *object)
-{
- clutter_gst_player_deinit (CLUTTER_GST_PLAYER (object));
-
- G_OBJECT_CLASS (clutter_gst_video_actor_parent_class)->dispose (object);
-}
-
-static void
-clutter_gst_video_actor_class_init (ClutterGstVideoActorClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- ClutterGstActorClass *gst_actor_class = CLUTTER_GST_ACTOR_CLASS (klass);
-
- //g_type_class_add_private (klass, sizeof (ClutterGstVideoActorPrivate));
-
- object_class->dispose = clutter_gst_video_actor_dispose;
-
- gst_actor_class->is_idle = clutter_gst_video_actor_is_idle;
-
- clutter_gst_player_class_init (object_class);
-}
-
-static gboolean
-setup_pipeline (ClutterGstVideoActor *video_actor)
-{
- GstElement *pipeline, *video_sink;
-
- pipeline =
- clutter_gst_player_get_pipeline (CLUTTER_GST_PLAYER (video_actor));
- if (!pipeline)
- {
- g_critical ("Unable to create pipeline");
- return FALSE;
- }
-
- video_sink = gst_element_factory_make ("cluttersink", NULL);
- g_object_set (video_sink,
- "actor", CLUTTER_GST_ACTOR (video_actor),
- NULL);
- g_object_set (pipeline,
- "video-sink", video_sink,
- "subtitle-font-desc", "Sans 16",
- NULL);
-
- return TRUE;
-}
-
-static void
-clutter_gst_video_actor_init (ClutterGstVideoActor *video_actor)
-{
- //video_actor->priv =
- // G_TYPE_INSTANCE_GET_PRIVATE (video_actor,
- // CLUTTER_GST_TYPE_VIDEO_ACTOR,
- // ClutterGstVideoActorPrivate);
-
- if (!clutter_gst_player_init (CLUTTER_GST_PLAYER (video_actor)))
- {
- g_warning ("Failed to initiate suitable playback pipeline.");
- return;
- }
-
- if (!setup_pipeline (video_actor))
- {
- g_warning ("Failed to initiate suitable sinks for pipeline.");
- return;
- }
-}
-
-/*
- * Public symbols
- */
-
-/**
- * clutter_gst_video_actor_new:
- *
- * Creates a video actor.
- *
- * <note>This function has to be called from Clutter's main thread. While
- * GStreamer will spawn threads to do its work, we want all the GL calls to
- * happen in the same thread. Clutter-gst knows which thread it is by
- * assuming this constructor is called from the Clutter thread.</note>
- *
- * Return value: the newly created video actor
- */
-ClutterActor*
-clutter_gst_video_actor_new (void)
-{
- return g_object_new (CLUTTER_GST_TYPE_VIDEO_ACTOR,
- NULL);
-}
diff --git a/clutter-gst/clutter-gst-video-actor.h b/clutter-gst/clutter-gst-video-actor.h
deleted file mode 100644
index 6f8bd1b..0000000
--- a/clutter-gst/clutter-gst-video-actor.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Clutter-GStreamer.
- *
- * GStreamer integration library for Clutter.
- *
- * clutter-gst-video-actor.h - ClutterActor using GStreamer to display a
- * video stream.
- *
- * Authored By Matthew Allum <mallum@openedhand.com>
- * Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk>
- *
- * Copyright (C) 2006 OpenedHand
- * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#if !defined(__CLUTTER_GST_H_INSIDE__) && !defined(CLUTTER_GST_COMPILATION)
-#error "Only <clutter-gst/clutter-gst.h> can be included directly."
-#endif
-
-#ifndef __CLUTTER_GST_VIDEO_ACTOR_H__
-#define __CLUTTER_GST_VIDEO_ACTOR_H__
-
-#include <glib-object.h>
-#include <clutter/clutter.h>
-#include <gst/gstelement.h>
-
-#include <clutter-gst/clutter-gst-actor.h>
-#include <clutter-gst/clutter-gst-types.h>
-
-G_BEGIN_DECLS
-
-#define CLUTTER_GST_TYPE_VIDEO_ACTOR clutter_gst_video_actor_get_type()
-
-#define CLUTTER_GST_VIDEO_ACTOR(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
- CLUTTER_GST_TYPE_VIDEO_ACTOR, ClutterGstVideoActor))
-
-#define CLUTTER_GST_VIDEO_ACTOR_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST ((klass), \
- CLUTTER_GST_TYPE_VIDEO_ACTOR, ClutterGstVideoActorClass))
-
-#define CLUTTER_GST_IS_VIDEO_ACTOR(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
- CLUTTER_GST_TYPE_VIDEO_ACTOR))
-
-#define CLUTTER_GST_IS_VIDEO_ACTOR_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((klass), \
- CLUTTER_GST_TYPE_VIDEO_ACTOR))
-
-#define CLUTTER_GST_VIDEO_ACTOR_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), \
- CLUTTER_GST_TYPE_VIDEO_ACTOR, ClutterGstVideoActorClass))
-
-typedef struct _ClutterGstVideoActor ClutterGstVideoActor;
-typedef struct _ClutterGstVideoActorClass ClutterGstVideoActorClass;
-typedef struct _ClutterGstVideoActorPrivate ClutterGstVideoActorPrivate;
-
-/**
- * ClutterGstVideoActor:
- *
- * Subclass of #ClutterGstActor that displays videos using GStreamer.
- *
- * The #ClutterGstVideoActor structure contains only private data and
- * should not be accessed directly.
- */
-struct _ClutterGstVideoActor
-{
- /*< private >*/
- ClutterGstActor parent;
- ClutterGstVideoActorPrivate *priv;
-};
-
-/**
- * ClutterGstVideoActorClass:
- *
- * Base class for #ClutterGstVideoActor.
- */
-struct _ClutterGstVideoActorClass
-{
- /*< private >*/
- ClutterGstActorClass parent_class;
-
- /* Future padding */
- void (* _clutter_reserved1) (void);
- void (* _clutter_reserved2) (void);
- void (* _clutter_reserved3) (void);
- void (* _clutter_reserved4) (void);
- void (* _clutter_reserved5) (void);
- void (* _clutter_reserved6) (void);
-};
-
-GType clutter_gst_video_actor_get_type (void) G_GNUC_CONST;
-
-ClutterActor * clutter_gst_video_actor_new (void);
-
-G_END_DECLS
-
-#endif /* __CLUTTER_GST_VIDEO_ACTOR_H__ */
diff --git a/clutter-gst/clutter-gst-video-sink.c b/clutter-gst/clutter-gst-video-sink.c
index 742b3a7..2104f70 100644
--- a/clutter-gst/clutter-gst-video-sink.c
+++ b/clutter-gst/clutter-gst-video-sink.c
@@ -131,10 +131,17 @@ GST_DEBUG_CATEGORY_STATIC (clutter_gst_video_sink_debug);
enum
{
PROP_0,
- PROP_ACTOR,
+ PROP_COGL_PIPELINE,
PROP_UPDATE_PRIORITY
};
+enum
+{
+ SEND_EVENT,
+
+ LAST_SIGNAL
+};
+
typedef enum
{
CLUTTER_GST_NOFORMAT,
@@ -194,8 +201,10 @@ typedef struct _ClutterGstRenderer
struct _ClutterGstVideoSinkPrivate
{
- ClutterActor *actor;
+ ClutterStage *default_stage;
+
CoglMaterial *material_template;
+ CoglMaterial *cogl_pipeline;
GstFlowReturn flow_ret;
@@ -227,8 +236,7 @@ G_DEFINE_TYPE_WITH_CODE (ClutterGstVideoSink, clutter_gst_video_sink,
GST_TYPE_BASE_SINK, G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
clutter_gst_navigation_interface_init));
-static void clutter_gst_video_sink_set_actor (ClutterGstVideoSink * sink,
- ClutterActor * actor);
+static guint sink_signals[LAST_SIGNAL] = { 0, };
/*
* ClutterGstSource implementation
@@ -297,18 +305,19 @@ ensure_texture_pixel_aspect_ratio (ClutterGstVideoSink * sink)
GParamSpec *pspec;
GValue par = { 0, };
- if (priv->actor == NULL)
- return;
+ /* if (priv->actor == NULL) */
+ /* return; */
- pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (priv->actor),
- "pixel-aspect-ratio");
- if (pspec) {
+ /* pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (priv->actor), */
+ /* "pixel-aspect-ratio"); */
+ /* if (pspec) { */
g_value_init (&par, GST_TYPE_FRACTION);
gst_value_set_fraction (&par, priv->info.par_n, priv->info.par_d);
- g_object_set_property (G_OBJECT (priv->actor),
- "pixel-aspect-ratio", &par);
+ /* TODO: propagate the value through property/signal */
+ /* g_object_set_property (G_OBJECT (priv->actor), */
+ /* "pixel-aspect-ratio", &par); */
g_value_unset (&par);
- }
+ /* } */
}
static gboolean
@@ -417,47 +426,47 @@ no_suitable_renderer:
}
}
-static gboolean
-on_stage_destroyed (ClutterStage * stage,
- ClutterEvent * event, gpointer user_data)
-{
- ClutterGstSource *gst_source = user_data;
- ClutterGstVideoSinkPrivate *priv = gst_source->sink->priv;
+/* static gboolean */
+/* on_stage_destroyed (ClutterStage * stage, */
+/* ClutterEvent * event, gpointer user_data) */
+/* { */
+/* ClutterGstSource *gst_source = user_data; */
+/* ClutterGstVideoSinkPrivate *priv = gst_source->sink->priv; */
- g_mutex_lock (&gst_source->buffer_lock);
+/* g_mutex_lock (&gst_source->buffer_lock); */
- clutter_actor_hide (CLUTTER_ACTOR (stage));
- clutter_actor_remove_child (CLUTTER_ACTOR (stage), priv->actor);
+/* clutter_actor_hide (CLUTTER_ACTOR (stage)); */
+/* clutter_actor_remove_child (CLUTTER_ACTOR (stage), priv->actor); */
- if (gst_source->buffer)
- gst_buffer_unref (gst_source->buffer);
+/* if (gst_source->buffer) */
+/* gst_buffer_unref (gst_source->buffer); */
- gst_source->stage_lost = TRUE;
- gst_source->buffer = NULL;
- priv->actor = NULL;
+/* gst_source->stage_lost = TRUE; */
+/* gst_source->buffer = NULL; */
+/* priv->actor = NULL; */
- g_mutex_unlock (&gst_source->buffer_lock);
+/* g_mutex_unlock (&gst_source->buffer_lock); */
- return TRUE;
-}
+/* return TRUE; */
+/* } */
-static void
-on_stage_allocation_changed (ClutterStage * stage,
- ClutterActorBox * box, ClutterAllocationFlags flags, gpointer user_data)
-{
- ClutterGstSource *gst_source = user_data;
- ClutterGstVideoSinkPrivate *priv = gst_source->sink->priv;
- gint width, height;
+/* static void */
+/* on_stage_allocation_changed (ClutterStage * stage, */
+/* ClutterActorBox * box, ClutterAllocationFlags flags, gpointer user_data) */
+/* { */
+/* ClutterGstSource *gst_source = user_data; */
+/* ClutterGstVideoSinkPrivate *priv = gst_source->sink->priv; */
+/* gint width, height; */
- if (gst_source->stage_lost)
- return;
+/* if (gst_source->stage_lost) */
+/* return; */
- width = (gint) (box->x2 - box->x1);
- height = (gint) (box->y2 - box->y1);
+/* width = (gint) (box->x2 - box->x1); */
+/* height = (gint) (box->y2 - box->y1); */
- GST_DEBUG ("Size changed to %i/%i", width, height);
- clutter_actor_set_size (priv->actor, width, height);
-}
+/* GST_DEBUG ("Size changed to %i/%i", width, height); */
+/* clutter_actor_set_size (priv->actor, width, height); */
+/* } */
static gboolean
clutter_gst_source_dispatch (GSource * source,
@@ -486,35 +495,35 @@ clutter_gst_source_dispatch (GSource * source,
goto negotiation_fail;
gst_source->has_new_caps = FALSE;
- if (!priv->actor) {
- ClutterActor *stage;
- ClutterActor *actor;
+ /* if (!priv->actor) { */
+ /* ClutterActor *stage; */
+ /* ClutterActor *actor; */
- GST_DEBUG_OBJECT (gst_source->sink,
- "No existing texture, creating stage and actor");
- stage = clutter_stage_new ();
- actor = g_object_new (CLUTTER_GST_TYPE_ACTOR, NULL);
+ /* GST_DEBUG_OBJECT (gst_source->sink, */
+ /* "No existing texture, creating stage and actor"); */
+ /* stage = clutter_stage_new (); */
+ /* actor = g_object_new (CLUTTER_GST_TYPE_ACTOR, NULL); */
- clutter_gst_video_sink_set_actor (gst_source->sink, actor);
- clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
- clutter_actor_add_child (stage, actor);
- clutter_stage_set_no_clear_hint (CLUTTER_STAGE (stage), TRUE);
+ /* clutter_gst_video_sink_set_actor (gst_source->sink, actor); */
+ /* clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); */
+ /* clutter_actor_add_child (stage, actor); */
+ /* clutter_stage_set_no_clear_hint (CLUTTER_STAGE (stage), TRUE); */
- g_signal_connect (stage, "delete-event",
- G_CALLBACK (on_stage_destroyed), gst_source);
- g_signal_connect (stage, "allocation-changed",
- G_CALLBACK (on_stage_allocation_changed), gst_source);
+ /* g_signal_connect (stage, "delete-event", */
+ /* G_CALLBACK (on_stage_destroyed), gst_source); */
+ /* g_signal_connect (stage, "allocation-changed", */
+ /* G_CALLBACK (on_stage_allocation_changed), gst_source); */
/* FIXME : We already call this above ? */
if (!clutter_gst_parse_caps (caps, gst_source->sink, TRUE))
goto negotiation_fail;
- clutter_actor_set_size (stage, priv->info.width, priv->info.height);
- clutter_actor_show (stage);
- } else {
+ /* clutter_actor_set_size (stage, priv->info.width, priv->info.height); */
+ /* clutter_actor_show (stage); */
+ /* } else { */
/* FIXME : We already call this above ? */
- if (!clutter_gst_parse_caps (caps, gst_source->sink, TRUE))
- goto negotiation_fail;
- }
+ /* if (!clutter_gst_parse_caps (caps, gst_source->sink, TRUE)) */
+ /* goto negotiation_fail; */
+ /* } */
if (priv->material_template)
cogl_object_unref (priv->material_template);
@@ -736,8 +745,13 @@ _create_paint_material (ClutterGstVideoSink * sink,
cogl_handle_unref (tex2);
}
- clutter_gst_actor_set_cogl_material (CLUTTER_GST_ACTOR (priv->actor), material);
- cogl_object_unref (material);
+ cogl_handle_unref (priv->cogl_pipeline);
+ priv->cogl_pipeline = material;
+
+ g_object_notify (sink, "cogl-pipeline");
+
+ /* clutter_gst_actor_set_cogl_material (CLUTTER_GST_ACTOR (priv->actor), material); */
+ /* cogl_object_unref (material); */
}
static void
@@ -1088,78 +1102,78 @@ static ClutterGstRenderer ayuv_glsl_renderer = {
* HW Surfaces
*/
-#ifdef HAVE_HW_DECODER_SUPPORT
-static CoglMaterial *
-clutter_gst_hw_init (ClutterGstVideoSink * sink)
-{
- ClutterGstVideoSinkPrivate *priv = sink->priv;
- CoglHandle tex;
- CoglHandle material;
-
- /* Default texture is 1x1, let's replace it with one big enough. */
- tex = cogl_texture_new_with_size (priv->info.width, priv->info.height,
- CLUTTER_GST_TEXTURE_FLAGS, COGL_PIXEL_FORMAT_BGRA_8888);
-
- material = cogl_material_new ();
- cogl_material_set_layer (material, 0, tex);
- clutter_gst_actor_set_cogl_material (CLUTTER_GST_ACTOR (priv->actor), material);
-
- cogl_object_unref (tex);
-
- return material;
-}
-
-static void
-clutter_gst_hw_deinit (ClutterGstVideoSink * sink)
-{
- ClutterGstVideoSinkPrivate *priv = sink->priv;
-
- if (priv->converter != NULL)
- g_object_unref (priv->converter);
- priv->converter = NULL;
-}
-
-static void
-clutter_gst_hw_upload (ClutterGstVideoSink * sink, GstBuffer * buffer)
-{
- ClutterGstVideoSinkPrivate *priv = sink->priv;
- GstSurfaceMeta *surface = gst_buffer_get_surface_meta (buffer);
-
- g_return_if_fail (surface != NULL);
-
- if (G_UNLIKELY (priv->converter == NULL)) {
- CoglHandle tex;
- unsigned int gl_texture;
- unsigned int gl_target;
- GValue value = { 0 };
-
- tex = clutter_gst_actor_get_cogl_texture (CLUTTER_GST_ACTOR (priv->actor));
- cogl_texture_get_gl_texture (tex, &gl_texture, &gl_target);
-
- g_value_init (&value, G_TYPE_UINT);
- g_value_set_uint (&value, gl_texture);
-
- priv->converter =
- gst_surface_meta_create_converter (surface, "opengl", &value);
- g_return_if_fail (priv->converter);
- }
-
- gst_surface_converter_upload (priv->converter, buffer);
-
- /* The actor is dirty, schedule a redraw */
- clutter_actor_queue_redraw (priv->actor);
-}
-
-static ClutterGstRenderer hw_renderer = {
- "HW surface",
- CLUTTER_GST_SURFACE,
- 0,
- GST_STATIC_CAPS ("x-video/surface, opengl=true"),
- clutter_gst_hw_init,
- clutter_gst_hw_deinit,
- clutter_gst_hw_upload,
-};
-#endif
+/* #ifdef HAVE_HW_DECODER_SUPPORT */
+/* static CoglMaterial * */
+/* clutter_gst_hw_init (ClutterGstVideoSink * sink) */
+/* { */
+/* ClutterGstVideoSinkPrivate *priv = sink->priv; */
+/* CoglHandle tex; */
+/* CoglHandle material; */
+
+/* /\* Default texture is 1x1, let's replace it with one big enough. *\/ */
+/* tex = cogl_texture_new_with_size (priv->info.width, priv->info.height, */
+/* CLUTTER_GST_TEXTURE_FLAGS, COGL_PIXEL_FORMAT_BGRA_8888); */
+
+/* material = cogl_material_new (); */
+/* cogl_material_set_layer (material, 0, tex); */
+/* clutter_gst_actor_set_cogl_material (CLUTTER_GST_ACTOR (priv->actor), material); */
+
+/* cogl_object_unref (tex); */
+
+/* return material; */
+/* } */
+
+/* static void */
+/* clutter_gst_hw_deinit (ClutterGstVideoSink * sink) */
+/* { */
+/* ClutterGstVideoSinkPrivate *priv = sink->priv; */
+
+/* if (priv->converter != NULL) */
+/* g_object_unref (priv->converter); */
+/* priv->converter = NULL; */
+/* } */
+
+/* static void */
+/* clutter_gst_hw_upload (ClutterGstVideoSink * sink, GstBuffer * buffer) */
+/* { */
+/* ClutterGstVideoSinkPrivate *priv = sink->priv; */
+/* GstSurfaceMeta *surface = gst_buffer_get_surface_meta (buffer); */
+
+/* g_return_if_fail (surface != NULL); */
+
+/* if (G_UNLIKELY (priv->converter == NULL)) { */
+/* CoglHandle tex; */
+/* unsigned int gl_texture; */
+/* unsigned int gl_target; */
+/* GValue value = { 0 }; */
+
+/* tex = clutter_gst_actor_get_cogl_texture (CLUTTER_GST_ACTOR (priv->actor)); */
+/* cogl_texture_get_gl_texture (tex, &gl_texture, &gl_target); */
+
+/* g_value_init (&value, G_TYPE_UINT); */
+/* g_value_set_uint (&value, gl_texture); */
+
+/* priv->converter = */
+/* gst_surface_meta_create_converter (surface, "opengl", &value); */
+/* g_return_if_fail (priv->converter); */
+/* } */
+
+/* gst_surface_converter_upload (priv->converter, buffer); */
+
+/* /\* The actor is dirty, schedule a redraw *\/ */
+/* clutter_actor_queue_redraw (priv->actor); */
+/* } */
+
+/* static ClutterGstRenderer hw_renderer = { */
+/* "HW surface", */
+/* CLUTTER_GST_SURFACE, */
+/* 0, */
+/* GST_STATIC_CAPS ("x-video/surface, opengl=true"), */
+/* clutter_gst_hw_init, */
+/* clutter_gst_hw_deinit, */
+/* clutter_gst_hw_upload, */
+/* }; */
+/* #endif */
static GSList *
clutter_gst_build_renderers_list (void)
@@ -1295,9 +1309,20 @@ navigation_event (ClutterActor * actor,
}
static void
+_default_stage_changed (ClutterStageManager *manager,
+ GParamSpec *param,
+ ClutterGstVideoSink *self)
+{
+ ClutterGstVideoSinkPrivate *priv = self->priv;
+
+ priv->default_stage = clutter_stage_manager_get_default_stage (manager);
+}
+
+static void
clutter_gst_video_sink_init (ClutterGstVideoSink * sink)
{
ClutterGstVideoSinkPrivate *priv;
+ ClutterStageManager *manager;
sink->priv = priv =
G_TYPE_INSTANCE_GET_PRIVATE (sink, CLUTTER_GST_TYPE_VIDEO_SINK,
@@ -1312,6 +1337,11 @@ clutter_gst_video_sink_init (ClutterGstVideoSink * sink)
priv->signal_handler_ids = g_array_new (FALSE, TRUE, sizeof (gulong));
priv->priority = CLUTTER_GST_DEFAULT_PRIORITY;
+
+ manager = clutter_stage_manager_get_default ();
+ priv->default_stage = clutter_stage_manager_get_default_stage (manager);
+ g_signal_connect (manager, "notify::default-stage",
+ G_CALLBACK (_default_stage_changed), sink);
}
static GstFlowReturn
@@ -1390,7 +1420,6 @@ clutter_gst_video_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
return TRUE;
}
-
static void
clutter_gst_video_sink_dispose (GObject * object)
{
@@ -1405,8 +1434,9 @@ clutter_gst_video_sink_dispose (GObject * object)
priv->renderer = NULL;
}
- if (priv->actor)
- clutter_gst_video_sink_set_actor (self, NULL);
+ g_object_notify (self, "cogl-pipeline");
+ /* if (priv->actor) */
+ /* clutter_gst_video_sink_set_actor (self, NULL); */
if (priv->caps) {
gst_caps_unref (priv->caps);
@@ -1433,52 +1463,12 @@ clutter_gst_video_sink_finalize (GObject * object)
}
static void
-clutter_gst_video_sink_set_actor (ClutterGstVideoSink * sink,
- ClutterActor * actor)
-{
- const char const *events[] = {
- "key-press-event",
- "key-release-event",
- "button-press-event",
- "button-release-event",
- "motion-event"
- };
- ClutterGstVideoSinkPrivate *priv = sink->priv;
- guint i;
-
- if (priv->actor) {
- for (i = 0; i < priv->signal_handler_ids->len; i++) {
- gulong id = g_array_index (priv->signal_handler_ids, gulong, i);
- g_signal_handler_disconnect (priv->actor, id);
- }
- g_array_set_size (priv->signal_handler_ids, 0);
- }
-
- priv->actor = actor;
- if (priv->actor == NULL)
- return;
-
- clutter_actor_set_reactive (priv->actor, TRUE);
- g_object_add_weak_pointer (G_OBJECT (priv->actor), (gpointer *) &(priv->actor));
-
- for (i = 0; i < G_N_ELEMENTS (events); i++) {
- gulong id;
- id = g_signal_connect (priv->actor, events[i],
- G_CALLBACK (navigation_event), sink);
- g_array_append_val (priv->signal_handler_ids, id);
- }
-}
-
-static void
clutter_gst_video_sink_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
ClutterGstVideoSink *sink = CLUTTER_GST_VIDEO_SINK (object);
switch (prop_id) {
- case PROP_ACTOR:
- clutter_gst_video_sink_set_actor (sink, g_value_get_object (value));
- break;
case PROP_UPDATE_PRIORITY:
clutter_gst_video_sink_set_priority (sink, g_value_get_int (value));
break;
@@ -1496,8 +1486,8 @@ clutter_gst_video_sink_get_property (GObject * object,
ClutterGstVideoSinkPrivate *priv = sink->priv;
switch (prop_id) {
- case PROP_ACTOR:
- g_value_set_object (value, priv->actor);
+ case PROP_COGL_PIPELINE:
+ g_value_set_object (value, priv->cogl_pipeline);
break;
case PROP_UPDATE_PRIORITY:
g_value_set_int (value, priv->priority);
@@ -1542,6 +1532,22 @@ clutter_gst_video_sink_stop (GstBaseSink * base_sink)
return TRUE;
}
+static gboolean
+_clutter_gst_point_handled_accumulator (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ const GValue *handler_return,
+ gpointer dummy)
+{
+ gboolean continue_emission;
+ gpointer translated_point;
+
+ translated_point = g_value_get_boxed (handler_return);
+ g_value_set_boxed (return_accu, translated_point);
+ continue_emission = (translated_point == NULL);
+
+ return continue_emission;
+}
+
static void
clutter_gst_video_sink_class_init (ClutterGstVideoSinkClass * klass)
{
@@ -1579,35 +1585,61 @@ clutter_gst_video_sink_class_init (ClutterGstVideoSinkClass * klass)
gstbase_sink_class->get_caps = clutter_gst_video_sink_get_caps;
/**
- * ClutterGstVideoSink:actor:
- *
- * This is the actor the video is decoded into. It can be any
- * #ClutterGstActor, however Cluter-Gst has a handy subclass,
- * #ClutterGstVideoActor, that implements the #ClutterGstPlayer
- * interface.
- */
- pspec = g_param_spec_object ("actor",
- "Actor",
- "ClutterGstActor the video will be decoded into",
- CLUTTER_GST_TYPE_ACTOR,
- CLUTTER_GST_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_ACTOR, pspec);
-
- /**
* ClutterGstVideoSink:update-priority:
*
* Clutter-Gst installs a #GSource to signal that a new frame is ready to
* the Clutter thread. This property allows to tweak the priority of the
* source (Lower value is higher priority).
*
- * Since 1.0
+ * Since 3.0
*/
pspec = g_param_spec_int ("update-priority",
- "Update Priority",
- "Priority of video updates in the Clutter thread",
- -G_MAXINT, G_MAXINT,
- CLUTTER_GST_DEFAULT_PRIORITY, CLUTTER_GST_PARAM_READWRITE);
+ "Update Priority",
+ "Priority of video updates in the Clutter thread",
+ -G_MAXINT, G_MAXINT,
+ CLUTTER_GST_DEFAULT_PRIORITY,
+ CLUTTER_GST_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_UPDATE_PRIORITY, pspec);
+
+ /**
+ * ClutterGstVideoSink:cogl-pipeline:
+ *
+ * Cogl pipeline to be used to paint a video frame
+ *
+ * Since 3.0
+ */
+ pspec = g_param_spec_boxed ("frame",
+ "Update Priority",
+ "Priority of video updates in the Clutter thread",
+ COGL_TYPE_HANDLE,
+ CLUTTER_GST_PARAM_READABLE);
+ g_object_class_install_property (gobject_class, PROP_COGL_PIPELINE, pspec);
+
+ /**
+ * ClutterGstVideoSink::send-event:
+ * @sink: the #ClutterGstVideoSink that emitted the signal
+ * @point: the position of the event
+ *
+ * The #ClutterGstVideoSink::send-event signal is emitted each time
+ * there is a need to get the coordinates of an event onto the
+ * screen.
+ *
+ * Return value: a #ClutterPoint if the position of the point in the
+ * stream can be translated into the window's coordinates, NULL
+ * otherwise.
+ *
+ * Since: 3.0
+ */
+ sink_signals[SEND_EVENT] =
+ g_signal_new ("send-event",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
+ 0,
+ _clutter_gst_point_handled_accumulator,
+ NULL,
+ NULL,
+ CLUTTER_TYPE_POINT, 1,
+ CLUTTER_TYPE_POINT);
}
static void
@@ -1625,20 +1657,23 @@ clutter_gst_navigation_send_event (GstNavigation * navigation,
* if the structure contains pointer coordinates */
if (gst_structure_get_double (structure, "pointer_x", &x) &&
gst_structure_get_double (structure, "pointer_y", &y)) {
- if (clutter_actor_transform_stage_point (CLUTTER_ACTOR (priv->actor), x,
- y, &x_out, &y_out) == FALSE) {
- g_warning ("Failed to convert non-scaled coordinates for video-sink");
- return;
- }
- x = x_out * priv->info.width /
- clutter_actor_get_width (CLUTTER_ACTOR (priv->actor));
- y = y_out * priv->info.height /
- clutter_actor_get_height (CLUTTER_ACTOR (priv->actor));
+ /* TODO: emit signal to get transformed point */
+
+ /* if (clutter_actor_transform_stage_point (CLUTTER_ACTOR (priv->actor), x, */
+ /* y, &x_out, &y_out) == FALSE) { */
+ /* g_warning ("Failed to convert non-scaled coordinates for video-sink"); */
+ /* return; */
+ /* } */
- gst_structure_set (structure,
- "pointer_x", G_TYPE_DOUBLE, (gdouble) x,
- "pointer_y", G_TYPE_DOUBLE, (gdouble) y, NULL);
+ /* x = x_out * priv->info.width / */
+ /* clutter_actor_get_width (CLUTTER_ACTOR (priv->actor)); */
+ /* y = y_out * priv->info.height / */
+ /* clutter_actor_get_height (CLUTTER_ACTOR (priv->actor)); */
+
+ /* gst_structure_set (structure, */
+ /* "pointer_x", G_TYPE_DOUBLE, (gdouble) x, */
+ /* "pointer_y", G_TYPE_DOUBLE, (gdouble) y, NULL); */
}
event = gst_event_new_navigation (structure);
@@ -1658,16 +1693,37 @@ clutter_gst_navigation_interface_init (GstNavigationInterface * iface)
iface->send_event = clutter_gst_navigation_send_event;
}
+/**
+ * clutter_gst_video_sink_get_frame:
+ * @self: a #ClutterGstVideoSink
+ *
+ * Retrieves the last frame from @self to present on the screen.
+ *
+ * Return value: (transfer none): A CoglHandle on a CoglPipeline
+ */
+ClutterGstFrame *
+clutter_gst_video_sink_get_frame (ClutterGstVideoSink *self)
+{
+ ClutterGstVideoSinkPrivate *priv;
+
+ g_return_val_if_fail (CLUTTER_GST_IS_VIDEO_SINK (self), COGL_INVALID_HANDLE);
+
+ priv = self->priv;
+
+ return priv->cogl_pipeline;
+}
+
+
gboolean
_internal_plugin_init (GstPlugin * plugin)
{
gboolean ret = gst_element_register (plugin,
- "cluttersink",
- GST_RANK_PRIMARY,
- CLUTTER_GST_TYPE_VIDEO_SINK);
+ "coglsink",
+ GST_RANK_PRIMARY,
+ CLUTTER_GST_TYPE_VIDEO_SINK);
GST_DEBUG_CATEGORY_INIT (clutter_gst_video_sink_debug,
- "cluttersink", 0, "clutter video sink");
+ "coglsink", 0, "cogl video sink");
return ret;
}
diff --git a/clutter-gst/clutter-gst-video-sink.h b/clutter-gst/clutter-gst-video-sink.h
index 92eb3e4..4726267 100644
--- a/clutter-gst/clutter-gst-video-sink.h
+++ b/clutter-gst/clutter-gst-video-sink.h
@@ -106,6 +106,8 @@ struct _ClutterGstVideoSinkClass
GType clutter_gst_video_sink_get_type (void) G_GNUC_CONST;
+CoglHandle clutter_gst_video_sink_get_frame (ClutterGstVideoSink *self);
+
G_END_DECLS
#endif /* __CLUTTER_GST_VIDEO_SINK_H__ */
diff --git a/clutter-gst/clutter-gst.h b/clutter-gst/clutter-gst.h
index cb657f9..b3790dd 100644
--- a/clutter-gst/clutter-gst.h
+++ b/clutter-gst/clutter-gst.h
@@ -33,12 +33,11 @@
#include "clutter-gst-types.h"
#include "clutter-gst-enum-types.h"
#include "clutter-gst-actor.h"
-#include "clutter-gst-video-sink.h"
-#include "clutter-gst-video-actor.h"
#include "clutter-gst-camera-device.h"
-#include "clutter-gst-camera-actor.h"
+#include "clutter-gst-camera.h"
#include "clutter-gst-util.h"
#include "clutter-gst-version.h"
#include "clutter-gst-player.h"
+#include "clutter-gst-playback.h"
#endif /* __CLUTTER_GST_H__ */
diff --git a/configure.ac b/configure.ac
index 690f8b6..cc55ef6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -80,6 +80,7 @@ AC_SUBST([CLUTTER_GST_RELEASE_STATUS], [clutter_gst_release_status])
# pkg-config requirements
GLIB_REQ_VERSION=2.18.0
COGL_REQ_VERSION=1.10.0
+COGL_GST_REQ_VERSION=1.99.0
CLUTTER_REQ_VERSION=1.6.0
GSTREAMER_REQ_VERSION=1.0.0
GST_PLUGINS_BAD_REQ_VERSION=1.0.0
@@ -142,6 +143,7 @@ dnl ========================================================================
PKG_CHECK_MODULES(CLUTTER_GST,
[clutter-1.0 >= $CLUTTER_REQ_VERSION
cogl-1.0 >= $COGL_REQ_VERSION
+ cogl-gst >= $COGL_GST_REQ_VERSION
gio-2.0 >= $GLIB_REQ_VERSION])
dnl ========================================================================
diff --git a/examples/camera-player.c b/examples/camera-player.c
index 1b816a7..e02ed5e 100644
--- a/examples/camera-player.c
+++ b/examples/camera-player.c
@@ -33,6 +33,7 @@ typedef struct _CameraApp
{
ClutterActor *stage;
ClutterActor *camera_actor;
+ ClutterGstCamera *camera_player;
const GPtrArray *camera_devices;
guint selected_camera_device;
gboolean decrease_selected;
@@ -57,24 +58,20 @@ update_gamma (CameraApp *app)
{
gdouble min, max, cur;
- if (!clutter_gst_camera_actor_supports_gamma_correction (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor)))
+ if (!clutter_gst_camera_supports_gamma_correction (app->camera_player))
{
g_print ("Cannot update gamma, not supported\n");
return;
}
- if (!clutter_gst_camera_actor_get_gamma_range (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
- &min, &max, NULL))
+ if (!clutter_gst_camera_get_gamma_range (app->camera_player,
+ &min, &max, NULL))
{
g_print ("Cannot update gamma, unable to get allowed range\n");
return;
}
- if (!clutter_gst_camera_actor_get_gamma (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
- &cur))
+ if (!clutter_gst_camera_get_gamma (app->camera_player, &cur))
{
g_print ("Cannot update gamma, unable to get current value\n");
return;
@@ -98,9 +95,7 @@ update_gamma (CameraApp *app)
}
g_print ("\tnew value: %0.2f\n", cur);
- clutter_gst_camera_actor_set_gamma (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
- cur);
+ clutter_gst_camera_set_gamma (app->camera_player, cur);
}
static void
@@ -109,8 +104,7 @@ update_color_balance (CameraApp *app,
{
gdouble min, max, cur;
- if (!clutter_gst_camera_actor_supports_color_balance (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor)))
+ if (!clutter_gst_camera_supports_color_balance (app->camera_player))
{
g_print ("Cannot update color balance property %s, "
"not supported\n",
@@ -118,9 +112,8 @@ update_color_balance (CameraApp *app,
return;
}
- if (!clutter_gst_camera_actor_get_color_balance_property_range (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
- property, &min, &max, NULL))
+ if (!clutter_gst_camera_get_color_balance_property_range (app->camera_player,
+ property, &min, &max, NULL))
{
g_print ("Cannot update color balance property %s, "
"unable to get allowed range\n",
@@ -128,9 +121,8 @@ update_color_balance (CameraApp *app,
return;
}
- if (!clutter_gst_camera_actor_get_color_balance_property (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
- property, &cur))
+ if (!clutter_gst_camera_get_color_balance_property (app->camera_player,
+ property, &cur))
{
g_print ("Cannot update color balance property %s, "
"unable to get current value\n",
@@ -156,9 +148,8 @@ update_color_balance (CameraApp *app,
}
g_print ("\tnew value: %0.2f\n", cur);
- clutter_gst_camera_actor_set_color_balance_property (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
- property, cur);
+ clutter_gst_camera_set_color_balance_property (app->camera_player,
+ property, cur);
}
static gboolean
@@ -214,8 +205,7 @@ input_cb (ClutterStage *stage,
g_print ("Selecting device %s (node=%s)\n",
clutter_gst_camera_device_get_name (device),
clutter_gst_camera_device_get_node (device));
- clutter_gst_camera_actor_set_camera_device (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor), device);
+ clutter_gst_camera_set_camera_device (app->camera_player, device);
break;
}
@@ -229,16 +219,13 @@ input_cb (ClutterStage *stage,
gchar *filename;
static guint photos_cnt = 0;
- if (clutter_gst_camera_actor_is_recording_video (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor)))
+ if (clutter_gst_camera_is_recording_video (app->camera_player))
{
g_print ("Stopping video recording\n");
- clutter_gst_camera_actor_stop_video_recording (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor));
+ clutter_gst_camera_stop_video_recording (app->camera_player);
}
- else if (!clutter_gst_camera_actor_is_ready_for_capture (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor)))
+ else if (!clutter_gst_camera_is_ready_for_capture (app->camera_player))
g_print ("Unable to record video as the camera is not ready for capture\n");
else
{
@@ -246,9 +233,8 @@ input_cb (ClutterStage *stage,
filename = g_strdup_printf ("camera-video-%d.ogv", photos_cnt++);
- clutter_gst_camera_actor_start_video_recording (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
- filename);
+ clutter_gst_camera_start_video_recording (app->camera_player,
+ filename);
g_free (filename);
}
break;
@@ -259,11 +245,9 @@ input_cb (ClutterStage *stage,
gchar *filename;
static guint photos_cnt = 0;
- if (clutter_gst_camera_actor_is_recording_video (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor)))
+ if (clutter_gst_camera_is_recording_video (app->camera_player))
g_print ("Unable to take photo as the camera is recording video\n");
- else if (!clutter_gst_camera_actor_is_ready_for_capture (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor)))
+ else if (!clutter_gst_camera_is_ready_for_capture (app->camera_player))
g_print ("Unable to take photo as the camera is not ready for capture\n");
else
{
@@ -271,9 +255,8 @@ input_cb (ClutterStage *stage,
filename = g_strdup_printf ("camera-photo-%d.jpg", photos_cnt++);
- clutter_gst_camera_actor_take_photo (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
- filename);
+ clutter_gst_camera_take_photo (app->camera_player,
+ filename);
g_free (filename);
}
break;
@@ -289,8 +272,7 @@ input_cb (ClutterStage *stage,
{
g_print ("ERROR: Unable to create 'dicetv' element, cannot set filter\n");
}
- ret = clutter_gst_camera_actor_set_filter (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor), filter);
+ ret = clutter_gst_camera_set_filter (app->camera_player, filter);
if (ret)
g_print ("Filter set successfully\n");
else
@@ -300,8 +282,7 @@ input_cb (ClutterStage *stage,
}
case CLUTTER_r:
- clutter_gst_camera_actor_remove_filter (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor));
+ clutter_gst_camera_remove_filter (app->camera_player);
break;
default:
@@ -316,7 +297,7 @@ input_cb (ClutterStage *stage,
}
static void
-ready_for_capture (ClutterGstCameraActor *camera_actor,
+ready_for_capture (ClutterGstCamera *camera_player,
gboolean ready)
{
if (ready)
@@ -324,13 +305,13 @@ ready_for_capture (ClutterGstCameraActor *camera_actor,
}
static void
-photo_saved (ClutterGstCameraActor *camera_actor)
+photo_saved (ClutterGstCamera *camera_player)
{
g_print ("Photo saved!\n");
}
static void
-video_saved (ClutterGstCameraActor *camera_actor)
+video_saved (ClutterGstCamera *camera_player)
{
g_print ("Video saved!\n");
}
@@ -406,16 +387,16 @@ main (int argc, char *argv[])
app = g_new0(CameraApp, 1);
app->stage = stage;
- app->camera_actor = clutter_gst_camera_actor_new ();
+ app->camera_actor = g_object_new (CLUTTER_GST_TYPE_ACTOR, NULL);
- if (app->camera_actor == NULL)
+ app->camera_player = clutter_gst_camera_new ();
+ if (app->camera_player == NULL)
{
- g_error ("failed to create camera_actor");
+ g_error ("failed to create camera player");
return EXIT_FAILURE;
}
- app->camera_devices = clutter_gst_camera_actor_get_camera_devices (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor));
+ app->camera_devices = clutter_gst_camera_get_camera_devices (app->camera_player);
if (!app->camera_devices)
{
g_error ("no suitable camera device available");
@@ -435,13 +416,13 @@ main (int argc, char *argv[])
}
app->selected_camera_device = 0;
- g_signal_connect (app->camera_actor, "ready-for-capture",
+ g_signal_connect (app->camera_player, "ready-for-capture",
G_CALLBACK (ready_for_capture),
app);
- g_signal_connect (app->camera_actor, "photo-saved",
+ g_signal_connect (app->camera_player, "photo-saved",
G_CALLBACK (photo_saved),
app);
- g_signal_connect (app->camera_actor, "video-saved",
+ g_signal_connect (app->camera_player, "video-saved",
G_CALLBACK (video_saved),
app);
/* Handle it ourselves so can scale up for fullscreen better */
@@ -457,8 +438,7 @@ main (int argc, char *argv[])
/* Hook up other events */
g_signal_connect (stage, "event", G_CALLBACK (input_cb), app);
- clutter_gst_camera_actor_set_playing (
- CLUTTER_GST_CAMERA_ACTOR (app->camera_actor), TRUE);
+ clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (app->camera_player), TRUE);
clutter_actor_show (stage);
diff --git a/examples/video-player.c b/examples/video-player.c
index 1d1ebbf..69c9364 100644
--- a/examples/video-player.c
+++ b/examples/video-player.c
@@ -41,6 +41,7 @@ typedef struct _VideoApp
ClutterActor *stage;
ClutterActor *vactor;
+ ClutterGstPlayback *player;
ClutterActor *control;
ClutterActor *control_bg;
@@ -163,16 +164,16 @@ toggle_pause_state (VideoApp *app)
if (app->paused)
{
- clutter_gst_player_set_playing (CLUTTER_GST_PLAYER(app->vactor),
- TRUE);
+ clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (app->player),
+ TRUE);
app->paused = FALSE;
clutter_actor_hide (app->control_play);
clutter_actor_show (app->control_pause);
}
else
{
- clutter_gst_player_set_playing (CLUTTER_GST_PLAYER(app->vactor),
- FALSE);
+ clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (app->player),
+ FALSE);
app->paused = TRUE;
clutter_actor_hide (app->control_pause);
clutter_actor_show (app->control_play);
@@ -232,8 +233,7 @@ input_cb (ClutterStage *stage,
progress = (gdouble) dist / SEEK_W;
- clutter_gst_player_set_progress (CLUTTER_GST_PLAYER (app->vactor),
- progress);
+ clutter_gst_playback_set_progress (app->player, progress);
}
}
handled = TRUE;
@@ -302,10 +302,10 @@ input_cb (ClutterStage *stage,
}
static void
-size_change (ClutterActor *actor,
- gint base_width,
- gint base_height,
- VideoApp *app)
+size_change (ClutterGstPlayer *player,
+ gint base_width,
+ gint base_height,
+ VideoApp *app)
{
ClutterActor *stage = app->stage;
gfloat new_x, new_y, new_width, new_height;
@@ -317,7 +317,9 @@ size_change (ClutterActor *actor,
/* base_width and base_height are the actual dimensions of the buffers before
* taking the pixel aspect ratio into account. We need to get the actual
* size of the actor to display */
- clutter_actor_get_size (actor, &frame_width, &frame_height);
+ /* clutter_actor_get_size (app->vactor, &frame_width, &frame_height); */
+ frame_width = base_width;
+ frame_height = base_height;
new_height = (frame_height * stage_width) / frame_width;
if (new_height <= stage_height)
@@ -336,8 +338,8 @@ size_change (ClutterActor *actor,
new_y = 0;
}
- clutter_actor_set_position (actor, new_x, new_y);
- clutter_actor_set_size (actor, new_width, new_height);
+ clutter_actor_set_position (app->vactor, new_x, new_y);
+ clutter_actor_set_size (app->vactor, new_width, new_height);
}
static void
@@ -370,8 +372,7 @@ tick (GObject *object,
GParamSpec *pspec,
VideoApp *app)
{
- ClutterGstPlayer *vactor = CLUTTER_GST_PLAYER (object);
- gdouble progress = clutter_gst_player_get_progress (vactor);
+ gdouble progress = clutter_gst_playback_get_progress (app->player);
clutter_actor_set_size (app->control_seekbar,
progress * SEEK_W,
@@ -384,7 +385,7 @@ on_video_actor_eos (ClutterGstPlayer *player,
{
if (opt_loop)
{
- clutter_gst_player_set_progress (player, 0.0);
+ clutter_gst_playback_set_progress (CLUTTER_GST_PLAYBACK (player), 0.0);
clutter_gst_player_set_playing (player, TRUE);
}
}
@@ -509,7 +510,10 @@ main (int argc, char *argv[])
app = g_new0(VideoApp, 1);
app->stage = stage;
- app->vactor = clutter_gst_video_actor_new ();
+ app->vactor = g_object_new (CLUTTER_GST_TYPE_ACTOR, NULL);
+ app->player = clutter_gst_playback_new ();
+
+ clutter_gst_actor_set_player (CLUTTER_GST_ACTOR (app->vactor), CLUTTER_GST_PLAYER (app->player));
if (app->vactor == NULL)
g_error("failed to create vactor");
@@ -519,10 +523,10 @@ main (int argc, char *argv[])
* goes to the key frame position that can be quite far from where you
* clicked. Using the ACCURATE flag tells playbin2 to seek to the actual
* frame */
- clutter_gst_player_set_seek_flags (CLUTTER_GST_PLAYER (app->vactor),
- CLUTTER_GST_SEEK_FLAG_ACCURATE);
+ clutter_gst_playback_set_seek_flags (app->player,
+ CLUTTER_GST_SEEK_FLAG_ACCURATE);
- g_signal_connect (app->vactor,
+ g_signal_connect (app->player,
"eos",
G_CALLBACK (on_video_actor_eos),
app);
@@ -532,13 +536,9 @@ main (int argc, char *argv[])
g_print ("Remote media detected, setting up buffering\n");
/* configure to 10 seconds of buffer duration */
- clutter_gst_player_set_buffer_duration (
- CLUTTER_GST_PLAYER (app->vactor),
- 10 * GST_SECOND);
- clutter_gst_player_set_buffering_mode (
- CLUTTER_GST_PLAYER (app->vactor),
- CLUTTER_GST_BUFFERING_MODE_STREAM);
- g_signal_connect (app->vactor,
+ clutter_gst_playback_set_buffer_duration (app->player, 10 * GST_SECOND);
+ clutter_gst_playback_set_buffering_mode (app->player, CLUTTER_GST_BUFFERING_MODE_STREAM);
+ g_signal_connect (app->player,
"notify::buffer-fill",
G_CALLBACK (on_video_actor_notify_buffer_fill),
app);
@@ -557,20 +557,20 @@ main (int argc, char *argv[])
NULL);
/* Handle it ourselves so can scale up for fullscreen better */
- g_signal_connect_after (app->vactor,
+ g_signal_connect_after (app->player,
"size-change",
G_CALLBACK (size_change), app);
/* Load up out video actor */
- clutter_gst_player_set_uri (CLUTTER_GST_PLAYER (app->vactor), uri);
+ clutter_gst_playback_set_filename (app->player, uri);
- if (clutter_gst_player_is_live_media (CLUTTER_GST_PLAYER (app->vactor)))
+ if (clutter_gst_playback_is_live_media (app->player))
g_print ("Playing live media\n");
else
g_print ("Playing non-live media\n");
/* Set up things so that a visualisation is played if there's no video */
- pipe = clutter_gst_player_get_pipeline (CLUTTER_GST_PLAYER (app->vactor));
+ pipe = clutter_gst_player_get_pipeline (CLUTTER_GST_PLAYER (app->player));
if (!pipe)
g_error ("Unable to get gstreamer pipeline!\n");
@@ -659,11 +659,11 @@ main (int argc, char *argv[])
/* Hook up other events */
g_signal_connect (stage, "event", G_CALLBACK (input_cb), app);
- g_signal_connect (app->vactor,
+ g_signal_connect (app->player,
"notify::progress", G_CALLBACK (tick),
app);
- clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (app->vactor), TRUE);
+ clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (app->player), TRUE);
clutter_actor_show (stage);
diff --git a/examples/video-sink.c b/examples/video-sink.c
index 82030d7..9fc7ab6 100644
--- a/examples/video-sink.c
+++ b/examples/video-sink.c
@@ -29,10 +29,10 @@
#include <clutter-gst/clutter-gst.h>
void
-size_change (ClutterActor *actor,
- gint width,
- gint height,
- gpointer user_data)
+size_change (ClutterGstPlayer *player,
+ gint width,
+ gint height,
+ ClutterActor *actor)
{
ClutterActor *stage;
gfloat new_x, new_y, new_width, new_height;
@@ -68,14 +68,14 @@ size_change (ClutterActor *actor,
int
main (int argc, char *argv[])
{
- ClutterTimeline *timeline;
- ClutterActor *stage;
- ClutterActor *actor;
- GstPipeline *pipeline;
- GstElement *src;
- GstElement *warp;
- GstElement *colorspace;
- GstElement *sink;
+ ClutterTimeline *timeline;
+ ClutterActor *stage;
+ ClutterActor *actor;
+ GstElement *src;
+ GstElement *warp;
+ GstElement *bin;
+ GstElement *pipeline;
+ ClutterGstPlayback *player;
if (argc < 1)
{
@@ -98,24 +98,23 @@ main (int argc, char *argv[])
actor = g_object_new (CLUTTER_GST_TYPE_ACTOR, NULL);
- g_signal_connect (actor,
- "size-change",
- G_CALLBACK (size_change), NULL);
-
/* Set up pipeline */
- pipeline = GST_PIPELINE (gst_pipeline_new (NULL));
+ player = clutter_gst_playback_new ();
+ pipeline = clutter_gst_player_get_pipeline (CLUTTER_GST_PLAYER (player));
+
+ g_signal_connect (player, "size-change",
+ G_CALLBACK (size_change), actor);
src = gst_element_factory_make ("videotestsrc", NULL);
warp = gst_element_factory_make ("warptv", NULL);
- colorspace = gst_element_factory_make ("videoconvert", NULL);
- sink = gst_element_factory_make ("cluttersink", NULL);
- g_object_set (sink, "actor", actor, NULL);
+ bin = gst_bin_new ("video-test-source");
+
+ gst_bin_add_many (GST_BIN (bin), src, warp, NULL);
+ gst_element_link_many (src, warp, NULL);
- // g_object_set (src , "pattern", 10, NULL);
+ g_object_set (pipeline, "source", bin);
- gst_bin_add_many (GST_BIN (pipeline), src, warp, colorspace, sink, NULL);
- gst_element_link_many (src, warp, colorspace, sink, NULL);
- gst_element_set_state (GST_ELEMENT(pipeline), GST_STATE_PLAYING);
+ clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (player), TRUE);
/* start the timeline */
clutter_timeline_start (timeline);
diff --git a/tests/test-start-stop.c b/tests/test-start-stop.c
index 5908e4e..d9b9e7e 100644
--- a/tests/test-start-stop.c
+++ b/tests/test-start-stop.c
@@ -76,17 +76,17 @@ gboolean
test (gpointer data)
{
static int count = 1;
- static ClutterGstPlayer *player = NULL;
+ static ClutterGstPlayback *player = NULL;
static char *uri[2] = {NULL, NULL};
const char *playing_uri = NULL;
/* Check until we get video playing */
- if (!clutter_gst_player_is_playing (CLUTTER_GST_PLAYER (data)))
+ if (!clutter_gst_player_get_playing (CLUTTER_GST_PLAYER (data)))
return TRUE;
- if (CLUTTER_GST_PLAYER (data) != player)
+ if (CLUTTER_GST_PLAYBACK (data) != player)
{
- player = CLUTTER_GST_PLAYER (data);
+ player = CLUTTER_GST_PLAYBACK (data);
count = 1;
g_free(uri[0]);
uri[0] = NULL;
@@ -94,25 +94,25 @@ test (gpointer data)
uri[1] = NULL;
}
- clutter_gst_player_set_filename (player, video_files[count & 1]);
+ clutter_gst_playback_set_filename (player, video_files[count & 1]);
g_print ("playing %s\n", video_files[count & 1]);
if (uri[count & 1] == NULL)
{
- uri[count & 1] = g_strdup (clutter_gst_player_get_uri (player));
+ uri[count & 1] = g_strdup (clutter_gst_playback_get_uri (player));
g_assert (uri[count & 1] != NULL);
}
/* See if it's still playing */
- g_assert (clutter_gst_player_is_playing (player));
+ g_assert (clutter_gst_player_get_playing (CLUTTER_GST_PLAYER (player)));
/* See if it's already change to play correct file */
- playing_uri = clutter_gst_player_get_uri (player);
+ playing_uri = clutter_gst_playback_get_uri (player);
g_assert_cmpstr (playing_uri, ==, uri[count & 1]);
if (count ++ > 10)
{
- clutter_gst_player_set_playing (player, FALSE);
+ clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (player), FALSE);
clutter_main_quit ();
return FALSE;
}
@@ -124,10 +124,11 @@ test (gpointer data)
int
main (int argc, char *argv[])
{
- ClutterInitError error;
- ClutterColor stage_color = { 0x00, 0x00, 0x00, 0x00 };
- ClutterActor *stage = NULL;
- ClutterActor *video = NULL;
+ ClutterInitError error;
+ ClutterColor stage_color = { 0x00, 0x00, 0x00, 0x00 };
+ ClutterActor *stage = NULL;
+ ClutterActor *video = NULL;
+ ClutterGstPlayback *player = NULL;
if (argc < 3)
{
@@ -144,23 +145,27 @@ main (int argc, char *argv[])
stage = clutter_stage_new ();
clutter_actor_set_background_color (stage, &stage_color);
- video = clutter_gst_video_actor_new ();
- g_assert (CLUTTER_GST_IS_VIDEO_ACTOR(video));
+ player = clutter_gst_playback_new ();
+
+ video = /* clutter_gst_actor_new () */ g_object_new (CLUTTER_GST_TYPE_ACTOR,
+ NULL);
+ g_assert (CLUTTER_GST_IS_ACTOR (video));
+ clutter_gst_actor_set_player (CLUTTER_GST_ACTOR (video), CLUTTER_GST_PLAYER (player));
+ clutter_actor_add_child (stage, video);
g_signal_connect (video,
"size-change",
G_CALLBACK(size_change),
stage);
- g_signal_connect (video,
+ g_signal_connect (player,
"error",
G_CALLBACK(on_error),
stage);
g_timeout_add (5000, test, video);
- clutter_gst_player_set_filename (CLUTTER_GST_PLAYER (video), video_files[0]);
- clutter_gst_player_set_audio_volume (CLUTTER_GST_PLAYER (video), 0.5);
- clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (video), TRUE);
+ clutter_gst_playback_set_filename (player, video_files[0]);
+ clutter_gst_player_set_audio_volume (CLUTTER_GST_PLAYER (player), 0.5);
+ clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (player), TRUE);
- clutter_actor_add_child (stage, video);
clutter_actor_show (stage);
clutter_main ();
diff --git a/tests/test-video-actor-new-unref-loop.c b/tests/test-video-actor-new-unref-loop.c
index 5a611f2..942f56a 100644
--- a/tests/test-video-actor-new-unref-loop.c
+++ b/tests/test-video-actor-new-unref-loop.c
@@ -43,7 +43,7 @@ main (int argc, char *argv[])
for (i = 0; ; i++)
{
g_debug("VideoActor #%d", i);
- vactor = clutter_gst_video_actor_new ();
+ vactor = g_object_new (CLUTTER_GST_TYPE_ACTOR, NULL);
g_object_ref_sink (vactor);
g_object_unref (vactor);
}