-/* Heavily based on totems bacon-video-widget .. */
+
#include "clutter-video-texture.h"
#include "clutter-main.h"
#include <glib.h>
-static void
-got_time_tick (GstElement *play,
- gint64 time_nanos,
- ClutterVideoTexture *video_texture);
-static void
-stop_play_pipeline (ClutterVideoTexture *video_texture);
-
-G_DEFINE_TYPE (ClutterVideoTexture, \
- clutter_video_texture, \
- CLUTTER_TYPE_TEXTURE);
-
-enum
+struct ClutterVideoTexturePrivate
{
- SIGNAL_ERROR,
- SIGNAL_EOS,
- SIGNAL_REDIRECT,
- SIGNAL_TITLE_CHANGE,
- SIGNAL_CHANNELS_CHANGE,
- SIGNAL_TICK,
- SIGNAL_GOT_METADATA,
- SIGNAL_BUFFERING,
- SIGNAL_SPEED_WARNING,
- LAST_SIGNAL
+ GstElement *playbin;
+ char *uri;
+ gboolean can_seek;
+ int buffer_percent;
+ int duration;
+ gboolean force_aspect_ratio;
+ guint tick_timeout_id;
};
-/* Properties */
-enum
-{
+enum {
PROP_0,
- PROP_POSITION,
- PROP_CURRENT_TIME,
- PROP_STREAM_LENGTH,
+ /* ClutterMedia proprs */
+ PROP_URI,
PROP_PLAYING,
- PROP_SEEKABLE,
-};
+ PROP_POSITION,
+ PROP_VOLUME,
+ PROP_CAN_SEEK,
+ PROP_BUFFER_PERCENT,
+ PROP_DURATION,
-struct ClutterVideoTexturePrivate
-{
- GstElement *play, *video_sink, *audio_sink;
- gboolean has_video, has_audio;
- gint64 stream_length;
- gint64 current_time_nanos;
- gint64 current_time;
- float current_position;
- gchar *mrl;
-
- gboolean got_redirect;
- gint eos_id;
- guint update_id;
-
- GstTagList *tagcache, *audiotags, *videotags;
-
- const GValue *movie_par; /* Movie pixel aspect ratio */
- gint video_fps_d, video_fps_n;
- gint video_width, video_height;
- ClutterVideoTextureAspectRatio ratio_type;
-
- GstMessageType ignore_messages_mask;
- GstBus *bus;
- gulong sig_bus_async;
+ /* Extra texture props */
+ PROP_FORCE_ASPECT_RATIO
};
-static int cvt_signals[LAST_SIGNAL] = { 0 };
-GQuark
-clutter_video_texture_error_quark (void)
-{
- return g_quark_from_static_string ("clutter-video-texture-error-quark");
-}
+#define TICK_TIMEOUT 0.5
-/* This is a hack to avoid doing poll_for_state_change() indirectly
- * from the bus message callback (via EOS => totem => close => wait for READY)
- * and deadlocking there. We need something like a
- * gst_bus_set_auto_flushing(bus, FALSE) ... */
-static gboolean
-signal_eos_delayed (gpointer user_data)
-{
- ClutterVideoTexture *video_texture = (ClutterVideoTexture*)user_data;
+static void clutter_media_init (ClutterMediaInterface *iface);
- g_signal_emit (video_texture, cvt_signals[SIGNAL_EOS], 0, NULL);
+static gboolean tick_timeout (ClutterVideoTexture *video_texture);
- video_texture->priv->eos_id = 0;
+G_DEFINE_TYPE_EXTENDED (ClutterVideoTexture, \
+ clutter_video_texture, \
+ CLUTTER_TYPE_TEXTURE, \
+ 0, \
+ G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_MEDIA, \
+ clutter_media_init));
- return FALSE;
-}
+/* Interface implementation */
-static gboolean
-query_timeout (ClutterVideoTexture *video_texture)
+static void
+set_uri (ClutterMedia *media,
+ const char *uri)
{
- ClutterVideoTexturePrivate *priv;
- GstFormat fmt = GST_FORMAT_TIME;
- gint64 prev_len = -1, pos = -1, len = -1;
+ ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+ ClutterVideoTexturePrivate *priv;
+ GstState state, pending;
+
+ g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
priv = video_texture->priv;
-
- /* check length/pos of stream */
- prev_len = priv->stream_length;
- if (gst_element_query_duration (priv->play, &fmt, &len))
+ if (!priv->playbin)
+ return;
+
+ if (priv->uri)
+ g_free (priv->uri);
+
+ if (uri)
{
- if (len != -1 && fmt == GST_FORMAT_TIME)
- {
- priv->stream_length = len / GST_MSECOND;
- if (priv->stream_length != prev_len)
- {
- g_signal_emit (video_texture,
- cvt_signals[SIGNAL_GOT_METADATA], 0, NULL);
- }
- }
+ 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 * 1000,
+ (GSourceFunc) tick_timeout,
+ video_texture);
+ }
}
else
{
- CLUTTER_DBG ("could not get duration");
- }
-
- if (gst_element_query_position (priv->play, &fmt, &pos))
- {
- if (pos != -1 && fmt == GST_FORMAT_TIME)
+ priv->uri = NULL;
+
+ if (priv->tick_timeout_id > 0)
{
- got_time_tick (GST_ELEMENT (priv->play), pos, video_texture);
+ g_source_remove (priv->tick_timeout_id);
+ priv->tick_timeout_id = 0;
}
- }
- else
- CLUTTER_DBG ("could not get position");
+ }
+
+ priv->can_seek = FALSE;
+ priv->duration = 0;
- return TRUE;
+ gst_element_get_state (priv->playbin, &state, &pending, 0);
+
+ if (pending)
+ state = pending;
+
+ gst_element_set_state (priv->playbin, GST_STATE_NULL);
+
+ g_object_set (priv->playbin,
+ "uri", uri,
+ NULL);
+
+ /**
+ * Restore state.
+ **/
+ if (uri)
+ gst_element_set_state (priv->playbin, state);
+
+ /**
+ * Emit notififications for all these to make sure UI is not showing
+ * any properties of the old URI.
+ **/
+ g_object_notify (G_OBJECT (video_texture), "uri");
+ g_object_notify (G_OBJECT (video_texture), "can-seek");
+ g_object_notify (G_OBJECT (video_texture), "duration");
+ g_object_notify (G_OBJECT (video_texture), "position");
+
}
-static void
-got_video_size (ClutterVideoTexture *video_texture)
+static const char *
+get_uri (ClutterMedia *media)
{
- GstMessage *msg;
-
- g_return_if_fail (video_texture != NULL);
+ ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+ ClutterVideoTexturePrivate *priv;
- /* Do we even care about this info as comes from texture sizing ? */
- CLUTTER_DBG("%ix%i",
- video_texture->priv->video_width,
- video_texture->priv->video_height);
+ g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), NULL);
- msg = gst_message_new_application
- (GST_OBJECT (video_texture->priv->play),
- gst_structure_new ("video-size",
- "width", G_TYPE_INT,
- video_texture->priv->video_width,
- "height", G_TYPE_INT,
- video_texture->priv->video_height, NULL));
+ priv = video_texture->priv;
- gst_element_post_message (video_texture->priv->play, msg);
+ return priv->uri;
}
-
static void
-caps_set (GObject *obj,
- GParamSpec *pspec,
- ClutterVideoTexture *video_texture)
+set_playing (ClutterMedia *media,
+ gboolean playing)
{
- ClutterVideoTexturePrivate *priv;
- GstPad *pad = GST_PAD (obj);
- GstStructure *s;
- GstCaps *caps;
+ ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+ ClutterVideoTexturePrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
priv = video_texture->priv;
- if (!(caps = gst_pad_get_negotiated_caps (pad)))
+ if (!priv->playbin)
return;
-
- /* Get video decoder caps */
- s = gst_caps_get_structure (caps, 0);
-
- /* Again do we even need this - sizing info from texture signal.. */
-
- if (s)
+
+ if (priv->uri)
{
- /* We need at least width/height and framerate */
- if (!(gst_structure_get_fraction (s, "framerate",
- &priv->video_fps_n,
- &priv->video_fps_d)
- &&
- gst_structure_get_int (s, "width", &priv->video_width) &&
- gst_structure_get_int (s, "height", &priv->video_height)))
- return;
-
- /* Get the movie PAR if available */
- priv->movie_par = gst_structure_get_value (s, "pixel-aspect-ratio");
+ GstState state;
- /* Now set for real */
- clutter_video_texture_set_aspect_ratio (video_texture, priv->ratio_type);
- }
-
- gst_caps_unref (caps);
+ if (playing)
+ state = GST_STATE_PLAYING;
+ else
+ state = GST_STATE_PAUSED;
+
+ gst_element_set_state (video_texture->priv->playbin, state);
+ }
+ else
+ {
+ if (playing)
+ g_warning ("Tried to play, but no URI is loaded.");
+ }
+
+ g_object_notify (G_OBJECT (video_texture), "playing");
+ g_object_notify (G_OBJECT (video_texture), "position");
}
-static void
-parse_stream_info (ClutterVideoTexture *video_texture)
+static gboolean
+get_playing (ClutterMedia *media)
{
- ClutterVideoTexturePrivate *priv;
- GList *streaminfo = NULL;
- GstPad *videopad = NULL;
+ ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+ ClutterVideoTexturePrivate *priv;
+ GstState state, pending;
+ g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
+
priv = video_texture->priv;
- g_object_get (priv->play, "stream-info", &streaminfo, NULL);
+ if (!priv->playbin)
+ return FALSE;
+
+ gst_element_get_state (priv->playbin, &state, &pending, 0);
+
+ if (pending)
+ return (pending == GST_STATE_PLAYING);
+ else
+ return (state == GST_STATE_PLAYING);
+}
- streaminfo = g_list_copy (streaminfo);
+static void
+set_position (ClutterMedia *media,
+ int position) /* seconds */
+{
+ ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+ ClutterVideoTexturePrivate *priv;
- g_list_foreach (streaminfo, (GFunc) g_object_ref, NULL);
+ g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
- for ( ; streaminfo != NULL; streaminfo = streaminfo->next)
- {
- GObject *info = streaminfo->data;
- gint type;
- GParamSpec *pspec;
- GEnumValue *val;
+ priv = video_texture->priv;
- if (!info)
- continue;
+ if (!priv->playbin)
+ return;
- g_object_get (info, "type", &type, NULL);
+ gst_element_seek (priv->playbin,
+ 1.0,
+ GST_FORMAT_TIME,
+ GST_SEEK_FLAG_FLUSH,
+ GST_SEEK_TYPE_SET,
+ position * GST_SECOND,
+ 0, 0);
+}
- pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (info), "type");
- val = g_enum_get_value (G_PARAM_SPEC_ENUM (pspec)->enum_class, type);
+static int
+get_position (ClutterMedia *media)
+{
+ ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+ ClutterVideoTexturePrivate *priv;
+ GstQuery *query;
+ gint64 position;
- if (!g_strcasecmp (val->value_nick, "audio"))
- {
- priv->has_audio = TRUE;
- }
- else if (!g_strcasecmp (val->value_nick, "video"))
- {
- priv->has_video = TRUE;
+ g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
- if (!videopad)
- g_object_get (info, "object", &videopad, NULL);
- }
- }
+ priv = video_texture->priv;
- if (videopad)
- {
- GstCaps *caps;
+ if (!priv->playbin)
+ return -1;
+
+ query = gst_query_new_position (GST_FORMAT_TIME);
+
+ if (gst_element_query (priv->playbin, query))
+ gst_query_parse_position (query, NULL, &position);
+ else
+ position = 0;
+
+ gst_query_unref (query);
+
+ return (position / GST_SECOND);
+}
- if ((caps = gst_pad_get_negotiated_caps (videopad)))
- {
- caps_set (G_OBJECT (videopad), NULL, video_texture);
- gst_caps_unref (caps);
- }
+static void
+set_volume (ClutterMedia *media,
+ double volume)
+{
+ ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+ ClutterVideoTexturePrivate *priv;
- g_signal_connect (videopad, "notify::caps",
- G_CALLBACK (caps_set), video_texture);
- }
+ g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
+ // g_return_if_fail (volume >= 0.0 && volume <= GST_VOL_MAX);
- g_list_foreach (streaminfo, (GFunc) g_object_unref, NULL);
- g_list_free (streaminfo);
+ priv = video_texture->priv;
+
+ if (!priv->playbin)
+ return;
+
+ g_object_set (G_OBJECT (video_texture->priv->playbin),
+ "volume", volume,
+ NULL);
+
+ g_object_notify (G_OBJECT (video_texture), "volume");
}
-static void
-handle_element_message (ClutterVideoTexture *video_texture, GstMessage *msg)
+static double
+get_volume (ClutterMedia *media)
{
- const gchar *type_name = NULL;
- gchar *src_name;
+ ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+ ClutterVideoTexturePrivate *priv;
+ double volume;
- CLUTTER_MARK();
+ g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), 0.0);
- src_name = gst_object_get_name (msg->src);
+ priv = video_texture->priv;
+
+ if (!priv->playbin)
+ return 0.0;
- if (msg->structure)
- type_name = gst_structure_get_name (msg->structure);
+ g_object_get (priv->playbin,
+ "volume", &volume,
+ NULL);
+
+ return volume;
+}
- if (type_name == NULL)
- goto unhandled;
+static gboolean
+can_seek (ClutterMedia *media)
+{
+ ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
- if (strcmp (type_name, "redirect") == 0)
- {
- const gchar *new_location;
+ g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
+
+ return video_texture->priv->can_seek;
+}
- new_location = gst_structure_get_string (msg->structure, "new-location");
+static int
+get_buffer_percent (ClutterMedia *media)
+{
+ ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
- CLUTTER_DBG ("Got redirect to '%s'", GST_STR_NULL (new_location));
+ g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
+
+ return video_texture->priv->buffer_percent;
+}
- if (new_location && *new_location)
- {
- g_signal_emit (video_texture,
- cvt_signals[SIGNAL_REDIRECT],
- 0,
- new_location);
- goto done;
- }
- }
+static int
+get_duration (ClutterMedia *media)
+{
+ ClutterVideoTexture *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+
+ g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
- unhandled:
- CLUTTER_DBG ("Unhandled element message '%s' from element '%s'",
- GST_STR_NULL (type_name), src_name);
- done:
- g_free (src_name);
+ return video_texture->priv->duration;
}
static void
-handle_application_message (ClutterVideoTexture *video_texture,
- GstMessage *msg)
+clutter_media_init (ClutterMediaInterface *iface)
{
- const gchar *msg_name;
+ iface->set_uri = set_uri;
+ iface->get_uri = get_uri;
+ iface->set_playing = set_playing;
+ iface->get_playing = get_playing;
+ iface->set_position = set_position;
+ iface->get_position = get_position;
+ iface->set_volume = set_volume;
+ iface->get_volume = get_volume;
+ iface->can_seek = can_seek;
+ iface->get_buffer_percent = get_buffer_percent;
+ iface->get_duration = get_duration;
+}
- msg_name = gst_structure_get_name (msg->structure);
+static void
+clutter_video_texture_dispose (GObject *object)
+{
+ ClutterVideoTexture *self;
+ ClutterVideoTexturePrivate *priv;
- g_return_if_fail (msg_name != NULL);
+ self = CLUTTER_VIDEO_TEXTURE(object);
+ priv = self->priv;
- CLUTTER_DBG ("Handling application message");
+ /* FIXME: flush an errors off bus ? */
+ /* gst_bus_set_flushing (priv->bus, TRUE); */
- if (strcmp (msg_name, "notify-streaminfo") == 0)
+ if (priv->playbin)
{
- g_signal_emit (video_texture, cvt_signals[SIGNAL_GOT_METADATA], 0, NULL);
- g_signal_emit (video_texture, cvt_signals[SIGNAL_CHANNELS_CHANGE], 0);
+ gst_element_set_state (priv->playbin, GST_STATE_NULL);
+ gst_object_unref (GST_OBJECT (priv->playbin));
+ priv->playbin = NULL;
}
- else if (strcmp (msg_name, "video-size") == 0)
- {
- g_signal_emit (video_texture, cvt_signals[SIGNAL_GOT_METADATA], 0, NULL);
- CLUTTER_DBG("Got video size");
+ if (priv->tick_timeout_id > 0)
+ {
+ g_source_remove (priv->tick_timeout_id);
+ priv->tick_timeout_id = 0;
}
- else
- CLUTTER_DBG ("Unhandled application message %s", msg_name);
+
+ G_OBJECT_CLASS (clutter_video_texture_parent_class)->dispose (object);
}
static void
-bus_message_cb (GstBus *bus, GstMessage *message, gpointer data)
+clutter_video_texture_finalize (GObject *object)
{
- ClutterVideoTexturePrivate *priv;
- ClutterVideoTexture *video_texture = (ClutterVideoTexture*)data;
- GstMessageType msg_type;
+ ClutterVideoTexture *self;
+ ClutterVideoTexturePrivate *priv;
+
+ self = CLUTTER_VIDEO_TEXTURE(object);
+ priv = self->priv;
- g_return_if_fail (video_texture != NULL);
- g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE(video_texture));
+ if (priv->uri)
+ g_free(priv->uri);
- priv = video_texture->priv;
+ G_OBJECT_CLASS (clutter_video_texture_parent_class)->finalize (object);
+}
- msg_type = GST_MESSAGE_TYPE (message);
+static void
+clutter_video_texture_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterVideoTexture *video_texture;
- /* somebody else is handling the message,
- probably in poll_for_state_change */
- if (priv->ignore_messages_mask & msg_type)
- {
- gchar *src_name = gst_object_get_name (message->src);
- CLUTTER_DBG ("Ignoring %s message from element %s as requested",
- gst_message_type_get_name (msg_type), src_name);
- g_free (src_name);
- return;
- }
+ video_texture = CLUTTER_VIDEO_TEXTURE(object);
- if (msg_type != GST_MESSAGE_STATE_CHANGED && clutter_want_debug())
+ switch (property_id)
{
- gchar *src_name = gst_object_get_name (message->src);
- CLUTTER_DBG ("Handling %s message from element %s",
- gst_message_type_get_name (msg_type), src_name);
- g_free (src_name);
+ case PROP_URI:
+ clutter_media_set_uri (CLUTTER_MEDIA(video_texture),
+ g_value_get_string (value));
+ break;
+ case PROP_PLAYING:
+ clutter_media_set_playing (CLUTTER_MEDIA(video_texture),
+ g_value_get_boolean (value));
+ break;
+ case PROP_POSITION:
+ clutter_media_set_position (CLUTTER_MEDIA(video_texture),
+ g_value_get_int (value));
+ break;
+ case PROP_VOLUME:
+ clutter_media_set_volume (CLUTTER_MEDIA(video_texture),
+ g_value_get_double (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
+}
- switch (msg_type)
- {
- case GST_MESSAGE_ERROR:
- {
- GError *error = NULL;
- gchar *debug = NULL;
+static void
+clutter_video_texture_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterVideoTexture *video_texture;
+ ClutterMedia *media;
- gst_message_parse_error (message, &error, &debug);
+ video_texture = CLUTTER_VIDEO_TEXTURE (object);
+ media = CLUTTER_MEDIA (video_texture);
- CLUTTER_DBG ("Error message: %s [%s]",
- GST_STR_NULL (error->message),
- GST_STR_NULL (debug));
+ switch (property_id)
+ {
+ case PROP_URI:
+ g_value_set_string (value, clutter_media_get_uri (media));
+ break;
+ case PROP_PLAYING:
+ g_value_set_boolean (value, clutter_media_get_playing (media));
+ break;
+ case PROP_POSITION:
+ g_value_set_int (value, clutter_media_get_position (media));
+ break;
+ case PROP_VOLUME:
+ g_value_set_double (value, clutter_media_get_volume (media));
+ break;
+ case PROP_CAN_SEEK:
+ g_value_set_boolean (value, clutter_media_get_can_seek (media));
+ break;
+ case PROP_BUFFER_PERCENT:
+ g_value_set_int (value, clutter_media_get_buffer_percent (media));
+ break;
+ case PROP_DURATION:
+ g_value_set_int (value, clutter_media_get_duration (media));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
- g_signal_emit (video_texture,
- cvt_signals[SIGNAL_ERROR],
- 0,
- error->message,
- TRUE,
- FALSE);
+static void
+clutter_video_texture_class_init (ClutterVideoTextureClass *klass)
+{
+ GObjectClass *object_class;
+ ClutterElementClass *element_class;
- g_error_free (error);
+ object_class = (GObjectClass*)klass;
+ element_class = (ClutterElementClass*)klass;
- if (priv->play)
- gst_element_set_state (priv->play, GST_STATE_NULL);
+ object_class->dispose = clutter_video_texture_dispose;
+ object_class->finalize = clutter_video_texture_finalize;
+ object_class->set_property = clutter_video_texture_set_property;
+ object_class->get_property = clutter_video_texture_get_property;
- g_free (debug);
- break;
- }
- case GST_MESSAGE_WARNING:
- {
- GError *error = NULL;
- gchar *debug = NULL;
+ /* Interface props */
- gst_message_parse_warning (message, &error, &debug);
+ 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_POSITION, "position");
+ g_object_class_override_property (object_class, PROP_VOLUME, "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_PERCENT,
+ "buffer-percent" );
+}
- g_warning ("%s [%s]",
- GST_STR_NULL (error->message),
- GST_STR_NULL (debug));
+static void
+bus_message_error_cb (GstBus *bus,
+ GstMessage *message,
+ ClutterVideoTexture *video_texture)
+{
+ GError *error;
- g_error_free (error);
- g_free (debug);
- break;
- }
- case GST_MESSAGE_TAG:
- {
- GstTagList *tag_list, *result;
- GstElementFactory *f;
+ error = NULL;
+ gst_message_parse_error (message, &error, NULL);
+
+ g_signal_emit_by_name (CLUTTER_MEDIA(video_texture), "error", error);
- gst_message_parse_tag (message, &tag_list);
+ g_error_free (error);
+}
- CLUTTER_DBG ("Tags: %p", tag_list);
+static void
+bus_message_eos_cb (GstBus *bus,
+ GstMessage *message,
+ ClutterVideoTexture *video_texture)
+{
+ g_object_notify (G_OBJECT (video_texture), "position");
- /* all tags */
- result = gst_tag_list_merge (priv->tagcache,
- tag_list,
- GST_TAG_MERGE_KEEP);
+ g_signal_emit_by_name (CLUTTER_MEDIA(video_texture), "eos");
+}
- if (priv->tagcache)
- gst_tag_list_free (priv->tagcache);
- priv->tagcache = result;
-
- /* media-type-specific tags */
- if (GST_IS_ELEMENT (message->src) &&
- (f = gst_element_get_factory (GST_ELEMENT (message->src))))
- {
- const gchar *klass = gst_element_factory_get_klass (f);
- GstTagList **cache = NULL;
-
- if (g_strrstr (klass, "Video"))
- {
- cache = &priv->videotags;
- }
- else if (g_strrstr (klass, "Audio"))
- {
- cache = &priv->audiotags;
- }
-
- if (cache)
- {
- result = gst_tag_list_merge (*cache, tag_list,
- GST_TAG_MERGE_KEEP);
- if (*cache)
- gst_tag_list_free (*cache);
- *cache = result;
- }
- }
-
- gst_tag_list_free (tag_list);
- g_signal_emit (video_texture, cvt_signals[SIGNAL_GOT_METADATA], 0);
- break;
- }
- case GST_MESSAGE_EOS:
- CLUTTER_DBG ("GST_MESSAGE_EOS");
+static void
+bus_message_tag_cb (GstBus *bus,
+ GstMessage *message,
+ ClutterVideoTexture *video_texture)
+{
+ GstTagList *tag_list;
- if (priv->eos_id == 0)
- priv->eos_id = g_idle_add (signal_eos_delayed, video_texture);
- break;
- case GST_MESSAGE_BUFFERING:
- {
- gint percent = 0;
- gst_structure_get_int (message->structure, "buffer-percent", &percent);
+ gst_message_parse_tag (message, &tag_list);
- CLUTTER_DBG ("Buffering message (%u%%)", percent);
+ g_signal_emit_by_name (CLUTTER_MEDIA(video_texture),
+ "metadata-available",
+ tag_list);
+
+ gst_tag_list_free (tag_list);
+}
- g_signal_emit (video_texture,
- cvt_signals[SIGNAL_BUFFERING],
- 0,
- percent);
- break;
- }
+static void
+bus_message_buffering_cb (GstBus *bus,
+ GstMessage *message,
+ ClutterVideoTexture *video_texture)
+{
+ const GstStructure *str;
+
+ str = gst_message_get_structure (message);
+ if (!str)
+ return;
- case GST_MESSAGE_APPLICATION:
- handle_application_message (video_texture, message);
- break;
+ if (!gst_structure_get_int (str,
+ "buffer-percent",
+ &video_texture->priv->buffer_percent))
+ return;
+
+ g_object_notify (G_OBJECT (video_texture), "buffer-percent");
+}
- case GST_MESSAGE_STATE_CHANGED:
- {
- GstState old_state, new_state;
- gchar *src_name;
+static void
+bus_message_duration_cb (GstBus *bus,
+ GstMessage *message,
+ ClutterVideoTexture *video_texture)
+{
+ GstFormat format;
+ gint64 duration;
- CLUTTER_DBG ("GST_MESSAGE_STATE_CHANGED");
+ gst_message_parse_duration (message,
+ &format,
+ &duration);
- gst_message_parse_state_changed (message,
- &old_state, &new_state, NULL);
+ if (format != GST_FORMAT_TIME)
+ return;
+
+ video_texture->priv->duration = duration / GST_SECOND;
- if (old_state == new_state)
- break;
+ g_object_notify (G_OBJECT (video_texture), "duration");
+}
- /* we only care about playbin (pipeline) state changes */
- if (GST_MESSAGE_SRC (message) != GST_OBJECT (priv->play))
- break;
+static void
+bus_message_element_cb (GstBus *bus,
+ GstMessage *message,
+ ClutterVideoTexture *video_texture)
+{
+ const GstStructure *str;
- src_name = gst_object_get_name (message->src);
+ str = gst_message_get_structure (message);
+ if (!str)
+ return;
+}
- CLUTTER_DBG ("%s changed state from %s to %s", src_name,
- gst_element_state_get_name (old_state),
- gst_element_state_get_name (new_state));
+static void
+bus_message_state_change_cb (GstBus *bus,
+ GstMessage *message,
+ ClutterVideoTexture *video_texture)
+{
+ gpointer src;
+ GstState old_state, new_state;
- g_free (src_name);
+ src = GST_MESSAGE_SRC (message);
+
+ if (src != video_texture->priv->playbin)
+ return;
- if (new_state <= GST_STATE_PAUSED)
- {
- if (priv->update_id != 0)
- {
- CLUTTER_DBG ("removing tick timeout");
- g_source_remove (priv->update_id);
- priv->update_id = 0;
- }
- }
- else if (new_state > GST_STATE_PAUSED)
- {
- if (priv->update_id == 0)
- {
- CLUTTER_DBG ("starting tick timeout");
+ gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
- priv->update_id = g_timeout_add (200,
- (GSourceFunc) query_timeout,
- video_texture);
- }
+ 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 (video_texture->priv->playbin, query)) {
+ gst_query_parse_seeking (query,
+ NULL,
+ &video_texture->priv->can_seek,
+ NULL,
+ NULL);
+ } else {
+ /**
+ * Could not query for ability to seek. Determine
+ * using URI.
+ **/
+
+ if (g_str_has_prefix (video_texture->priv->uri,
+ "http://")) {
+ video_texture->priv->can_seek = FALSE;
+ } else {
+ video_texture->priv->can_seek = TRUE;
}
-
- if (old_state == GST_STATE_READY && new_state == GST_STATE_PAUSED)
- {
- parse_stream_info (video_texture);
- }
- else if (old_state == GST_STATE_PAUSED && new_state == GST_STATE_READY)
+ }
+
+ gst_query_unref (query);
+
+ g_object_notify (G_OBJECT (video_texture), "can-seek");
+
+ /**
+ * Determine the duration.
+ **/
+ query = gst_query_new_duration (GST_FORMAT_TIME);
+
+ if (gst_element_query (video_texture->priv->playbin, query))
{
- priv->has_video = FALSE;
- priv->has_audio = FALSE;
-
- /* clean metadata cache */
- if (priv->tagcache)
- {
- gst_tag_list_free (priv->tagcache);
- priv->tagcache = NULL;
- }
-
- if (priv->audiotags)
- {
- gst_tag_list_free (priv->audiotags);
- priv->audiotags = NULL;
- }
-
- if (priv->videotags)
- {
- gst_tag_list_free (priv->videotags);
- priv->videotags = NULL;
- }
+ gint64 duration;
- priv->video_width = 0;
- priv->video_height = 0;
- }
- break;
- }
-
- case GST_MESSAGE_ELEMENT:
- handle_element_message (video_texture, message);
- break;
-
- case GST_MESSAGE_DURATION:
- {
- CLUTTER_DBG ("GST_MESSAGE_DURATION");
- /* force _get_stream_length() to do new duration query */
- priv->stream_length = 0;
- if (clutter_video_texture_get_stream_length (video_texture) == 0)
- CLUTTER_DBG ("Failed to query duration after DURATION message?!");
- break;
- }
-
- case GST_MESSAGE_CLOCK_PROVIDE:
- case GST_MESSAGE_CLOCK_LOST:
- case GST_MESSAGE_NEW_CLOCK:
- case GST_MESSAGE_STATE_DIRTY:
- break;
- default:
- CLUTTER_DBG ("Unhandled message of type '%s' (0x%x)",
- gst_message_type_get_name (msg_type), msg_type);
- break;
- }
-}
-
-static void
-got_time_tick (GstElement *play,
- gint64 time_nanos,
- ClutterVideoTexture *video_texture)
-{
- gboolean seekable;
- ClutterVideoTexturePrivate *priv;
+ gst_query_parse_duration (query, NULL, &duration);
- g_return_if_fail (video_texture != NULL);
- g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE(video_texture));
-
- priv = video_texture->priv;
-
- priv->current_time_nanos = time_nanos;
- priv->current_time = (gint64) time_nanos / GST_MSECOND;
+ video_texture->priv->duration = duration / GST_SECOND;
+
+ g_object_notify (G_OBJECT (video_texture), "duration");
+ }
- if (priv->stream_length == 0)
- {
- priv->current_position = 0;
- seekable = clutter_video_texture_is_seekable (video_texture);
- }
- else
- {
- priv->current_position =
- (gfloat) priv->current_time / priv->stream_length;
- seekable = TRUE;
+ gst_query_unref (query);
}
-
- g_signal_emit (video_texture,
- cvt_signals[SIGNAL_TICK],
- 0,
- priv->current_time,
- priv->stream_length,
- priv->current_position,
- seekable);
}
-static void
-playbin_got_source (GObject *play,
- GParamSpec *pspec,
- ClutterVideoTexture *video_texture)
-{
- /* Called via notify::source on playbin */
-
- ClutterVideoTexturePrivate *priv;
- GObject *source = NULL;
-
- priv = video_texture->priv;
-
- if (priv->tagcache)
- {
- gst_tag_list_free (priv->tagcache);
- priv->tagcache = NULL;
- }
-
- if (priv->audiotags)
- {
- gst_tag_list_free (priv->audiotags);
- priv->audiotags = NULL;
- }
-
- if (priv->videotags)
- {
- gst_tag_list_free (priv->videotags);
- priv->videotags = NULL;
- }
-
- g_object_get (play, "source", &source, NULL);
-
- if (!source)
- return;
-
- g_object_unref (source);
-}
-
-static void
-playbin_stream_info_set (GObject *obj,
- GParamSpec *pspec,
- ClutterVideoTexture *video_texture)
-{
- ClutterVideoTexturePrivate *priv;
- GstMessage *msg;
-
- priv = video_texture->priv;
-
- parse_stream_info (video_texture);
-
- msg = gst_message_new_application (GST_OBJECT (priv->play),
- gst_structure_new ("notify-streaminfo",
- NULL));
- gst_element_post_message (priv->play, msg);
-}
-
-
static gboolean
-poll_for_state_change_full (ClutterVideoTexture *video_texture,
- GstElement *element,
- GstState state,
- GError **error,
- gint64 timeout)
+tick_timeout (ClutterVideoTexture *video_texture)
{
- GstBus *bus;
- GstMessageType events, saved_events;
- ClutterVideoTexturePrivate *priv;
-
- priv = video_texture->priv;
- bus = gst_element_get_bus (element);
- saved_events = priv->ignore_messages_mask;
-
- events = GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS;
-
- if (element != NULL && element == priv->play)
- {
- /* we do want the main handler to process state changed messages for
- * playbin as well, otherwise it won't hook up the timeout etc. */
- priv->ignore_messages_mask |= (events ^ GST_MESSAGE_STATE_CHANGED);
- }
- else
- priv->ignore_messages_mask |= events;
-
- while (TRUE)
- {
- GstMessage *message;
- GstElement *src;
-
- message = gst_bus_poll (bus, events, timeout);
-
- if (!message)
- goto timed_out;
-
- src = (GstElement*)GST_MESSAGE_SRC (message);
-
- switch (GST_MESSAGE_TYPE (message))
- {
- case GST_MESSAGE_STATE_CHANGED:
- {
- GstState old, new, pending;
-
- if (src == element)
- {
- gst_message_parse_state_changed (message,
- &old, &new, &pending);
- if (new == state)
- {
- gst_message_unref (message);
- goto success;
- }
- }
- }
- break;
- case GST_MESSAGE_ERROR:
- {
- gchar *debug = NULL;
- GError *gsterror = NULL;
-
- gst_message_parse_error (message, &gsterror, &debug);
-
- g_warning ("Error: %s (%s)", gsterror->message, debug);
-
- gst_message_unref (message);
- g_error_free (gsterror);
- g_free (debug);
- goto error;
- }
- break;
- case GST_MESSAGE_EOS:
- g_set_error (error, CLUTTER_VIDEO_TEXTURE_ERROR,
- CLUTTER_VIDEO_TEXTURE_ERROR_FILE_GENERIC,
- "Media file could not be played.");
- gst_message_unref (message);
- goto error;
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- gst_message_unref (message);
- }
-
- g_assert_not_reached ();
-
-success:
- /* state change succeeded */
- CLUTTER_DBG ("state change to %s succeeded",
- gst_element_state_get_name (state));
-
- priv->ignore_messages_mask = saved_events;
- return TRUE;
+ g_object_notify (G_OBJECT (video_texture), "position");
-timed_out:
- /* it's taking a long time to open -- just tell totem it was ok, this allows
- * the user to stop the loading process with the normal stop button */
- CLUTTER_DBG ("state change to %s timed out, returning success and handling "
- "errors asynchroneously", gst_element_state_get_name (state));
- priv->ignore_messages_mask = saved_events;
return TRUE;
-
-error:
- CLUTTER_DBG ("error while waiting for state change to %s: %s",
- gst_element_state_get_name (state),
- (error && *error) ? (*error)->message : "unknown");
- priv->ignore_messages_mask = saved_events;
- return FALSE;
-}
-
-static gboolean
-poll_for_state_change (ClutterVideoTexture *video_texture,
- GstElement *element,
- GstState state,
- GError **error)
-{
- return poll_for_state_change_full (video_texture,
- element,
- state,
- error,
- GST_SECOND/4 );
}
static void
GstPad *pad,
gpointer user_data)
{
-
GstStructure *structure;
int width, height;
GdkPixbuf *pixb;
(3 * width + 3) &~ 3,
NULL,
NULL);
-
+
if (pixb)
{
clutter_texture_set_pixbuf (CLUTTER_TEXTURE(user_data), pixb);
}
}
-static void
-clutter_video_texture_finalize (GObject *object)
-{
- ClutterVideoTexture *self;
- ClutterVideoTexturePrivate *priv;
-
- self = CLUTTER_VIDEO_TEXTURE(object);
- priv = self->priv;
-
- if (priv->bus)
- {
- /* make bus drop all messages to make sure none of our callbacks is ever
- * called again (main loop might be run again to display error dialog) */
- gst_bus_set_flushing (priv->bus, TRUE);
-
- if (priv->sig_bus_async)
- g_signal_handler_disconnect (priv->bus, priv->sig_bus_async);
-
- gst_object_unref (priv->bus);
- priv->bus = NULL;
- }
-
- if (priv->mrl)
- g_free (priv->mrl);
- priv->mrl = NULL;
-
- if (priv->play != NULL && GST_IS_ELEMENT (priv->play))
- {
- gst_element_set_state (priv->play, GST_STATE_NULL);
- gst_object_unref (priv->play);
- priv->play = NULL;
- }
-
- if (priv->update_id)
- {
- g_source_remove (priv->update_id);
- priv->update_id = 0;
- }
-
- if (priv->tagcache)
- {
- gst_tag_list_free (priv->tagcache);
- priv->tagcache = NULL;
- }
-
- if (priv->audiotags)
- {
- gst_tag_list_free (priv->audiotags);
- priv->audiotags = NULL;
- }
-
- if (priv->videotags)
- {
- gst_tag_list_free (priv->videotags);
- priv->videotags = NULL;
- }
-
- if (priv->eos_id != 0)
- g_source_remove (priv->eos_id);
-
- g_free (priv);
-
- self->priv = NULL;
-
- G_OBJECT_CLASS (clutter_video_texture_parent_class)->finalize (object);
-}
-
-static void
-clutter_video_texture_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- switch (property_id)
- {
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- }
-}
-
-static void
-clutter_video_texture_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ClutterVideoTexture *video_texture;
-
- video_texture = CLUTTER_VIDEO_TEXTURE (object);
-
- switch (property_id)
- {
- case PROP_POSITION:
- g_value_set_int64 (value,
- clutter_video_texture_get_position (video_texture));
- break;
- case PROP_STREAM_LENGTH:
- g_value_set_int64 (value,
- clutter_video_texture_get_stream_length (video_texture));
- break;
- case PROP_PLAYING:
- g_value_set_boolean (value,
- clutter_video_texture_is_playing (video_texture));
- break;
- case PROP_SEEKABLE:
- g_value_set_boolean (value,
- clutter_video_texture_is_seekable (video_texture));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- }
-}
-
-
-static void
-clutter_video_texture_class_init (ClutterVideoTextureClass *klass)
-{
- GObjectClass *object_class;
- ClutterElementClass *element_class;
-
- object_class = (GObjectClass*)klass;
- element_class = (ClutterElementClass*)klass;
-
- object_class->finalize = clutter_video_texture_finalize;
- object_class->set_property = clutter_video_texture_set_property;
- object_class->get_property = clutter_video_texture_get_property;
-
- /* Properties */
- g_object_class_install_property (object_class, PROP_POSITION,
- g_param_spec_int ("position", NULL, NULL,
- 0, G_MAXINT, 0,
- G_PARAM_READABLE));
- g_object_class_install_property (object_class, PROP_STREAM_LENGTH,
- g_param_spec_int64 ("stream_length", NULL,
- NULL, 0, G_MAXINT64, 0,
- G_PARAM_READABLE));
- g_object_class_install_property (object_class, PROP_PLAYING,
- g_param_spec_boolean ("playing", NULL,
- NULL, FALSE,
- G_PARAM_READABLE));
- g_object_class_install_property (object_class, PROP_SEEKABLE,
- g_param_spec_boolean ("seekable", NULL,
- NULL, FALSE,
- G_PARAM_READABLE));
-
- /* Signals */
- cvt_signals[SIGNAL_ERROR] =
- g_signal_new ("error",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterVideoTextureClass, error),
- NULL, NULL,
- clutter_marshal_VOID__STRING_BOOLEAN_BOOLEAN,
- G_TYPE_NONE, 3, G_TYPE_STRING,
- G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
-
- cvt_signals[SIGNAL_EOS] =
- g_signal_new ("eos",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterVideoTextureClass, eos),
- NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
- cvt_signals[SIGNAL_GOT_METADATA] =
- g_signal_new ("got-metadata",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterVideoTextureClass, got_metadata),
- NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
- cvt_signals[SIGNAL_REDIRECT] =
- g_signal_new ("got-redirect",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterVideoTextureClass, got_redirect),
- NULL, NULL, g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE, 1, G_TYPE_STRING);
-
- cvt_signals[SIGNAL_TITLE_CHANGE] =
- g_signal_new ("title-change",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterVideoTextureClass, title_change),
- NULL, NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE, 1, G_TYPE_STRING);
-
- cvt_signals[SIGNAL_CHANNELS_CHANGE] =
- g_signal_new ("channels-change",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterVideoTextureClass, channels_change),
- NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
- cvt_signals[SIGNAL_TICK] =
- g_signal_new ("tick",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterVideoTextureClass, tick),
- NULL, NULL,
- clutter_marshal_VOID__INT64_INT64_FLOAT_BOOLEAN,
- G_TYPE_NONE, 4, G_TYPE_INT64, G_TYPE_INT64, G_TYPE_FLOAT,
- G_TYPE_BOOLEAN);
-
- cvt_signals[SIGNAL_BUFFERING] =
- g_signal_new ("buffering",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterVideoTextureClass, buffering),
- NULL, NULL,
- g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
-
- cvt_signals[SIGNAL_SPEED_WARNING] =
- g_signal_new ("speed-warning",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterVideoTextureClass, speed_warning),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
-}
-
-
-static void
-clutter_video_texture_init (ClutterVideoTexture *video_texture)
+static gboolean
+lay_pipeline (ClutterVideoTexture *video_texture)
{
ClutterVideoTexturePrivate *priv;
- GstElement *audio_sink, *video_sink, *bin, *capsfilter;
- GstCaps *filtercaps;
- GstPad *ghost_pad;
+ GstElement *audio_sink = NULL;
+ GstElement *video_sink, *video_bin, *video_capsfilter;
+ GstCaps *video_filtercaps;
+ GstPad *video_ghost_pad;
- priv = g_new0 (ClutterVideoTexturePrivate, 1);
- video_texture->priv = priv;
+ priv = video_texture->priv;
- priv->ratio_type = CLUTTER_VIDEO_TEXTURE_AUTO;
+ priv->playbin = gst_element_factory_make ("playbin", "playbin");
- priv->play = gst_element_factory_make ("playbin", "play");
-
- if (!priv->play)
+ if (!priv->playbin)
{
- g_warning ("Could not create element 'playbin'");
- return;
+ g_warning ("Unable to create playbin GST element.");
+ return FALSE;
}
- priv->bus = gst_element_get_bus (priv->play);
- gst_bus_add_signal_watch (priv->bus);
- priv->sig_bus_async = g_signal_connect (priv->bus,
- "message",
- G_CALLBACK (bus_message_cb),
- video_texture);
-
audio_sink = gst_element_factory_make ("gconfaudiosink", "audio-sink");
-
- if (audio_sink == NULL)
+ if (!audio_sink)
{
- g_warning ("Could not create element 'gconfaudiosink' trying autosink");
audio_sink = gst_element_factory_make ("autoaudiosink", "audio-sink");
-
- if (audio_sink == NULL)
+ if (!audio_sink)
{
- g_warning ("Could not create element 'autoaudiosink' "
- "trying fakesink");
- audio_sink = gst_element_factory_make ("fakesink",
- "audio-fake-sink");
- if (audio_sink == NULL)
- {
- g_warning ("Could not create element 'fakesink' for audio, giving up. ");
- }
+ audio_sink = gst_element_factory_make ("alsasink", "audio-sink");
+ g_warning ("Could not create a GST audio_sink. "
+ "Audio unavailable.");
+
+ if (!audio_sink) /* Need to bother ? */
+ audio_sink = gst_element_factory_make ("fakesink", "audio-sink");
}
}
-
- priv->audio_sink = audio_sink;
video_sink = gst_element_factory_make ("fakesink", "fakesink");
if (video_sink == NULL)
{
g_warning ("Could not create element 'fakesink' for video playback");
- return;
+ priv->playbin = NULL;
+ return FALSE;
}
- bin = gst_bin_new ("video-bin");
+ video_bin = gst_bin_new ("video-bin");
- capsfilter = gst_element_factory_make ("capsfilter", "vfilter");
+ video_capsfilter = gst_element_factory_make ("capsfilter",
+ "video-capsfilter");
- filtercaps
+ video_filtercaps
= gst_caps_new_simple("video/x-raw-rgb",
"bpp", G_TYPE_INT, 24,
"depth", G_TYPE_INT, 24,
"endianness", G_TYPE_INT, G_BIG_ENDIAN,
- "red_mask", G_TYPE_INT, 0xff0000 /* >> 8 for 24bpp */,
+ /* >> 8 for 24bpp */
+ "red_mask", G_TYPE_INT, 0xff0000,
"green_mask", G_TYPE_INT, 0xff00,
"blue_mask", G_TYPE_INT, 0xff,
"width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
0, 1, G_MAXINT, 1,
NULL);
- g_object_set(G_OBJECT(capsfilter), "caps", filtercaps, NULL);
+ g_object_set(G_OBJECT(video_capsfilter),
+ "caps", video_filtercaps,
+ NULL);
- gst_bin_add(GST_BIN(bin), capsfilter);
- gst_bin_add(GST_BIN(bin), video_sink);
+ gst_bin_add(GST_BIN(video_bin), video_capsfilter);
+ gst_bin_add(GST_BIN(video_bin), video_sink);
- gst_element_link (capsfilter, video_sink);
+ gst_element_link (video_capsfilter, video_sink);
- ghost_pad = gst_ghost_pad_new ("sink",
- gst_element_get_pad (capsfilter, "sink"));
-
- gst_element_add_pad (bin, ghost_pad);
+ video_ghost_pad = gst_ghost_pad_new ("sink",
+ gst_element_get_pad (video_capsfilter,
+ "sink"));
+ gst_element_add_pad (video_bin, video_ghost_pad);
g_object_set (G_OBJECT(video_sink),
"signal-handoffs", TRUE,
"sync", TRUE,
NULL);
- g_signal_connect(G_OBJECT (video_sink), "handoff",
- G_CALLBACK(fakesink_handoff_cb), video_texture);
-
- priv->video_sink = bin;
-
- if (priv->video_sink)
- g_object_set (priv->play, "video-sink", bin, NULL);
-
- if (priv->audio_sink)
- g_object_set (priv->play, "audio-sink", audio_sink, NULL);
-
- g_signal_connect (priv->play, "notify::source",
- G_CALLBACK (playbin_got_source), video_texture);
- g_signal_connect (priv->play, "notify::stream-info",
- G_CALLBACK (playbin_stream_info_set), video_texture);
- return;
-}
-
-ClutterElement*
-clutter_video_texture_new (void)
-{
- ClutterVideoTexture *video_texture;
-
- video_texture = g_object_new (CLUTTER_TYPE_VIDEO_TEXTURE,
- "tiled", FALSE,
- "pixel-format", GL_RGB,
- NULL);
-
- return CLUTTER_ELEMENT(video_texture);
-}
-
-gboolean
-clutter_video_texture_open (ClutterVideoTexture *video_texture,
- const gchar *mrl,
- const gchar *subtitle_uri,
- GError **error)
-{
- ClutterVideoTexturePrivate *priv;
- gboolean ret;
-
- priv = video_texture->priv;
-
- g_return_val_if_fail (video_texture != NULL, FALSE);
- g_return_val_if_fail (mrl != NULL, FALSE);
- g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE(video_texture), FALSE);
- g_return_val_if_fail (priv->play != NULL, FALSE);
-
- if (priv->mrl && strcmp (priv->mrl, mrl) == 0)
- return TRUE;
-
- /* this allows non-URI type of files in the thumbnailer and so on */
- if (priv->mrl)
- g_free (priv->mrl);
-
- if (mrl[0] == '/')
- {
- priv->mrl = g_strdup_printf ("file://%s", mrl);
- }
- else
- {
- if (strchr (mrl, ':'))
- {
- priv->mrl = g_strdup (mrl);
- }
- else
- {
- gchar *cur_dir = g_get_current_dir ();
- if (!cur_dir)
- {
- g_set_error (error, CLUTTER_VIDEO_TEXTURE_ERROR,
- CLUTTER_VIDEO_TEXTURE_ERROR_GENERIC,
- "Failed to retrieve working directory");
- return FALSE;
- }
- priv->mrl = g_strdup_printf ("file://%s/%s", cur_dir, mrl);
- g_free (cur_dir);
- }
- }
-
- priv->got_redirect = FALSE;
- priv->has_video = FALSE;
- priv->has_audio = FALSE;
- priv->stream_length = 0;
-
- if (g_strrstr (priv->mrl, "#subtitle:"))
- {
- gchar **uris;
- gchar *subtitle_uri;
-
- uris = g_strsplit (priv->mrl, "#subtitle:", 2);
- /* Try to fix subtitle uri if needed */
- if (uris[1][0] == '/')
- {
- subtitle_uri = g_strdup_printf ("file://%s", uris[1]);
- }
- else
- {
- if (strchr (uris[1], ':'))
- {
- subtitle_uri = g_strdup (uris[1]);
- }
- else
- {
- gchar *cur_dir = g_get_current_dir ();
- if (!cur_dir)
- {
- g_set_error (error, CLUTTER_VIDEO_TEXTURE_ERROR,
- CLUTTER_VIDEO_TEXTURE_ERROR_GENERIC,
- "Failed to retrieve working directory");
- return FALSE;
- }
-
- subtitle_uri = g_strdup_printf ("file://%s/%s",
- cur_dir, uris[1]);
- g_free (cur_dir);
- }
- }
-
- g_object_set (priv->play,
- "uri", priv->mrl,
- "suburi", subtitle_uri,
- NULL);
- g_free (subtitle_uri);
- g_strfreev (uris);
- }
- else
- {
- g_object_set (priv->play,
- "uri", priv->mrl,
- "suburi", subtitle_uri,
- NULL);
- }
-
- gst_element_set_state (priv->play, GST_STATE_PAUSED);
-
- ret = poll_for_state_change (video_texture,
- priv->play,
- GST_STATE_PAUSED,
- NULL);
-
- if (!ret)
- {
- priv->ignore_messages_mask |= GST_MESSAGE_ERROR;
- stop_play_pipeline (video_texture);
- g_free (priv->mrl);
- priv->mrl = NULL;
- }
- else
- g_signal_emit (video_texture, cvt_signals[SIGNAL_CHANNELS_CHANGE], 0);
-
- return ret;
-}
-
-gboolean
-clutter_video_texture_play (ClutterVideoTexture *video_texture,
- GError ** error)
-{
- ClutterVideoTexturePrivate *priv;
- gboolean ret;
-
- priv = video_texture->priv;
-
- g_return_val_if_fail (video_texture != NULL, FALSE);
- g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE(video_texture), FALSE);
- g_return_val_if_fail (priv->play != NULL, FALSE);
-
- gst_element_set_state (priv->play, GST_STATE_PLAYING);
-
- ret = poll_for_state_change (video_texture,
- priv->play,
- GST_STATE_PLAYING,
- error);
- return ret;
-}
-
-void
-clutter_video_texture_pause (ClutterVideoTexture *video_texture)
-{
- g_return_if_fail (video_texture != NULL);
- g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
- g_return_if_fail (GST_IS_ELEMENT (video_texture->priv->play));
-
- CLUTTER_DBG ("Pausing");
-
- gst_element_set_state (GST_ELEMENT (video_texture->priv->play),
- GST_STATE_PAUSED);
-}
-
-
-gboolean
-clutter_video_texture_can_direct_seek (ClutterVideoTexture *video_texture)
-{
- g_return_val_if_fail (video_texture != NULL, FALSE);
- g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
- g_return_val_if_fail (GST_IS_ELEMENT (video_texture->priv->play), FALSE);
-
- if (!video_texture->priv->mrl)
- return FALSE;
-
- /* (instant seeking only make sense with video, hence no cdda:// here) */
- if (g_str_has_prefix (video_texture->priv->mrl, "file://") ||
- g_str_has_prefix (video_texture->priv->mrl, "dvd://") ||
- g_str_has_prefix (video_texture->priv->mrl, "vcd://"))
- return TRUE;
-
- return FALSE;
-}
-
-gboolean
-clutter_video_texture_seek_time (ClutterVideoTexture *video_texture,
- gint64 time,
- GError **gerror)
-{
- g_return_val_if_fail (video_texture != NULL, FALSE);
- g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
- g_return_val_if_fail (GST_IS_ELEMENT (video_texture->priv->play), FALSE);
-
- got_time_tick (video_texture->priv->play, time * GST_MSECOND, video_texture);
-
- gst_element_seek (video_texture->priv->play,
- 1.0,
- GST_FORMAT_TIME,
- GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT,
- GST_SEEK_TYPE_SET,
- time * GST_MSECOND,
- GST_SEEK_TYPE_NONE,
- GST_CLOCK_TIME_NONE);
-
- gst_element_get_state (video_texture->priv->play,
- NULL, NULL, 100 * GST_MSECOND);
- return TRUE;
-}
-
-gboolean
-clutter_video_texture_seek (ClutterVideoTexture *video_texture,
- float position,
- GError **error)
-{
- gint64 seek_time, length_nanos;
+ g_signal_connect(G_OBJECT (video_sink),
+ "handoff",
+ G_CALLBACK(fakesink_handoff_cb),
+ video_texture);
- g_return_val_if_fail (video_texture != NULL, FALSE);
- g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
- g_return_val_if_fail (GST_IS_ELEMENT (video_texture->priv->play), FALSE);
-
- length_nanos = (gint64) (video_texture->priv->stream_length * GST_MSECOND);
- seek_time = (gint64) (length_nanos * position);
-
- return clutter_video_texture_seek_time (video_texture,
- seek_time / GST_MSECOND, error);
-}
-
-static void
-stop_play_pipeline (ClutterVideoTexture *video_texture)
-{
- GstElement *playbin = video_texture->priv->play;
- GstState current_state;
-
- /* first go to ready, that way our state change handler gets to see
- * our state change messages (before the bus goes to flushing) and
- * cleans up */
- gst_element_get_state (playbin, ¤t_state, NULL, 0);
-
- if (current_state > GST_STATE_READY)
- {
- GError *err = NULL;
-
- gst_element_set_state (playbin, GST_STATE_READY);
- poll_for_state_change_full (video_texture,
- playbin,
- GST_STATE_READY, &err, -1);
- if (err)
- g_error_free (err);
- }
-
- /* now finally go to null state */
- gst_element_set_state (playbin, GST_STATE_NULL);
- gst_element_get_state (playbin, NULL, NULL, -1);
-}
-
-void
-clutter_video_texture_stop (ClutterVideoTexture *video_texture)
-{
- g_return_if_fail (video_texture != NULL);
- g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
- g_return_if_fail (GST_IS_ELEMENT (video_texture->priv->play));
-
- stop_play_pipeline (video_texture);
-
- /* Reset position to 0 when stopping */
- got_time_tick (GST_ELEMENT (video_texture->priv->play), 0, video_texture);
-}
+ g_object_set (G_OBJECT (priv->playbin),
+ "video-sink", video_bin,
+ "audio-sink", audio_sink,
+ NULL);
-gboolean
-clutter_video_texture_can_set_volume (ClutterVideoTexture *video_texture)
-{
- g_return_val_if_fail (video_texture != NULL, FALSE);
- g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
- g_return_val_if_fail (GST_IS_ELEMENT (video_texture->priv->play), FALSE);
-
return TRUE;
}
-void
-clutter_video_texture_set_volume (ClutterVideoTexture *video_texture,
- int volume)
-{
- g_return_if_fail (video_texture != NULL);
- g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
- g_return_if_fail (GST_IS_ELEMENT (video_texture->priv->play));
-
- if (clutter_video_texture_can_set_volume (video_texture) != FALSE)
- {
- volume = CLAMP (volume, 0, 100);
- g_object_set (video_texture->priv->play, "volume",
- (gdouble) (1. * volume / 100), NULL);
- }
-}
-
-int
-clutter_video_texture_get_volume (ClutterVideoTexture *video_texture)
-{
- gdouble vol;
-
- g_return_val_if_fail (video_texture != NULL, -1);
- g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
- g_return_val_if_fail (GST_IS_ELEMENT (video_texture->priv->play), -1);
-
- g_object_get (G_OBJECT (video_texture->priv->play), "volume", &vol, NULL);
-
- return (gint) (vol * 100 + 0.5);
-}
-
-gint64
-clutter_video_texture_get_current_time (ClutterVideoTexture *video_texture)
-{
- g_return_val_if_fail (video_texture != NULL, -1);
- g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
-
- return video_texture->priv->current_time;
-}
-
-gint64
-clutter_video_texture_get_stream_length (ClutterVideoTexture *video_texture)
-{
- ClutterVideoTexturePrivate *priv;
-
- g_return_val_if_fail (video_texture != NULL, -1);
- g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
-
- priv = video_texture->priv;
-
- if (priv->stream_length == 0 && priv->play != NULL)
- {
- GstFormat fmt = GST_FORMAT_TIME;
- gint64 len = -1;
-
- if (gst_element_query_duration (priv->play, &fmt, &len) && len != -1)
- priv->stream_length = len / GST_MSECOND;
- }
-
- return priv->stream_length;
-}
-
-gboolean
-clutter_video_texture_is_playing (ClutterVideoTexture *video_texture)
-{
- GstState cur, pending;
-
- g_return_val_if_fail (video_texture != NULL, FALSE);
- g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
- g_return_val_if_fail (GST_IS_ELEMENT (video_texture->priv->play), FALSE);
-
- gst_element_get_state (video_texture->priv->play, &cur, &pending, 0);
-
- if (cur == GST_STATE_PLAYING || pending == GST_STATE_PLAYING)
- return TRUE;
-
- return FALSE;
-}
-
-gboolean
-clutter_video_texture_is_seekable (ClutterVideoTexture *video_texture)
-{
- gboolean res;
-
- g_return_val_if_fail (video_texture != NULL, FALSE);
- g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
- g_return_val_if_fail (GST_IS_ELEMENT (video_texture->priv->play), FALSE);
-
- if (video_texture->priv->stream_length == 0)
- res = (clutter_video_texture_get_stream_length (video_texture) > 0);
- else
- res = (video_texture->priv->stream_length > 0);
-
- return res;
-}
-
-float
-clutter_video_texture_get_position (ClutterVideoTexture *video_texture)
-{
- g_return_val_if_fail (video_texture != NULL, -1);
- g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
-
- return video_texture->priv->current_position;
-}
-
-void
-clutter_video_texture_set_aspect_ratio (ClutterVideoTexture *video_texture,
- ClutterVideoTextureAspectRatio ratio)
-{
- g_return_if_fail (video_texture != NULL);
- g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
-
- video_texture->priv->ratio_type = ratio;
- got_video_size (video_texture);
-}
-
-ClutterVideoTextureAspectRatio
-clutter_video_texture_get_aspect_ratio (ClutterVideoTexture *video_texture)
-{
- g_return_val_if_fail (video_texture != NULL, 0);
- g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), 0);
-
- return video_texture->priv->ratio_type;
-}
-
-/* Metadata */
-
-static const struct _metadata_map_info
-{
- ClutterVideoTextureMetadataType type;
- const gchar *str;
-} metadata_str_map[] = {
- { CLUTTER_INFO_TITLE, "title" },
- { CLUTTER_INFO_ARTIST, "artist" },
- { CLUTTER_INFO_YEAR, "year" },
- { CLUTTER_INFO_ALBUM, "album" },
- { CLUTTER_INFO_DURATION, "duration" },
- { CLUTTER_INFO_TRACK_NUMBER, "track-number" },
- { CLUTTER_INFO_HAS_VIDEO, "has-video" },
- { CLUTTER_INFO_DIMENSION_X, "dimension-x" },
- { CLUTTER_INFO_DIMENSION_Y, "dimension-y" },
- { CLUTTER_INFO_VIDEO_BITRATE,"video-bitrate" },
- { CLUTTER_INFO_VIDEO_CODEC, "video-codec" },
- { CLUTTER_INFO_FPS, "fps" },
- { CLUTTER_INFO_HAS_AUDIO, "has-audio" },
- { CLUTTER_INFO_AUDIO_BITRATE,"audio-bitrate" },
- { CLUTTER_INFO_AUDIO_CODEC, "audio-codec" }
-};
-
-static const gchar*
-get_metadata_type_name (ClutterVideoTextureMetadataType type)
-{
- guint i;
- for (i = 0; i < G_N_ELEMENTS (metadata_str_map); ++i)
- {
- if (metadata_str_map[i].type == type)
- return metadata_str_map[i].str;
- }
- return "unknown";
-}
-
static void
-get_metadata_string (ClutterVideoTexture *video_texture,
- ClutterVideoTextureMetadataType type,
- GValue *value)
+clutter_video_texture_init (ClutterVideoTexture *video_texture)
{
ClutterVideoTexturePrivate *priv;
- char *string = NULL;
- gboolean res = FALSE;
-
- priv = video_texture->priv;
+ GstBus *bus;
- g_value_init (value, G_TYPE_STRING);
+ priv = g_new0 (ClutterVideoTexturePrivate, 1);
+ video_texture->priv = priv;
- if (priv->play == NULL || priv->tagcache == NULL)
+ if (!lay_pipeline(video_texture))
{
- g_value_set_string (value, NULL);
+ g_warning("Failed to initiate suitable playback pipeline.");
return;
}
- switch (type)
- {
- case CLUTTER_INFO_TITLE:
- res = gst_tag_list_get_string_index (priv->tagcache,
- GST_TAG_TITLE, 0, &string);
- break;
- case CLUTTER_INFO_ARTIST:
- res = gst_tag_list_get_string_index (priv->tagcache,
- GST_TAG_ARTIST, 0, &string);
- break;
- case CLUTTER_INFO_YEAR:
- {
- GDate *date;
- if ((res = gst_tag_list_get_date (priv->tagcache,
- GST_TAG_DATE, &date)))
- {
- string = g_strdup_printf ("%d", g_date_get_year (date));
- g_date_free (date);
- }
- break;
- }
- case CLUTTER_INFO_ALBUM:
- res = gst_tag_list_get_string_index (priv->tagcache,
- GST_TAG_ALBUM, 0, &string);
- break;
- case CLUTTER_INFO_VIDEO_CODEC:
- res = gst_tag_list_get_string (priv->tagcache,
- GST_TAG_VIDEO_CODEC, &string);
- break;
- case CLUTTER_INFO_AUDIO_CODEC:
- res = gst_tag_list_get_string (priv->tagcache,
- GST_TAG_AUDIO_CODEC, &string);
- break;
- default:
- g_assert_not_reached ();
- }
+ bus = gst_pipeline_get_bus (GST_PIPELINE (priv->playbin));
- if (res)
- {
- g_value_take_string (value, string);
- CLUTTER_DBG ("%s = '%s'", get_metadata_type_name (type), string);
- }
- else
- g_value_set_string (value, NULL);
+ gst_bus_add_signal_watch (bus);
- return;
-}
+ g_signal_connect_object (bus,
+ "message::error",
+ G_CALLBACK (bus_message_error_cb),
+ video_texture,
+ 0);
-static void
-get_metadata_int (ClutterVideoTexture *video_texture,
- ClutterVideoTextureMetadataType type,
- GValue *value)
-{
- ClutterVideoTexturePrivate *priv;
- int integer = 0;
-
- priv = video_texture->priv;
-
- g_value_init (value, G_TYPE_INT);
-
- if (priv->play == NULL)
- {
- g_value_set_int (value, 0);
- return;
- }
-
- switch (type)
- {
- case CLUTTER_INFO_DURATION:
- integer = clutter_video_texture_get_stream_length (video_texture) / 1000;
- break;
- case CLUTTER_INFO_TRACK_NUMBER:
- if (!gst_tag_list_get_uint (priv->tagcache,
- GST_TAG_TRACK_NUMBER, (guint *) &integer))
- integer = 0;
- break;
- case CLUTTER_INFO_DIMENSION_X:
- integer = priv->video_width;
- break;
- case CLUTTER_INFO_DIMENSION_Y:
- integer = priv->video_height;
- break;
- case CLUTTER_INFO_FPS:
- if (priv->video_fps_d > 0)
- {
- /* Round up/down to the nearest integer framerate */
- integer = (priv->video_fps_n + priv->video_fps_d/2) /
- priv->video_fps_d;
- }
- else
- integer = 0;
- break;
- case CLUTTER_INFO_AUDIO_BITRATE:
- if (priv->audiotags == NULL)
- break;
- if (gst_tag_list_get_uint (priv->audiotags, GST_TAG_BITRATE,
- (guint *)&integer) ||
- gst_tag_list_get_uint (priv->audiotags, GST_TAG_NOMINAL_BITRATE,
- (guint *)&integer)) {
- integer /= 1000;
- }
- break;
- case CLUTTER_INFO_VIDEO_BITRATE:
- if (priv->videotags == NULL)
- break;
- if (gst_tag_list_get_uint (priv->videotags, GST_TAG_BITRATE,
- (guint *)&integer) ||
- gst_tag_list_get_uint (priv->videotags, GST_TAG_NOMINAL_BITRATE,
- (guint *)&integer)) {
- integer /= 1000;
- }
- break;
- default:
- g_assert_not_reached ();
- }
+ g_signal_connect_object (bus,
+ "message::eos",
+ G_CALLBACK (bus_message_eos_cb),
+ video_texture,
+ 0);
- g_value_set_int (value, integer);
- CLUTTER_DBG ("%s = %d", get_metadata_type_name (type), integer);
-
- return;
-}
+ g_signal_connect_object (bus,
+ "message::tag",
+ G_CALLBACK (bus_message_tag_cb),
+ video_texture,
+ 0);
-static void
-get_metadata_bool (ClutterVideoTexture *video_texture,
- ClutterVideoTextureMetadataType type,
- GValue *value)
-{
- ClutterVideoTexturePrivate *priv;
- gboolean boolean = FALSE;
+ g_signal_connect_object (bus,
+ "message::buffering",
+ G_CALLBACK (bus_message_buffering_cb),
+ video_texture,
+ 0);
- priv = video_texture->priv;
+ g_signal_connect_object (bus,
+ "message::duration",
+ G_CALLBACK (bus_message_duration_cb),
+ video_texture,
+ 0);
- g_value_init (value, G_TYPE_BOOLEAN);
+ g_signal_connect_object (bus,
+ "message::element",
+ G_CALLBACK (bus_message_element_cb),
+ video_texture,
+ 0);
- if (priv->play == NULL)
- {
- g_value_set_boolean (value, FALSE);
- return;
- }
+ g_signal_connect_object (bus,
+ "message::state-changed",
+ G_CALLBACK (bus_message_state_change_cb),
+ video_texture,
+ 0);
- switch (type)
- {
- case CLUTTER_INFO_HAS_VIDEO:
- boolean = priv->has_video;
- /* if properties dialog, show the metadata we
- * have even if we cannot decode the stream */
- if (!boolean
- && priv->tagcache != NULL
- && gst_structure_has_field ((GstStructure *) priv->tagcache,
- GST_TAG_VIDEO_CODEC))
- boolean = TRUE;
- break;
- case CLUTTER_INFO_HAS_AUDIO:
- boolean = priv->has_audio;
- /* if properties dialog, show the metadata we
- * have even if we cannot decode the stream */
- if (!boolean
- && priv->tagcache != NULL
- && gst_structure_has_field ((GstStructure *) priv->tagcache,
- GST_TAG_AUDIO_CODEC))
- boolean = TRUE;
- break;
- default:
- g_assert_not_reached ();
- }
+ gst_object_unref (GST_OBJECT (bus));
- g_value_set_boolean (value, boolean);
- CLUTTER_DBG ("%s = %s", get_metadata_type_name (type),
- (boolean) ? "yes" : "no");
return;
}
-void
-clutter_video_texture_get_metadata (ClutterVideoTexture *video_texture,
- ClutterVideoTextureMetadataType type,
- GValue *value)
+ClutterElement*
+clutter_video_texture_new (void)
{
- g_return_if_fail (video_texture != NULL);
- g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
- g_return_if_fail (GST_IS_ELEMENT (video_texture->priv->play));
+ ClutterVideoTexture *video_texture;
- switch (type)
- {
- case CLUTTER_INFO_TITLE:
- case CLUTTER_INFO_ARTIST:
- case CLUTTER_INFO_YEAR:
- case CLUTTER_INFO_ALBUM:
- case CLUTTER_INFO_VIDEO_CODEC:
- case CLUTTER_INFO_AUDIO_CODEC:
- get_metadata_string (video_texture, type, value);
- break;
- case CLUTTER_INFO_DURATION:
- case CLUTTER_INFO_DIMENSION_X:
- case CLUTTER_INFO_DIMENSION_Y:
- case CLUTTER_INFO_FPS:
- case CLUTTER_INFO_AUDIO_BITRATE:
- case CLUTTER_INFO_VIDEO_BITRATE:
- case CLUTTER_INFO_TRACK_NUMBER:
- get_metadata_int (video_texture, type, value);
- break;
- case CLUTTER_INFO_HAS_VIDEO:
- case CLUTTER_INFO_HAS_AUDIO:
- get_metadata_bool (video_texture, type, value);
- break;
- default:
- g_return_if_reached ();
- }
+ video_texture = g_object_new (CLUTTER_TYPE_VIDEO_TEXTURE,
+ "tiled", FALSE,
+ "pixel-format", GL_RGB,
+ NULL);
- return;
+ return CLUTTER_ELEMENT(video_texture);
}
+