| /* |
| * GStreamer |
| * Copyright (C) 2012-2014 Matthew Waters <ystree00@gmail.com> |
| * Copyright (C) 2015 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/gl/gl.h> |
| #include "gstglcolorconvertelement.h" |
| |
| GST_DEBUG_CATEGORY_STATIC (gst_gl_color_convert_element_debug); |
| #define GST_CAT_DEFAULT gst_gl_color_convert_element_debug |
| |
| G_DEFINE_TYPE_WITH_CODE (GstGLColorConvertElement, gst_gl_color_convert_element, |
| GST_TYPE_GL_BASE_FILTER, |
| GST_DEBUG_CATEGORY_INIT (gst_gl_color_convert_element_debug, |
| "glconvertelement", 0, "convert"); |
| ); |
| |
| enum |
| { |
| GL_COLOR_CONVERT_PROP_0, |
| GL_COLOR_CONVERT_PROP_DISABLE_PASSTHROUGH |
| }; |
| |
| #define DISABLE_PASSTHROUGH_DAFAULT FALSE |
| |
| static gboolean gst_gl_color_convert_element_set_caps (GstBaseTransform * bt, |
| 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_decide_allocation (GstBaseTransform |
| * trans, GstQuery * query); |
| static GstFlowReturn |
| 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 void gst_gl_color_convert_set_property (GObject *object, |
| guint prop_id, |
| const GValue *value, |
| GParamSpec *pspec); |
| static void gst_gl_color_convert_get_property (GObject *object, |
| guint prop_id, |
| GValue *value, |
| GParamSpec *pspec); |
| |
| static GstStaticPadTemplate gst_gl_color_convert_element_src_pad_template = |
| GST_STATIC_PAD_TEMPLATE ("src", |
| GST_PAD_SRC, |
| GST_PAD_ALWAYS, |
| GST_STATIC_CAPS (GST_GL_COLOR_CONVERT_VIDEO_CAPS)); |
| |
| static GstStaticPadTemplate gst_gl_color_convert_element_sink_pad_template = |
| GST_STATIC_PAD_TEMPLATE ("sink", |
| GST_PAD_SINK, |
| GST_PAD_ALWAYS, |
| GST_STATIC_CAPS (GST_GL_COLOR_CONVERT_VIDEO_CAPS)); |
| |
| static gboolean |
| gst_gl_color_convert_element_stop (GstBaseTransform * bt) |
| { |
| GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (bt); |
| |
| if (convert->convert) { |
| gst_object_unref (convert->convert); |
| convert->convert = NULL; |
| } |
| |
| gst_caps_replace (&convert->in_caps, NULL); |
| gst_caps_replace (&convert->out_caps, NULL); |
| |
| return |
| GST_BASE_TRANSFORM_CLASS (gst_gl_color_convert_element_parent_class)->stop |
| (bt); |
| } |
| |
| static void |
| gst_gl_color_convert_element_class_init (GstGLColorConvertElementClass * klass) |
| { |
| GstBaseTransformClass *bt_class = GST_BASE_TRANSFORM_CLASS (klass); |
| GstElementClass *element_class = GST_ELEMENT_CLASS (klass); |
| GObjectClass *object_class = G_OBJECT_CLASS (klass); |
| |
| object_class->set_property = gst_gl_color_convert_set_property; |
| object_class->get_property = gst_gl_color_convert_get_property; |
| |
| 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; |
| |
| gst_element_class_add_static_pad_template (element_class, |
| &gst_gl_color_convert_element_src_pad_template); |
| gst_element_class_add_static_pad_template (element_class, |
| &gst_gl_color_convert_element_sink_pad_template); |
| |
| g_object_class_install_property (object_class, GL_COLOR_CONVERT_PROP_DISABLE_PASSTHROUGH, |
| g_param_spec_boolean ("disable_passthrough", |
| "Disable passthrough", |
| "Disable passthrough mode", |
| DISABLE_PASSTHROUGH_DAFAULT, |
| G_PARAM_READWRITE)); |
| |
| gst_element_class_set_metadata (element_class, |
| "OpenGL color converter", "Filter/Converter/Video", |
| "Converts between color spaces using OpenGL shaders", |
| "Matthew Waters <matthew@centricular.com>"); |
| } |
| |
| static void |
| gst_gl_color_convert_element_init (GstGLColorConvertElement * convert) |
| { |
| gst_base_transform_set_prefer_passthrough (GST_BASE_TRANSFORM (convert), |
| TRUE); |
| convert->disable_passthrough = FALSE; |
| } |
| |
| static void |
| gst_gl_color_convert_set_property (GObject *object, |
| guint prop_id, |
| const GValue *value, |
| GParamSpec *pspec) |
| { |
| GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (object); |
| switch (prop_id) { |
| case GL_COLOR_CONVERT_PROP_DISABLE_PASSTHROUGH: |
| convert->disable_passthrough = g_value_get_boolean (value); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static void |
| gst_gl_color_convert_get_property (GObject *object, |
| guint prop_id, |
| GValue *value, |
| GParamSpec *pspec) |
| { |
| GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (object); |
| switch (prop_id) { |
| case GL_COLOR_CONVERT_PROP_DISABLE_PASSTHROUGH: |
| g_value_set_boolean (value, convert->disable_passthrough); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static gboolean |
| gst_gl_color_convert_element_set_caps (GstBaseTransform * bt, |
| GstCaps * in_caps, GstCaps * out_caps) |
| { |
| GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (bt); |
| |
| gst_caps_replace (&convert->in_caps, in_caps); |
| gst_caps_replace (&convert->out_caps, out_caps); |
| |
| if (convert->convert) |
| gst_gl_color_convert_set_caps (convert->convert, in_caps, out_caps); |
| |
| if(gst_base_transform_is_passthrough (bt) && convert->disable_passthrough){ |
| /* if in passthrough mode and disable_passthrough is set to true, |
| * set passthrough to FALSE*/ |
| GST_DEBUG_OBJECT(convert, "Disable passthrough mode"); |
| gst_base_transform_set_passthrough(bt, FALSE); |
| } |
| |
| return TRUE; |
| } |
| |
| static GstCaps * |
| gst_gl_color_convert_element_transform_caps (GstBaseTransform * bt, |
| GstPadDirection direction, GstCaps * caps, GstCaps * filter) |
| { |
| GstGLContext *context = GST_GL_BASE_FILTER (bt)->context; |
| |
| return gst_gl_color_convert_transform_caps (context, direction, caps, filter); |
| } |
| |
| static gboolean |
| gst_gl_color_convert_element_get_unit_size (GstBaseTransform * trans, |
| GstCaps * caps, gsize * size) |
| { |
| gboolean ret = FALSE; |
| GstVideoInfo info; |
| |
| ret = gst_video_info_from_caps (&info, caps); |
| if (ret) |
| *size = GST_VIDEO_INFO_SIZE (&info); |
| |
| return TRUE; |
| } |
| |
| static gboolean |
| gst_gl_color_convert_element_filter_meta (GstBaseTransform * trans, |
| GstQuery * query, GType api, const GstStructure * params) |
| { |
| /* propose all metadata upstream */ |
| return TRUE; |
| } |
| |
| static gboolean |
| gst_gl_color_convert_element_decide_allocation (GstBaseTransform * trans, |
| GstQuery * query) |
| { |
| GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (trans); |
| GstGLContext *context; |
| |
| /* get gl context */ |
| if (!GST_BASE_TRANSFORM_CLASS |
| (gst_gl_color_convert_element_parent_class)->decide_allocation (trans, |
| query)) |
| return FALSE; |
| |
| context = GST_GL_BASE_FILTER (trans)->context; |
| |
| if (!convert->convert) |
| convert->convert = gst_gl_color_convert_new (context); |
| |
| if (!gst_gl_color_convert_set_caps (convert->convert, convert->in_caps, |
| convert->out_caps)) |
| return FALSE; |
| |
| if (!gst_gl_color_convert_decide_allocation (convert->convert, query)) |
| return FALSE; |
| |
| return TRUE; |
| } |
| |
| static GstFlowReturn |
| gst_gl_color_convert_element_prepare_output_buffer (GstBaseTransform * bt, |
| GstBuffer * inbuf, GstBuffer ** outbuf) |
| { |
| GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (bt); |
| GstBaseTransformClass *bclass; |
| |
| bclass = GST_BASE_TRANSFORM_GET_CLASS (bt); |
| |
| if (gst_base_transform_is_passthrough (bt)) { |
| *outbuf = inbuf; |
| return GST_FLOW_OK; |
| } |
| |
| if (!convert->convert) |
| return GST_FLOW_NOT_NEGOTIATED; |
| |
| *outbuf = gst_gl_color_convert_perform (convert->convert, inbuf); |
| if (!*outbuf) { |
| GST_ELEMENT_ERROR (bt, RESOURCE, NOT_FOUND, |
| ("%s", "Failed to convert video buffer"), (NULL)); |
| return GST_FLOW_ERROR; |
| } |
| |
| /* basetransform doesn't unref if they're the same */ |
| if (inbuf == *outbuf) |
| gst_buffer_unref (*outbuf); |
| else |
| bclass->copy_metadata (bt, inbuf, *outbuf); |
| |
| return GST_FLOW_OK; |
| } |
| |
| static GstFlowReturn |
| gst_gl_color_convert_element_transform (GstBaseTransform * bt, |
| GstBuffer * inbuf, GstBuffer * outbuf) |
| { |
| return GST_FLOW_OK; |
| } |
| |
| static GstCaps * |
| gst_gl_color_convert_element_fixate_caps (GstBaseTransform * |
| bt, GstPadDirection direction, GstCaps * caps, GstCaps * othercaps) |
| { |
| GstGLContext *context = GST_GL_BASE_FILTER (bt)->context; |
| |
| return gst_gl_color_convert_fixate_caps (context, direction, caps, othercaps); |
| } |