diff options
author | Lionel Landwerlin <llandwerlin@gmail.com> | 2013-07-22 13:31:52 +0100 |
---|---|---|
committer | Lionel Landwerlin <llandwerlin@gmail.com> | 2013-07-22 13:31:52 +0100 |
commit | c23cdfc584b2051c2962673b9078a5c92d9b30a8 (patch) | |
tree | 583b4936958193560c7ac3f06d419a7e47ff8f84 /clutter-gst/clutter-gst-auto-video-sink.c | |
parent | 8b12180346be221cf25216f884d3a8b9f069141f (diff) | |
download | clutter-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.c | 930 |
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; } |