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