summaryrefslogtreecommitdiff
path: root/clutter-gst/clutter-gst-auto-video-sink.c
diff options
context:
space:
mode:
authorLionel Landwerlin <llandwerlin@gmail.com>2013-07-22 13:31:52 +0100
committerLionel Landwerlin <llandwerlin@gmail.com>2013-07-22 13:31:52 +0100
commitc23cdfc584b2051c2962673b9078a5c92d9b30a8 (patch)
tree583b4936958193560c7ac3f06d419a7e47ff8f84 /clutter-gst/clutter-gst-auto-video-sink.c
parent8b12180346be221cf25216f884d3a8b9f069141f (diff)
downloadclutter-gst-c23cdfc584b2051c2962673b9078a5c92d9b30a8.tar.gz
remove ClutterGstActor now replaced by ClutterGstContent
Diffstat (limited to 'clutter-gst/clutter-gst-auto-video-sink.c')
-rw-r--r--clutter-gst/clutter-gst-auto-video-sink.c930
1 files changed, 190 insertions, 740 deletions
diff --git a/clutter-gst/clutter-gst-auto-video-sink.c b/clutter-gst/clutter-gst-auto-video-sink.c
index c434e9a..4f0fd57 100644
--- a/clutter-gst/clutter-gst-auto-video-sink.c
+++ b/clutter-gst/clutter-gst-auto-video-sink.c
@@ -1,816 +1,266 @@
-/*
- * Clutter-GStreamer.
- *
- * GStreamer integration library for Clutter.
- *
- * clutter-gst-auto-video-sink.c - GStreamer Auto Clutter Video Sink bin.
- *
- * Authored by Josep Torra <support@fluendo.com>
- *
- * Copyright (C) 2011 Fluendo, S.A.
- *
- * 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.
- */
+/* GStreamer
+ * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+ * (c) 2006 Jan Schmidt <thaytan@noraisin.net>
+ * (c) 2013 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-autovideosink
+ * @see_also: autoaudiosink, ximagesink, xvimagesink, sdlvideosink
+ *
+ * autovideosink is a video sink that automatically detects an appropriate
+ * video sink to use. It does so by scanning the registry for all elements
+ * that have <quote>Sink</quote> and <quote>Video</quote> in the class field
+ * of their element information, and also have a non-zero autoplugging rank.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 -v -m videotestsrc ! clutterautovideosink
+ * ]|
+ * </refsect2>
+ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
-#include <clutter/clutter.h>
+#include "clutter-gst-aspectratio.h"
#include "clutter-gst-auto-video-sink.h"
-#include "clutter-gst-private.h"
+#include "clutter-gst-util.h"
-GST_DEBUG_CATEGORY_EXTERN (clutter_gst_auto_video_sink_debug);
-#define GST_CAT_DEFAULT clutter_gst_auto_video_sink_debug
-
-static GstStaticPadTemplate sink_template_factory =
-GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS_ANY);
+#define DEFAULT_TS_OFFSET 0
+/* Properties */
enum
{
PROP_0,
- PROP_ACTOR,
- PROP_TS_OFFSET
+ PROP_TS_OFFSET,
+ PROP_CONTENT,
};
-#define DEFAULT_TS_OFFSET 0
-
-static gboolean clutter_gst_auto_video_sink_add (GstBin * bin,
- GstElement *element);
-static gboolean clutter_gst_auto_video_sink_remove (GstBin * bin,
- GstElement *element);
+static GstStateChangeReturn
+clutter_gst_auto_video_sink_change_state (GstElement *element,
+ GstStateChange transition);
+static void clutter_gst_auto_video_sink_dispose (ClutterGstAutoVideoSink *sink);
+static void clutter_gst_auto_video_sink_clear_kid (ClutterGstAutoVideoSink *sink);
+
+static void clutter_gst_auto_video_sink_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void clutter_gst_auto_video_sink_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+#define clutter_gst_auto_video_sink_parent_class parent_class
G_DEFINE_TYPE (ClutterGstAutoVideoSink,
- clutter_gst_auto_video_sink, GST_TYPE_BIN);
+ clutter_gst_auto_video_sink,
+ GST_TYPE_BIN)
-#define parent_class clutter_gst_auto_video_sink_parent_class
-
-typedef struct
-{
- const gchar *factory_name;
- GstElement *element;
- GstCaps *caps;
-} SinkElement;
-
-static GstCaps *
-_get_sink_caps (GstElement * sink)
-{
- GstPad *sinkpad;
- GstCaps *caps = NULL;
-
- /* try to activate */
- if (GST_STATE (sink) < GST_STATE_READY &&
- gst_element_set_state (sink, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE)
- {
- goto beach;
- }
-
- if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
- /* Got the sink pad, now let's see which caps will be accepted */
- caps = gst_pad_query_caps (sinkpad, NULL);
- }
- gst_object_unref (sinkpad);
-
-beach:
- return caps;
-}
-
-static SinkElement *
-_sink_element_create (GstElement * element)
-{
- SinkElement *se = NULL;
- GstCaps *caps = NULL;
-
- /* Check if the sink can be set to READY and recover it's caps */
- if (!(caps = _get_sink_caps (element))) {
- gst_element_set_state (element, GST_STATE_NULL);
- gst_object_unref (element);
- goto beach;
- }
-
- if ((se = g_new0 (SinkElement, 1))) {
- gst_object_ref_sink (element);
- se->element = element;
- se->caps = caps;
- } else {
- gst_caps_unref (caps);
- gst_object_unref (element);
- }
-
-beach:
- return se;
-}
+static GstStaticPadTemplate sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
static void
-_sink_element_free (gpointer data, gpointer user_data)
+clutter_gst_auto_video_sink_class_init (ClutterGstAutoVideoSinkClass *klass)
{
- SinkElement *se = (SinkElement *) data;
-
- gst_element_set_state (se->element, GST_STATE_NULL);
- gst_caps_unref (se->caps);
- gst_object_unref (se->element);
- g_free (se);
-}
-
-static gboolean
-_factory_filter (GstPluginFeature * feature, gpointer data)
-{
- const gchar *klass;
- guint rank;
-
- /* we only care about element factories */
- if (!GST_IS_ELEMENT_FACTORY (feature))
- return FALSE;
-
- /* video sinks */
- klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY (feature),
- GST_ELEMENT_METADATA_KLASS);
- if (!(strstr (klass, "Sink") && strstr (klass, "Video")))
- return FALSE;
-
- /* only select elements with autoplugging rank */
- rank = gst_plugin_feature_get_rank (feature);
- if (rank < GST_RANK_MARGINAL)
- return FALSE;
-
- return TRUE;
-}
-
-static gint
-_factories_compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
-{
- gint diff;
-
- diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
-
- if (diff != 0)
- return diff;
-
- return strcmp (gst_plugin_feature_get_name (f2),
- gst_plugin_feature_get_name (f1));
-}
-
-static GstElement *
-_create_element_with_pretty_name (ClutterGstAutoVideoSink * bin,
- GstElementFactory * factory)
-{
- GstElement *element;
- gchar *name, *marker;
-
- marker =
- g_strdup (gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
- if (g_str_has_suffix (marker, "sink"))
- marker[strlen (marker) - 4] = '\0';
- if (g_str_has_prefix (marker, "gst"))
- g_memmove (marker, marker + 3, strlen (marker + 3) + 1);
- name = g_strdup_printf ("%s-actual-sink-%s", GST_OBJECT_NAME (bin), marker);
- g_free (marker);
-
- element = gst_element_factory_create (factory, name);
- g_free (name);
-
- return element;
-}
-
-static inline gboolean
-_is_clutter_sink (GstElement * element)
-{
- GParamSpec *pspec;
-
- pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (element),
- "actor");
-
- if (pspec == NULL) {
- GST_DEBUG_OBJECT (element, "don't have an actor property");
- return FALSE;
- }
-
- if (CLUTTER_GST_TYPE_ACTOR == pspec->value_type ||
- g_type_is_a (pspec->value_type, CLUTTER_GST_TYPE_ACTOR)) {
- GST_DEBUG_OBJECT (element, "has an actor property");
- return TRUE;
- }
-
- GST_WARNING_OBJECT (element, "has actor property, but it's of type %s "
- "and we expected it to be of type CLUTTER_GST_TYPE_ACTOR",
- g_type_name (pspec->value_type));
-
- return FALSE;
-}
-
-static inline void
-_sinks_discover (ClutterGstAutoVideoSink * bin)
-{
- GstCaps *caps = gst_caps_new_empty ();
- GList *factories, *item;
-
- factories = gst_registry_feature_filter (gst_registry_get (),
- (GstPluginFeatureFilter) _factory_filter, FALSE, bin);
- factories = g_list_sort (factories, (GCompareFunc) _factories_compare_ranks);
-
- for (item = factories; item != NULL; item = item->next) {
- GstElementFactory *f = GST_ELEMENT_FACTORY (item->data);
- GstElement *el;
- SinkElement *se;
-
- if ((el = _create_element_with_pretty_name (bin, f))) {
- GST_DEBUG_OBJECT (bin, "Testing %s",
- gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (f)));
-
- /* Check for an actor property with CLUTTER_GST_TYPE_ACTOR type */
- if (!_is_clutter_sink (el)) {
- gst_object_unref (el);
- continue;
- }
- se = _sink_element_create (el);
- if (se) {
- GstCaps *caps_union = gst_caps_merge (caps, gst_caps_ref (se->caps));
- caps = caps_union;
- bin->sinks = g_slist_append (bin->sinks, se);
- GST_DEBUG_OBJECT (bin, "Added %s with caps %" GST_PTR_FORMAT,
- gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (f)), se->caps);
- } else {
- gst_object_unref (el);
- }
- }
- }
-
- if (!gst_caps_is_empty (caps)) {
- gst_caps_replace (&bin->video_caps, caps);
- GST_DEBUG_OBJECT (bin, "Supported caps %" GST_PTR_FORMAT, bin->video_caps);
- }
- gst_caps_unref (caps);
-}
-
-static inline void
-_sinks_destroy (ClutterGstAutoVideoSink * bin)
-{
- g_slist_foreach (bin->sinks, _sink_element_free, NULL);
- g_slist_free (bin->sinks);
- bin->sinks = NULL;
-}
-
-static inline GstElement *
-_sinks_find_sink_by_caps (ClutterGstAutoVideoSink * bin, GstCaps * caps)
-{
- GstElement *element = NULL;
- GSList *walk = bin->sinks;
-
- while (walk) {
- SinkElement *se = (SinkElement *) walk->data;
- if (se) {
- GstCaps *intersect = NULL;
-
- intersect = gst_caps_intersect (caps, se->caps);
- if (!gst_caps_is_empty (intersect)) {
- element = se->element;
- gst_caps_unref (intersect);
- GST_DEBUG_OBJECT (bin, "found sink %" GST_PTR_FORMAT, element);
- goto beach;
- }
- gst_caps_unref (intersect);
- }
- walk = g_slist_next (walk);
- }
-
-beach:
- return element;
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
+
+ gobject_class->dispose = (GObjectFinalizeFunc) clutter_gst_auto_video_sink_dispose;
+ gobject_class->set_property = clutter_gst_auto_video_sink_set_property;
+ gobject_class->get_property = clutter_gst_auto_video_sink_get_property;
+
+ eklass->change_state = GST_DEBUG_FUNCPTR (clutter_gst_auto_video_sink_change_state);
+
+ g_object_class_install_property (gobject_class,
+ PROP_TS_OFFSET,
+ g_param_spec_int64 ("ts-offset",
+ "TS Offset",
+ "Timestamp offset in nanoseconds",
+ G_MININT64,
+ G_MAXINT64,
+ DEFAULT_TS_OFFSET,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class,
+ PROP_CONTENT,
+ g_param_spec_object ("content",
+ "Clutter Content",
+ "Clutter Content",
+ CLUTTER_GST_TYPE_CONTENT,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_add_pad_template (eklass,
+ gst_static_pad_template_get (&sink_template));
+ gst_element_class_set_static_metadata (eklass, "Clutter Auto video sink",
+ "Sink/Video",
+ "Video sink using a Clutter as output",
+ "Lionel Landwerlin <lionel.g.landwerlin@linux.intel.com>");
}
static void
-clutter_gst_auto_video_sink_do_async_start (ClutterGstAutoVideoSink * bin)
+clutter_gst_auto_video_sink_dispose (ClutterGstAutoVideoSink *sink)
{
- GstMessage *message;
-
- if (!bin->need_async_start) {
- GST_DEBUG_OBJECT (bin, "no async_start needed");
- return;
- }
+ clutter_gst_auto_video_sink_clear_kid (sink);
- bin->async_pending = TRUE;
-
- GST_INFO_OBJECT (bin, "Sending async_start message");
- message = gst_message_new_async_start (GST_OBJECT_CAST (bin));
- GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST (bin), message);
+ G_OBJECT_CLASS (parent_class)->dispose ((GObject *) sink);
}
static void
-clutter_gst_auto_video_sink_do_async_done (ClutterGstAutoVideoSink * bin)
-{
- GstMessage *message;
-
- if (bin->async_pending) {
- GST_INFO_OBJECT (bin, "Sending async_done message");
- message = gst_message_new_async_done (GST_OBJECT_CAST (bin), FALSE);
- GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST (bin), message);
-
- bin->async_pending = FALSE;
- }
- bin->need_async_start = FALSE;
-}
-
-static gboolean
-clutter_gst_auto_video_sink_reconfigure (ClutterGstAutoVideoSink * bin,
- GstCaps * caps)
-{
- GstElement *sink;
- GstPad *sink_pad_target = NULL;
- gboolean ret = FALSE;
-
- GST_DEBUG_OBJECT (bin, "reconfigure the bin");
-
- sink = _sinks_find_sink_by_caps (bin, caps);
-
- if (sink && sink == bin->child) {
- GST_DEBUG_OBJECT (bin, "we already using that sink, done");
- ret = TRUE;
- goto beach;
- }
-
- if (bin->child) {
- /* Deactivate current child */
- GST_DEBUG_OBJECT (bin, "going to remove %" GST_PTR_FORMAT, bin->child);
- gst_ghost_pad_set_target (GST_GHOST_PAD (bin->sink_pad), NULL);
- gst_element_set_state (bin->child, GST_STATE_NULL);
- gst_bin_remove (GST_BIN (bin), bin->child);
- bin->child = NULL;
- }
-
- /* This might have failed */
- if (!sink) {
- GST_ELEMENT_ERROR (bin, LIBRARY, INIT,
- ("No usable video rendering element found."),
- ("Failed detecting a video sink for the requested" " caps."));
- goto beach;
- }
-
- /* Now we are ready to add the sink to bin */
- bin->child = gst_object_ref (sink);
- g_object_set (G_OBJECT(bin->child), "actor", bin->actor,
- "ts-offset", bin->ts_offset, NULL);
-
- GST_DEBUG_OBJECT (bin, "going to add %" GST_PTR_FORMAT, bin->child);
- /* Add our child */
- gst_bin_add (GST_BIN (bin), bin->child);
- /* Bring all elements to the bin's state */
- gst_element_sync_state_with_parent (bin->child);
- /* Get the child's sink pad */
- sink_pad_target = gst_element_get_static_pad (bin->child, "sink");
-
- /* Ghost the sink pad to the appropriate element */
- GST_DEBUG_OBJECT (sink_pad_target, "ghosting pad as bin sink pad");
- gst_ghost_pad_set_target (GST_GHOST_PAD (bin->sink_pad), sink_pad_target);
- gst_object_unref (sink_pad_target);
- ret = TRUE;
-beach:
- return ret;
-}
-
-static GstPadProbeReturn
-clutter_gst_auto_video_sink_sink_pad_blocked_cb (GstPad * pad,
- GstPadProbeInfo * info, gpointer user_data)
+clutter_gst_auto_video_sink_clear_kid (ClutterGstAutoVideoSink *sink)
{
- ClutterGstAutoVideoSink *bin = CLUTTER_GST_AUTO_VIDEO_SINK_CAST (user_data);
- GstCaps *caps = NULL;
-
- /* This only occurs when our bin is first initialised || stream changes */
- if (G_UNLIKELY (!bin->setup)) {
-
- caps = gst_pad_peer_query_caps (bin->sink_pad, NULL);
-
- if (G_UNLIKELY (!caps)) {
- GST_WARNING_OBJECT (bin, "no incoming caps defined, can't setup");
- goto beach;
- }
-
- if (G_UNLIKELY (gst_caps_is_empty (caps))) {
- GST_WARNING_OBJECT (bin, "caps empty, can't setup");
- goto beach;
- }
-
- GST_DEBUG_OBJECT (bin, "incoming caps %" GST_PTR_FORMAT, caps);
-
- if (!clutter_gst_auto_video_sink_reconfigure (bin, caps))
- goto beach;
-
- /* We won't be doing this again unless stream changes */
- bin->setup = TRUE;
- }
-
- /* Note that we finished our ASYNC state change but our children will have
- * posted their own messages on our bus. */
- clutter_gst_auto_video_sink_do_async_done (bin);
-
- GST_DEBUG_OBJECT (bin, "unblock the pad");
-
-beach:
- if (caps) {
- gst_caps_unref (caps);
- }
- bin->sink_block_id = 0;
- return GST_PAD_PROBE_REMOVE;
-}
-
-static GstCaps *
-clutter_gst_auto_video_sink_get_caps (ClutterGstAutoVideoSink * bin)
-{
- GstCaps *ret;
-
- if (bin->video_caps) {
- ret = gst_caps_ref (bin->video_caps);
- } else {
- ret = gst_static_pad_template_get_caps (&sink_template_factory);
- }
-
- return ret;
-}
-
-static gboolean
-clutter_gst_auto_video_sink_accept_caps (ClutterGstAutoVideoSink * bin,
- GstCaps * caps)
-{
- gboolean ret = FALSE;
- GstCaps *allowed_caps = clutter_gst_auto_video_sink_get_caps (bin);
-
- if (allowed_caps) {
- GstCaps *result = NULL;
-
- result = gst_caps_intersect (caps, allowed_caps);
-
- if (!gst_caps_is_empty (result))
- ret = TRUE;
-
- caps = result;
- }
-
- gst_caps_unref (allowed_caps);
-
- return ret;
-}
-
-static gboolean
-clutter_gst_auto_video_sink_query (GstPad * pad, GstObject * parent,
- GstQuery * query)
-{
- gboolean res;
- ClutterGstAutoVideoSink *bin = CLUTTER_GST_AUTO_VIDEO_SINK (parent);
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_ACCEPT_CAPS:
- {
- GstCaps *caps;
-
- gst_query_parse_accept_caps (query, &caps);
- res = clutter_gst_auto_video_sink_accept_caps (bin, caps);
- gst_query_set_accept_caps_result (query, res);
- /* return TRUE, we have answered the query */
- res = TRUE;
- }
- break;
- case GST_QUERY_CAPS:
+ if (sink->kid)
{
- GstCaps *caps, *filter;
-
- gst_query_parse_caps (query, &filter);
- caps = clutter_gst_auto_video_sink_get_caps (bin);
- gst_query_set_caps_result (query, caps);
- gst_caps_unref (caps);
- res = TRUE;
+ gst_element_set_state (sink->kid, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN (sink), sink->kid);
+ sink->kid = NULL;
+ /* Don't lose the SINK flag */
+ GST_OBJECT_FLAG_SET (sink, GST_ELEMENT_FLAG_SINK);
}
- break;
- default:
- res = gst_pad_query_default (pad, parent, query);
- break;
- }
- return res;
-}
-
-
-static GstStateChangeReturn
-clutter_gst_auto_video_sink_change_state (GstElement * element,
- GstStateChange transition)
-{
- GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS, bret;
- ClutterGstAutoVideoSink *bin = CLUTTER_GST_AUTO_VIDEO_SINK (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- _sinks_discover (bin);
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- CLUTTER_GST_AUTO_VIDEO_SINK_LOCK (bin);
- bin->need_async_start = TRUE;
- /* Here we set our callback to intercept data flow on the first buffer */
- GST_DEBUG_OBJECT (bin, "try to block input pad to setup internal "
- "pipeline");
-
- if (bin->sink_block_id == 0)
- bin->sink_block_id =
- gst_pad_add_probe (bin->sink_block_pad,
- GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
- clutter_gst_auto_video_sink_sink_pad_blocked_cb, bin, NULL);
- ret = GST_STATE_CHANGE_ASYNC;
- clutter_gst_auto_video_sink_do_async_start (bin);
- CLUTTER_GST_AUTO_VIDEO_SINK_UNLOCK (bin);
- break;
- default:
- break;
- }
-
- /* do the state change of the children */
- bret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
- /* now look at the result of our children and adjust the return value */
- switch (bret) {
- case GST_STATE_CHANGE_FAILURE:
- /* failure, we stop */
- goto activate_failed;
- case GST_STATE_CHANGE_NO_PREROLL:
- /* some child returned NO_PREROLL. This is strange but we never know. We
- * commit our async state change (if any) and return the NO_PREROLL */
- clutter_gst_auto_video_sink_do_async_done (bin);
- ret = bret;
- break;
- case GST_STATE_CHANGE_ASYNC:
- /* some child was async, return this */
- ret = bret;
- break;
- default:
- /* return our previously configured return value */
- break;
- }
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- bin->need_async_start = TRUE;
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- CLUTTER_GST_AUTO_VIDEO_SINK_LOCK (bin);
-
- /* Unblock pad */
- if (bin->sink_block_id != 0) {
- gst_pad_remove_probe (bin->sink_block_pad, bin->sink_block_id);
- bin->sink_block_id = 0;
- }
- /* Unset ghost pad target */
- GST_DEBUG_OBJECT (bin, "setting ghost pad target to NULL");
- gst_ghost_pad_set_target (GST_GHOST_PAD (bin->sink_pad), NULL);
-
- /* Destroy our child */
- if (bin->child) {
- GST_DEBUG_OBJECT (bin->child, "removing child sink");
- gst_element_set_state (bin->child, GST_STATE_NULL);
- gst_bin_remove (GST_BIN (bin), bin->child);
- bin->child = NULL;
- }
-
- bin->setup = FALSE;
- CLUTTER_GST_AUTO_VIDEO_SINK_UNLOCK (bin);
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- _sinks_destroy (bin);
- clutter_gst_auto_video_sink_do_async_done (bin);
- break;
- default:
- break;
- }
-
- return ret;
- /* ERRORS */
-activate_failed:
- {
- GST_DEBUG_OBJECT (bin,
- "element failed to change states -- activation problem?");
- return GST_STATE_CHANGE_FAILURE;
- }
-}
-
-/*
- * Call the base class implementation and make
- * sure that the GST_ELEMENT_FLAG_SINK flag is still
- * set afterwards.
- */
-static gboolean
-clutter_gst_auto_video_sink_add (GstBin * bin, GstElement * element)
-{
- gboolean result;
-
- result = GST_BIN_CLASS (parent_class)->add_element (bin, element);
- GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_FLAG_SINK);
- return result;
}
/*
- * Call the base class implementation and make
- * sure that the GST_ELEMENT_FLAG_SINK flag is still
- * set afterwards.
+ * Hack to make initial linking work; ideally, this'd work even when
+ * no target has been assigned to the ghostpad yet.
*/
-static gboolean
-clutter_gst_auto_video_sink_remove (GstBin * bin, GstElement * element) {
- gboolean result;
-
- result = GST_BIN_CLASS (parent_class)->remove_element (bin, element);
- GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_FLAG_SINK);
- return result;
-}
static void
-clutter_gst_auto_video_sink_dispose (GObject * object)
+clutter_gst_auto_video_sink_reset (ClutterGstAutoVideoSink *sink)
{
- ClutterGstAutoVideoSink *bin = CLUTTER_GST_AUTO_VIDEO_SINK (object);
-
- GST_DEBUG_OBJECT (bin, "Disposing");
+ GstPad *targetpad;
- if (bin->child) {
- gst_element_set_state (bin->child, GST_STATE_NULL);
- gst_object_unref (bin->child);
- bin->child = NULL;
- }
-
- if (bin->sink_block_pad) {
- gst_object_unref (bin->sink_block_pad);
- bin->sink_block_pad = NULL;
- }
+ /* Remove any existing element */
+ clutter_gst_auto_video_sink_clear_kid (sink);
- bin->actor = NULL;
+ /* video sink */
+ sink->kid = clutter_gst_create_video_sink ();
+ gst_bin_add (GST_BIN (sink), sink->kid);
- G_OBJECT_CLASS (parent_class)->dispose ((GObject *) object);
+ /* pad, setting this target should always work */
+ targetpad = gst_element_get_static_pad (sink->kid, "sink");
+ gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
+ gst_object_unref (targetpad);
}
+static GstStaticCaps raw_caps = GST_STATIC_CAPS ("video/x-raw");
+
static void
-clutter_gst_auto_video_sink_finalize (GObject * object)
+clutter_gst_auto_video_sink_init (ClutterGstAutoVideoSink *sink)
{
- ClutterGstAutoVideoSink *bin = CLUTTER_GST_AUTO_VIDEO_SINK (object);
-
- GST_DEBUG_OBJECT (bin, "Destroying");
+ sink->pad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
+ gst_element_add_pad (GST_ELEMENT (sink), sink->pad);
- _sinks_destroy (bin);
+ clutter_gst_auto_video_sink_reset (sink);
- g_mutex_clear (&bin->lock);
-
- GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
-}
+ sink->ts_offset = DEFAULT_TS_OFFSET;
-static void
-clutter_gst_auto_video_sink_set_actor (ClutterGstAutoVideoSink * bin,
- ClutterGstActor * actor)
-{
- bin->actor = actor;
- if (bin->setup) {
- g_object_set (G_OBJECT (bin->child), "actor", actor, NULL);
- }
+ /* mark as sink */
+ GST_OBJECT_FLAG_SET (sink, GST_ELEMENT_FLAG_SINK);
}
static void
-clutter_gst_auto_video_sink_set_property (GObject * object,
- guint prop_id, const GValue * value, GParamSpec * pspec)
+clutter_gst_auto_video_sink_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- ClutterGstAutoVideoSink *bin = CLUTTER_GST_AUTO_VIDEO_SINK (object);
+ ClutterGstAutoVideoSink *sink = CLUTTER_GST_AUTO_VIDEO_SINK (object);
- switch (prop_id) {
- case PROP_ACTOR:
- clutter_gst_auto_video_sink_set_actor (bin, g_value_get_object (value));
- break;
+ switch (prop_id)
+ {
case PROP_TS_OFFSET:
- bin->ts_offset = g_value_get_int64 (value);
- if (bin->child) {
- g_object_set_property (G_OBJECT (bin->child), pspec->name,
- value);
- }
+ sink->ts_offset = g_value_get_int64 (value);
+ if (sink->kid)
+ g_object_set_property (G_OBJECT (sink->kid), pspec->name, value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
- }
+ }
}
static void
-clutter_gst_auto_video_sink_get_property (GObject * object,
- guint prop_id, GValue * value, GParamSpec * pspec)
+clutter_gst_auto_video_sink_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- ClutterGstAutoVideoSink *bin = CLUTTER_GST_AUTO_VIDEO_SINK (object);
+ ClutterGstAutoVideoSink *sink = CLUTTER_GST_AUTO_VIDEO_SINK (object);
- switch (prop_id) {
- case PROP_ACTOR:
- g_value_set_object (value, bin->actor);
- break;
+ switch (prop_id)
+ {
case PROP_TS_OFFSET:
- g_value_set_int64 (value, bin->ts_offset);
+ g_value_set_int64 (value, sink->ts_offset);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
- }
+ }
}
-static void
-clutter_gst_auto_video_sink_class_init (ClutterGstAutoVideoSinkClass * klass)
+static GstStateChangeReturn
+clutter_gst_auto_video_sink_change_state (GstElement *element,
+ GstStateChange transition)
{
- GObjectClass *oclass = G_OBJECT_CLASS (klass);
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
- GstBinClass *gstbin_class = GST_BIN_CLASS (klass);
- GParamSpec *pspec;
-
- oclass->dispose = clutter_gst_auto_video_sink_dispose;
- oclass->finalize = clutter_gst_auto_video_sink_finalize;
- oclass->set_property = clutter_gst_auto_video_sink_set_property;
- oclass->get_property = clutter_gst_auto_video_sink_get_property;
-
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&sink_template_factory));
-
- gst_element_class_set_metadata (gstelement_class,
- "Auto Clutter Sink",
- "Sink/Video",
- "Autoplug clutter capable video sinks",
- "Josep Torra <support@fluendo.com>");
-
- /**
- * ClutterGstAutoVideoSink: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",
- "Actor the video will be decoded into",
- CLUTTER_GST_TYPE_ACTOR,
- CLUTTER_GST_PARAM_READWRITE);
-
- g_object_class_install_property (oclass, PROP_ACTOR, pspec);
-
- g_object_class_install_property (oclass, PROP_TS_OFFSET,
- g_param_spec_int64 ("ts-offset", "TS Offset",
- "Timestamp offset in nanoseconds", G_MININT64, G_MAXINT64,
- DEFAULT_TS_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (clutter_gst_auto_video_sink_change_state);
-
- gstbin_class->add_element =
- GST_DEBUG_FUNCPTR (clutter_gst_auto_video_sink_add);
- gstbin_class->remove_element =
- GST_DEBUG_FUNCPTR (clutter_gst_auto_video_sink_remove);
-}
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ ClutterGstAutoVideoSink *sink = CLUTTER_GST_AUTO_VIDEO_SINK (element);
-static void
-clutter_gst_auto_video_sink_init (ClutterGstAutoVideoSink * bin)
-{
- GstPad *proxypad;
- GstPadTemplate *template;
- GValue val = { 0, };
-
- bin->setup = FALSE;
- bin->actor = NULL;
- bin->ts_offset = DEFAULT_TS_OFFSET;
-
- /* Create a ghost pad with no target at first */
- template = gst_static_pad_template_get (&sink_template_factory);
- bin->sink_pad = gst_ghost_pad_new_no_target_from_template ("sink", template);
- gst_object_unref (template);
-
- gst_pad_set_active (bin->sink_pad, TRUE);
-
- proxypad = NULL;
-
- if (bin->sink_pad) {
- GstIterator *it = gst_pad_iterate_internal_links (bin->sink_pad);
- if (G_UNLIKELY (!it ||
- gst_iterator_next (it,
- &val) !=
- GST_ITERATOR_OK || g_value_get_object (&val) == NULL)) {
- GST_ERROR_OBJECT (bin,
- "failed to get internally linked pad from sinkpad");
- }
- if (it)
- gst_iterator_free (it);
- proxypad = GST_PAD_CAST (g_value_get_object (&val));
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!sink->content)
+ {
+ ClutterActor *stage = clutter_stage_new ();
+ ClutterActor *actor = clutter_actor_new ();
+ sink->content = clutter_gst_aspectratio_new ();
+
+ clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
+ clutter_actor_set_layout_manager (stage,
+ clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_FILL,
+ CLUTTER_BIN_ALIGNMENT_FILL));
+
+ clutter_actor_add_child (stage, actor);
+
+ clutter_actor_set_content (actor, sink->content);
+ clutter_actor_show (stage);
+ }
+ clutter_gst_content_set_sink (CLUTTER_GST_CONTENT (sink->content),
+ COGL_GST_VIDEO_SINK (sink->kid));
+ break;
+ default:
+ break;
}
- bin->sink_block_pad = proxypad;
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ /* switch (transition) { */
+ /* case GST_STATE_CHANGE_READY_TO_NULL: */
+ /* gst_auto_video_sink_reset (sink); */
+ /* break; */
+ /* default: */
+ /* break; */
+ /* } */
- gst_pad_set_query_function (bin->sink_pad,
- GST_DEBUG_FUNCPTR (clutter_gst_auto_video_sink_query));
- gst_element_add_pad (GST_ELEMENT (bin), bin->sink_pad);
- /* Setup the element */
- GST_OBJECT_FLAG_SET (GST_OBJECT (bin), GST_ELEMENT_FLAG_SINK);
- g_mutex_init (&bin->lock);
+ return ret;
}