Merge branch 'upstream/1.16' into tizen_gst_1.16.2
[platform/upstream/gst-plugins-base.git] / gst / videoconvert / gstvideoconvert.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * This file:
4  * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
5  * Copyright (C) 2010 David Schleef <ds@schleef.org>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 /**
24  * SECTION:element-videoconvert
25  * @title: videoconvert
26  *
27  * Convert video frames between a great variety of video formats.
28  *
29  * ## Example launch line
30  * |[
31  * gst-launch-1.0 -v videotestsrc ! video/x-raw,format=YUY2 ! videoconvert ! autovideosink
32  * ]|
33  *  This will output a test video (generated in YUY2 format) in a video
34  * window. If the video sink selected does not support YUY2 videoconvert will
35  * automatically convert the video to a format understood by the video sink.
36  *
37  */
38
39 #ifdef HAVE_CONFIG_H
40 #  include "config.h"
41 #endif
42
43 #include "gstvideoconvert.h"
44
45 #include <gst/video/video.h>
46 #include <gst/video/gstvideometa.h>
47 #include <gst/video/gstvideopool.h>
48
49 #ifdef USE_TBM
50 #include <gst/allocators/gsttizenbufferpool.h>
51 #endif
52
53 #include <string.h>
54
55 GST_DEBUG_CATEGORY (videoconvert_debug);
56 #define GST_CAT_DEFAULT videoconvert_debug
57 GST_DEBUG_CATEGORY_STATIC (CAT_PERFORMANCE);
58
59 GType gst_video_convert_get_type (void);
60
61 static GQuark _colorspace_quark;
62
63 #define gst_video_convert_parent_class parent_class
64 G_DEFINE_TYPE (GstVideoConvert, gst_video_convert, GST_TYPE_VIDEO_FILTER);
65
66 #define DEFAULT_PROP_DITHER      GST_VIDEO_DITHER_BAYER
67 #define DEFAULT_PROP_DITHER_QUANTIZATION 1
68 #define DEFAULT_PROP_CHROMA_RESAMPLER   GST_VIDEO_RESAMPLER_METHOD_LINEAR
69 #define DEFAULT_PROP_ALPHA_MODE GST_VIDEO_ALPHA_MODE_COPY
70 #define DEFAULT_PROP_ALPHA_VALUE 1.0
71 #define DEFAULT_PROP_CHROMA_MODE GST_VIDEO_CHROMA_MODE_FULL
72 #define DEFAULT_PROP_MATRIX_MODE GST_VIDEO_MATRIX_MODE_FULL
73 #define DEFAULT_PROP_GAMMA_MODE GST_VIDEO_GAMMA_MODE_NONE
74 #define DEFAULT_PROP_PRIMARIES_MODE GST_VIDEO_PRIMARIES_MODE_NONE
75 #define DEFAULT_PROP_N_THREADS 1
76
77 enum
78 {
79   PROP_0,
80   PROP_DITHER,
81   PROP_DITHER_QUANTIZATION,
82   PROP_CHROMA_RESAMPLER,
83   PROP_ALPHA_MODE,
84   PROP_ALPHA_VALUE,
85   PROP_CHROMA_MODE,
86   PROP_MATRIX_MODE,
87   PROP_GAMMA_MODE,
88   PROP_PRIMARIES_MODE,
89   PROP_N_THREADS
90 };
91
92 #define CSP_VIDEO_CAPS GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) ";" \
93     GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", GST_VIDEO_FORMATS_ALL) ";" \
94     GST_VIDEO_CAPS_MAKE("{ SUYV , SYVY , S420 , ITLV }") ";" \
95     GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", "{ SUYV , SYVY , S420 , ITLV }")
96
97 #define CSP_VIDEO_SRC_CAPS GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) ";" \
98     GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", GST_VIDEO_FORMATS_ALL) ";" \
99     GST_VIDEO_CAPS_MAKE("{ SUYV , SYVY , S420 , ITLV , SN12 }") ";" \
100     GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", "{ SUYV , SYVY , S420 , ITLV , SN12 }")
101
102 static GstStaticPadTemplate gst_video_convert_src_template =
103 GST_STATIC_PAD_TEMPLATE ("src",
104     GST_PAD_SRC,
105     GST_PAD_ALWAYS,
106     GST_STATIC_CAPS (CSP_VIDEO_SRC_CAPS)
107     );
108
109 static GstStaticPadTemplate gst_video_convert_sink_template =
110 GST_STATIC_PAD_TEMPLATE ("sink",
111     GST_PAD_SINK,
112     GST_PAD_ALWAYS,
113     GST_STATIC_CAPS (CSP_VIDEO_CAPS)
114     );
115
116 static void gst_video_convert_set_property (GObject * object,
117     guint property_id, const GValue * value, GParamSpec * pspec);
118 static void gst_video_convert_get_property (GObject * object,
119     guint property_id, GValue * value, GParamSpec * pspec);
120
121 static gboolean gst_video_convert_set_info (GstVideoFilter * filter,
122     GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
123     GstVideoInfo * out_info);
124 static GstFlowReturn gst_video_convert_transform_frame (GstVideoFilter * filter,
125     GstVideoFrame * in_frame, GstVideoFrame * out_frame);
126
127 #ifdef USE_TBM
128 static gboolean gst_video_convert_decide_allocation (GstBaseTransform * bsrc,
129     GstQuery * query);
130 static GstFlowReturn gst_video_convert_prepare_output_buffer (GstBaseTransform * trans,
131     GstBuffer *input, GstBuffer **outbuf);
132 #endif
133
134 /* copies the given caps */
135 static GstCaps *
136 gst_video_convert_caps_remove_format_info (GstCaps * caps)
137 {
138   GstStructure *st;
139   GstCapsFeatures *f;
140   gint i, n;
141   GstCaps *res;
142
143   res = gst_caps_new_empty ();
144
145   n = gst_caps_get_size (caps);
146   for (i = 0; i < n; i++) {
147     st = gst_caps_get_structure (caps, i);
148     f = gst_caps_get_features (caps, i);
149
150     /* If this is already expressed by the existing caps
151      * skip this structure */
152     if (i > 0 && gst_caps_is_subset_structure_full (res, st, f))
153       continue;
154
155     st = gst_structure_copy (st);
156     /* Only remove format info for the cases when we can actually convert */
157     if (!gst_caps_features_is_any (f)
158         && gst_caps_features_is_equal (f,
159             GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY))
160       gst_structure_remove_fields (st, "format", "colorimetry", "chroma-site",
161           NULL);
162
163     gst_caps_append_structure_full (res, st, gst_caps_features_copy (f));
164   }
165
166   return res;
167 }
168
169 /*
170  * This is an incomplete matrix of in formats and a score for the prefered output
171  * format.
172  *
173  *         out: RGB24   RGB16  ARGB  AYUV  YUV444  YUV422 YUV420 YUV411 YUV410  PAL  GRAY
174  *  in
175  * RGB24          0      2       1     2     2       3      4      5      6      7    8
176  * RGB16          1      0       1     2     2       3      4      5      6      7    8
177  * ARGB           2      3       0     1     4       5      6      7      8      9    10
178  * AYUV           3      4       1     0     2       5      6      7      8      9    10
179  * YUV444         2      4       3     1     0       5      6      7      8      9    10
180  * YUV422         3      5       4     2     1       0      6      7      8      9    10
181  * YUV420         4      6       5     3     2       1      0      7      8      9    10
182  * YUV411         4      6       5     3     2       1      7      0      8      9    10
183  * YUV410         6      8       7     5     4       3      2      1      0      9    10
184  * PAL            1      3       2     6     4       6      7      8      9      0    10
185  * GRAY           1      4       3     2     1       5      6      7      8      9    0
186  *
187  * PAL or GRAY are never prefered, if we can we would convert to PAL instead
188  * of GRAY, though
189  * less subsampling is prefered and if any, preferably horizontal
190  * We would like to keep the alpha, even if we would need to to colorspace conversion
191  * or lose depth.
192  */
193 #define SCORE_FORMAT_CHANGE       1
194 #define SCORE_DEPTH_CHANGE        1
195 #define SCORE_ALPHA_CHANGE        1
196 #define SCORE_CHROMA_W_CHANGE     1
197 #define SCORE_CHROMA_H_CHANGE     1
198 #define SCORE_PALETTE_CHANGE      1
199
200 #define SCORE_COLORSPACE_LOSS     2     /* RGB <-> YUV */
201 #define SCORE_DEPTH_LOSS          4     /* change bit depth */
202 #define SCORE_ALPHA_LOSS          8     /* lose the alpha channel */
203 #define SCORE_CHROMA_W_LOSS      16     /* vertical subsample */
204 #define SCORE_CHROMA_H_LOSS      32     /* horizontal subsample */
205 #define SCORE_PALETTE_LOSS       64     /* convert to palette format */
206 #define SCORE_COLOR_LOSS        128     /* convert to GRAY */
207
208 #define COLORSPACE_MASK (GST_VIDEO_FORMAT_FLAG_YUV | \
209                          GST_VIDEO_FORMAT_FLAG_RGB | GST_VIDEO_FORMAT_FLAG_GRAY)
210 #define ALPHA_MASK      (GST_VIDEO_FORMAT_FLAG_ALPHA)
211 #define PALETTE_MASK    (GST_VIDEO_FORMAT_FLAG_PALETTE)
212
213 /* calculate how much loss a conversion would be */
214 static void
215 score_value (GstBaseTransform * base, const GstVideoFormatInfo * in_info,
216     const GValue * val, gint * min_loss, const GstVideoFormatInfo ** out_info)
217 {
218   const gchar *fname;
219   const GstVideoFormatInfo *t_info;
220   GstVideoFormatFlags in_flags, t_flags;
221   gint loss;
222
223   fname = g_value_get_string (val);
224   t_info = gst_video_format_get_info (gst_video_format_from_string (fname));
225   if (!t_info)
226     return;
227
228   /* accept input format immediately without loss */
229   if (in_info == t_info) {
230     *min_loss = 0;
231     *out_info = t_info;
232     return;
233   }
234
235   loss = SCORE_FORMAT_CHANGE;
236
237   in_flags = GST_VIDEO_FORMAT_INFO_FLAGS (in_info);
238   in_flags &= ~GST_VIDEO_FORMAT_FLAG_LE;
239   in_flags &= ~GST_VIDEO_FORMAT_FLAG_COMPLEX;
240   in_flags &= ~GST_VIDEO_FORMAT_FLAG_UNPACK;
241
242   t_flags = GST_VIDEO_FORMAT_INFO_FLAGS (t_info);
243   t_flags &= ~GST_VIDEO_FORMAT_FLAG_LE;
244   t_flags &= ~GST_VIDEO_FORMAT_FLAG_COMPLEX;
245   t_flags &= ~GST_VIDEO_FORMAT_FLAG_UNPACK;
246
247   if ((t_flags & PALETTE_MASK) != (in_flags & PALETTE_MASK)) {
248     loss += SCORE_PALETTE_CHANGE;
249     if (t_flags & PALETTE_MASK)
250       loss += SCORE_PALETTE_LOSS;
251   }
252
253   if ((t_flags & COLORSPACE_MASK) != (in_flags & COLORSPACE_MASK)) {
254     loss += SCORE_COLORSPACE_LOSS;
255     if (t_flags & GST_VIDEO_FORMAT_FLAG_GRAY)
256       loss += SCORE_COLOR_LOSS;
257   }
258
259   if ((t_flags & ALPHA_MASK) != (in_flags & ALPHA_MASK)) {
260     loss += SCORE_ALPHA_CHANGE;
261     if (in_flags & ALPHA_MASK)
262       loss += SCORE_ALPHA_LOSS;
263   }
264
265   if ((in_info->h_sub[1]) != (t_info->h_sub[1])) {
266     loss += SCORE_CHROMA_H_CHANGE;
267     if ((in_info->h_sub[1]) < (t_info->h_sub[1]))
268       loss += SCORE_CHROMA_H_LOSS;
269   }
270   if ((in_info->w_sub[1]) != (t_info->w_sub[1])) {
271     loss += SCORE_CHROMA_W_CHANGE;
272     if ((in_info->w_sub[1]) < (t_info->w_sub[1]))
273       loss += SCORE_CHROMA_W_LOSS;
274   }
275
276   if ((in_info->bits) != (t_info->bits)) {
277     loss += SCORE_DEPTH_CHANGE;
278     if ((in_info->bits) > (t_info->bits))
279       loss += SCORE_DEPTH_LOSS;
280   }
281
282   GST_DEBUG_OBJECT (base, "score %s -> %s = %d",
283       GST_VIDEO_FORMAT_INFO_NAME (in_info),
284       GST_VIDEO_FORMAT_INFO_NAME (t_info), loss);
285
286   if (loss < *min_loss) {
287     GST_DEBUG_OBJECT (base, "found new best %d", loss);
288     *out_info = t_info;
289     *min_loss = loss;
290   }
291 }
292
293 static void
294 gst_video_convert_fixate_format (GstBaseTransform * base, GstCaps * caps,
295     GstCaps * result)
296 {
297   GstStructure *ins, *outs;
298   const gchar *in_format;
299   const GstVideoFormatInfo *in_info, *out_info = NULL;
300   gint min_loss = G_MAXINT;
301   guint i, capslen;
302
303   ins = gst_caps_get_structure (caps, 0);
304   in_format = gst_structure_get_string (ins, "format");
305   if (!in_format)
306     return;
307
308   GST_DEBUG_OBJECT (base, "source format %s", in_format);
309
310   in_info =
311       gst_video_format_get_info (gst_video_format_from_string (in_format));
312   if (!in_info)
313     return;
314
315   outs = gst_caps_get_structure (result, 0);
316
317   capslen = gst_caps_get_size (result);
318   GST_DEBUG_OBJECT (base, "iterate %d structures", capslen);
319   for (i = 0; i < capslen; i++) {
320     GstStructure *tests;
321     const GValue *format;
322
323     tests = gst_caps_get_structure (result, i);
324     format = gst_structure_get_value (tests, "format");
325     /* should not happen */
326     if (format == NULL)
327       continue;
328
329     if (GST_VALUE_HOLDS_LIST (format)) {
330       gint j, len;
331
332       len = gst_value_list_get_size (format);
333       GST_DEBUG_OBJECT (base, "have %d formats", len);
334       for (j = 0; j < len; j++) {
335         const GValue *val;
336
337         val = gst_value_list_get_value (format, j);
338         if (G_VALUE_HOLDS_STRING (val)) {
339           score_value (base, in_info, val, &min_loss, &out_info);
340           if (min_loss == 0)
341             break;
342         }
343       }
344     } else if (G_VALUE_HOLDS_STRING (format)) {
345       score_value (base, in_info, format, &min_loss, &out_info);
346     }
347   }
348   if (out_info)
349     gst_structure_set (outs, "format", G_TYPE_STRING,
350         GST_VIDEO_FORMAT_INFO_NAME (out_info), NULL);
351 }
352
353
354 static GstCaps *
355 gst_video_convert_fixate_caps (GstBaseTransform * trans,
356     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
357 {
358   GstCaps *result;
359
360   GST_DEBUG_OBJECT (trans, "trying to fixate othercaps %" GST_PTR_FORMAT
361       " based on caps %" GST_PTR_FORMAT, othercaps, caps);
362
363   result = gst_caps_intersect (othercaps, caps);
364   if (gst_caps_is_empty (result)) {
365     gst_caps_unref (result);
366     result = othercaps;
367   } else {
368     gst_caps_unref (othercaps);
369   }
370
371   GST_DEBUG_OBJECT (trans, "now fixating %" GST_PTR_FORMAT, result);
372
373   result = gst_caps_make_writable (result);
374   gst_video_convert_fixate_format (trans, caps, result);
375
376   /* fixate remaining fields */
377   result = gst_caps_fixate (result);
378
379   if (direction == GST_PAD_SINK) {
380     if (gst_caps_is_subset (caps, result)) {
381       gst_caps_replace (&result, caps);
382     }
383   }
384
385   return result;
386 }
387
388 static gboolean
389 gst_video_convert_filter_meta (GstBaseTransform * trans, GstQuery * query,
390     GType api, const GstStructure * params)
391 {
392   /* This element cannot passthrough the crop meta, because it would convert the
393    * wrong sub-region of the image, and worst, our output image may not be large
394    * enough for the crop to be applied later */
395   if (api == GST_VIDEO_CROP_META_API_TYPE)
396     return FALSE;
397
398   /* propose all other metadata upstream */
399   return TRUE;
400 }
401
402 /* The caps can be transformed into any other caps with format info removed.
403  * However, we should prefer passthrough, so if passthrough is possible,
404  * put it first in the list. */
405 static GstCaps *
406 gst_video_convert_transform_caps (GstBaseTransform * btrans,
407     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
408 {
409   GstCaps *tmp, *tmp2;
410   GstCaps *result;
411
412   /* Get all possible caps that we can transform to */
413   tmp = gst_video_convert_caps_remove_format_info (caps);
414
415   if (filter) {
416     tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
417     gst_caps_unref (tmp);
418     tmp = tmp2;
419   }
420
421   result = tmp;
422
423   GST_DEBUG_OBJECT (btrans, "transformed %" GST_PTR_FORMAT " into %"
424       GST_PTR_FORMAT, caps, result);
425
426   return result;
427 }
428
429 static gboolean
430 gst_video_convert_transform_meta (GstBaseTransform * trans, GstBuffer * outbuf,
431     GstMeta * meta, GstBuffer * inbuf)
432 {
433   const GstMetaInfo *info = meta->info;
434   gboolean ret;
435
436   if (gst_meta_api_type_has_tag (info->api, _colorspace_quark)) {
437     /* don't copy colorspace specific metadata, FIXME, we need a MetaTransform
438      * for the colorspace metadata. */
439     ret = FALSE;
440   } else {
441     /* copy other metadata */
442     ret = TRUE;
443   }
444   return ret;
445 }
446
447 static gboolean
448 gst_video_convert_set_info (GstVideoFilter * filter,
449     GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
450     GstVideoInfo * out_info)
451 {
452   GstVideoConvert *space;
453
454   space = GST_VIDEO_CONVERT_CAST (filter);
455
456   if (space->convert) {
457     gst_video_converter_free (space->convert);
458     space->convert = NULL;
459   }
460
461   /* these must match */
462   if (in_info->width != out_info->width || in_info->height != out_info->height
463       || in_info->fps_n != out_info->fps_n || in_info->fps_d != out_info->fps_d)
464     goto format_mismatch;
465
466   /* if present, these must match too */
467   if (in_info->par_n != out_info->par_n || in_info->par_d != out_info->par_d)
468     goto format_mismatch;
469
470   /* if present, these must match too */
471   if (in_info->interlace_mode != out_info->interlace_mode)
472     goto format_mismatch;
473
474
475   space->convert = gst_video_converter_new (in_info, out_info,
476       gst_structure_new ("GstVideoConvertConfig",
477           GST_VIDEO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_VIDEO_DITHER_METHOD,
478           space->dither,
479           GST_VIDEO_CONVERTER_OPT_DITHER_QUANTIZATION, G_TYPE_UINT,
480           space->dither_quantization,
481           GST_VIDEO_CONVERTER_OPT_CHROMA_RESAMPLER_METHOD,
482           GST_TYPE_VIDEO_RESAMPLER_METHOD, space->chroma_resampler,
483           GST_VIDEO_CONVERTER_OPT_ALPHA_MODE,
484           GST_TYPE_VIDEO_ALPHA_MODE, space->alpha_mode,
485           GST_VIDEO_CONVERTER_OPT_ALPHA_VALUE,
486           G_TYPE_DOUBLE, space->alpha_value,
487           GST_VIDEO_CONVERTER_OPT_CHROMA_MODE,
488           GST_TYPE_VIDEO_CHROMA_MODE, space->chroma_mode,
489           GST_VIDEO_CONVERTER_OPT_MATRIX_MODE,
490           GST_TYPE_VIDEO_MATRIX_MODE, space->matrix_mode,
491           GST_VIDEO_CONVERTER_OPT_GAMMA_MODE,
492           GST_TYPE_VIDEO_GAMMA_MODE, space->gamma_mode,
493           GST_VIDEO_CONVERTER_OPT_PRIMARIES_MODE,
494           GST_TYPE_VIDEO_PRIMARIES_MODE, space->primaries_mode,
495           GST_VIDEO_CONVERTER_OPT_THREADS, G_TYPE_UINT,
496           space->n_threads, NULL));
497   if (space->convert == NULL)
498     goto no_convert;
499
500   GST_DEBUG ("reconfigured %d %d", GST_VIDEO_INFO_FORMAT (in_info),
501       GST_VIDEO_INFO_FORMAT (out_info));
502
503   return TRUE;
504
505   /* ERRORS */
506 format_mismatch:
507   {
508     GST_ERROR_OBJECT (space, "input and output formats do not match");
509     return FALSE;
510   }
511 no_convert:
512   {
513     GST_ERROR_OBJECT (space, "could not create converter");
514     return FALSE;
515   }
516 }
517
518 static void
519 gst_video_convert_finalize (GObject * obj)
520 {
521   GstVideoConvert *space = GST_VIDEO_CONVERT (obj);
522
523 #ifdef USE_TBM
524   if (space->pool) {
525      gst_buffer_pool_set_active (space->pool, FALSE);
526      gst_object_unref (space->pool);
527      space->pool = NULL;
528   }
529 #endif
530
531   if (space->convert) {
532     gst_video_converter_free (space->convert);
533   }
534
535   G_OBJECT_CLASS (parent_class)->finalize (obj);
536 }
537
538 static void
539 gst_video_convert_class_init (GstVideoConvertClass * klass)
540 {
541   GObjectClass *gobject_class = (GObjectClass *) klass;
542   GstElementClass *gstelement_class = (GstElementClass *) klass;
543   GstBaseTransformClass *gstbasetransform_class =
544       (GstBaseTransformClass *) klass;
545   GstVideoFilterClass *gstvideofilter_class = (GstVideoFilterClass *) klass;
546
547   gobject_class->set_property = gst_video_convert_set_property;
548   gobject_class->get_property = gst_video_convert_get_property;
549   gobject_class->finalize = gst_video_convert_finalize;
550
551   gst_element_class_add_static_pad_template (gstelement_class,
552       &gst_video_convert_src_template);
553   gst_element_class_add_static_pad_template (gstelement_class,
554       &gst_video_convert_sink_template);
555
556   gst_element_class_set_static_metadata (gstelement_class,
557       "Colorspace converter", "Filter/Converter/Video",
558       "Converts video from one colorspace to another",
559       "GStreamer maintainers <gstreamer-devel@lists.freedesktop.org>");
560
561   gstbasetransform_class->transform_caps =
562       GST_DEBUG_FUNCPTR (gst_video_convert_transform_caps);
563   gstbasetransform_class->fixate_caps =
564       GST_DEBUG_FUNCPTR (gst_video_convert_fixate_caps);
565   gstbasetransform_class->filter_meta =
566       GST_DEBUG_FUNCPTR (gst_video_convert_filter_meta);
567   gstbasetransform_class->transform_meta =
568       GST_DEBUG_FUNCPTR (gst_video_convert_transform_meta);
569
570   gstbasetransform_class->passthrough_on_same_caps = TRUE;
571
572   gstvideofilter_class->set_info =
573       GST_DEBUG_FUNCPTR (gst_video_convert_set_info);
574   gstvideofilter_class->transform_frame =
575       GST_DEBUG_FUNCPTR (gst_video_convert_transform_frame);
576
577 #ifdef USE_TBM
578   gstbasetransform_class->decide_allocation = gst_video_convert_decide_allocation;
579   gstbasetransform_class->prepare_output_buffer = gst_video_convert_prepare_output_buffer;
580 #endif
581
582   g_object_class_install_property (gobject_class, PROP_DITHER,
583       g_param_spec_enum ("dither", "Dither", "Apply dithering while converting",
584           gst_video_dither_method_get_type (), DEFAULT_PROP_DITHER,
585           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
586   g_object_class_install_property (gobject_class, PROP_DITHER_QUANTIZATION,
587       g_param_spec_uint ("dither-quantization", "Dither Quantize",
588           "Quantizer to use", 0, G_MAXUINT, DEFAULT_PROP_DITHER_QUANTIZATION,
589           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
590   g_object_class_install_property (gobject_class, PROP_CHROMA_RESAMPLER,
591       g_param_spec_enum ("chroma-resampler", "Chroma resampler",
592           "Chroma resampler method", gst_video_resampler_method_get_type (),
593           DEFAULT_PROP_CHROMA_RESAMPLER,
594           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
595   g_object_class_install_property (gobject_class, PROP_ALPHA_MODE,
596       g_param_spec_enum ("alpha-mode", "Alpha Mode",
597           "Alpha Mode to use", gst_video_alpha_mode_get_type (),
598           DEFAULT_PROP_ALPHA_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
599   g_object_class_install_property (gobject_class, PROP_ALPHA_VALUE,
600       g_param_spec_double ("alpha-value", "Alpha Value",
601           "Alpha Value to use", 0.0, 1.0,
602           DEFAULT_PROP_ALPHA_VALUE,
603           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
604   g_object_class_install_property (gobject_class, PROP_CHROMA_MODE,
605       g_param_spec_enum ("chroma-mode", "Chroma Mode", "Chroma Resampling Mode",
606           gst_video_chroma_mode_get_type (), DEFAULT_PROP_CHROMA_MODE,
607           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
608   g_object_class_install_property (gobject_class, PROP_MATRIX_MODE,
609       g_param_spec_enum ("matrix-mode", "Matrix Mode", "Matrix Conversion Mode",
610           gst_video_matrix_mode_get_type (), DEFAULT_PROP_MATRIX_MODE,
611           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
612   g_object_class_install_property (gobject_class, PROP_GAMMA_MODE,
613       g_param_spec_enum ("gamma-mode", "Gamma Mode", "Gamma Conversion Mode",
614           gst_video_gamma_mode_get_type (), DEFAULT_PROP_GAMMA_MODE,
615           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
616   g_object_class_install_property (gobject_class, PROP_PRIMARIES_MODE,
617       g_param_spec_enum ("primaries-mode", "Primaries Mode",
618           "Primaries Conversion Mode", gst_video_primaries_mode_get_type (),
619           DEFAULT_PROP_PRIMARIES_MODE,
620           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
621   g_object_class_install_property (gobject_class, PROP_N_THREADS,
622       g_param_spec_uint ("n-threads", "Threads",
623           "Maximum number of threads to use", 0, G_MAXUINT,
624           DEFAULT_PROP_N_THREADS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
625 }
626
627 static void
628 gst_video_convert_init (GstVideoConvert * space)
629 {
630 #ifdef USE_TBM
631   space->pool = NULL;
632 #endif
633   space->dither = DEFAULT_PROP_DITHER;
634   space->dither_quantization = DEFAULT_PROP_DITHER_QUANTIZATION;
635   space->chroma_resampler = DEFAULT_PROP_CHROMA_RESAMPLER;
636   space->alpha_mode = DEFAULT_PROP_ALPHA_MODE;
637   space->alpha_value = DEFAULT_PROP_ALPHA_VALUE;
638   space->chroma_mode = DEFAULT_PROP_CHROMA_MODE;
639   space->matrix_mode = DEFAULT_PROP_MATRIX_MODE;
640   space->gamma_mode = DEFAULT_PROP_GAMMA_MODE;
641   space->primaries_mode = DEFAULT_PROP_PRIMARIES_MODE;
642   space->n_threads = DEFAULT_PROP_N_THREADS;
643 }
644
645 void
646 gst_video_convert_set_property (GObject * object, guint property_id,
647     const GValue * value, GParamSpec * pspec)
648 {
649   GstVideoConvert *csp;
650
651   csp = GST_VIDEO_CONVERT (object);
652
653   switch (property_id) {
654     case PROP_DITHER:
655       csp->dither = g_value_get_enum (value);
656       break;
657     case PROP_CHROMA_RESAMPLER:
658       csp->chroma_resampler = g_value_get_enum (value);
659       break;
660     case PROP_ALPHA_MODE:
661       csp->alpha_mode = g_value_get_enum (value);
662       break;
663     case PROP_ALPHA_VALUE:
664       csp->alpha_value = g_value_get_double (value);
665       break;
666     case PROP_CHROMA_MODE:
667       csp->chroma_mode = g_value_get_enum (value);
668       break;
669     case PROP_MATRIX_MODE:
670       csp->matrix_mode = g_value_get_enum (value);
671       break;
672     case PROP_GAMMA_MODE:
673       csp->gamma_mode = g_value_get_enum (value);
674       break;
675     case PROP_PRIMARIES_MODE:
676       csp->primaries_mode = g_value_get_enum (value);
677       break;
678     case PROP_DITHER_QUANTIZATION:
679       csp->dither_quantization = g_value_get_uint (value);
680       break;
681     case PROP_N_THREADS:
682       csp->n_threads = g_value_get_uint (value);
683       break;
684     default:
685       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
686       break;
687   }
688 }
689
690 void
691 gst_video_convert_get_property (GObject * object, guint property_id,
692     GValue * value, GParamSpec * pspec)
693 {
694   GstVideoConvert *csp;
695
696   csp = GST_VIDEO_CONVERT (object);
697
698   switch (property_id) {
699     case PROP_DITHER:
700       g_value_set_enum (value, csp->dither);
701       break;
702     case PROP_CHROMA_RESAMPLER:
703       g_value_set_enum (value, csp->chroma_resampler);
704       break;
705     case PROP_ALPHA_MODE:
706       g_value_set_enum (value, csp->alpha_mode);
707       break;
708     case PROP_ALPHA_VALUE:
709       g_value_set_double (value, csp->alpha_value);
710       break;
711     case PROP_CHROMA_MODE:
712       g_value_set_enum (value, csp->chroma_mode);
713       break;
714     case PROP_MATRIX_MODE:
715       g_value_set_enum (value, csp->matrix_mode);
716       break;
717     case PROP_GAMMA_MODE:
718       g_value_set_enum (value, csp->gamma_mode);
719       break;
720     case PROP_PRIMARIES_MODE:
721       g_value_set_enum (value, csp->primaries_mode);
722       break;
723     case PROP_DITHER_QUANTIZATION:
724       g_value_set_uint (value, csp->dither_quantization);
725       break;
726     case PROP_N_THREADS:
727       g_value_set_uint (value, csp->n_threads);
728       break;
729     default:
730       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
731       break;
732   }
733 }
734
735 static GstFlowReturn
736 gst_video_convert_transform_frame (GstVideoFilter * filter,
737     GstVideoFrame * in_frame, GstVideoFrame * out_frame)
738 {
739   GstVideoConvert *space;
740
741   space = GST_VIDEO_CONVERT_CAST (filter);
742
743   GST_CAT_DEBUG_OBJECT (CAT_PERFORMANCE, filter,
744       "doing colorspace conversion from %s -> to %s",
745       GST_VIDEO_INFO_NAME (&filter->in_info),
746       GST_VIDEO_INFO_NAME (&filter->out_info));
747
748   gst_video_converter_frame (space->convert, in_frame, out_frame);
749
750   return GST_FLOW_OK;
751 }
752
753 #ifdef USE_TBM
754 static gboolean
755 gst_video_convert_decide_allocation (GstBaseTransform * trans,
756     GstQuery * query)
757 {
758   GstVideoConvert *vc = NULL;
759   GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
760   vc = GST_VIDEO_CONVERT_CAST(trans);
761
762   if (filter->out_info.finfo->format == GST_VIDEO_FORMAT_SN12 ) {
763     guint size;
764     GstStructure *config;
765     GstCaps *caps = NULL;
766     GstVideoInfo vinfo;
767     gst_query_parse_allocation (query, &caps, NULL);
768     gst_video_info_init (&vinfo);
769     gst_video_info_from_caps (&vinfo, caps);
770
771     size = vinfo.size;
772
773     if (caps) {
774       vc->pool = gst_tizen_buffer_pool_new ();
775       config = gst_buffer_pool_get_config (vc->pool);
776
777       gst_buffer_pool_config_set_params (config, caps, size, 4, 10);
778       gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
779       gst_buffer_pool_set_config (vc->pool, config);
780
781       if (!gst_buffer_pool_set_active (vc->pool, TRUE)) {
782         gst_object_unref (vc->pool);
783         vc->pool = NULL;
784         GST_INFO ("Failed to activate internal pool");
785       }
786     } else {
787       GST_ERROR("Not using our internal pool and copying buffers for downstream");
788       return FALSE;
789     }
790   }
791   GST_DEBUG("[%s]Creating Tizen Buffer Pool", __FUNCTION__);
792
793   return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans, query);
794 }
795
796 static GstFlowReturn
797 gst_video_convert_prepare_output_buffer (GstBaseTransform * trans,
798     GstBuffer *input, GstBuffer **outbuf)
799 {
800   GstBuffer *buf = NULL;
801   GstVideoConvert *vc = NULL;
802   GstVideoFilter *filter = GST_VIDEO_FILTER_CAST (trans);
803
804   vc = GST_VIDEO_CONVERT_CAST (trans);
805
806   if (filter->out_info.finfo->format == GST_VIDEO_FORMAT_SN12 ) {
807     if (gst_buffer_pool_acquire_buffer (vc->pool, &buf, 0) != GST_FLOW_OK) {
808       GST_ERROR("[%s] memory prepare failed.",__FUNCTION__);
809       return GST_FLOW_ERROR;
810     }
811
812     if (input != buf)
813       GST_BASE_TRANSFORM_CLASS (parent_class)->copy_metadata (trans, input, buf);
814     *outbuf = buf;
815
816     return GST_FLOW_OK;
817   }
818   return GST_BASE_TRANSFORM_CLASS (parent_class)->prepare_output_buffer(trans, input, outbuf);
819 }
820 #endif
821
822 static gboolean
823 plugin_init (GstPlugin * plugin)
824 {
825   GST_DEBUG_CATEGORY_INIT (videoconvert_debug, "videoconvert", 0,
826       "Colorspace Converter");
827
828   GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE");
829
830   _colorspace_quark = g_quark_from_static_string ("colorspace");
831
832   return gst_element_register (plugin, "videoconvert",
833       GST_RANK_NONE, GST_TYPE_VIDEO_CONVERT);
834 }
835
836 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
837     GST_VERSION_MINOR,
838     videoconvert, "Colorspace conversion", plugin_init, VERSION, GST_LICENSE,
839     GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)