From ba97ec74bedd3d8e910052d8345becc42ad75813 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 9 Sep 2015 19:51:18 -0300 Subject: [PATCH] videoaggregator: fix caps query to properly handle alpha formats Only accept alpha if downstream has alpha as well. It could theoretically accept alpha unconditionally if blending is properly implemented for handle it but at the moment this is a missing feature. Improves the caps query by also comparing with the template caps to filter by what the subclass supports. https://bugzilla.gnome.org/show_bug.cgi?id=754465 --- gst-libs/gst/video/gstvideoaggregator.c | 211 ++++++++++++++++++++++-- gst-libs/gst/video/gstvideoaggregator.h | 2 + 2 files changed, 200 insertions(+), 13 deletions(-) diff --git a/gst-libs/gst/video/gstvideoaggregator.c b/gst-libs/gst/video/gstvideoaggregator.c index 80b10d4452..053e81be6b 100644 --- a/gst-libs/gst/video/gstvideoaggregator.c +++ b/gst-libs/gst/video/gstvideoaggregator.c @@ -76,6 +76,7 @@ struct _GstVideoAggregatorPadPrivate GstClockTime end_time; }; + G_DEFINE_TYPE (GstVideoAggregatorPad, gst_videoaggregator_pad, GST_TYPE_AGGREGATOR_PAD); @@ -429,9 +430,44 @@ struct _GstVideoAggregatorPrivate gboolean live; }; -G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstVideoAggregator, gst_videoaggregator, - GST_TYPE_AGGREGATOR, G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY, - gst_videoaggregator_child_proxy_init)); +/* Can't use the G_DEFINE_TYPE macros because we need the + * videoaggregator class in the _init to be able to set + * the sink pad non-alpha caps. Using the G_DEFINE_TYPE there + * seems to be no way of getting the real class being initialized */ +static void gst_videoaggregator_init (GstVideoAggregator * self, + GstVideoAggregatorClass * klass); +static void gst_videoaggregator_class_init (GstVideoAggregatorClass * klass); +static gpointer gst_videoaggregator_parent_class = NULL; +static gint GstVideoAggregator_private_offset; + +_G_DEFINE_TYPE_EXTENDED_CLASS_INIT (GstVideoAggregator, gst_videoaggregator); + +G_GNUC_UNUSED static inline gpointer +gst_videoaggregator_get_instance_private (const GstVideoAggregator * self) +{ + return (G_STRUCT_MEMBER_P (self, GstVideoAggregator_private_offset)); +} + +GType +gst_videoaggregator_get_type (void) +{ + static volatile gsize g_define_type_id_volatile = 0; + if (g_once_init_enter (&g_define_type_id_volatile)) { + GType g_define_type_id = g_type_register_static_simple (GST_TYPE_AGGREGATOR, + g_intern_static_string ("GstVideoAggregator"), + sizeof (GstVideoAggregatorClass), + (GClassInitFunc) gst_videoaggregator_class_intern_init, + sizeof (GstVideoAggregator), + (GInstanceInitFunc) gst_videoaggregator_init, + (GTypeFlags) G_TYPE_FLAG_ABSTRACT); + { + G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY, + gst_videoaggregator_child_proxy_init); + } + g_once_init_leave (&g_define_type_id_volatile, g_define_type_id); + } + return g_define_type_id_volatile; +} static void gst_videoaggreagator_find_best_format (GstVideoAggregator * vagg, @@ -833,27 +869,80 @@ beach: return ret; } +static gboolean +gst_videoaggregator_caps_has_alpha (GstCaps * caps) +{ + guint size = gst_caps_get_size (caps); + guint i; + + for (i = 0; i < size; i++) { + GstStructure *s = gst_caps_get_structure (caps, i); + const GValue *formats = gst_structure_get_value (s, "format"); + + if (formats) { + const GstVideoFormatInfo *info; + + if (GST_VALUE_HOLDS_LIST (formats)) { + guint list_size = gst_value_list_get_size (formats); + guint index; + + for (index = 0; index < list_size; index++) { + const GValue *list_item = gst_value_list_get_value (formats, index); + info = + gst_video_format_get_info (gst_video_format_from_string + (g_value_get_string (list_item))); + if (GST_VIDEO_FORMAT_INFO_HAS_ALPHA (info)) + return TRUE; + } + + } else if (G_VALUE_HOLDS_STRING (formats)) { + info = + gst_video_format_get_info (gst_video_format_from_string + (g_value_get_string (formats))); + if (GST_VIDEO_FORMAT_INFO_HAS_ALPHA (info)) + return TRUE; + + } else { + g_assert_not_reached (); + GST_WARNING ("Unexpected type for video 'format' field: %s", + G_VALUE_TYPE_NAME (formats)); + } + + } else { + return TRUE; + } + } + return FALSE; +} + static GstCaps * gst_videoaggregator_pad_sink_getcaps (GstPad * pad, GstVideoAggregator * vagg, GstCaps * filter) { GstCaps *srccaps; - GstCaps *template_caps; + GstCaps *template_caps, *sink_template_caps; GstCaps *returned_caps; GstStructure *s; - gboolean had_current_caps = TRUE; gint i, n; GstAggregator *agg = GST_AGGREGATOR (vagg); + GstPad *srcpad = GST_PAD (agg->srcpad); + gboolean has_alpha; - template_caps = gst_pad_get_pad_template_caps (GST_PAD (agg->srcpad)); + template_caps = gst_pad_get_pad_template_caps (srcpad); - srccaps = gst_pad_get_current_caps (GST_PAD (agg->srcpad)); + GST_DEBUG_OBJECT (pad, "Get caps with filter: %" GST_PTR_FORMAT, filter); + + srccaps = gst_pad_get_current_caps (srcpad); if (srccaps == NULL) { - had_current_caps = FALSE; - srccaps = template_caps; + srccaps = gst_pad_peer_query_caps (srcpad, template_caps); + GST_DEBUG_OBJECT (pad, "No output caps, using possible formats: %" + GST_PTR_FORMAT, srccaps); + } else { + GST_DEBUG_OBJECT (pad, "Using output caps: %" GST_PTR_FORMAT, srccaps); } srccaps = gst_caps_make_writable (srccaps); + has_alpha = gst_videoaggregator_caps_has_alpha (srccaps); n = gst_caps_get_size (srccaps); for (i = 0; i < n; i++) { @@ -873,8 +962,23 @@ gst_videoaggregator_pad_sink_getcaps (GstPad * pad, GstVideoAggregator * vagg, returned_caps = srccaps; } - if (had_current_caps) - gst_caps_unref (template_caps); + if (has_alpha) { + sink_template_caps = gst_pad_get_pad_template_caps (pad); + } else { + GstVideoAggregatorClass *klass = GST_VIDEO_AGGREGATOR_GET_CLASS (vagg); + sink_template_caps = gst_caps_ref (klass->sink_non_alpha_caps); + } + + { + GstCaps *intersect = gst_caps_intersect (returned_caps, sink_template_caps); + gst_caps_unref (returned_caps); + returned_caps = intersect; + } + + gst_caps_unref (template_caps); + gst_caps_unref (sink_template_caps); + + GST_DEBUG_OBJECT (pad, "Returning caps: %" GST_PTR_FORMAT, returned_caps); return returned_caps; } @@ -1974,9 +2078,83 @@ gst_videoaggregator_class_init (GstVideoAggregatorClass * klass) g_type_class_ref (GST_TYPE_VIDEO_AGGREGATOR_PAD); } -static void -gst_videoaggregator_init (GstVideoAggregator * vagg) +static inline GstCaps * +_get_non_alpha_caps_from_template (GstVideoAggregatorClass * klass) { + GstCaps *result; + GstCaps *templatecaps; + guint i, size; + + templatecaps = + gst_pad_template_get_caps (gst_element_class_get_pad_template + (GST_ELEMENT_CLASS (klass), "sink_%u")); + + size = gst_caps_get_size (templatecaps); + result = gst_caps_new_empty (); + for (i = 0; i < size; i++) { + GstStructure *s = gst_caps_get_structure (templatecaps, i); + const GValue *formats = gst_structure_get_value (s, "format"); + GValue new_formats = { 0, }; + gboolean has_format = FALSE; + + /* FIXME what to do if formats are missing? */ + if (formats) { + const GstVideoFormatInfo *info; + + if (GST_VALUE_HOLDS_LIST (formats)) { + guint list_size = gst_value_list_get_size (formats); + guint index; + + g_value_init (&new_formats, GST_TYPE_LIST); + + for (index = 0; index < list_size; index++) { + const GValue *list_item = gst_value_list_get_value (formats, index); + + info = + gst_video_format_get_info (gst_video_format_from_string + (g_value_get_string (list_item))); + if (!GST_VIDEO_FORMAT_INFO_HAS_ALPHA (info)) { + has_format = TRUE; + gst_value_list_append_value (&new_formats, list_item); + } + } + + } else if (G_VALUE_HOLDS_STRING (formats)) { + info = + gst_video_format_get_info (gst_video_format_from_string + (g_value_get_string (formats))); + if (!GST_VIDEO_FORMAT_INFO_HAS_ALPHA (info)) { + has_format = TRUE; + gst_value_init_and_copy (&new_formats, formats); + } + + } else { + g_assert_not_reached (); + GST_WARNING ("Unexpected type for video 'format' field: %s", + G_VALUE_TYPE_NAME (formats)); + } + + if (has_format) { + s = gst_structure_copy (s); + gst_structure_take_value (s, "format", &new_formats); + gst_caps_append_structure (result, s); + } + + } + } + + gst_caps_unref (templatecaps); + + return result; +} + +static GMutex sink_caps_mutex; + +static void +gst_videoaggregator_init (GstVideoAggregator * vagg, + GstVideoAggregatorClass * klass) +{ + vagg->priv = G_TYPE_INSTANCE_GET_PRIVATE (vagg, GST_TYPE_VIDEO_AGGREGATOR, GstVideoAggregatorPrivate); @@ -1984,6 +2162,13 @@ gst_videoaggregator_init (GstVideoAggregator * vagg) vagg->priv->current_caps = NULL; g_mutex_init (&vagg->priv->lock); + /* initialize variables */ + g_mutex_lock (&sink_caps_mutex); + if (klass->sink_non_alpha_caps == NULL) { + klass->sink_non_alpha_caps = _get_non_alpha_caps_from_template (klass); + } + g_mutex_unlock (&sink_caps_mutex); + gst_videoaggregator_reset (vagg); } diff --git a/gst-libs/gst/video/gstvideoaggregator.h b/gst-libs/gst/video/gstvideoaggregator.h index b3c5c53e78..f95d0d2674 100644 --- a/gst-libs/gst/video/gstvideoaggregator.h +++ b/gst-libs/gst/video/gstvideoaggregator.h @@ -111,6 +111,8 @@ struct _GstVideoAggregatorClass gboolean preserve_update_caps_result; + GstCaps *sink_non_alpha_caps; + /* < private > */ gpointer _gst_reserved[GST_PADDING_LARGE]; };