From 86110c4765cb267ec02821a00269c7393fbc8753 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 4 Jan 2016 20:26:09 +1100 Subject: [PATCH] glupload: always add texture-target field to GL caps 1. Various elements/base classes only perform a subset check on accept-caps 2. Some GL elements have texture-target in their pad template 3. When checking subsets, only the caps to check are allowed to contain extra fields. If the 'template' caps have extra fields, the subset fails. Thus without texture-target on the caps, various accept-caps implementations were failing. Also, add some convenience functions for setting and retrieving texture targets to/from GValue. https://bugzilla.gnome.org/show_bug.cgi?id=759860 --- gst-libs/gst/gl/gstglcolorconvert.c | 39 +-------- gst-libs/gst/gl/gstglupload.c | 64 ++++++++++++++ gst-libs/gst/gl/gstglutils.c | 129 ++++++++++++++++++++++++++++ gst-libs/gst/gl/gstglutils.h | 5 ++ 4 files changed, 200 insertions(+), 37 deletions(-) diff --git a/gst-libs/gst/gl/gstglcolorconvert.c b/gst-libs/gst/gl/gstglcolorconvert.c index ae0557a9e7..99d264d94c 100644 --- a/gst-libs/gst/gl/gstglcolorconvert.c +++ b/gst-libs/gst/gl/gstglcolorconvert.c @@ -701,41 +701,6 @@ gst_gl_color_convert_set_caps (GstGLColorConvert * convert, return ret; } -static guint -_get_target_bitmask_from_g_value (const GValue * targets) -{ - guint new_targets = 0; - - if (targets == NULL) { - new_targets = 1 << GST_GL_TEXTURE_TARGET_2D; - } else if (G_TYPE_CHECK_VALUE_TYPE (targets, G_TYPE_STRING)) { - GstGLTextureTarget target; - const gchar *str; - - str = g_value_get_string (targets); - target = gst_gl_texture_target_from_string (str); - - if (target) - new_targets |= 1 << target; - } else if (G_TYPE_CHECK_VALUE_TYPE (targets, GST_TYPE_LIST)) { - gint j, m; - - m = gst_value_list_get_size (targets); - for (j = 0; j < m; j++) { - const GValue *val = gst_value_list_get_value (targets, j); - GstGLTextureTarget target; - const gchar *str; - - str = g_value_get_string (val); - target = gst_gl_texture_target_from_string (str); - if (target) - new_targets |= 1 << target; - } - } - - return new_targets; -} - /* copies the given caps */ static GstCaps * gst_gl_color_convert_caps_remove_format_info (GstCaps * caps) @@ -809,8 +774,8 @@ gst_gl_color_convert_fixate_caps (GstGLContext * convert, targets = gst_structure_get_value (s, "texture-target"); other_targets = gst_structure_get_value (s_other, "texture-target"); - targets_mask = _get_target_bitmask_from_g_value (targets); - other_targets_mask = _get_target_bitmask_from_g_value (other_targets); + targets_mask = gst_gl_value_get_texture_target_mask (targets); + other_targets_mask = gst_gl_value_get_texture_target_mask (other_targets); /* XXX: attempt to fixate the format/colorimetry/etc */ other = gst_caps_fixate (other); diff --git a/gst-libs/gst/gl/gstglupload.c b/gst-libs/gst/gl/gstglupload.c index c484d989ac..16ed5eaab0 100644 --- a/gst-libs/gst/gl/gstglupload.c +++ b/gst-libs/gst/gl/gstglupload.c @@ -142,6 +142,22 @@ _set_caps_features_with_passthrough (const GstCaps * caps, return tmp; } +static GstCaps * +_caps_intersect_texture_target (GstCaps * caps, GstGLTextureTarget target_mask) +{ + GValue targets = G_VALUE_INIT; + GstCaps *ret, *target; + + target = gst_caps_copy (caps); + gst_gl_value_set_texture_target_from_mask (&targets, target_mask); + gst_caps_set_value (target, "texture-target", &targets); + + ret = gst_caps_intersect_full (caps, target, GST_CAPS_INTERSECT_FIRST); + + gst_caps_unref (target); + return ret; +} + typedef enum { METHOD_FLAG_CAN_SHARE_CONTEXT = 1, @@ -196,6 +212,27 @@ _gl_memory_upload_transform_caps (GstGLContext * context, gst_caps_features_free (passthrough); + if (direction == GST_PAD_SINK) { + GstGLTextureTarget target_mask = 0; + GstCaps *tmp; + + target_mask |= 1 << GST_GL_TEXTURE_TARGET_2D; + target_mask |= 1 << GST_GL_TEXTURE_TARGET_RECTANGLE; + target_mask |= 1 << GST_GL_TEXTURE_TARGET_EXTERNAL_OES; + tmp = _caps_intersect_texture_target (ret, target_mask); + gst_caps_unref (ret); + ret = tmp; + } else { + gint i, n; + + n = gst_caps_get_size (ret); + for (i = 0; i < n; i++) { + GstStructure *s = gst_caps_get_structure (ret, i); + + gst_structure_remove_fields (s, "texture-target", NULL); + } + } + return ret; } @@ -407,9 +444,15 @@ _egl_image_upload_transform_caps (GstGLContext * context, GstCaps *ret; if (direction == GST_PAD_SINK) { + GstCaps *tmp; + ret = _set_caps_features_with_passthrough (caps, GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough); + + tmp = _caps_intersect_texture_target (ret, 1 << GST_GL_TEXTURE_TARGET_2D); + gst_caps_unref (ret); + ret = tmp; } else { gint i, n; @@ -622,9 +665,15 @@ _dma_buf_upload_transform_caps (GstGLContext * context, GstCaps *ret; if (direction == GST_PAD_SINK) { + GstCaps *tmp; + ret = _set_caps_features_with_passthrough (caps, GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough); + + tmp = _caps_intersect_texture_target (ret, 1 << GST_GL_TEXTURE_TARGET_2D); + gst_caps_unref (ret); + ret = tmp; } else { gint i, n; @@ -888,9 +937,15 @@ _upload_meta_upload_transform_caps (GstGLContext * context, GstCaps *ret; if (direction == GST_PAD_SINK) { + GstCaps *tmp; + ret = _set_caps_features_with_passthrough (caps, GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough); + + tmp = _caps_intersect_texture_target (ret, 1 << GST_GL_TEXTURE_TARGET_2D); + gst_caps_unref (ret); + ret = tmp; } else { gint i, n; @@ -1176,9 +1231,18 @@ _raw_data_upload_transform_caps (GstGLContext * context, GstCaps *ret; if (direction == GST_PAD_SINK) { + GstGLTextureTarget target_mask = 0; + GstCaps *tmp; + ret = _set_caps_features_with_passthrough (caps, GST_CAPS_FEATURE_MEMORY_GL_MEMORY, passthrough); + + target_mask |= 1 << GST_GL_TEXTURE_TARGET_2D; + target_mask |= 1 << GST_GL_TEXTURE_TARGET_RECTANGLE; + tmp = _caps_intersect_texture_target (ret, target_mask); + gst_caps_unref (ret); + ret = tmp; } else { gint i, n; diff --git a/gst-libs/gst/gl/gstglutils.c b/gst-libs/gst/gl/gstglutils.c index 080c17b400..2b0104f538 100644 --- a/gst-libs/gst/gl/gstglutils.c +++ b/gst-libs/gst/gl/gstglutils.c @@ -947,3 +947,132 @@ gst_gl_caps_replace_all_caps_features (const GstCaps * caps, return tmp; } + +/** + * gst_gl_value_get_texture_target_mask: + * @value: an initialized #GValue of type G_TYPE_STRING + * + * See gst_gl_value_set_texture_target_mask() for what entails a mask + * + * Returns: the mask of #GstGLTextureTarget's in @value + */ +GstGLTextureTarget +gst_gl_value_get_texture_target_mask (const GValue * targets) +{ + guint new_targets = 0; + + g_return_val_if_fail (targets != NULL, GST_GL_TEXTURE_TARGET_NONE); + + if (G_TYPE_CHECK_VALUE_TYPE (targets, G_TYPE_STRING)) { + GstGLTextureTarget target; + const gchar *str; + + str = g_value_get_string (targets); + target = gst_gl_texture_target_from_string (str); + + if (target) + new_targets |= 1 << target; + } else if (G_TYPE_CHECK_VALUE_TYPE (targets, GST_TYPE_LIST)) { + gint j, m; + + m = gst_value_list_get_size (targets); + for (j = 0; j < m; j++) { + const GValue *val = gst_value_list_get_value (targets, j); + GstGLTextureTarget target; + const gchar *str; + + str = g_value_get_string (val); + target = gst_gl_texture_target_from_string (str); + if (target) + new_targets |= 1 << target; + } + } + + return new_targets; +} + +/** + * gst_gl_value_set_texture_target: + * @value: an initialized #GValue of type G_TYPE_STRING + * @target: a #GstGLTextureTarget's + * + * Returns: whether the @target could be set on @value + */ +gboolean +gst_gl_value_set_texture_target (GValue * value, GstGLTextureTarget target) +{ + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (target != GST_GL_TEXTURE_TARGET_NONE, FALSE); + + if (target == GST_GL_TEXTURE_TARGET_2D) { + g_value_set_static_string (value, GST_GL_TEXTURE_TARGET_2D_STR); + } else if (target == GST_GL_TEXTURE_TARGET_RECTANGLE) { + g_value_set_static_string (value, GST_GL_TEXTURE_TARGET_RECTANGLE_STR); + } else if (target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES) { + g_value_set_static_string (value, GST_GL_TEXTURE_TARGET_EXTERNAL_OES_STR); + } else { + return FALSE; + } + + return TRUE; +} + +static guint64 +_gst_gl_log2_int64 (guint64 value) +{ + guint64 ret = 0; + + while (value >>= 1) + ret++; + + return ret; +} + +/** + * gst_gl_value_set_texture_target_from_mask: + * @value: an uninitialized #GValue + * @target_mask: a bitwise mask of #GstGLTextureTarget's + * + * A mask is a bitwise OR of (1 << target) where target is a valid + * #GstGLTextureTarget + * + * Returns: whether the @target_mask could be set on @value + */ +gboolean +gst_gl_value_set_texture_target_from_mask (GValue * value, + GstGLTextureTarget target_mask) +{ + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (target_mask != GST_GL_TEXTURE_TARGET_NONE, FALSE); + + if ((target_mask & (target_mask - 1)) == 0) { + /* only one texture target set */ + g_value_init (value, G_TYPE_STRING); + return gst_gl_value_set_texture_target (value, + _gst_gl_log2_int64 (target_mask)); + } else { + GValue item = G_VALUE_INIT; + gboolean ret = FALSE; + + g_value_init (value, GST_TYPE_LIST); + g_value_init (&item, G_TYPE_STRING); + if (target_mask & (1 << GST_GL_TEXTURE_TARGET_2D)) { + gst_gl_value_set_texture_target (&item, GST_GL_TEXTURE_TARGET_2D); + gst_value_list_append_value (value, &item); + ret = TRUE; + } + if (target_mask & (1 << GST_GL_TEXTURE_TARGET_RECTANGLE)) { + gst_gl_value_set_texture_target (&item, GST_GL_TEXTURE_TARGET_RECTANGLE); + gst_value_list_append_value (value, &item); + ret = TRUE; + } + if (target_mask & (1 << GST_GL_TEXTURE_TARGET_EXTERNAL_OES)) { + gst_gl_value_set_texture_target (&item, + GST_GL_TEXTURE_TARGET_EXTERNAL_OES); + gst_value_list_append_value (value, &item); + ret = TRUE; + } + + return ret; + } +} diff --git a/gst-libs/gst/gl/gstglutils.h b/gst-libs/gst/gl/gstglutils.h index 3c8460b795..1c5ab12344 100644 --- a/gst-libs/gst/gl/gstglutils.h +++ b/gst-libs/gst/gl/gstglutils.h @@ -111,6 +111,11 @@ gsize gst_gl_get_plane_start (GstVideoInfo * info, GstVideoAlignment * valign, GstCaps * gst_gl_caps_replace_all_caps_features (const GstCaps * caps, const gchar * feature_name); +gboolean gst_gl_value_set_texture_target_from_mask (GValue * value, + GstGLTextureTarget target_mask); +gboolean gst_gl_value_set_texture_target (GValue * value, GstGLTextureTarget target); +GstGLTextureTarget gst_gl_value_get_texture_target_mask (const GValue * value); + G_END_DECLS #endif /* __GST_GL_UTILS_H__ */