glcolorconver: Return empty caps in transform_caps if fails.
[platform/upstream/gstreamer.git] / ext / gl / gstglcolorconvertelement.c
1 /*
2  * GStreamer
3  * Copyright (C) 2012-2014 Matthew Waters <ystree00@gmail.com>
4  * Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <gst/gl/gl.h>
27 #include "gstglcolorconvertelement.h"
28
29 GST_DEBUG_CATEGORY_STATIC (gst_gl_color_convert_element_debug);
30 #define gst_gl_color_convert_element_parent_class parent_class
31 #define GST_CAT_DEFAULT gst_gl_color_convert_element_debug
32
33 G_DEFINE_TYPE_WITH_CODE (GstGLColorConvertElement, gst_gl_color_convert_element,
34     GST_TYPE_GL_BASE_FILTER,
35     GST_DEBUG_CATEGORY_INIT (gst_gl_color_convert_element_debug,
36         "glconvertelement", 0, "convert");
37     );
38
39 static gboolean gst_gl_color_convert_element_gl_set_caps (GstGLBaseFilter *
40     base_filter, GstCaps * in_caps, GstCaps * out_caps);
41 static GstCaps *gst_gl_color_convert_element_transform_caps (GstBaseTransform *
42     bt, GstPadDirection direction, GstCaps * caps, GstCaps * filter);
43 static gboolean gst_gl_color_convert_element_get_unit_size (GstBaseTransform *
44     trans, GstCaps * caps, gsize * size);
45 static gboolean gst_gl_color_convert_element_filter_meta (GstBaseTransform *
46     trans, GstQuery * query, GType api, const GstStructure * params);
47 static gboolean gst_gl_color_convert_element_decide_allocation (GstBaseTransform
48     * trans, GstQuery * query);
49 static GstFlowReturn
50 gst_gl_color_convert_element_prepare_output_buffer (GstBaseTransform * bt,
51     GstBuffer * inbuf, GstBuffer ** outbuf);
52 static GstFlowReturn gst_gl_color_convert_element_transform (GstBaseTransform *
53     bt, GstBuffer * inbuf, GstBuffer * outbuf);
54 static GstCaps *gst_gl_color_convert_element_fixate_caps (GstBaseTransform * bt,
55     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
56 static GstStateChangeReturn
57 gst_gl_color_convert_element_change_state (GstElement * element,
58     GstStateChange transition);
59
60 static GstStaticPadTemplate gst_gl_color_convert_element_src_pad_template =
61 GST_STATIC_PAD_TEMPLATE ("src",
62     GST_PAD_SRC,
63     GST_PAD_ALWAYS,
64     GST_STATIC_CAPS (GST_GL_COLOR_CONVERT_VIDEO_CAPS));
65
66 static GstStaticPadTemplate gst_gl_color_convert_element_sink_pad_template =
67 GST_STATIC_PAD_TEMPLATE ("sink",
68     GST_PAD_SINK,
69     GST_PAD_ALWAYS,
70     GST_STATIC_CAPS (GST_GL_COLOR_CONVERT_VIDEO_CAPS));
71
72 static void
73 gst_gl_color_convert_element_gl_stop (GstGLBaseFilter * filter)
74 {
75   GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (filter);
76
77   if (convert->convert) {
78     gst_object_unref (convert->convert);
79     convert->convert = NULL;
80   }
81
82   GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (filter);
83 }
84
85 static void
86 gst_gl_color_convert_element_class_init (GstGLColorConvertElementClass * klass)
87 {
88   GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_CLASS (klass);
89   GstBaseTransformClass *bt_class = GST_BASE_TRANSFORM_CLASS (klass);
90   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
91
92   bt_class->transform_caps = gst_gl_color_convert_element_transform_caps;
93   bt_class->get_unit_size = gst_gl_color_convert_element_get_unit_size;
94   bt_class->filter_meta = gst_gl_color_convert_element_filter_meta;
95   bt_class->decide_allocation = gst_gl_color_convert_element_decide_allocation;
96   bt_class->prepare_output_buffer =
97       gst_gl_color_convert_element_prepare_output_buffer;
98   bt_class->transform = gst_gl_color_convert_element_transform;
99   bt_class->fixate_caps = gst_gl_color_convert_element_fixate_caps;
100
101   bt_class->passthrough_on_same_caps = TRUE;
102
103   element_class->change_state = gst_gl_color_convert_element_change_state;
104
105   gst_element_class_add_static_pad_template (element_class,
106       &gst_gl_color_convert_element_src_pad_template);
107   gst_element_class_add_static_pad_template (element_class,
108       &gst_gl_color_convert_element_sink_pad_template);
109
110   gst_element_class_set_metadata (element_class,
111       "OpenGL color converter", "Filter/Converter/Video",
112       "Converts between color spaces using OpenGL shaders",
113       "Matthew Waters <matthew@centricular.com>");
114
115   filter_class->gl_stop = gst_gl_color_convert_element_gl_stop;
116   filter_class->gl_set_caps = gst_gl_color_convert_element_gl_set_caps;
117 }
118
119 static void
120 gst_gl_color_convert_element_init (GstGLColorConvertElement * convert)
121 {
122   gst_base_transform_set_prefer_passthrough (GST_BASE_TRANSFORM (convert),
123       TRUE);
124 }
125
126 static gboolean
127 gst_gl_color_convert_element_gl_set_caps (GstGLBaseFilter * base_filter,
128     GstCaps * in_caps, GstCaps * out_caps)
129 {
130   GstGLColorConvertElement *convert =
131       GST_GL_COLOR_CONVERT_ELEMENT (base_filter);
132
133   if (!convert->convert && base_filter->context)
134     convert->convert = gst_gl_color_convert_new (base_filter->context);
135
136   if (!gst_gl_color_convert_set_caps (convert->convert, in_caps, out_caps))
137     return FALSE;
138
139   return TRUE;
140 }
141
142 static GstCaps *
143 gst_gl_color_convert_element_transform_caps (GstBaseTransform * bt,
144     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
145 {
146   GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (bt);
147   GstGLBaseFilter *base_filter = GST_GL_BASE_FILTER (bt);
148   GstGLContext *context;
149   GstCaps *ret;
150
151   if (base_filter->display && !gst_gl_base_filter_find_gl_context (base_filter))
152     return gst_caps_new_empty ();
153
154   context = gst_gl_base_filter_get_gl_context (base_filter);
155
156   if (!convert->convert && context)
157     convert->convert = gst_gl_color_convert_new (context);
158
159   ret = gst_gl_color_convert_transform_caps (context, direction, caps, filter);
160
161   gst_clear_object (&context);
162
163   return ret;
164 }
165
166 static gboolean
167 gst_gl_color_convert_element_get_unit_size (GstBaseTransform * trans,
168     GstCaps * caps, gsize * size)
169 {
170   gboolean ret = FALSE;
171   GstVideoInfo info;
172
173   ret = gst_video_info_from_caps (&info, caps);
174   if (ret)
175     *size = GST_VIDEO_INFO_SIZE (&info);
176
177   return TRUE;
178 }
179
180 static gboolean
181 gst_gl_color_convert_element_filter_meta (GstBaseTransform * trans,
182     GstQuery * query, GType api, const GstStructure * params)
183 {
184   /* propose all metadata upstream */
185   return TRUE;
186 }
187
188 static gboolean
189 gst_gl_color_convert_element_decide_allocation (GstBaseTransform * trans,
190     GstQuery * query)
191 {
192   GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (trans);
193
194   /* get gl context */
195   if (!GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans,
196           query))
197     return FALSE;
198
199   if (!gst_gl_color_convert_decide_allocation (convert->convert, query))
200     return FALSE;
201
202   return TRUE;
203 }
204
205 static GstFlowReturn
206 gst_gl_color_convert_element_prepare_output_buffer (GstBaseTransform * bt,
207     GstBuffer * inbuf, GstBuffer ** outbuf)
208 {
209   GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (bt);
210   GstBaseTransformClass *bclass;
211
212   bclass = GST_BASE_TRANSFORM_GET_CLASS (bt);
213
214   if (gst_base_transform_is_passthrough (bt)) {
215     *outbuf = inbuf;
216     return GST_FLOW_OK;
217   }
218
219   if (!convert->convert)
220     return GST_FLOW_NOT_NEGOTIATED;
221
222   *outbuf = gst_gl_color_convert_perform (convert->convert, inbuf);
223   if (!*outbuf) {
224     GST_ELEMENT_ERROR (bt, RESOURCE, NOT_FOUND,
225         ("%s", "Failed to convert video buffer"), (NULL));
226     return GST_FLOW_ERROR;
227   }
228
229   /* basetransform doesn't unref if they're the same */
230   if (inbuf == *outbuf)
231     gst_buffer_unref (*outbuf);
232   else
233     bclass->copy_metadata (bt, inbuf, *outbuf);
234
235   return GST_FLOW_OK;
236 }
237
238 static GstFlowReturn
239 gst_gl_color_convert_element_transform (GstBaseTransform * bt,
240     GstBuffer * inbuf, GstBuffer * outbuf)
241 {
242   return GST_FLOW_OK;
243 }
244
245 static GstCaps *
246 gst_gl_color_convert_element_fixate_caps (GstBaseTransform *
247     bt, GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
248 {
249   GstGLContext *context = GST_GL_BASE_FILTER (bt)->context;
250
251   return gst_gl_color_convert_fixate_caps (context, direction, caps, othercaps);
252 }
253
254 static GstStateChangeReturn
255 gst_gl_color_convert_element_change_state (GstElement * element,
256     GstStateChange transition)
257 {
258   GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (element);
259   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
260
261   GST_DEBUG_OBJECT (convert, "changing state: %s => %s",
262       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
263       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
264
265   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
266   if (ret == GST_STATE_CHANGE_FAILURE)
267     return ret;
268
269   switch (transition) {
270     case GST_STATE_CHANGE_READY_TO_NULL:
271       if (convert->convert) {
272         gst_object_unref (convert->convert);
273         convert->convert = NULL;
274       }
275       break;
276     default:
277       break;
278   }
279
280   return ret;
281 }