1 /*
2  * GStreamer
3  * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 /**
22  * SECTION:element-glcolorscale
23  * @title: glcolorscale
24  *
25  * video frame scaling and colorspace conversion.
26  *
27  * ## Scaling and Color space conversion
28  *
29  * Equivalent to glupload ! gldownload.
30  *
31  * ## Examples
32  * |[
33  * gst-launch-1.0 -v videotestsrc ! video/x-raw ! glcolorscale ! ximagesink
34  * ]| A pipeline to test colorspace conversion.
35  * FBO is required.
36   |[
37  * gst-launch-1.0 -v videotestsrc ! video/x-raw, width=640, height=480, format=AYUV ! glcolorscale ! \
38  *   video/x-raw, width=320, height=240, format=YV12 ! videoconvert ! autovideosink
39  * ]| A pipeline to test hardware scaling and colorspace conversion.
40  * FBO and GLSL are required.
41  *
42  */
43 
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47 
48 #include "gstglcolorscale.h"
49 
50 #define GST_CAT_DEFAULT gst_gl_colorscale_debug
51 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
52 
53 /* Properties */
54 enum
55 {
56   PROP_0
57 };
58 
59 #define DEBUG_INIT \
60   GST_DEBUG_CATEGORY_INIT (gst_gl_colorscale_debug, "glcolorscale", 0, "glcolorscale element");
61 #define gst_gl_colorscale_parent_class parent_class
62 G_DEFINE_TYPE_WITH_CODE (GstGLColorscale, gst_gl_colorscale,
63     GST_TYPE_GL_FILTER, DEBUG_INIT);
64 
65 static void gst_gl_colorscale_set_property (GObject * object, guint prop_id,
66     const GValue * value, GParamSpec * pspec);
67 static void gst_gl_colorscale_get_property (GObject * object, guint prop_id,
68     GValue * value, GParamSpec * pspec);
69 
70 static gboolean gst_gl_colorscale_gl_start (GstGLBaseFilter * base_filter);
71 static void gst_gl_colorscale_gl_stop (GstGLBaseFilter * base_filter);
72 
73 static gboolean gst_gl_colorscale_filter_texture (GstGLFilter * filter,
74     GstGLMemory * in_tex, GstGLMemory * out_tex);
75 
76 static void
gst_gl_colorscale_class_init(GstGLColorscaleClass * klass)77 gst_gl_colorscale_class_init (GstGLColorscaleClass * klass)
78 {
79   GObjectClass *gobject_class;
80   GstElementClass *element_class;
81   GstBaseTransformClass *basetransform_class;
82   GstGLBaseFilterClass *base_filter_class;
83   GstGLFilterClass *filter_class;
84 
85   gobject_class = (GObjectClass *) klass;
86   element_class = GST_ELEMENT_CLASS (klass);
87   basetransform_class = GST_BASE_TRANSFORM_CLASS (klass);
88   base_filter_class = GST_GL_BASE_FILTER_CLASS (klass);
89   filter_class = GST_GL_FILTER_CLASS (klass);
90 
91   gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_CLASS (klass));
92 
93   gobject_class->set_property = gst_gl_colorscale_set_property;
94   gobject_class->get_property = gst_gl_colorscale_get_property;
95 
96   gst_element_class_set_metadata (element_class, "OpenGL color scale",
97       "Filter/Effect/Video", "Colorspace converter and video scaler",
98       "Julien Isorce <julien.isorce@gmail.com>\n"
99       "Matthew Waters <matthew@centricular.com>");
100 
101   basetransform_class->passthrough_on_same_caps = TRUE;
102 
103   base_filter_class->gl_start = GST_DEBUG_FUNCPTR (gst_gl_colorscale_gl_start);
104   base_filter_class->gl_stop = GST_DEBUG_FUNCPTR (gst_gl_colorscale_gl_stop);
105   base_filter_class->supported_gl_api =
106       GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2;
107 
108   filter_class->filter_texture = gst_gl_colorscale_filter_texture;
109 }
110 
111 static void
gst_gl_colorscale_init(GstGLColorscale * colorscale)112 gst_gl_colorscale_init (GstGLColorscale * colorscale)
113 {
114 }
115 
116 static void
gst_gl_colorscale_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)117 gst_gl_colorscale_set_property (GObject * object, guint prop_id,
118     const GValue * value, GParamSpec * pspec)
119 {
120   switch (prop_id) {
121     default:
122       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
123       break;
124   }
125 }
126 
127 static void
gst_gl_colorscale_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)128 gst_gl_colorscale_get_property (GObject * object, guint prop_id,
129     GValue * value, GParamSpec * pspec)
130 {
131   switch (prop_id) {
132     default:
133       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
134       break;
135   }
136 }
137 
138 static gboolean
gst_gl_colorscale_gl_start(GstGLBaseFilter * base_filter)139 gst_gl_colorscale_gl_start (GstGLBaseFilter * base_filter)
140 {
141   GstGLColorscale *colorscale = GST_GL_COLORSCALE (base_filter);
142   GstGLFilter *filter = GST_GL_FILTER (base_filter);
143   GstGLShader *shader;
144   GError *error = NULL;
145 
146   if (!(shader = gst_gl_shader_new_default (base_filter->context, &error))) {
147     GST_ERROR_OBJECT (colorscale, "Failed to initialize shader: %s",
148         error->message);
149     gst_object_unref (shader);
150     return FALSE;
151   }
152 
153   filter->draw_attr_position_loc =
154       gst_gl_shader_get_attribute_location (shader, "a_position");
155   filter->draw_attr_texture_loc =
156       gst_gl_shader_get_attribute_location (shader, "a_texcoord");
157 
158   colorscale->shader = shader;
159 
160   return GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base_filter);
161 }
162 
163 static void
gst_gl_colorscale_gl_stop(GstGLBaseFilter * base_filter)164 gst_gl_colorscale_gl_stop (GstGLBaseFilter * base_filter)
165 {
166   GstGLColorscale *colorscale = GST_GL_COLORSCALE (base_filter);
167 
168   if (colorscale->shader) {
169     gst_object_unref (colorscale->shader);
170     colorscale->shader = NULL;
171   }
172 
173   GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (base_filter);
174 }
175 
176 static gboolean
gst_gl_colorscale_filter_texture(GstGLFilter * filter,GstGLMemory * in_tex,GstGLMemory * out_tex)177 gst_gl_colorscale_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
178     GstGLMemory * out_tex)
179 {
180   GstGLColorscale *colorscale = GST_GL_COLORSCALE (filter);
181 
182   if (gst_gl_context_get_gl_api (GST_GL_BASE_FILTER (filter)->context))
183     gst_gl_filter_render_to_target_with_shader (filter, in_tex, out_tex,
184         colorscale->shader);
185 
186   return TRUE;
187 }
188