Merge branch 'move_subdir_base' into tizen_gst_1.19.2_mono
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-base / gst-libs / gst / video / gstvideofilter.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2003> David Schleef <ds@schleef.org>
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:gstvideofilter
23  * @title: GstVideoFilter
24  * @short_description: Base class for video filters
25  *
26  * Provides useful functions and a base class for video filters.
27  *
28  * The videofilter will by default enable QoS on the parent GstBaseTransform
29  * to implement frame dropping.
30  *
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "gstvideofilter.h"
38
39 #include <gst/video/video.h>
40 #include <gst/video/gstvideometa.h>
41 #include <gst/video/gstvideopool.h>
42
43 GST_DEBUG_CATEGORY_STATIC (gst_video_filter_debug);
44 #define GST_CAT_DEFAULT gst_video_filter_debug
45
46 #define gst_video_filter_parent_class parent_class
47 G_DEFINE_ABSTRACT_TYPE (GstVideoFilter, gst_video_filter,
48     GST_TYPE_BASE_TRANSFORM);
49
50 /* cached quark to avoid contention on the global quark table lock */
51 #define META_TAG_VIDEO meta_tag_video_quark
52 static GQuark meta_tag_video_quark;
53
54 /* Answer the allocation query downstream. */
55 static gboolean
56 gst_video_filter_propose_allocation (GstBaseTransform * trans,
57     GstQuery * decide_query, GstQuery * query)
58 {
59   GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
60   GstVideoInfo info;
61   GstBufferPool *pool;
62   GstCaps *caps;
63   guint size;
64
65   if (!GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans,
66           decide_query, query))
67     return FALSE;
68
69   /* passthrough, we're done */
70   if (decide_query == NULL)
71     return TRUE;
72
73   gst_query_parse_allocation (query, &caps, NULL);
74
75   if (caps == NULL)
76     return FALSE;
77
78   if (!gst_video_info_from_caps (&info, caps))
79     return FALSE;
80
81   size = GST_VIDEO_INFO_SIZE (&info);
82
83   if (gst_query_get_n_allocation_pools (query) == 0) {
84     GstStructure *structure;
85     GstAllocator *allocator = NULL;
86     GstAllocationParams params = { 0, 15, 0, 0, };
87
88     if (gst_query_get_n_allocation_params (query) > 0)
89       gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
90     else
91       gst_query_add_allocation_param (query, allocator, &params);
92
93     pool = gst_video_buffer_pool_new ();
94
95     structure = gst_buffer_pool_get_config (pool);
96     gst_buffer_pool_config_set_params (structure, caps, size, 0, 0);
97     gst_buffer_pool_config_set_allocator (structure, allocator, &params);
98
99     if (allocator)
100       gst_object_unref (allocator);
101
102     if (!gst_buffer_pool_set_config (pool, structure))
103       goto config_failed;
104
105     gst_query_add_allocation_pool (query, pool, size, 0, 0);
106     gst_object_unref (pool);
107     gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
108   }
109
110   return TRUE;
111
112   /* ERRORS */
113 config_failed:
114   {
115     GST_ERROR_OBJECT (filter, "failed to set config");
116     gst_object_unref (pool);
117     return FALSE;
118   }
119 }
120
121 /* configure the allocation query that was answered downstream, we can configure
122  * some properties on it. Only called when not in passthrough mode. */
123 static gboolean
124 gst_video_filter_decide_allocation (GstBaseTransform * trans, GstQuery * query)
125 {
126   GstBufferPool *pool = NULL;
127   GstStructure *config;
128   guint min, max, size;
129   gboolean update_pool;
130   GstCaps *outcaps = NULL;
131
132   if (gst_query_get_n_allocation_pools (query) > 0) {
133     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
134
135     if (!pool)
136       gst_query_parse_allocation (query, &outcaps, NULL);
137
138     update_pool = TRUE;
139   } else {
140     GstVideoInfo vinfo;
141
142     gst_query_parse_allocation (query, &outcaps, NULL);
143     gst_video_info_init (&vinfo);
144     gst_video_info_from_caps (&vinfo, outcaps);
145     size = vinfo.size;
146     min = max = 0;
147     update_pool = FALSE;
148   }
149
150   if (!pool)
151     pool = gst_video_buffer_pool_new ();
152
153   config = gst_buffer_pool_get_config (pool);
154   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
155   if (outcaps)
156     gst_buffer_pool_config_set_params (config, outcaps, size, 0, 0);
157   gst_buffer_pool_set_config (pool, config);
158
159   if (update_pool)
160     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
161   else
162     gst_query_add_allocation_pool (query, pool, size, min, max);
163
164   gst_object_unref (pool);
165
166   return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans,
167       query);
168 }
169
170
171 /* our output size only depends on the caps, not on the input caps */
172 static gboolean
173 gst_video_filter_transform_size (GstBaseTransform * btrans,
174     GstPadDirection direction, GstCaps * caps, gsize size,
175     GstCaps * othercaps, gsize * othersize)
176 {
177   gboolean ret = TRUE;
178   GstVideoInfo info;
179
180   g_assert (size);
181
182   ret = gst_video_info_from_caps (&info, othercaps);
183   if (ret)
184     *othersize = info.size;
185
186   return ret;
187 }
188
189 static gboolean
190 gst_video_filter_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
191     gsize * size)
192 {
193   GstVideoInfo info;
194
195   if (!gst_video_info_from_caps (&info, caps)) {
196     GST_WARNING_OBJECT (btrans, "Failed to parse caps %" GST_PTR_FORMAT, caps);
197     return FALSE;
198   }
199
200   *size = info.size;
201
202   GST_DEBUG_OBJECT (btrans, "Returning size %" G_GSIZE_FORMAT " bytes"
203       "for caps %" GST_PTR_FORMAT, *size, caps);
204
205   return TRUE;
206 }
207
208 static gboolean
209 gst_video_filter_set_caps (GstBaseTransform * trans, GstCaps * incaps,
210     GstCaps * outcaps)
211 {
212   GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
213   GstVideoFilterClass *fclass;
214   GstVideoInfo in_info, out_info;
215   gboolean res;
216
217   /* input caps */
218   if (!gst_video_info_from_caps (&in_info, incaps))
219     goto invalid_caps;
220
221   /* output caps */
222   if (!gst_video_info_from_caps (&out_info, outcaps))
223     goto invalid_caps;
224
225   fclass = GST_VIDEO_FILTER_GET_CLASS (filter);
226   if (fclass->set_info)
227     res = fclass->set_info (filter, incaps, &in_info, outcaps, &out_info);
228   else
229     res = TRUE;
230
231   if (res) {
232     filter->in_info = in_info;
233     filter->out_info = out_info;
234     if (fclass->transform_frame == NULL)
235       gst_base_transform_set_in_place (trans, TRUE);
236     if (fclass->transform_frame_ip == NULL)
237       GST_BASE_TRANSFORM_CLASS (fclass)->transform_ip_on_passthrough = FALSE;
238   }
239   filter->negotiated = res;
240
241   return res;
242
243   /* ERRORS */
244 invalid_caps:
245   {
246     GST_ERROR_OBJECT (filter, "invalid caps");
247     filter->negotiated = FALSE;
248     return FALSE;
249   }
250 }
251
252 static GstFlowReturn
253 gst_video_filter_transform (GstBaseTransform * trans, GstBuffer * inbuf,
254     GstBuffer * outbuf)
255 {
256   GstFlowReturn res;
257   GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
258   GstVideoFilterClass *fclass;
259 #ifdef USE_TBM
260   GstMapFlags map_flags;
261 #endif
262
263   if (G_UNLIKELY (!filter->negotiated))
264     goto unknown_format;
265
266   fclass = GST_VIDEO_FILTER_GET_CLASS (filter);
267   if (fclass->transform_frame) {
268     GstVideoFrame in_frame, out_frame;
269
270 #ifdef USE_TBM
271     map_flags = GST_MAP_READ;
272     if (filter->in_info.finfo->format != GST_VIDEO_FORMAT_SN12 &&
273       filter->in_info.finfo->format != GST_VIDEO_FORMAT_SR32)
274       map_flags |= GST_VIDEO_FRAME_MAP_FLAG_NO_REF;
275
276     GST_LOG_OBJECT (trans, "IN format %d, flags 0x%x",
277       filter->in_info.finfo->format, map_flags);
278
279     if (!gst_video_frame_map (&in_frame, &filter->in_info, inbuf, map_flags))
280       goto invalid_buffer;
281
282     map_flags = GST_MAP_WRITE;
283     if (filter->out_info.finfo->format != GST_VIDEO_FORMAT_SN12 &&
284       filter->out_info.finfo->format != GST_VIDEO_FORMAT_SR32)
285       map_flags |= GST_VIDEO_FRAME_MAP_FLAG_NO_REF;
286
287     GST_LOG_OBJECT (trans, "OUT format %d, flags 0x%x",
288       filter->out_info.finfo->format, map_flags);
289
290     if (!gst_video_frame_map (&out_frame, &filter->out_info, outbuf, map_flags)) {
291       gst_video_frame_unmap (&in_frame);
292       goto invalid_buffer;
293     }
294 #else
295     if (!gst_video_frame_map (&in_frame, &filter->in_info, inbuf,
296             GST_MAP_READ | GST_VIDEO_FRAME_MAP_FLAG_NO_REF))
297       goto invalid_buffer;
298
299     if (!gst_video_frame_map (&out_frame, &filter->out_info, outbuf,
300             GST_MAP_WRITE | GST_VIDEO_FRAME_MAP_FLAG_NO_REF)) {
301       gst_video_frame_unmap (&in_frame);
302       goto invalid_buffer;
303     }
304 #endif
305     res = fclass->transform_frame (filter, &in_frame, &out_frame);
306
307     gst_video_frame_unmap (&out_frame);
308     gst_video_frame_unmap (&in_frame);
309   } else {
310     GST_DEBUG_OBJECT (trans, "no transform_frame vmethod");
311     res = GST_FLOW_OK;
312   }
313
314   return res;
315
316   /* ERRORS */
317 unknown_format:
318   {
319     GST_ELEMENT_ERROR (filter, CORE, NOT_IMPLEMENTED, (NULL),
320         ("unknown format"));
321     return GST_FLOW_NOT_NEGOTIATED;
322   }
323 invalid_buffer:
324   {
325     GST_ELEMENT_WARNING (filter, CORE, NOT_IMPLEMENTED, (NULL),
326         ("invalid video buffer received"));
327     return GST_FLOW_OK;
328   }
329 }
330
331 static GstFlowReturn
332 gst_video_filter_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
333 {
334   GstFlowReturn res;
335   GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
336   GstVideoFilterClass *fclass;
337
338   if (G_UNLIKELY (!filter->negotiated))
339     goto unknown_format;
340
341   fclass = GST_VIDEO_FILTER_GET_CLASS (filter);
342   if (fclass->transform_frame_ip) {
343     GstVideoFrame frame;
344     GstMapFlags flags;
345
346     flags = GST_MAP_READ | GST_VIDEO_FRAME_MAP_FLAG_NO_REF;
347
348     if (!gst_base_transform_is_passthrough (trans))
349       flags |= GST_MAP_WRITE;
350
351     if (!gst_video_frame_map (&frame, &filter->in_info, buf, flags))
352       goto invalid_buffer;
353
354     res = fclass->transform_frame_ip (filter, &frame);
355
356     gst_video_frame_unmap (&frame);
357   } else {
358     GST_DEBUG_OBJECT (trans, "no transform_frame_ip vmethod");
359     res = GST_FLOW_OK;
360   }
361
362   return res;
363
364   /* ERRORS */
365 unknown_format:
366   {
367     GST_ELEMENT_ERROR (filter, CORE, NOT_IMPLEMENTED, (NULL),
368         ("unknown format"));
369     return GST_FLOW_NOT_NEGOTIATED;
370   }
371 invalid_buffer:
372   {
373     GST_ELEMENT_WARNING (filter, CORE, NOT_IMPLEMENTED, (NULL),
374         ("invalid video buffer received"));
375     return GST_FLOW_OK;
376   }
377 }
378
379 static gboolean
380 gst_video_filter_transform_meta (GstBaseTransform * trans, GstBuffer * outbuf,
381     GstMeta * meta, GstBuffer * inbuf)
382 {
383   const GstMetaInfo *info = meta->info;
384   const gchar *const *tags;
385
386   tags = gst_meta_api_type_get_tags (info->api);
387
388   if (!tags || (g_strv_length ((gchar **) tags) == 1
389           && gst_meta_api_type_has_tag (info->api, META_TAG_VIDEO)))
390     return TRUE;
391
392   return GST_BASE_TRANSFORM_CLASS (parent_class)->transform_meta (trans, outbuf,
393       meta, inbuf);
394 }
395
396 static void
397 gst_video_filter_class_init (GstVideoFilterClass * g_class)
398 {
399   GstBaseTransformClass *trans_class;
400   GstVideoFilterClass *klass;
401
402   klass = (GstVideoFilterClass *) g_class;
403   trans_class = (GstBaseTransformClass *) klass;
404
405   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_video_filter_set_caps);
406   trans_class->propose_allocation =
407       GST_DEBUG_FUNCPTR (gst_video_filter_propose_allocation);
408   trans_class->decide_allocation =
409       GST_DEBUG_FUNCPTR (gst_video_filter_decide_allocation);
410   trans_class->transform_size =
411       GST_DEBUG_FUNCPTR (gst_video_filter_transform_size);
412   trans_class->get_unit_size =
413       GST_DEBUG_FUNCPTR (gst_video_filter_get_unit_size);
414   trans_class->transform = GST_DEBUG_FUNCPTR (gst_video_filter_transform);
415   trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_video_filter_transform_ip);
416   trans_class->transform_meta =
417       GST_DEBUG_FUNCPTR (gst_video_filter_transform_meta);
418
419   GST_DEBUG_CATEGORY_INIT (gst_video_filter_debug, "videofilter", 0,
420       "videofilter");
421
422   meta_tag_video_quark = g_quark_from_static_string (GST_META_TAG_VIDEO_STR);
423 }
424
425 static void
426 gst_video_filter_init (GstVideoFilter * instance)
427 {
428   GstVideoFilter *videofilter = GST_VIDEO_FILTER (instance);
429
430   GST_DEBUG_OBJECT (videofilter, "gst_video_filter_init");
431
432   videofilter->negotiated = FALSE;
433   /* enable QoS */
434   gst_base_transform_set_qos_enabled (GST_BASE_TRANSFORM (videofilter), TRUE);
435 }