| From 56d9fb13f93abbf5aa5af81e39ae73642016fe95 Mon Sep 17 00:00:00 2001 |
| From: Matthew Waters <matthew@centricular.com> |
| Date: Wed, 5 Feb 2020 12:26:54 +1100 |
| Subject: [PATCH] glbasefilter: add support for changing the display |
| |
| Each element will remove its usage of the old display and context and |
| try to retrieve a new GL context. |
| --- |
| ext/gl/gstglcolorconvertelement.c | 44 ++++--- |
| gst-libs/gst/gl/gstglbasefilter.c | 195 ++++++++++++++++++++++-------- |
| gst-libs/gst/gl/gstglbasefilter.h | 4 + |
| tests/check/elements/glfilter.c | 131 ++++++++++++++++++++ |
| tests/check/meson.build | 1 + |
| 5 files changed, 310 insertions(+), 65 deletions(-) |
| create mode 100644 tests/check/elements/glfilter.c |
| |
| diff --git a/ext/gl/gstglcolorconvertelement.c b/ext/gl/gstglcolorconvertelement.c |
| index 25e7daab9..256e5ef5a 100644 |
| --- a/ext/gl/gstglcolorconvertelement.c |
| +++ b/ext/gl/gstglcolorconvertelement.c |
| @@ -36,15 +36,14 @@ G_DEFINE_TYPE_WITH_CODE (GstGLColorConvertElement, gst_gl_color_convert_element, |
| "glconvertelement", 0, "convert"); |
| ); |
| |
| -static gboolean gst_gl_color_convert_element_set_caps (GstBaseTransform * bt, |
| - GstCaps * in_caps, GstCaps * out_caps); |
| +static gboolean gst_gl_color_convert_element_gl_set_caps (GstGLBaseFilter * |
| + base_filter, GstCaps * in_caps, GstCaps * out_caps); |
| static GstCaps *gst_gl_color_convert_element_transform_caps (GstBaseTransform * |
| bt, GstPadDirection direction, GstCaps * caps, GstCaps * filter); |
| static gboolean gst_gl_color_convert_element_get_unit_size (GstBaseTransform * |
| trans, GstCaps * caps, gsize * size); |
| -static gboolean |
| -gst_gl_color_convert_element_filter_meta (GstBaseTransform * trans, |
| - GstQuery * query, GType api, const GstStructure * params); |
| +static gboolean gst_gl_color_convert_element_filter_meta (GstBaseTransform * |
| + trans, GstQuery * query, GType api, const GstStructure * params); |
| static gboolean gst_gl_color_convert_element_decide_allocation (GstBaseTransform |
| * trans, GstQuery * query); |
| static GstFlowReturn |
| @@ -52,8 +51,8 @@ gst_gl_color_convert_element_prepare_output_buffer (GstBaseTransform * bt, |
| GstBuffer * inbuf, GstBuffer ** outbuf); |
| static GstFlowReturn gst_gl_color_convert_element_transform (GstBaseTransform * |
| bt, GstBuffer * inbuf, GstBuffer * outbuf); |
| -static GstCaps *gst_gl_color_convert_element_fixate_caps (GstBaseTransform * |
| - bt, GstPadDirection direction, GstCaps * caps, GstCaps * othercaps); |
| +static GstCaps *gst_gl_color_convert_element_fixate_caps (GstBaseTransform * bt, |
| + GstPadDirection direction, GstCaps * caps, GstCaps * othercaps); |
| static GstStateChangeReturn |
| gst_gl_color_convert_element_change_state (GstElement * element, |
| GstStateChange transition); |
| @@ -70,34 +69,33 @@ GST_STATIC_PAD_TEMPLATE ("sink", |
| GST_PAD_ALWAYS, |
| GST_STATIC_CAPS (GST_GL_COLOR_CONVERT_VIDEO_CAPS)); |
| |
| -static gboolean |
| -gst_gl_color_convert_element_stop (GstBaseTransform * bt) |
| +static void |
| +gst_gl_color_convert_element_gl_stop (GstGLBaseFilter * filter) |
| { |
| - GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (bt); |
| + GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (filter); |
| |
| if (convert->convert) { |
| gst_object_unref (convert->convert); |
| convert->convert = NULL; |
| } |
| |
| - return GST_BASE_TRANSFORM_CLASS (parent_class)->stop (bt); |
| + GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (filter); |
| } |
| |
| static void |
| gst_gl_color_convert_element_class_init (GstGLColorConvertElementClass * klass) |
| { |
| + GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_CLASS (klass); |
| GstBaseTransformClass *bt_class = GST_BASE_TRANSFORM_CLASS (klass); |
| GstElementClass *element_class = GST_ELEMENT_CLASS (klass); |
| |
| bt_class->transform_caps = gst_gl_color_convert_element_transform_caps; |
| - bt_class->set_caps = gst_gl_color_convert_element_set_caps; |
| bt_class->get_unit_size = gst_gl_color_convert_element_get_unit_size; |
| bt_class->filter_meta = gst_gl_color_convert_element_filter_meta; |
| bt_class->decide_allocation = gst_gl_color_convert_element_decide_allocation; |
| bt_class->prepare_output_buffer = |
| gst_gl_color_convert_element_prepare_output_buffer; |
| bt_class->transform = gst_gl_color_convert_element_transform; |
| - bt_class->stop = gst_gl_color_convert_element_stop; |
| bt_class->fixate_caps = gst_gl_color_convert_element_fixate_caps; |
| |
| bt_class->passthrough_on_same_caps = TRUE; |
| @@ -113,6 +111,9 @@ gst_gl_color_convert_element_class_init (GstGLColorConvertElementClass * klass) |
| "OpenGL color converter", "Filter/Converter/Video", |
| "Converts between color spaces using OpenGL shaders", |
| "Matthew Waters <matthew@centricular.com>"); |
| + |
| + filter_class->gl_stop = gst_gl_color_convert_element_gl_stop; |
| + filter_class->gl_set_caps = gst_gl_color_convert_element_gl_set_caps; |
| } |
| |
| static void |
| @@ -123,10 +124,14 @@ gst_gl_color_convert_element_init (GstGLColorConvertElement * convert) |
| } |
| |
| static gboolean |
| -gst_gl_color_convert_element_set_caps (GstBaseTransform * bt, |
| +gst_gl_color_convert_element_gl_set_caps (GstGLBaseFilter * base_filter, |
| GstCaps * in_caps, GstCaps * out_caps) |
| { |
| - GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (bt); |
| + GstGLColorConvertElement *convert = |
| + GST_GL_COLOR_CONVERT_ELEMENT (base_filter); |
| + |
| + if (!convert->convert && base_filter->context) |
| + convert->convert = gst_gl_color_convert_new (base_filter->context); |
| |
| if (!gst_gl_color_convert_set_caps (convert->convert, in_caps, out_caps)) |
| return FALSE; |
| @@ -141,16 +146,21 @@ gst_gl_color_convert_element_transform_caps (GstBaseTransform * bt, |
| GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (bt); |
| GstGLBaseFilter *base_filter = GST_GL_BASE_FILTER (bt); |
| GstGLContext *context; |
| + GstCaps *ret; |
| |
| if (base_filter->display && !gst_gl_base_filter_find_gl_context (base_filter)) |
| return NULL; |
| |
| - context = GST_GL_BASE_FILTER (bt)->context; |
| + context = gst_gl_base_filter_get_gl_context (base_filter); |
| |
| if (!convert->convert && context) |
| convert->convert = gst_gl_color_convert_new (context); |
| |
| - return gst_gl_color_convert_transform_caps (context, direction, caps, filter); |
| + ret = gst_gl_color_convert_transform_caps (context, direction, caps, filter); |
| + |
| + gst_clear_object (&context); |
| + |
| + return ret; |
| } |
| |
| static gboolean |
| diff --git a/gst-libs/gst/gl/gstglbasefilter.c b/gst-libs/gst/gl/gstglbasefilter.c |
| index 155d9002b..1d57b4051 100644 |
| --- a/gst-libs/gst/gl/gstglbasefilter.c |
| +++ b/gst-libs/gst/gl/gstglbasefilter.c |
| @@ -48,6 +48,9 @@ struct _GstGLBaseFilterPrivate |
| |
| gboolean gl_result; |
| gboolean gl_started; |
| + |
| + GRecMutex context_lock; |
| + gboolean new_gl_context; |
| }; |
| |
| /* Properties */ |
| @@ -91,6 +94,8 @@ static void gst_gl_base_filter_gl_stop (GstGLContext * context, gpointer data); |
| static gboolean gst_gl_base_filter_default_gl_start (GstGLBaseFilter * filter); |
| static void gst_gl_base_filter_default_gl_stop (GstGLBaseFilter * filter); |
| |
| +static gboolean gst_gl_base_filter_find_gl_context_unlocked (GstGLBaseFilter * |
| + filter); |
| static void |
| gst_gl_base_filter_class_init (GstGLBaseFilterClass * klass) |
| { |
| @@ -131,6 +136,8 @@ gst_gl_base_filter_init (GstGLBaseFilter * filter) |
| gst_base_transform_set_qos_enabled (GST_BASE_TRANSFORM (filter), TRUE); |
| |
| filter->priv = gst_gl_base_filter_get_instance_private (filter); |
| + |
| + g_rec_mutex_init (&filter->priv->context_lock); |
| } |
| |
| static void |
| @@ -141,6 +148,8 @@ gst_gl_base_filter_finalize (GObject * object) |
| gst_caps_replace (&filter->in_caps, NULL); |
| gst_caps_replace (&filter->out_caps, NULL); |
| |
| + g_rec_mutex_clear (&filter->priv->context_lock); |
| + |
| G_OBJECT_CLASS (parent_class)->finalize (object); |
| } |
| |
| @@ -171,32 +180,30 @@ gst_gl_base_filter_get_property (GObject * object, guint prop_id, |
| } |
| } |
| |
| -static void |
| -gst_gl_base_filter_set_context (GstElement * element, GstContext * context) |
| -{ |
| - GstGLBaseFilter *filter = GST_GL_BASE_FILTER (element); |
| - GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter); |
| - |
| - GST_OBJECT_LOCK (filter); |
| - gst_gl_handle_set_context (element, context, &filter->display, |
| - &filter->priv->other_context); |
| - if (filter->display) |
| - gst_gl_display_filter_gl_api (filter->display, |
| - filter_class->supported_gl_api); |
| - GST_OBJECT_UNLOCK (filter); |
| - |
| - GST_ELEMENT_CLASS (parent_class)->set_context (element, context); |
| -} |
| - |
| static gboolean |
| _find_local_gl_context (GstGLBaseFilter * filter) |
| { |
| + GstGLContext *context = filter->context; |
| + |
| if (gst_gl_query_local_gl_context (GST_ELEMENT (filter), GST_PAD_SRC, |
| - &filter->context)) |
| - return TRUE; |
| + &context)) { |
| + if (context->display == filter->display) { |
| + filter->context = context; |
| + return TRUE; |
| + } |
| + if (context != filter->context) |
| + gst_clear_object (&context); |
| + } |
| + context = filter->context; |
| if (gst_gl_query_local_gl_context (GST_ELEMENT (filter), GST_PAD_SINK, |
| - &filter->context)) |
| - return TRUE; |
| + &context)) { |
| + if (context->display == filter->display) { |
| + filter->context = context; |
| + return TRUE; |
| + } |
| + if (context != filter->context) |
| + gst_clear_object (&context); |
| + } |
| return FALSE; |
| } |
| |
| @@ -211,7 +218,9 @@ gst_gl_base_filter_query (GstBaseTransform * trans, GstPadDirection direction, |
| { |
| if (direction == GST_PAD_SINK |
| && gst_base_transform_is_passthrough (trans)) { |
| + g_rec_mutex_lock (&filter->priv->context_lock); |
| _find_local_gl_context (filter); |
| + g_rec_mutex_unlock (&filter->priv->context_lock); |
| |
| return gst_pad_peer_query (GST_BASE_TRANSFORM_SRC_PAD (trans), query); |
| } |
| @@ -220,10 +229,10 @@ gst_gl_base_filter_query (GstBaseTransform * trans, GstPadDirection direction, |
| case GST_QUERY_CONTEXT: |
| { |
| gboolean ret; |
| - GST_OBJECT_LOCK (filter); |
| + g_rec_mutex_lock (&filter->priv->context_lock); |
| ret = gst_gl_handle_context_query ((GstElement *) filter, query, |
| filter->display, filter->context, filter->priv->other_context); |
| - GST_OBJECT_UNLOCK (filter); |
| + g_rec_mutex_unlock (&filter->priv->context_lock); |
| if (ret) |
| return TRUE; |
| break; |
| @@ -239,17 +248,14 @@ gst_gl_base_filter_query (GstBaseTransform * trans, GstPadDirection direction, |
| static void |
| gst_gl_base_filter_reset (GstGLBaseFilter * filter) |
| { |
| - GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter); |
| - |
| + g_rec_mutex_lock (&filter->priv->context_lock); |
| if (filter->context) { |
| - if (filter_class->gl_stop != NULL) { |
| - gst_gl_context_thread_add (filter->context, gst_gl_base_filter_gl_stop, |
| - filter); |
| - } |
| - |
| + gst_gl_context_thread_add (filter->context, gst_gl_base_filter_gl_stop, |
| + filter); |
| gst_object_unref (filter->context); |
| filter->context = NULL; |
| } |
| + g_rec_mutex_unlock (&filter->priv->context_lock); |
| } |
| |
| static gboolean |
| @@ -280,6 +286,7 @@ gst_gl_base_filter_gl_start (GstGLContext * context, gpointer data) |
| GstGLBaseFilter *filter = GST_GL_BASE_FILTER (data); |
| GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter); |
| |
| + GST_INFO_OBJECT (filter, "starting"); |
| gst_gl_insert_debug_marker (filter->context, |
| "starting element %s", GST_OBJECT_NAME (filter)); |
| |
| @@ -297,6 +304,7 @@ gst_gl_base_filter_gl_stop (GstGLContext * context, gpointer data) |
| GstGLBaseFilter *filter = GST_GL_BASE_FILTER (data); |
| GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter); |
| |
| + GST_INFO_OBJECT (filter, "stopping"); |
| gst_gl_insert_debug_marker (filter->context, |
| "stopping element %s", GST_OBJECT_NAME (filter)); |
| |
| @@ -311,33 +319,53 @@ _gl_set_caps (GstGLContext * context, GstGLBaseFilter * filter) |
| { |
| GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter); |
| |
| + GST_INFO_OBJECT (filter, "set GL caps input %" GST_PTR_FORMAT, |
| + filter->in_caps); |
| + GST_INFO_OBJECT (filter, "set GL caps output %" GST_PTR_FORMAT, |
| + filter->out_caps); |
| + |
| if (filter_class->gl_set_caps) |
| filter->priv->gl_result = |
| filter_class->gl_set_caps (filter, filter->in_caps, filter->out_caps); |
| } |
| |
| static gboolean |
| -gst_gl_base_filter_decide_allocation (GstBaseTransform * trans, |
| - GstQuery * query) |
| +gl_set_caps_unlocked (GstGLBaseFilter * filter) |
| { |
| - GstGLBaseFilter *filter = GST_GL_BASE_FILTER (trans); |
| GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter); |
| |
| - if (!gst_gl_base_filter_find_gl_context (filter)) |
| - return FALSE; |
| - |
| if (filter_class->gl_set_caps) { |
| gst_gl_context_thread_add (filter->context, |
| (GstGLContextThreadFunc) _gl_set_caps, filter); |
| - if (!filter->priv->gl_result) |
| - goto error; |
| + return filter->priv->gl_result; |
| } |
| |
| + return TRUE; |
| +} |
| + |
| +static gboolean |
| +gst_gl_base_filter_decide_allocation (GstBaseTransform * trans, |
| + GstQuery * query) |
| +{ |
| + GstGLBaseFilter *filter = GST_GL_BASE_FILTER (trans); |
| + |
| + g_rec_mutex_lock (&filter->priv->context_lock); |
| + if (!gst_gl_base_filter_find_gl_context_unlocked (filter)) { |
| + g_rec_mutex_unlock (&filter->priv->context_lock); |
| + return FALSE; |
| + } |
| + |
| + if (!gl_set_caps_unlocked (filter)) |
| + goto error; |
| + |
| + g_rec_mutex_unlock (&filter->priv->context_lock); |
| + |
| return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans, |
| query); |
| |
| error: |
| { |
| + g_rec_mutex_unlock (&filter->priv->context_lock); |
| GST_ELEMENT_ERROR (trans, LIBRARY, INIT, |
| ("Subclass failed to initialize."), (NULL)); |
| return FALSE; |
| @@ -389,6 +417,7 @@ gst_gl_base_filter_change_state (GstElement * element, |
| |
| switch (transition) { |
| case GST_STATE_CHANGE_READY_TO_NULL: |
| + g_rec_mutex_lock (&filter->priv->context_lock); |
| if (filter->priv->other_context) { |
| gst_object_unref (filter->priv->other_context); |
| filter->priv->other_context = NULL; |
| @@ -403,6 +432,7 @@ gst_gl_base_filter_change_state (GstElement * element, |
| gst_object_unref (filter->context); |
| filter->context = NULL; |
| } |
| + g_rec_mutex_unlock (&filter->priv->context_lock); |
| break; |
| default: |
| break; |
| @@ -411,21 +441,49 @@ gst_gl_base_filter_change_state (GstElement * element, |
| return ret; |
| } |
| |
| -/** |
| - * gst_gl_base_filter_find_gl_context: |
| - * @filter: a #GstGLBaseFilter |
| - * |
| - * Returns: Whether an OpenGL context could be retrieved or created successfully |
| - * |
| - * Since: 1.16 |
| - */ |
| -gboolean |
| -gst_gl_base_filter_find_gl_context (GstGLBaseFilter * filter) |
| +static void |
| +gst_gl_base_filter_set_context (GstElement * element, GstContext * context) |
| +{ |
| + GstGLBaseFilter *filter = GST_GL_BASE_FILTER (element); |
| + GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter); |
| + GstGLDisplay *old_display, *new_display; |
| + |
| + g_rec_mutex_lock (&filter->priv->context_lock); |
| + old_display = filter->display ? gst_object_ref (filter->display) : NULL; |
| + gst_gl_handle_set_context (element, context, &filter->display, |
| + &filter->priv->other_context); |
| + if (filter->display) |
| + gst_gl_display_filter_gl_api (filter->display, |
| + filter_class->supported_gl_api); |
| + new_display = filter->display ? gst_object_ref (filter->display) : NULL; |
| + |
| + if (old_display && new_display) { |
| + if (old_display != new_display) { |
| + gst_clear_object (&filter->context); |
| + if (gst_gl_base_filter_find_gl_context_unlocked (filter)) { |
| + if (filter->in_caps && filter->out_caps) { |
| + gl_set_caps_unlocked (filter); |
| + } |
| + } |
| + } |
| + } |
| + g_rec_mutex_unlock (&filter->priv->context_lock); |
| + gst_clear_object (&old_display); |
| + gst_clear_object (&new_display); |
| + |
| + GST_ELEMENT_CLASS (parent_class)->set_context (element, context); |
| +} |
| + |
| +static gboolean |
| +gst_gl_base_filter_find_gl_context_unlocked (GstGLBaseFilter * filter) |
| { |
| GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter); |
| GError *error = NULL; |
| gboolean new_context = FALSE; |
| |
| + GST_DEBUG_OBJECT (filter, "attempting to find an OpenGL context, existing %" |
| + GST_PTR_FORMAT, filter->context); |
| + |
| if (!filter->context) |
| new_context = TRUE; |
| |
| @@ -449,6 +507,8 @@ gst_gl_base_filter_find_gl_context (GstGLBaseFilter * filter) |
| } while (!gst_gl_display_add_context (filter->display, filter->context)); |
| GST_OBJECT_UNLOCK (filter->display); |
| } |
| + GST_INFO_OBJECT (filter, "found OpenGL context %" GST_PTR_FORMAT, |
| + filter->context); |
| |
| if (new_context || !filter->priv->gl_started) { |
| if (filter->priv->gl_started) |
| @@ -499,3 +559,42 @@ error: |
| return FALSE; |
| } |
| } |
| + |
| +/** |
| + * gst_gl_base_filter_find_gl_context: |
| + * @filter: a #GstGLBaseFilter |
| + * |
| + * Returns: Whether an OpenGL context could be retrieved or created successfully |
| + * |
| + * Since: 1.16 |
| + */ |
| +gboolean |
| +gst_gl_base_filter_find_gl_context (GstGLBaseFilter * filter) |
| +{ |
| + gboolean ret; |
| + g_rec_mutex_lock (&filter->priv->context_lock); |
| + ret = gst_gl_base_filter_find_gl_context_unlocked (filter); |
| + g_rec_mutex_unlock (&filter->priv->context_lock); |
| + return ret; |
| +} |
| + |
| +/** |
| + * gst_gl_base_filter_get_gl_context: |
| + * @filter: a #GstGLBaseFilter |
| + * |
| + * Returns: (transfer full) (nullable): the #GstGLContext found by @filter |
| + * |
| + * Since: 1.18 |
| + */ |
| +GstGLContext * |
| +gst_gl_base_filter_get_gl_context (GstGLBaseFilter * filter) |
| +{ |
| + GstGLContext *ret; |
| + |
| + g_return_val_if_fail (GST_IS_GL_BASE_FILTER (filter), NULL); |
| + |
| + g_rec_mutex_lock (&filter->priv->context_lock); |
| + ret = filter->context ? gst_object_ref (filter->context) : NULL; |
| + g_rec_mutex_unlock (&filter->priv->context_lock); |
| + return ret; |
| +} |
| diff --git a/gst-libs/gst/gl/gstglbasefilter.h b/gst-libs/gst/gl/gstglbasefilter.h |
| index 15361ade1..57fb3df5b 100644 |
| --- a/gst-libs/gst/gl/gstglbasefilter.h |
| +++ b/gst-libs/gst/gl/gstglbasefilter.h |
| @@ -70,6 +70,8 @@ struct _GstGLBaseFilter |
| * @gl_start: called in the GL thread to setup the element GL state. |
| * @gl_stop: called in the GL thread to setup the element GL state. |
| * @gl_set_caps: called in the GL thread when caps are set on @filter. |
| + * Note: this will also be called when changing OpenGL contexts |
| + * where #GstBaseTransform::set_caps may not. |
| * |
| * The base class for GStreamer GL Filter. |
| */ |
| @@ -90,6 +92,8 @@ struct _GstGLBaseFilterClass |
| |
| GST_GL_API |
| gboolean gst_gl_base_filter_find_gl_context (GstGLBaseFilter * filter); |
| +GST_GL_API |
| +GstGLContext * gst_gl_base_filter_get_gl_context (GstGLBaseFilter * filter); |
| |
| G_END_DECLS |
| |
| diff --git a/tests/check/elements/glfilter.c b/tests/check/elements/glfilter.c |
| new file mode 100644 |
| index 000000000..0d8d67687 |
| --- /dev/null |
| +++ b/tests/check/elements/glfilter.c |
| @@ -0,0 +1,131 @@ |
| +/* GStreamer |
| + * |
| + * Copyright (C) 2019 Matthew Waters <matthew@centricular.com> |
| + * |
| + * 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. |
| + */ |
| + |
| + |
| +#ifdef HAVE_CONFIG_H |
| +#include "config.h" |
| +#endif |
| + |
| +#include <gst/gst.h> |
| +#include <gst/gl/gl.h> |
| +#include <gst/check/gstcheck.h> |
| +#include <gst/check/gstharness.h> |
| + |
| +static void |
| +replace_display (GstHarness * h) |
| +{ |
| + GstContext *new_context; |
| + GstGLDisplay *new_display; |
| + GstGLContext *expected, *gl_context; |
| + GstBuffer *buf; |
| + |
| + /* replaces the GstGLDisplay used by @h with verification */ |
| + |
| + buf = gst_harness_create_buffer (h, 4); |
| + buf = gst_harness_push_and_pull (h, buf); |
| + fail_unless (buf != NULL); |
| + gst_clear_buffer (&buf); |
| + |
| + g_object_get (G_OBJECT (h->element), "context", &gl_context, NULL); |
| + fail_unless (gl_context != NULL); |
| + gst_clear_object (&gl_context); |
| + |
| + new_display = gst_gl_display_new (); |
| + fail_unless (gst_gl_display_create_context (new_display, NULL, &expected, |
| + NULL)); |
| + fail_unless (expected != NULL); |
| + gst_gl_display_add_context (new_display, expected); |
| + |
| + new_context = gst_context_new (GST_GL_DISPLAY_CONTEXT_TYPE, TRUE); |
| + gst_context_set_gl_display (new_context, new_display); |
| + |
| + gst_element_set_context (h->element, new_context); |
| + gst_context_unref (new_context); |
| + new_context = NULL; |
| + |
| + buf = gst_harness_create_buffer (h, 4); |
| + buf = gst_harness_push_and_pull (h, buf); |
| + fail_unless (buf != NULL); |
| + gst_clear_buffer (&buf); |
| + |
| + g_object_get (G_OBJECT (h->element), "context", &gl_context, NULL); |
| + fail_unless (gl_context != NULL); |
| + |
| + fail_unless (gl_context == expected); |
| + fail_unless (new_display == gl_context->display); |
| + |
| + gst_object_unref (expected); |
| + gst_object_unref (gl_context); |
| + gst_object_unref (new_display); |
| +} |
| + |
| +GST_START_TEST (test_glupload_display_replace) |
| +{ |
| + GstHarness *upload; |
| + |
| + upload = gst_harness_new ("glupload"); |
| + gst_harness_set_caps_str (upload, "video/x-raw,format=RGBA,width=1,height=1", |
| + "video/x-raw(memory:GLMemory),format=RGBA,width=1,height=1"); |
| + |
| + replace_display (upload); |
| + |
| + gst_harness_teardown (upload); |
| +} |
| + |
| +GST_END_TEST; |
| + |
| +GST_START_TEST (test_glcolorconvert_display_replace) |
| +{ |
| + GstHarness *convert; |
| + |
| + convert = gst_harness_new ("glcolorconvert"); |
| + gst_harness_set_caps_str (convert, |
| + "video/x-raw(memory:GLMemory),format=RGBA,width=1,height=1,texture-target=2D", |
| + "video/x-raw(memory:GLMemory),format=RGBA,width=1,height=1,texture-target=2D"); |
| + |
| + replace_display (convert); |
| + |
| + gst_harness_teardown (convert); |
| +} |
| + |
| +GST_END_TEST; |
| + |
| +static Suite * |
| +glfilter_suite (void) |
| +{ |
| + Suite *s = suite_create ("glfilter"); |
| + TCase *tc = tcase_create ("general"); |
| + |
| + tcase_add_test (tc, test_glupload_display_replace); |
| + tcase_add_test (tc, test_glcolorconvert_display_replace); |
| + suite_add_tcase (s, tc); |
| + |
| + return s; |
| +} |
| + |
| +int |
| +main (int argc, char **argv) |
| +{ |
| + Suite *s; |
| + g_setenv ("GST_GL_XINITTHREADS", "1", TRUE); |
| + gst_check_init (&argc, &argv); |
| + s = glfilter_suite (); |
| + return gst_check_run_suite (s, "glfilter", __FILE__); |
| +} |
| diff --git a/tests/check/meson.build b/tests/check/meson.build |
| index 31fb67f15..c3f5bdd9a 100644 |
| --- a/tests/check/meson.build |
| +++ b/tests/check/meson.build |
| @@ -99,6 +99,7 @@ if build_gstgl and host_machine.system() != 'windows' |
| [ 'elements/glimagesink.c', not build_gstgl, [gstgl_dep]], |
| [ 'elements/glbin.c', not build_gstgl ], |
| [ 'pipelines/gl-launch-lines.c', not build_gstgl ], |
| + [ 'elements/glfilter.c', not build_gstgl, [gstgl_dep]], |
| ] |
| endif |
| |
| -- |
| 2.25.4 |
| |