libs: filter: use macro for returning op default value
[platform/upstream/gstreamer.git] / gst-libs / gst / vaapi / gstvaapifilter.c
1 /*
2  *  gstvaapifilter.c - Video processing abstraction
3  *
4  *  Copyright (C) 2013-2014 Intel Corporation
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public License
9  *  as published by the Free Software Foundation; either version 2.1
10  *  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  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free
19  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301 USA
21  */
22
23 #include "sysdeps.h"
24 #include "gstvaapicompat.h"
25 #include "gstvaapifilter.h"
26 #include "gstvaapiutils.h"
27 #include "gstvaapivalue.h"
28 #include "gstvaapiminiobject.h"
29 #include "gstvaapidisplay_priv.h"
30 #include "gstvaapisurface_priv.h"
31 #include "gstvaapiutils_core.h"
32
33 #define GST_VAAPI_FILTER_CAST(obj) \
34     ((GstVaapiFilter *)(obj))
35
36 typedef struct _GstVaapiFilterOpData GstVaapiFilterOpData;
37 struct _GstVaapiFilterOpData
38 {
39   GstVaapiFilterOp op;
40   GParamSpec *pspec;
41   volatile gint ref_count;
42   guint va_type;
43   guint va_subtype;
44   gpointer va_caps;
45   guint va_num_caps;
46   guint va_cap_size;
47   VABufferID va_buffer;
48   guint va_buffer_size;
49   guint is_enabled:1;
50 };
51
52 struct _GstVaapiFilter
53 {
54   /*< private > */
55   GstObject parent_instance;
56
57   GstVaapiDisplay *display;
58   VADisplay va_display;
59   VAConfigID va_config;
60   VAContextID va_context;
61   GPtrArray *operations;
62   GstVideoFormat format;
63   GstVaapiScaleMethod scale_method;
64   GstVideoOrientationMethod video_direction;
65   GstVaapiConfigSurfaceAttributes *attribs;
66   GArray *forward_references;
67   GArray *backward_references;
68   GstVaapiRectangle crop_rect;
69   GstVaapiRectangle target_rect;
70   guint use_crop_rect:1;
71   guint use_target_rect:1;
72   guint32 mirror_flags;
73   guint32 rotation_flags;
74 };
75
76 typedef struct _GstVaapiFilterClass GstVaapiFilterClass;
77 struct _GstVaapiFilterClass
78 {
79   /*< private > */
80   GstObjectClass parent_class;
81 };
82
83 /* Debug category for VaapiFilter */
84 GST_DEBUG_CATEGORY (gst_debug_vaapi_filter);
85 #define GST_CAT_DEFAULT gst_debug_vaapi_filter
86
87 #define _do_init                                                       \
88     GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_filter, "vaapifilter", 0, \
89     "VA-API Filter");
90
91 G_DEFINE_TYPE_WITH_CODE (GstVaapiFilter, gst_vaapi_filter, GST_TYPE_OBJECT,
92     _do_init);
93
94 /* ------------------------------------------------------------------------- */
95 /* --- VPP Types                                                         --- */
96 /* ------------------------------------------------------------------------- */
97
98 static GType
99 gst_vaapi_scale_method_get_type (void)
100 {
101   static gsize g_type = 0;
102
103   static const GEnumValue enum_values[] = {
104     {GST_VAAPI_SCALE_METHOD_DEFAULT,
105         "Default scaling mode", "default"},
106     {GST_VAAPI_SCALE_METHOD_FAST,
107         "Fast scaling mode", "fast"},
108     {GST_VAAPI_SCALE_METHOD_HQ,
109         "High quality scaling mode", "hq"},
110     {0, NULL, NULL},
111   };
112
113   if (g_once_init_enter (&g_type)) {
114     const GType type =
115         g_enum_register_static ("GstVaapiScaleMethod", enum_values);
116     g_once_init_leave (&g_type, type);
117   }
118   return g_type;
119 }
120
121 GType
122 gst_vaapi_deinterlace_method_get_type (void)
123 {
124   static gsize g_type = 0;
125
126   static const GEnumValue enum_values[] = {
127     {GST_VAAPI_DEINTERLACE_METHOD_NONE,
128         "Disable deinterlacing", "none"},
129     {GST_VAAPI_DEINTERLACE_METHOD_BOB,
130         "Bob deinterlacing", "bob"},
131     {GST_VAAPI_DEINTERLACE_METHOD_WEAVE,
132         "Weave deinterlacing", "weave"},
133     {GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE,
134         "Motion adaptive deinterlacing", "motion-adaptive"},
135     {GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED,
136         "Motion compensated deinterlacing", "motion-compensated"},
137     {0, NULL, NULL},
138   };
139
140   if (g_once_init_enter (&g_type)) {
141     const GType type =
142         g_enum_register_static ("GstVaapiDeinterlaceMethod", enum_values);
143     g_once_init_leave (&g_type, type);
144   }
145   return g_type;
146 }
147
148 GType
149 gst_vaapi_deinterlace_flags_get_type (void)
150 {
151   static gsize g_type = 0;
152
153   static const GEnumValue enum_values[] = {
154     {GST_VAAPI_DEINTERLACE_FLAG_TFF,
155         "Top-field first", "top-field-first"},
156     {GST_VAAPI_DEINTERLACE_FLAG_ONEFIELD,
157         "One field", "one-field"},
158     {GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD,
159         "Top field", "top-field"},
160     {0, NULL, NULL}
161   };
162
163   if (g_once_init_enter (&g_type)) {
164     const GType type =
165         g_enum_register_static ("GstVaapiDeinterlaceFlags", enum_values);
166     g_once_init_leave (&g_type, type);
167   }
168   return g_type;
169 }
170
171 /* ------------------------------------------------------------------------- */
172 /* --- VPP Helpers                                                       --- */
173 /* ------------------------------------------------------------------------- */
174
175 static VAProcFilterType *
176 vpp_get_filters_unlocked (GstVaapiFilter * filter, guint * num_filters_ptr)
177 {
178   VAProcFilterType *filters = NULL;
179   guint num_filters = 0;
180   VAStatus va_status;
181
182   num_filters = VAProcFilterCount;
183   filters = g_malloc_n (num_filters, sizeof (*filters));
184   if (!filters)
185     goto error;
186
187   va_status = vaQueryVideoProcFilters (filter->va_display, filter->va_context,
188       filters, &num_filters);
189
190   // Try to reallocate to the expected number of filters
191   if (va_status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) {
192     VAProcFilterType *const new_filters =
193         g_try_realloc_n (filters, num_filters, sizeof (*new_filters));
194     if (!new_filters)
195       goto error;
196     filters = new_filters;
197
198     va_status = vaQueryVideoProcFilters (filter->va_display,
199         filter->va_context, filters, &num_filters);
200   }
201   if (!vaapi_check_status (va_status, "vaQueryVideoProcFilters()"))
202     goto error;
203
204   *num_filters_ptr = num_filters;
205   return filters;
206
207   /* ERRORS */
208 error:
209   {
210     g_free (filters);
211     return NULL;
212   }
213 }
214
215 static VAProcFilterType *
216 vpp_get_filters (GstVaapiFilter * filter, guint * num_filters_ptr)
217 {
218   VAProcFilterType *filters;
219
220   GST_VAAPI_DISPLAY_LOCK (filter->display);
221   filters = vpp_get_filters_unlocked (filter, num_filters_ptr);
222   GST_VAAPI_DISPLAY_UNLOCK (filter->display);
223   return filters;
224 }
225
226 static gpointer
227 vpp_get_filter_caps_unlocked (GstVaapiFilter * filter, VAProcFilterType type,
228     guint cap_size, guint * num_caps_ptr)
229 {
230   gpointer caps;
231   guint num_caps = 1;
232   VAStatus va_status;
233
234   caps = g_malloc (cap_size);
235   if (!caps)
236     goto error;
237
238   va_status = vaQueryVideoProcFilterCaps (filter->va_display,
239       filter->va_context, type, caps, &num_caps);
240
241   // Try to reallocate to the expected number of filters
242   if (va_status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) {
243     gpointer const new_caps = g_try_realloc_n (caps, num_caps, cap_size);
244     if (!new_caps)
245       goto error;
246     caps = new_caps;
247
248     va_status = vaQueryVideoProcFilterCaps (filter->va_display,
249         filter->va_context, type, caps, &num_caps);
250   }
251   if (!vaapi_check_status (va_status, "vaQueryVideoProcFilterCaps()"))
252     goto error;
253
254   *num_caps_ptr = num_caps;
255   return caps;
256
257   /* ERRORS */
258 error:
259   {
260     g_free (caps);
261     return NULL;
262   }
263 }
264
265 static gpointer
266 vpp_get_filter_caps (GstVaapiFilter * filter, VAProcFilterType type,
267     guint cap_size, guint * num_caps_ptr)
268 {
269   gpointer caps;
270
271   GST_VAAPI_DISPLAY_LOCK (filter->display);
272   caps = vpp_get_filter_caps_unlocked (filter, type, cap_size, num_caps_ptr);
273   GST_VAAPI_DISPLAY_UNLOCK (filter->display);
274   return caps;
275 }
276
277 static void
278 vpp_get_pipeline_caps_unlocked (GstVaapiFilter * filter)
279 {
280 #if VA_CHECK_VERSION(1,1,0)
281   VAProcPipelineCaps pipeline_caps = { 0, };
282
283   VAStatus va_status = vaQueryVideoProcPipelineCaps (filter->va_display,
284       filter->va_context, NULL, 0, &pipeline_caps);
285
286   if (vaapi_check_status (va_status, "vaQueryVideoProcPipelineCaps()")) {
287     filter->mirror_flags = pipeline_caps.mirror_flags;
288     filter->rotation_flags = pipeline_caps.rotation_flags;
289     return;
290   }
291 #endif
292
293   filter->mirror_flags = 0;
294   filter->rotation_flags = 0;
295 }
296
297 static void
298 vpp_get_pipeline_caps (GstVaapiFilter * filter)
299 {
300   GST_VAAPI_DISPLAY_LOCK (filter->display);
301   vpp_get_pipeline_caps_unlocked (filter);
302   GST_VAAPI_DISPLAY_UNLOCK (filter->display);
303 }
304
305 /* ------------------------------------------------------------------------- */
306 /* --- VPP Operations                                                   --- */
307 /* ------------------------------------------------------------------------- */
308
309 #define DEFAULT_FORMAT  GST_VIDEO_FORMAT_UNKNOWN
310
311 #define OP_DATA_DEFAULT_VALUE(type, op_data) \
312     g_value_get_##type (g_param_spec_get_default_value (op_data->pspec))
313
314 #define OP_RET_DEFAULT_VALUE(type, filter, op) \
315     do { \
316       g_return_val_if_fail (filter != NULL, FALSE); \
317       return OP_DATA_DEFAULT_VALUE (type, find_operation (filter, op)); \
318     } while (0)
319
320 enum
321 {
322   PROP_DISPLAY = 1,
323 };
324
325 enum
326 {
327   PROP_0,
328
329   PROP_FORMAT = GST_VAAPI_FILTER_OP_FORMAT,
330   PROP_CROP = GST_VAAPI_FILTER_OP_CROP,
331   PROP_DENOISE = GST_VAAPI_FILTER_OP_DENOISE,
332   PROP_SHARPEN = GST_VAAPI_FILTER_OP_SHARPEN,
333   PROP_HUE = GST_VAAPI_FILTER_OP_HUE,
334   PROP_SATURATION = GST_VAAPI_FILTER_OP_SATURATION,
335   PROP_BRIGHTNESS = GST_VAAPI_FILTER_OP_BRIGHTNESS,
336   PROP_CONTRAST = GST_VAAPI_FILTER_OP_CONTRAST,
337   PROP_DEINTERLACING = GST_VAAPI_FILTER_OP_DEINTERLACING,
338   PROP_SCALING = GST_VAAPI_FILTER_OP_SCALING,
339   PROP_VIDEO_DIRECTION = GST_VAAPI_FILTER_OP_VIDEO_DIRECTION,
340 #ifndef GST_REMOVE_DEPRECATED
341   PROP_SKINTONE = GST_VAAPI_FILTER_OP_SKINTONE,
342 #endif
343   PROP_SKINTONE_LEVEL = GST_VAAPI_FILTER_OP_SKINTONE_LEVEL,
344
345   N_PROPERTIES
346 };
347
348 static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
349
350 static gsize g_properties_initialized = FALSE;
351
352 static void
353 init_properties (void)
354 {
355   /**
356    * GstVaapiFilter:format:
357    *
358    * The forced output pixel format, expressed as a #GstVideoFormat.
359    */
360   g_properties[PROP_FORMAT] = g_param_spec_enum ("format",
361       "Format",
362       "The forced output pixel format",
363       GST_TYPE_VIDEO_FORMAT,
364       DEFAULT_FORMAT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
365
366   /**
367    * GstVaapiFilter:crop-rect:
368    *
369    * The cropping rectangle, expressed as a #GstVaapiRectangle.
370    */
371   g_properties[PROP_CROP] = g_param_spec_boxed ("crop-rect",
372       "Cropping Rectangle",
373       "The cropping rectangle",
374       GST_VAAPI_TYPE_RECTANGLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
375
376   /**
377    * GstVaapiFilter:denoise:
378    *
379    * The level of noise reduction to apply.
380    */
381   g_properties[PROP_DENOISE] = g_param_spec_float ("denoise",
382       "Denoising Level",
383       "The level of denoising to apply",
384       0.0, 1.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
385
386   /**
387    * GstVaapiFilter:sharpen:
388    *
389    * The level of sharpening to apply for positive values, or the
390    * level of blurring for negative values.
391    */
392   g_properties[PROP_SHARPEN] = g_param_spec_float ("sharpen",
393       "Sharpening Level",
394       "The level of sharpening/blurring to apply",
395       -1.0, 1.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
396
397   /**
398    * GstVaapiFilter:hue:
399    *
400    * The color hue, expressed as a float value. Range is -180.0 to
401    * 180.0. Default value is 0.0 and represents no modification.
402    */
403   g_properties[PROP_HUE] = g_param_spec_float ("hue",
404       "Hue",
405       "The color hue value",
406       -180.0, 180.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
407
408   /**
409    * GstVaapiFilter:saturation:
410    *
411    * The color saturation, expressed as a float value. Range is 0.0 to
412    * 2.0. Default value is 1.0 and represents no modification.
413    */
414   g_properties[PROP_SATURATION] = g_param_spec_float ("saturation",
415       "Saturation",
416       "The color saturation value",
417       0.0, 2.0, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
418
419   /**
420    * GstVaapiFilter:brightness:
421    *
422    * The color brightness, expressed as a float value. Range is -1.0
423    * to 1.0. Default value is 0.0 and represents no modification.
424    */
425   g_properties[PROP_BRIGHTNESS] = g_param_spec_float ("brightness",
426       "Brightness",
427       "The color brightness value",
428       -1.0, 1.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
429
430   /**
431    * GstVaapiFilter:contrast:
432    *
433    * The color contrast, expressed as a float value. Range is 0.0 to
434    * 2.0. Default value is 1.0 and represents no modification.
435    */
436   g_properties[PROP_CONTRAST] = g_param_spec_float ("contrast",
437       "Contrast",
438       "The color contrast value",
439       0.0, 2.0, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
440
441   /**
442    * GstVaapiFilter:deinterlace-method:
443    *
444    * The deinterlacing algorithm to apply, expressed a an enum
445    * value. See #GstVaapiDeinterlaceMethod.
446    */
447   g_properties[PROP_DEINTERLACING] = g_param_spec_enum ("deinterlace",
448       "Deinterlacing Method",
449       "Deinterlacing method to apply",
450       GST_VAAPI_TYPE_DEINTERLACE_METHOD,
451       GST_VAAPI_DEINTERLACE_METHOD_NONE,
452       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
453
454   /**
455    * GstVaapiFilter:scale-method:
456    *
457    * The scaling method to use, expressed as an enum value. See
458    * #GstVaapiScaleMethod.
459    */
460   g_properties[PROP_SCALING] = g_param_spec_enum ("scale-method",
461       "Scaling Method",
462       "Scaling method to use",
463       GST_VAAPI_TYPE_SCALE_METHOD,
464       GST_VAAPI_SCALE_METHOD_DEFAULT,
465       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
466
467   /**
468    * GstVaapiFilter:video-direction:
469    *
470    * The video-direction to use, expressed as an enum value. See
471    * #GstVideoOrientationMethod.
472    */
473   g_properties[PROP_VIDEO_DIRECTION] = g_param_spec_enum ("video-direction",
474       "Video Direction",
475       "Video direction: rotation and flipping",
476       GST_TYPE_VIDEO_ORIENTATION_METHOD,
477       GST_VIDEO_ORIENTATION_IDENTITY,
478       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
479
480 #ifndef GST_REMOVE_DEPRECATED
481   /**
482    * GstVaapiFilter:skin-tone-enhancement:
483    *
484    * Apply the skin tone enhancement algorithm.
485    */
486   g_properties[PROP_SKINTONE] = g_param_spec_boolean ("skin-tone-enhancement",
487       "Skin tone enhancement",
488       "Apply the skin tone enhancement algorithm",
489       FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
490 #endif
491
492   /**
493    * GstVaapiFilter:skin-tone-enhancement-level:
494    *
495    * Apply the skin tone enhancement algorithm with specified value.
496    */
497   g_properties[PROP_SKINTONE_LEVEL] =
498       g_param_spec_uint ("skin-tone-enhancement-level",
499       "Skin tone enhancement level",
500       "Apply the skin tone enhancement algorithm with specified level", 0, 9, 3,
501       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
502 }
503
504 static void
505 ensure_properties (void)
506 {
507   if (g_once_init_enter (&g_properties_initialized)) {
508     init_properties ();
509     g_once_init_leave (&g_properties_initialized, TRUE);
510   }
511 }
512
513 static void
514 op_data_free (GstVaapiFilterOpData * op_data)
515 {
516   g_free (op_data->va_caps);
517   g_slice_free (GstVaapiFilterOpData, op_data);
518 }
519
520 static inline gpointer
521 op_data_new (GstVaapiFilterOp op, GParamSpec * pspec)
522 {
523   GstVaapiFilterOpData *op_data;
524
525   op_data = g_slice_new0 (GstVaapiFilterOpData);
526   if (!op_data)
527     return NULL;
528
529   op_data->op = op;
530   op_data->pspec = pspec;
531   op_data->ref_count = 1;
532   op_data->va_buffer = VA_INVALID_ID;
533
534   switch (op) {
535     case GST_VAAPI_FILTER_OP_FORMAT:
536     case GST_VAAPI_FILTER_OP_CROP:
537     case GST_VAAPI_FILTER_OP_SCALING:
538     case GST_VAAPI_FILTER_OP_VIDEO_DIRECTION:
539       op_data->va_type = VAProcFilterNone;
540       break;
541     case GST_VAAPI_FILTER_OP_DENOISE:
542       op_data->va_type = VAProcFilterNoiseReduction;
543       op_data->va_cap_size = sizeof (VAProcFilterCap);
544       op_data->va_buffer_size = sizeof (VAProcFilterParameterBuffer);
545       break;
546     case GST_VAAPI_FILTER_OP_SHARPEN:
547       op_data->va_type = VAProcFilterSharpening;
548       op_data->va_cap_size = sizeof (VAProcFilterCap);
549       op_data->va_buffer_size = sizeof (VAProcFilterParameterBuffer);
550       break;
551 #ifndef GST_REMOVE_DEPRECATED
552     case GST_VAAPI_FILTER_OP_SKINTONE:
553 #endif
554     case GST_VAAPI_FILTER_OP_SKINTONE_LEVEL:
555       op_data->va_type = VAProcFilterSkinToneEnhancement;
556       op_data->va_buffer_size = sizeof (VAProcFilterParameterBuffer);
557       break;
558     case GST_VAAPI_FILTER_OP_HUE:
559       op_data->va_subtype = VAProcColorBalanceHue;
560       goto op_colorbalance;
561     case GST_VAAPI_FILTER_OP_SATURATION:
562       op_data->va_subtype = VAProcColorBalanceSaturation;
563       goto op_colorbalance;
564     case GST_VAAPI_FILTER_OP_BRIGHTNESS:
565       op_data->va_subtype = VAProcColorBalanceBrightness;
566       goto op_colorbalance;
567     case GST_VAAPI_FILTER_OP_CONTRAST:
568       op_data->va_subtype = VAProcColorBalanceContrast;
569     op_colorbalance:
570       op_data->va_type = VAProcFilterColorBalance;
571       op_data->va_cap_size = sizeof (VAProcFilterCapColorBalance);
572       op_data->va_buffer_size =
573           sizeof (VAProcFilterParameterBufferColorBalance);
574       break;
575     case GST_VAAPI_FILTER_OP_DEINTERLACING:
576       op_data->va_type = VAProcFilterDeinterlacing;
577       op_data->va_cap_size = sizeof (VAProcFilterCapDeinterlacing);
578       op_data->va_buffer_size =
579           sizeof (VAProcFilterParameterBufferDeinterlacing);
580       break;
581     default:
582       g_assert (0 && "unsupported operation");
583       goto error;
584   }
585   return op_data;
586
587   /* ERRORS */
588 error:
589   {
590     op_data_free (op_data);
591     return NULL;
592   }
593 }
594
595 static inline gpointer
596 op_data_ref (gpointer data)
597 {
598   GstVaapiFilterOpData *const op_data = data;
599
600   g_return_val_if_fail (op_data != NULL, NULL);
601
602   g_atomic_int_inc (&op_data->ref_count);
603   return op_data;
604 }
605
606 static void
607 op_data_unref (gpointer data)
608 {
609   GstVaapiFilterOpData *const op_data = data;
610
611   g_return_if_fail (op_data != NULL);
612   g_return_if_fail (op_data->ref_count > 0);
613
614   if (g_atomic_int_dec_and_test (&op_data->ref_count))
615     op_data_free (op_data);
616 }
617
618 /* Ensure capability info is set up for the VA filter we are interested in */
619 static gboolean
620 op_data_ensure_caps (GstVaapiFilterOpData * op_data, gpointer filter_caps,
621     guint num_filter_caps)
622 {
623   guchar *filter_cap = filter_caps;
624   guint i, va_num_caps = num_filter_caps;
625
626   // Find the VA filter cap matching the op info sub-type
627   if (op_data->va_subtype) {
628     for (i = 0; i < num_filter_caps; i++) {
629       /* XXX: sub-type shall always be the first field */
630       if (op_data->va_subtype == *(guint *) filter_cap) {
631         va_num_caps = 1;
632         break;
633       }
634       filter_cap += op_data->va_cap_size;
635     }
636     if (i == num_filter_caps)
637       return FALSE;
638   }
639
640   op_data->va_caps = g_memdup (filter_cap, op_data->va_cap_size * va_num_caps);
641   if (!op_data->va_caps)
642     return FALSE;
643
644   op_data->va_num_caps = va_num_caps;
645   return TRUE;
646 }
647
648 /* Scale the filter value wrt. library spec and VA driver spec */
649 static gboolean
650 op_data_get_value_float (GstVaapiFilterOpData * op_data,
651     const VAProcFilterValueRange * range, gfloat value, gfloat * out_value_ptr)
652 {
653   GParamSpecFloat *const pspec = G_PARAM_SPEC_FLOAT (op_data->pspec);
654   gfloat out_value;
655
656   g_return_val_if_fail (range != NULL, FALSE);
657   g_return_val_if_fail (out_value_ptr != NULL, FALSE);
658
659   if (value < pspec->minimum || value > pspec->maximum)
660     return FALSE;
661
662   // Scale wrt. the medium ("default") value
663   out_value = range->default_value;
664   if (value > pspec->default_value)
665     out_value += ((value - pspec->default_value) /
666         (pspec->maximum - pspec->default_value) *
667         (range->max_value - range->default_value));
668   else if (value < pspec->default_value)
669     out_value -= ((pspec->default_value - value) /
670         (pspec->default_value - pspec->minimum) *
671         (range->default_value - range->min_value));
672
673   *out_value_ptr = out_value;
674   return TRUE;
675 }
676
677 /* Get default list of operations supported by the library */
678 static GPtrArray *
679 get_operations_default (void)
680 {
681   GPtrArray *ops;
682   guint i;
683
684   ops = g_ptr_array_new_full (N_PROPERTIES, op_data_unref);
685   if (!ops)
686     return NULL;
687
688   ensure_properties ();
689
690   for (i = 0; i < N_PROPERTIES; i++) {
691     GstVaapiFilterOpData *op_data;
692     GParamSpec *const pspec = g_properties[i];
693     if (!pspec)
694       continue;
695
696     op_data = op_data_new (i, pspec);
697     if (!op_data)
698       goto error;
699     g_ptr_array_add (ops, op_data);
700   }
701   return ops;
702
703   /* ERRORS */
704 error:
705   {
706     g_ptr_array_unref (ops);
707     return NULL;
708   }
709 }
710
711 /* Get the ordered list of operations, based on VA/VPP queries */
712 static GPtrArray *
713 get_operations_ordered (GstVaapiFilter * filter, GPtrArray * default_ops)
714 {
715   GPtrArray *ops;
716   VAProcFilterType *filters;
717   gpointer filter_caps = NULL;
718   guint i, j, num_filters, num_filter_caps = 0;
719
720   ops = g_ptr_array_new_full (default_ops->len, op_data_unref);
721   if (!ops)
722     return NULL;
723
724   filters = vpp_get_filters (filter, &num_filters);
725   if (!filters)
726     goto error;
727
728   // Append virtual ops first, i.e. those without an associated VA filter
729   for (i = 0; i < default_ops->len; i++) {
730     GstVaapiFilterOpData *const op_data = g_ptr_array_index (default_ops, i);
731     if (op_data->va_type == VAProcFilterNone)
732       g_ptr_array_add (ops, op_data_ref (op_data));
733   }
734
735   // Append ops, while preserving the VA filters ordering
736   for (i = 0; i < num_filters; i++) {
737     const VAProcFilterType va_type = filters[i];
738     if (va_type == VAProcFilterNone)
739       continue;
740
741     for (j = 0; j < default_ops->len; j++) {
742       GstVaapiFilterOpData *const op_data = g_ptr_array_index (default_ops, j);
743       if (op_data->va_type != va_type)
744         continue;
745
746       if (op_data->va_cap_size == 0) {  /* no caps, like skintone */
747         g_ptr_array_add (ops, op_data_ref (op_data));
748         continue;
749       }
750
751       if (!filter_caps) {
752         filter_caps = vpp_get_filter_caps (filter, va_type,
753             op_data->va_cap_size, &num_filter_caps);
754         if (!filter_caps)
755           goto error;
756       }
757       if (!op_data_ensure_caps (op_data, filter_caps, num_filter_caps))
758         goto error;
759       g_ptr_array_add (ops, op_data_ref (op_data));
760     }
761     free (filter_caps);
762     filter_caps = NULL;
763   }
764
765   vpp_get_pipeline_caps (filter);
766
767   if (filter->operations)
768     g_ptr_array_unref (filter->operations);
769   filter->operations = g_ptr_array_ref (ops);
770
771   g_free (filters);
772   g_ptr_array_unref (default_ops);
773   return ops;
774
775   /* ERRORS */
776 error:
777   {
778     g_free (filter_caps);
779     g_free (filters);
780     g_ptr_array_unref (ops);
781     g_ptr_array_unref (default_ops);
782     return NULL;
783   }
784 }
785
786 /* Determine the set of supported VPP operations by the specific
787    filter, or known to this library if filter is NULL */
788 static GPtrArray *
789 get_operations (GstVaapiFilter * filter)
790 {
791   GPtrArray *ops;
792
793   if (filter && filter->operations)
794     return g_ptr_array_ref (filter->operations);
795
796   ops = get_operations_default ();
797   if (!ops)
798     return NULL;
799   return filter ? get_operations_ordered (filter, ops) : ops;
800 }
801
802 /* Ensure the set of supported VPP operations is cached into the
803    GstVaapiFilter::operations member */
804 static inline gboolean
805 ensure_operations (GstVaapiFilter * filter)
806 {
807   GPtrArray *ops;
808
809   if (!filter)
810     return FALSE;
811
812   if (filter->operations)
813     return TRUE;
814
815   ops = get_operations (filter);
816   if (!ops)
817     return FALSE;
818
819   g_ptr_array_unref (ops);
820   return TRUE;
821 }
822
823 /* Find whether the VPP operation is supported or not */
824 static GstVaapiFilterOpData *
825 find_operation (GstVaapiFilter * filter, GstVaapiFilterOp op)
826 {
827   guint i;
828
829   if (!ensure_operations (filter))
830     return NULL;
831
832   for (i = 0; i < filter->operations->len; i++) {
833     GstVaapiFilterOpData *const op_data =
834         g_ptr_array_index (filter->operations, i);
835     if (op_data->op == op)
836       return op_data;
837   }
838   return NULL;
839 }
840
841 /* Ensure the operation's VA buffer is allocated */
842 static inline gboolean
843 op_ensure_n_elements_buffer (GstVaapiFilter * filter,
844     GstVaapiFilterOpData * op_data, gint op_num)
845 {
846   if (G_LIKELY (op_data->va_buffer != VA_INVALID_ID))
847     return TRUE;
848   return vaapi_create_n_elements_buffer (filter->va_display, filter->va_context,
849       VAProcFilterParameterBufferType, op_data->va_buffer_size, NULL,
850       &op_data->va_buffer, NULL, op_num);
851 }
852
853 static inline gboolean
854 op_ensure_buffer (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data)
855 {
856   return op_ensure_n_elements_buffer (filter, op_data, 1);
857 }
858
859 /* Update a generic filter (float value) */
860 static gboolean
861 op_set_generic_unlocked (GstVaapiFilter * filter,
862     GstVaapiFilterOpData * op_data, gfloat value)
863 {
864   VAProcFilterParameterBuffer *buf;
865   VAProcFilterCap *filter_cap;
866   gfloat va_value;
867
868   if (!op_data || !op_ensure_buffer (filter, op_data))
869     return FALSE;
870
871   op_data->is_enabled =
872       (value != G_PARAM_SPEC_FLOAT (op_data->pspec)->default_value);
873   if (!op_data->is_enabled)
874     return TRUE;
875
876   filter_cap = op_data->va_caps;
877   if (!op_data_get_value_float (op_data, &filter_cap->range, value, &va_value))
878     return FALSE;
879
880   buf = vaapi_map_buffer (filter->va_display, op_data->va_buffer);
881   if (!buf)
882     return FALSE;
883
884   buf->type = op_data->va_type;
885   buf->value = va_value;
886   vaapi_unmap_buffer (filter->va_display, op_data->va_buffer, NULL);
887   return TRUE;
888 }
889
890 static inline gboolean
891 op_set_generic (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data,
892     gfloat value)
893 {
894   gboolean success = FALSE;
895
896   GST_VAAPI_DISPLAY_LOCK (filter->display);
897   success = op_set_generic_unlocked (filter, op_data, value);
898   GST_VAAPI_DISPLAY_UNLOCK (filter->display);
899   return success;
900 }
901
902 /* Update the color balance filter */
903 #define COLOR_BALANCE_NUM \
904     GST_VAAPI_FILTER_OP_CONTRAST - GST_VAAPI_FILTER_OP_HUE + 1
905
906 static gboolean
907 op_set_color_balance_unlocked (GstVaapiFilter * filter,
908     GstVaapiFilterOpData * op_data, gfloat value)
909 {
910   VAProcFilterParameterBufferColorBalance *buf;
911   VAProcFilterCapColorBalance *filter_cap;
912   gfloat va_value;
913   gint i;
914   GstVaapiFilterOpData *color_data[COLOR_BALANCE_NUM];
915   GstVaapiFilterOpData *enabled_data = NULL;
916   gboolean ret = TRUE;
917
918   if (!op_data)
919     return FALSE;
920
921   /* collect all the Color Balance operators and find the first
922    * enabled one */
923   for (i = 0; i < COLOR_BALANCE_NUM; i++) {
924     color_data[i] = find_operation (filter, GST_VAAPI_FILTER_OP_HUE + i);
925     if (!color_data[i])
926       return FALSE;
927
928     if (!enabled_data && color_data[i]->is_enabled)
929       enabled_data = color_data[i];
930   }
931
932   /* If there's no enabled operators let's enable this one.
933    *
934    * HACK: This operator will be the only one with an allocated buffer
935    * which will store all the color balance operators.
936    */
937   if (!enabled_data) {
938     if (value == G_PARAM_SPEC_FLOAT (op_data->pspec)->default_value)
939       return TRUE;
940
941     if (!op_ensure_n_elements_buffer (filter, op_data, COLOR_BALANCE_NUM))
942       return FALSE;
943
944     enabled_data = op_data;
945
946     buf = vaapi_map_buffer (filter->va_display, enabled_data->va_buffer);
947     if (!buf)
948       return FALSE;
949
950     /* Write all the color balance operator values in the buffer. --
951      * Use the default value for all the operators except the set
952      * one. */
953     for (i = 0; i < COLOR_BALANCE_NUM; i++) {
954       buf[i].type = color_data[i]->va_type;
955       buf[i].attrib = color_data[i]->va_subtype;
956
957       va_value = G_PARAM_SPEC_FLOAT (color_data[i]->pspec)->default_value;
958       if (color_data[i]->op == op_data->op) {
959         filter_cap = color_data[i]->va_caps;
960         /* fail but ignore current value and set default one */
961         if (!op_data_get_value_float (color_data[i], &filter_cap->range, value,
962                 &va_value))
963           ret = FALSE;
964       }
965
966       buf[i].value = va_value;
967     }
968
969     enabled_data->is_enabled = 1;
970   } else {
971     /* There's already one operator enabled, *in theory* with a
972      * buffer associated. */
973     if (G_UNLIKELY (enabled_data->va_buffer == VA_INVALID_ID))
974       return FALSE;
975
976     filter_cap = op_data->va_caps;
977     if (!op_data_get_value_float (op_data, &filter_cap->range, value,
978             &va_value))
979       return FALSE;
980
981     buf = vaapi_map_buffer (filter->va_display, enabled_data->va_buffer);
982     if (!buf)
983       return FALSE;
984
985     buf[op_data->op - GST_VAAPI_FILTER_OP_HUE].value = va_value;
986   }
987
988   vaapi_unmap_buffer (filter->va_display, enabled_data->va_buffer, NULL);
989
990   return ret;
991 }
992
993 static inline gboolean
994 op_set_color_balance (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data,
995     gfloat value)
996 {
997   gboolean success = FALSE;
998
999   GST_VAAPI_DISPLAY_LOCK (filter->display);
1000   success = op_set_color_balance_unlocked (filter, op_data, value);
1001   GST_VAAPI_DISPLAY_UNLOCK (filter->display);
1002   return success;
1003 }
1004
1005 /* Update deinterlace filter */
1006 static gboolean
1007 op_set_deinterlace_unlocked (GstVaapiFilter * filter,
1008     GstVaapiFilterOpData * op_data, GstVaapiDeinterlaceMethod method,
1009     guint flags)
1010 {
1011   VAProcFilterParameterBufferDeinterlacing *buf;
1012   const VAProcFilterCapDeinterlacing *filter_caps;
1013   VAProcDeinterlacingType algorithm;
1014   guint i;
1015
1016   if (!op_data || !op_ensure_buffer (filter, op_data))
1017     return FALSE;
1018
1019   op_data->is_enabled = (method != GST_VAAPI_DEINTERLACE_METHOD_NONE);
1020   if (!op_data->is_enabled)
1021     return TRUE;
1022
1023   algorithm = from_GstVaapiDeinterlaceMethod (method);
1024   for (i = 0, filter_caps = op_data->va_caps; i < op_data->va_num_caps; i++) {
1025     if (filter_caps[i].type == algorithm)
1026       break;
1027   }
1028   if (i == op_data->va_num_caps)
1029     return FALSE;
1030
1031   buf = vaapi_map_buffer (filter->va_display, op_data->va_buffer);
1032   if (!buf)
1033     return FALSE;
1034
1035   buf->type = op_data->va_type;
1036   buf->algorithm = algorithm;
1037   buf->flags = from_GstVaapiDeinterlaceFlags (flags);
1038   vaapi_unmap_buffer (filter->va_display, op_data->va_buffer, NULL);
1039   return TRUE;
1040 }
1041
1042 static inline gboolean
1043 op_set_deinterlace (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data,
1044     GstVaapiDeinterlaceMethod method, guint flags)
1045 {
1046   gboolean success = FALSE;
1047
1048   GST_VAAPI_DISPLAY_LOCK (filter->display);
1049   success = op_set_deinterlace_unlocked (filter, op_data, method, flags);
1050   GST_VAAPI_DISPLAY_UNLOCK (filter->display);
1051   return success;
1052 }
1053
1054 /* Update skin tone enhancement level */
1055 static gboolean
1056 op_set_skintone_level_unlocked (GstVaapiFilter * filter,
1057     GstVaapiFilterOpData * op_data, guint value)
1058 {
1059   VAProcFilterParameterBuffer *buf;
1060
1061   if (!op_data || !op_ensure_buffer (filter, op_data))
1062     return FALSE;
1063
1064   op_data->is_enabled = 1;
1065
1066   buf = vaapi_map_buffer (filter->va_display, op_data->va_buffer);
1067   if (!buf)
1068     return FALSE;
1069   buf->type = op_data->va_type;
1070   buf->value = value;
1071   vaapi_unmap_buffer (filter->va_display, op_data->va_buffer, NULL);
1072   return TRUE;
1073 }
1074
1075 static inline gboolean
1076 op_set_skintone_level (GstVaapiFilter * filter,
1077     GstVaapiFilterOpData * op_data, guint value)
1078 {
1079   gboolean success = FALSE;
1080
1081   GST_VAAPI_DISPLAY_LOCK (filter->display);
1082   success = op_set_skintone_level_unlocked (filter, op_data, value);
1083   GST_VAAPI_DISPLAY_UNLOCK (filter->display);
1084   return success;
1085 }
1086
1087 #ifndef GST_REMOVE_DEPRECATED
1088 /* Update skin tone enhancement */
1089 static gboolean
1090 op_set_skintone_unlocked (GstVaapiFilter * filter,
1091     GstVaapiFilterOpData * op_data, gboolean value)
1092 {
1093   if (!op_data)
1094     return FALSE;
1095
1096   if (!value) {
1097     op_data->is_enabled = 0;
1098     return TRUE;
1099   }
1100
1101   return op_set_skintone_level_unlocked (filter, op_data, 3);
1102 }
1103
1104 static inline gboolean
1105 op_set_skintone (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data,
1106     gboolean enhance)
1107 {
1108   gboolean success = FALSE;
1109
1110   GST_VAAPI_DISPLAY_LOCK (filter->display);
1111   success = op_set_skintone_unlocked (filter, op_data, enhance);
1112   GST_VAAPI_DISPLAY_UNLOCK (filter->display);
1113   return success;
1114 }
1115 #endif
1116
1117 static gboolean
1118 deint_refs_set (GArray * refs, GstVaapiSurface ** surfaces, guint num_surfaces)
1119 {
1120   guint i;
1121
1122   if (num_surfaces > 0 && !surfaces)
1123     return FALSE;
1124
1125   for (i = 0; i < num_surfaces; i++)
1126     g_array_append_val (refs, GST_VAAPI_OBJECT_ID (surfaces[i]));
1127   return TRUE;
1128 }
1129
1130 static void
1131 deint_refs_clear (GArray * refs)
1132 {
1133   if (refs->len > 0)
1134     g_array_remove_range (refs, 0, refs->len);
1135 }
1136
1137 static inline void
1138 deint_refs_clear_all (GstVaapiFilter * filter)
1139 {
1140   deint_refs_clear (filter->forward_references);
1141   deint_refs_clear (filter->backward_references);
1142 }
1143
1144 /* ------------------------------------------------------------------------- */
1145 /* --- Surface Attribs                                                   --- */
1146 /* ------------------------------------------------------------------------- */
1147
1148 static gboolean
1149 ensure_attributes (GstVaapiFilter * filter)
1150 {
1151   if (G_LIKELY (filter->attribs))
1152     return TRUE;
1153
1154   filter->attribs = gst_vaapi_config_surface_attributes_get (filter->display,
1155       filter->va_config);
1156   return (filter->attribs != NULL);
1157 }
1158
1159 static inline gboolean
1160 is_special_format (GstVideoFormat format)
1161 {
1162   return format == GST_VIDEO_FORMAT_UNKNOWN ||
1163       format == GST_VIDEO_FORMAT_ENCODED;
1164 }
1165
1166 static gboolean
1167 find_format (GstVaapiFilter * filter, GstVideoFormat format)
1168 {
1169   guint i;
1170   GArray *formats;
1171
1172   formats = filter->attribs->formats;
1173   if (is_special_format (format) || !formats)
1174     return FALSE;
1175
1176   for (i = 0; i < formats->len; i++) {
1177     if (g_array_index (formats, GstVideoFormat, i) == format)
1178       return TRUE;
1179   }
1180   return FALSE;
1181 }
1182
1183 /* ------------------------------------------------------------------------- */
1184 /* --- Interface                                                         --- */
1185 /* ------------------------------------------------------------------------- */
1186
1187 static void
1188 gst_vaapi_filter_init (GstVaapiFilter * filter)
1189 {
1190   filter->va_config = VA_INVALID_ID;
1191   filter->va_context = VA_INVALID_ID;
1192   filter->format = DEFAULT_FORMAT;
1193
1194   filter->forward_references =
1195       g_array_sized_new (FALSE, FALSE, sizeof (VASurfaceID), 4);
1196
1197   filter->backward_references =
1198       g_array_sized_new (FALSE, FALSE, sizeof (VASurfaceID), 4);
1199 }
1200
1201 static gboolean
1202 gst_vaapi_filter_initialize (GstVaapiFilter * filter)
1203 {
1204   VAStatus va_status;
1205
1206   if (!filter->display)
1207     return FALSE;
1208
1209   va_status = vaCreateConfig (filter->va_display, VAProfileNone,
1210       VAEntrypointVideoProc, NULL, 0, &filter->va_config);
1211   if (!vaapi_check_status (va_status, "vaCreateConfig() [VPP]"))
1212     return FALSE;
1213
1214   va_status = vaCreateContext (filter->va_display, filter->va_config, 0, 0, 0,
1215       NULL, 0, &filter->va_context);
1216   if (!vaapi_check_status (va_status, "vaCreateContext() [VPP]"))
1217     return FALSE;
1218   return TRUE;
1219 }
1220
1221 static void
1222 gst_vaapi_filter_finalize (GObject * object)
1223 {
1224   GstVaapiFilter *const filter = GST_VAAPI_FILTER (object);
1225   guint i;
1226
1227   GST_VAAPI_DISPLAY_LOCK (filter->display);
1228   if (filter->operations) {
1229     for (i = 0; i < filter->operations->len; i++) {
1230       GstVaapiFilterOpData *const op_data =
1231           g_ptr_array_index (filter->operations, i);
1232       vaapi_destroy_buffer (filter->va_display, &op_data->va_buffer);
1233     }
1234     g_ptr_array_unref (filter->operations);
1235     filter->operations = NULL;
1236   }
1237
1238   if (filter->va_context != VA_INVALID_ID) {
1239     vaDestroyContext (filter->va_display, filter->va_context);
1240     filter->va_context = VA_INVALID_ID;
1241   }
1242
1243   if (filter->va_config != VA_INVALID_ID) {
1244     vaDestroyConfig (filter->va_display, filter->va_config);
1245     filter->va_config = VA_INVALID_ID;
1246   }
1247   GST_VAAPI_DISPLAY_UNLOCK (filter->display);
1248   gst_vaapi_display_replace (&filter->display, NULL);
1249
1250   if (filter->forward_references) {
1251     g_array_unref (filter->forward_references);
1252     filter->forward_references = NULL;
1253   }
1254
1255   if (filter->backward_references) {
1256     g_array_unref (filter->backward_references);
1257     filter->backward_references = NULL;
1258   }
1259
1260   if (filter->attribs) {
1261     gst_vaapi_config_surface_attributes_free (filter->attribs);
1262     filter->attribs = NULL;
1263   }
1264
1265   G_OBJECT_CLASS (gst_vaapi_filter_parent_class)->finalize (object);
1266 }
1267
1268 static void
1269 gst_vaapi_filter_set_property (GObject * object, guint property_id,
1270     const GValue * value, GParamSpec * pspec)
1271 {
1272   GstVaapiFilter *const filter = GST_VAAPI_FILTER (object);
1273
1274   switch (property_id) {
1275     case PROP_DISPLAY:{
1276       GstVaapiDisplay *display = g_value_get_object (value);;
1277
1278       if (display) {
1279         if (GST_VAAPI_DISPLAY_HAS_VPP (display)) {
1280           filter->display = gst_object_ref (display);
1281           filter->va_display = GST_VAAPI_DISPLAY_VADISPLAY (filter->display);
1282         } else {
1283           GST_WARNING_OBJECT (filter, "VA display doesn't support VPP");
1284         }
1285       }
1286       break;
1287     }
1288     default:
1289       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1290   }
1291 }
1292
1293 static void
1294 gst_vaapi_filter_get_property (GObject * object, guint property_id,
1295     GValue * value, GParamSpec * pspec)
1296 {
1297   GstVaapiFilter *const filter = GST_VAAPI_FILTER (object);
1298
1299   switch (property_id) {
1300     case PROP_DISPLAY:
1301       g_value_set_object (value, filter->display);
1302       break;
1303     default:
1304       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1305   }
1306 }
1307
1308 static void
1309 gst_vaapi_filter_class_init (GstVaapiFilterClass * klass)
1310 {
1311   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
1312
1313   object_class->set_property = gst_vaapi_filter_set_property;
1314   object_class->get_property = gst_vaapi_filter_get_property;
1315   object_class->finalize = gst_vaapi_filter_finalize;
1316
1317   /**
1318    * GstVaapiFilter:display:
1319    *
1320    * #GstVaapiDisplay to be used.
1321    */
1322   g_object_class_install_property (object_class, PROP_DISPLAY,
1323       g_param_spec_object ("display", "Gst VA-API Display",
1324           "The VA-API display object to use", GST_TYPE_VAAPI_DISPLAY,
1325           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME));
1326 }
1327
1328 /**
1329  * gst_vaapi_filter_new:
1330  * @display: a #GstVaapiDisplay
1331  *
1332  * Creates a new #GstVaapiFilter set up to operate in "identity"
1333  * mode. This means that no other operation than scaling is performed.
1334  *
1335  * Return value: the newly created #GstVaapiFilter object
1336  */
1337 GstVaapiFilter *
1338 gst_vaapi_filter_new (GstVaapiDisplay * display)
1339 {
1340   GstVaapiFilter *filter;
1341
1342   filter = g_object_new (GST_TYPE_VAAPI_FILTER, "display", display, NULL);
1343   if (!gst_vaapi_filter_initialize (filter))
1344     goto error;
1345   return filter;
1346
1347   /* ERRORS */
1348 error:
1349   {
1350     gst_object_unref (filter);
1351     return NULL;
1352   }
1353 }
1354
1355 /**
1356  * gst_vaapi_filter_replace:
1357  * @old_filter_ptr: a pointer to a #GstVaapiFilter
1358  * @new_filter: a #GstVaapiFilter
1359  *
1360  * Atomically replaces the filter held in @old_filter_ptr with
1361  * @new_filter. This means that @old_filter_ptr shall reference a
1362  * valid filter. However, @new_filter can be NULL.
1363  */
1364 void
1365 gst_vaapi_filter_replace (GstVaapiFilter ** old_filter_ptr,
1366     GstVaapiFilter * new_filter)
1367 {
1368   g_return_if_fail (old_filter_ptr != NULL);
1369
1370   gst_object_replace ((GstObject **) old_filter_ptr, GST_OBJECT (new_filter));
1371 }
1372
1373 /**
1374  * gst_vaapi_filter_get_operations:
1375  * @filter: a #GstVaapiFilter, or %NULL
1376  *
1377  * Determines the set of supported operations for video processing.
1378  * The caller owns an extra reference to the resulting array of
1379  * #GstVaapiFilterOpInfo elements, so it shall be released with
1380  * g_ptr_array_unref() after usage.
1381  *
1382  * If @filter is %NULL, then this function returns the video
1383  * processing operations supported by this library.
1384  *
1385  * Return value: the set of supported operations, or %NULL if an error
1386  *   occurred.
1387  */
1388 GPtrArray *
1389 gst_vaapi_filter_get_operations (GstVaapiFilter * filter)
1390 {
1391   return get_operations (filter);
1392 }
1393
1394 /**
1395  * gst_vaapi_filter_has_operation:
1396  * @filter: a #GstVaapiFilter
1397  * @op: a #GstVaapiFilterOp
1398  *
1399  * Determines whether the underlying VA driver advertises support for
1400  * the supplied operation @op.
1401  *
1402  * Return value: %TRUE if the specified operation may be supported by
1403  *   the underlying hardware, %FALSE otherwise
1404  */
1405 gboolean
1406 gst_vaapi_filter_has_operation (GstVaapiFilter * filter, GstVaapiFilterOp op)
1407 {
1408   g_return_val_if_fail (filter != NULL, FALSE);
1409
1410   return find_operation (filter, op) != NULL;
1411 }
1412
1413 /**
1414  * gst_vaapi_filter_use_operation:
1415  * @filter: a #GstVaapiFilter
1416  * @op: a #GstVaapiFilterOp
1417  *
1418  * Determines whether the supplied operation @op was already enabled
1419  * through a prior call to gst_vaapi_filter_set_operation() or any
1420  * other operation-specific function.
1421  *
1422  * Note: should an operation be set to its default value, this means
1423  * that it is actually not enabled.
1424  *
1425  * Return value: %TRUE if the specified operation was already enabled,
1426  *   %FALSE otherwise
1427  */
1428 gboolean
1429 gst_vaapi_filter_use_operation (GstVaapiFilter * filter, GstVaapiFilterOp op)
1430 {
1431   GstVaapiFilterOpData *op_data;
1432
1433   g_return_val_if_fail (filter != NULL, FALSE);
1434
1435   op_data = find_operation (filter, op);
1436   if (!op_data)
1437     return FALSE;
1438   return op_data->is_enabled;
1439 }
1440
1441 /**
1442  * gst_vaapi_filter_set_operation:
1443  * @filter: a #GstVaapiFilter
1444  * @op: a #GstVaapiFilterOp
1445  * @value: the @op settings
1446  *
1447  * Enable the specified operation @op to be performed during video
1448  * processing, i.e. in gst_vaapi_filter_process(). The @value argument
1449  * specifies the operation settings. e.g. deinterlacing method for
1450  * deinterlacing, denoising level for noise reduction, etc.
1451  *
1452  * If @value is %NULL, then this function resets the operation
1453  * settings to their default values.
1454  *
1455  * Return value: %TRUE if the specified operation may be supported,
1456  *   %FALSE otherwise
1457  */
1458 gboolean
1459 gst_vaapi_filter_set_operation (GstVaapiFilter * filter, GstVaapiFilterOp op,
1460     const GValue * value)
1461 {
1462   GstVaapiFilterOpData *op_data;
1463
1464   g_return_val_if_fail (filter != NULL, FALSE);
1465
1466   op_data = find_operation (filter, op);
1467   if (!op_data)
1468     return FALSE;
1469
1470   if (value && !G_VALUE_HOLDS (value, G_PARAM_SPEC_VALUE_TYPE (op_data->pspec)))
1471     return FALSE;
1472
1473   switch (op) {
1474     case GST_VAAPI_FILTER_OP_FORMAT:
1475       return gst_vaapi_filter_set_format (filter, value ?
1476           g_value_get_enum (value) : DEFAULT_FORMAT);
1477     case GST_VAAPI_FILTER_OP_CROP:
1478       return gst_vaapi_filter_set_cropping_rectangle (filter, value ?
1479           g_value_get_boxed (value) : NULL);
1480     case GST_VAAPI_FILTER_OP_DENOISE:
1481     case GST_VAAPI_FILTER_OP_SHARPEN:
1482       return op_set_generic (filter, op_data,
1483           (value ? g_value_get_float (value) :
1484               G_PARAM_SPEC_FLOAT (op_data->pspec)->default_value));
1485     case GST_VAAPI_FILTER_OP_HUE:
1486     case GST_VAAPI_FILTER_OP_SATURATION:
1487     case GST_VAAPI_FILTER_OP_BRIGHTNESS:
1488     case GST_VAAPI_FILTER_OP_CONTRAST:
1489       return op_set_color_balance (filter, op_data,
1490           (value ? g_value_get_float (value) :
1491               G_PARAM_SPEC_FLOAT (op_data->pspec)->default_value));
1492     case GST_VAAPI_FILTER_OP_DEINTERLACING:
1493       return op_set_deinterlace (filter, op_data,
1494           (value ? g_value_get_enum (value) :
1495               G_PARAM_SPEC_ENUM (op_data->pspec)->default_value), 0);
1496       break;
1497     case GST_VAAPI_FILTER_OP_SCALING:
1498       return gst_vaapi_filter_set_scaling (filter,
1499           (value ? g_value_get_enum (value) :
1500               G_PARAM_SPEC_ENUM (op_data->pspec)->default_value));
1501 #ifndef GST_REMOVE_DEPRECATED
1502     case GST_VAAPI_FILTER_OP_SKINTONE:
1503       return op_set_skintone (filter, op_data,
1504           (value ? g_value_get_boolean (value) :
1505               G_PARAM_SPEC_BOOLEAN (op_data->pspec)->default_value));
1506 #endif
1507     case GST_VAAPI_FILTER_OP_SKINTONE_LEVEL:
1508       return op_set_skintone_level (filter, op_data,
1509           (value ? g_value_get_uint (value) :
1510               G_PARAM_SPEC_UINT (op_data->pspec)->default_value));
1511     case GST_VAAPI_FILTER_OP_VIDEO_DIRECTION:
1512       return gst_vaapi_filter_set_video_direction (filter,
1513           (value ? g_value_get_enum (value) :
1514               G_PARAM_SPEC_ENUM (op_data->pspec)->default_value));
1515     default:
1516       break;
1517   }
1518   return FALSE;
1519 }
1520
1521 /**
1522  * gst_vaapi_filter_process:
1523  * @filter: a #GstVaapiFilter
1524  * @src_surface: the source @GstVaapiSurface
1525  * @dst_surface: the destination @GstVaapiSurface
1526  * @flags: #GstVaapiSurfaceRenderFlags that apply to @src_surface
1527  *
1528  * Applies the operations currently defined in the @filter to
1529  * @src_surface and return the output in @dst_surface. The order of
1530  * operations is determined in a way that suits best the underlying
1531  * hardware. i.e. the only guarantee held is the generated outcome,
1532  * not any specific order of operations.
1533  *
1534  * Return value: a #GstVaapiFilterStatus
1535  */
1536 static GstVaapiFilterStatus
1537 gst_vaapi_filter_process_unlocked (GstVaapiFilter * filter,
1538     GstVaapiSurface * src_surface, GstVaapiSurface * dst_surface, guint flags)
1539 {
1540   VAProcPipelineParameterBuffer *pipeline_param = NULL;
1541   VABufferID pipeline_param_buf_id = VA_INVALID_ID;
1542   VABufferID filters[N_PROPERTIES];
1543   VAProcPipelineCaps pipeline_caps;
1544   guint i, num_filters = 0;
1545   VAStatus va_status;
1546   VARectangle src_rect, dst_rect;
1547   guint va_mirror = 0, va_rotation = 0;
1548
1549   if (!ensure_operations (filter))
1550     return GST_VAAPI_FILTER_STATUS_ERROR_ALLOCATION_FAILED;
1551
1552   /* Build surface region (source) */
1553   if (filter->use_crop_rect) {
1554     const GstVaapiRectangle *const crop_rect = &filter->crop_rect;
1555
1556     if ((crop_rect->x + crop_rect->width >
1557             GST_VAAPI_SURFACE_WIDTH (src_surface)) ||
1558         (crop_rect->y + crop_rect->height >
1559             GST_VAAPI_SURFACE_HEIGHT (src_surface)))
1560       goto error;
1561
1562     src_rect.x = crop_rect->x;
1563     src_rect.y = crop_rect->y;
1564     src_rect.width = crop_rect->width;
1565     src_rect.height = crop_rect->height;
1566   } else {
1567     src_rect.x = 0;
1568     src_rect.y = 0;
1569     src_rect.width = GST_VAAPI_SURFACE_WIDTH (src_surface);
1570     src_rect.height = GST_VAAPI_SURFACE_HEIGHT (src_surface);
1571   }
1572
1573   /* Build output region (target) */
1574   if (filter->use_target_rect) {
1575     const GstVaapiRectangle *const target_rect = &filter->target_rect;
1576
1577     if ((target_rect->x + target_rect->width >
1578             GST_VAAPI_SURFACE_WIDTH (dst_surface)) ||
1579         (target_rect->y + target_rect->height >
1580             GST_VAAPI_SURFACE_HEIGHT (dst_surface)))
1581       goto error;
1582
1583     dst_rect.x = target_rect->x;
1584     dst_rect.y = target_rect->y;
1585     dst_rect.width = target_rect->width;
1586     dst_rect.height = target_rect->height;
1587   } else {
1588     dst_rect.x = 0;
1589     dst_rect.y = 0;
1590     dst_rect.width = GST_VAAPI_SURFACE_WIDTH (dst_surface);
1591     dst_rect.height = GST_VAAPI_SURFACE_HEIGHT (dst_surface);
1592   }
1593
1594   for (i = 0, num_filters = 0; i < filter->operations->len; i++) {
1595     GstVaapiFilterOpData *const op_data =
1596         g_ptr_array_index (filter->operations, i);
1597     if (!op_data->is_enabled)
1598       continue;
1599     if (op_data->va_buffer == VA_INVALID_ID) {
1600       GST_ERROR ("invalid VA buffer for operation %s",
1601           g_param_spec_get_name (op_data->pspec));
1602       goto error;
1603     }
1604     filters[num_filters++] = op_data->va_buffer;
1605   }
1606
1607   /* Validate pipeline caps */
1608   va_status = vaQueryVideoProcPipelineCaps (filter->va_display,
1609       filter->va_context, filters, num_filters, &pipeline_caps);
1610   if (!vaapi_check_status (va_status, "vaQueryVideoProcPipelineCaps()"))
1611     goto error;
1612
1613   if (!vaapi_create_buffer (filter->va_display, filter->va_context,
1614           VAProcPipelineParameterBufferType, sizeof (*pipeline_param),
1615           NULL, &pipeline_param_buf_id, (gpointer *) & pipeline_param))
1616     goto error;
1617
1618   memset (pipeline_param, 0, sizeof (*pipeline_param));
1619   pipeline_param->surface = GST_VAAPI_OBJECT_ID (src_surface);
1620   pipeline_param->surface_region = &src_rect;
1621   pipeline_param->surface_color_standard = VAProcColorStandardNone;
1622   pipeline_param->output_region = &dst_rect;
1623   pipeline_param->output_color_standard = VAProcColorStandardNone;
1624   pipeline_param->output_background_color = 0xff000000;
1625   pipeline_param->filter_flags = from_GstVaapiSurfaceRenderFlags (flags) |
1626       from_GstVaapiScaleMethod (filter->scale_method);
1627   pipeline_param->filters = filters;
1628   pipeline_param->num_filters = num_filters;
1629
1630   from_GstVideoOrientationMethod (filter->video_direction, &va_mirror,
1631       &va_rotation);
1632
1633 #if VA_CHECK_VERSION(1,1,0)
1634   pipeline_param->mirror_state = va_mirror;
1635   pipeline_param->rotation_state = va_rotation;
1636 #endif
1637
1638   // Reference frames for advanced deinterlacing
1639   if (filter->forward_references->len > 0) {
1640     pipeline_param->forward_references = (VASurfaceID *)
1641         filter->forward_references->data;
1642     pipeline_param->num_forward_references =
1643         MIN (filter->forward_references->len,
1644         pipeline_caps.num_forward_references);
1645   } else {
1646     pipeline_param->forward_references = NULL;
1647     pipeline_param->num_forward_references = 0;
1648   }
1649
1650   if (filter->backward_references->len > 0) {
1651     pipeline_param->backward_references = (VASurfaceID *)
1652         filter->backward_references->data;
1653     pipeline_param->num_backward_references =
1654         MIN (filter->backward_references->len,
1655         pipeline_caps.num_backward_references);
1656   } else {
1657     pipeline_param->backward_references = NULL;
1658     pipeline_param->num_backward_references = 0;
1659   }
1660
1661   vaapi_unmap_buffer (filter->va_display, pipeline_param_buf_id, NULL);
1662
1663   va_status = vaBeginPicture (filter->va_display, filter->va_context,
1664       GST_VAAPI_OBJECT_ID (dst_surface));
1665   if (!vaapi_check_status (va_status, "vaBeginPicture()"))
1666     goto error;
1667
1668   va_status = vaRenderPicture (filter->va_display, filter->va_context,
1669       &pipeline_param_buf_id, 1);
1670   if (!vaapi_check_status (va_status, "vaRenderPicture()"))
1671     goto error;
1672
1673   va_status = vaEndPicture (filter->va_display, filter->va_context);
1674   if (!vaapi_check_status (va_status, "vaEndPicture()"))
1675     goto error;
1676
1677   deint_refs_clear_all (filter);
1678   vaapi_destroy_buffer (filter->va_display, &pipeline_param_buf_id);
1679   return GST_VAAPI_FILTER_STATUS_SUCCESS;
1680
1681   /* ERRORS */
1682 error:
1683   {
1684     deint_refs_clear_all (filter);
1685     vaapi_destroy_buffer (filter->va_display, &pipeline_param_buf_id);
1686     return GST_VAAPI_FILTER_STATUS_ERROR_OPERATION_FAILED;
1687   }
1688 }
1689
1690 GstVaapiFilterStatus
1691 gst_vaapi_filter_process (GstVaapiFilter * filter,
1692     GstVaapiSurface * src_surface, GstVaapiSurface * dst_surface, guint flags)
1693 {
1694   GstVaapiFilterStatus status;
1695
1696   g_return_val_if_fail (filter != NULL,
1697       GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
1698   g_return_val_if_fail (src_surface != NULL,
1699       GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
1700   g_return_val_if_fail (dst_surface != NULL,
1701       GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
1702
1703   GST_VAAPI_DISPLAY_LOCK (filter->display);
1704   status = gst_vaapi_filter_process_unlocked (filter,
1705       src_surface, dst_surface, flags);
1706   GST_VAAPI_DISPLAY_UNLOCK (filter->display);
1707   return status;
1708 }
1709
1710 /**
1711  * gst_vaapi_filter_get_formats:
1712  * @filter: a #GstVaapiFilter
1713  *
1714  * Determines the set of supported source or target formats for video
1715  * processing.  The caller owns an extra reference to the resulting
1716  * array of #GstVideoFormat elements, so it shall be released with
1717  * g_array_unref() after usage.
1718  *
1719  * Return value: the set of supported target formats for video processing.
1720  */
1721 GArray *
1722 gst_vaapi_filter_get_formats (GstVaapiFilter * filter)
1723 {
1724   g_return_val_if_fail (filter != NULL, NULL);
1725
1726   if (!ensure_attributes (filter))
1727     return NULL;
1728   if (filter->attribs->formats)
1729     return g_array_ref (filter->attribs->formats);
1730   return NULL;
1731 }
1732
1733 /**
1734  * gst_vaapi_filter_set_format:
1735  * @filter: a #GstVaapiFilter
1736  * @format: the target surface format
1737  *
1738  * Sets the desired pixel format of the resulting video processing
1739  * operations.
1740  *
1741  * If @format is #GST_VIDEO_FORMAT_UNKNOWN, the filter will assume iso
1742  * format conversion, i.e. no color conversion at all and the target
1743  * surface format shall match the source surface format.
1744  *
1745  * If @format is #GST_VIDEO_FORMAT_ENCODED, the filter will use the pixel
1746  * format of the target surface passed to gst_vaapi_filter_process().
1747  *
1748  * Return value: %TRUE if the color conversion to the specified @format
1749  *   may be supported, %FALSE otherwise.
1750  */
1751 gboolean
1752 gst_vaapi_filter_set_format (GstVaapiFilter * filter, GstVideoFormat format)
1753 {
1754   g_return_val_if_fail (filter != NULL, FALSE);
1755
1756   if (!ensure_attributes (filter))
1757     return FALSE;
1758
1759   if (!is_special_format (format) && !find_format (filter, format))
1760     return FALSE;
1761
1762   filter->format = format;
1763   return TRUE;
1764 }
1765
1766 /**
1767  * gst_vaapi_filter_append_caps:
1768  * @filter: a #GstVaapiFilter
1769  * @structure: a #GstStructure from #GstCaps
1770  *
1771  * Extracts the config's surface attributes, from @filter's context,
1772  * and transforms it into a caps formats and appended them into
1773  * @structure.
1774  *
1775  * Returns: %TRUE if the capabilities could be extracted and appended
1776  * into @structure; otherwise %FALSE
1777  **/
1778 gboolean
1779 gst_vaapi_filter_append_caps (GstVaapiFilter * filter, GstStructure * structure)
1780 {
1781   GstVaapiConfigSurfaceAttributes *attribs;
1782
1783   g_return_val_if_fail (filter != NULL, FALSE);
1784   g_return_val_if_fail (structure != NULL, FALSE);
1785
1786   if (!ensure_attributes (filter))
1787     return FALSE;
1788
1789   attribs = filter->attribs;
1790
1791   if (attribs->min_width >= attribs->max_width ||
1792       attribs->min_height >= attribs->max_height)
1793     return FALSE;
1794
1795   gst_structure_set (structure, "width", GST_TYPE_INT_RANGE, attribs->min_width,
1796       attribs->max_width, "height", GST_TYPE_INT_RANGE, attribs->min_height,
1797       attribs->max_height, NULL);
1798
1799   return TRUE;
1800
1801 }
1802
1803 /**
1804  * gst_vaapi_filter_set_cropping_rectangle:
1805  * @filter: a #GstVaapiFilter
1806  * @rect: the cropping region
1807  *
1808  * Sets the source surface cropping rectangle to use during the video
1809  * processing. If @rect is %NULL, the whole source surface will be used.
1810  *
1811  * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1812  */
1813 gboolean
1814 gst_vaapi_filter_set_cropping_rectangle (GstVaapiFilter * filter,
1815     const GstVaapiRectangle * rect)
1816 {
1817   g_return_val_if_fail (filter != NULL, FALSE);
1818
1819   filter->use_crop_rect = rect != NULL;
1820   if (filter->use_crop_rect)
1821     filter->crop_rect = *rect;
1822   return TRUE;
1823 }
1824
1825 /**
1826  * gst_vaapi_filter_set_target_rectangle:
1827  * @filter: a #GstVaapiFilter
1828  * @rect: the target render region
1829  *
1830  * Sets the region within the target surface where the source surface
1831  * would be rendered. i.e. where the hardware accelerator would emit
1832  * the outcome of video processing. If @rect is %NULL, the whole
1833  * source surface will be used.
1834  *
1835  * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1836  */
1837 gboolean
1838 gst_vaapi_filter_set_target_rectangle (GstVaapiFilter * filter,
1839     const GstVaapiRectangle * rect)
1840 {
1841   g_return_val_if_fail (filter != NULL, FALSE);
1842
1843   filter->use_target_rect = rect != NULL;
1844   if (filter->use_target_rect)
1845     filter->target_rect = *rect;
1846   return TRUE;
1847 }
1848
1849 /**
1850  * gst_vaapi_filter_set_denoising_level:
1851  * @filter: a #GstVaapiFilter
1852  * @level: the level of noise reduction to apply
1853  *
1854  * Sets the noise reduction level to apply. If @level is 0.0f, this
1855  * corresponds to disabling the noise reduction algorithm.
1856  *
1857  * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1858  */
1859 gboolean
1860 gst_vaapi_filter_set_denoising_level (GstVaapiFilter * filter, gfloat level)
1861 {
1862   g_return_val_if_fail (filter != NULL, FALSE);
1863
1864   return op_set_generic (filter,
1865       find_operation (filter, GST_VAAPI_FILTER_OP_DENOISE), level);
1866 }
1867
1868 /**
1869  * gst_vaapi_filter_set_sharpening_level:
1870  * @filter: a #GstVaapiFilter
1871  * @level: the sharpening factor
1872  *
1873  * Enables noise reduction with the specified factor.
1874  *
1875  * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1876  */
1877 gboolean
1878 gst_vaapi_filter_set_sharpening_level (GstVaapiFilter * filter, gfloat level)
1879 {
1880   g_return_val_if_fail (filter != NULL, FALSE);
1881
1882   return op_set_generic (filter,
1883       find_operation (filter, GST_VAAPI_FILTER_OP_SHARPEN), level);
1884 }
1885
1886 /**
1887  * gst_vaapi_filter_set_hue:
1888  * @filter: a #GstVaapiFilter
1889  * @value: the color hue value
1890  *
1891  * Enables color hue adjustment to the specified value.
1892  *
1893  * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1894  */
1895 gboolean
1896 gst_vaapi_filter_set_hue (GstVaapiFilter * filter, gfloat value)
1897 {
1898   g_return_val_if_fail (filter != NULL, FALSE);
1899
1900   return op_set_color_balance (filter,
1901       find_operation (filter, GST_VAAPI_FILTER_OP_HUE), value);
1902 }
1903
1904 /**
1905  * gst_vaapi_filter_set_saturation:
1906  * @filter: a #GstVaapiFilter
1907  * @value: the color saturation value
1908  *
1909  * Enables color saturation adjustment to the specified value.
1910  *
1911  * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1912  */
1913 gboolean
1914 gst_vaapi_filter_set_saturation (GstVaapiFilter * filter, gfloat value)
1915 {
1916   g_return_val_if_fail (filter != NULL, FALSE);
1917
1918   return op_set_color_balance (filter,
1919       find_operation (filter, GST_VAAPI_FILTER_OP_SATURATION), value);
1920 }
1921
1922 /**
1923  * gst_vaapi_filter_set_brightness:
1924  * @filter: a #GstVaapiFilter
1925  * @value: the color brightness value
1926  *
1927  * Enables color brightness adjustment to the specified value.
1928  *
1929  * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1930  */
1931 gboolean
1932 gst_vaapi_filter_set_brightness (GstVaapiFilter * filter, gfloat value)
1933 {
1934   g_return_val_if_fail (filter != NULL, FALSE);
1935
1936   return op_set_color_balance (filter,
1937       find_operation (filter, GST_VAAPI_FILTER_OP_BRIGHTNESS), value);
1938 }
1939
1940 /**
1941  * gst_vaapi_filter_set_contrast:
1942  * @filter: a #GstVaapiFilter
1943  * @value: the color contrast value
1944  *
1945  * Enables color contrast adjustment to the specified value.
1946  *
1947  * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1948  */
1949 gboolean
1950 gst_vaapi_filter_set_contrast (GstVaapiFilter * filter, gfloat value)
1951 {
1952   g_return_val_if_fail (filter != NULL, FALSE);
1953
1954   return op_set_color_balance (filter,
1955       find_operation (filter, GST_VAAPI_FILTER_OP_CONTRAST), value);
1956 }
1957
1958 /**
1959  * gst_vaapi_filter_set_deinterlacing:
1960  * @filter: a #GstVaapiFilter
1961  * @method: the deinterlacing algorithm (see #GstVaapiDeinterlaceMethod)
1962  * @flags: the additional flags
1963  *
1964  * Applies deinterlacing to the video processing pipeline. If @method
1965  * is not @GST_VAAPI_DEINTERLACE_METHOD_NONE, then @flags could
1966  * represent the initial picture structure of the source frame.
1967  *
1968  * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1969  */
1970 gboolean
1971 gst_vaapi_filter_set_deinterlacing (GstVaapiFilter * filter,
1972     GstVaapiDeinterlaceMethod method, guint flags)
1973 {
1974   g_return_val_if_fail (filter != NULL, FALSE);
1975
1976   return op_set_deinterlace (filter,
1977       find_operation (filter, GST_VAAPI_FILTER_OP_DEINTERLACING), method,
1978       flags);
1979 }
1980
1981 /**
1982  * gst_vaapi_filter_set_deinterlacing_references:
1983  * @filter: a #GstVaapiFilter
1984  * @forward_references: the set of #GstVaapiSurface objects used as
1985  *   forward references
1986  * @num_forward_references: the number of elements in the
1987  *   @forward_references array
1988  * @backward_references: the set of #GstVaapiSurface objects used as
1989  *   backward references
1990  * @num_backward_references: the number of elements in the
1991  *   @backward_references array
1992  *
1993  * Specifies the list of surfaces used for forward or backward reference in
1994  * advanced deinterlacing mode. The caller is responsible for maintaining
1995  * the associated surfaces live until gst_vaapi_filter_process() completes.
1996  * e.g. by holding an extra reference to the associated #GstVaapiSurfaceProxy.
1997  *
1998  * Temporal ordering is maintained as follows: the shorter index in
1999  * either array is, the closest the matching surface is relatively to
2000  * the current source surface to process. e.g. surface in
2001  * @forward_references array index 0 represents the immediately
2002  * preceding surface in display order, surface at index 1 is the one
2003  * preceding surface at index 0, etc.
2004  *
2005  * The video processing filter will only use the recommended number of
2006  * surfaces for backward and forward references.
2007  *
2008  * Note: the supplied lists of reference surfaces are not sticky. This
2009  * means that they are only valid for the next gst_vaapi_filter_process()
2010  * call, and thus needs to be submitted again for subsequent calls.
2011  *
2012  * Return value: %TRUE if the operation is supported, %FALSE otherwise.
2013  */
2014 gboolean
2015 gst_vaapi_filter_set_deinterlacing_references (GstVaapiFilter * filter,
2016     GstVaapiSurface ** forward_references, guint num_forward_references,
2017     GstVaapiSurface ** backward_references, guint num_backward_references)
2018 {
2019   g_return_val_if_fail (filter != NULL, FALSE);
2020
2021   deint_refs_clear_all (filter);
2022
2023   if (!deint_refs_set (filter->forward_references, forward_references,
2024           num_forward_references))
2025     return FALSE;
2026
2027   if (!deint_refs_set (filter->backward_references, backward_references,
2028           num_backward_references))
2029     return FALSE;
2030   return TRUE;
2031 }
2032
2033 /**
2034  * gst_vaapi_filter_set_scaling:
2035  * @filter: a #GstVaapiFilter
2036  * @method: the scaling algorithm (see #GstVaapiScaleMethod)
2037  *
2038  * Applies scaling algorithm to the video processing pipeline.
2039  *
2040  * Return value: %TRUE if the operation is supported, %FALSE otherwise.
2041  */
2042 gboolean
2043 gst_vaapi_filter_set_scaling (GstVaapiFilter * filter,
2044     GstVaapiScaleMethod method)
2045 {
2046   g_return_val_if_fail (filter != NULL, FALSE);
2047
2048   filter->scale_method = method;
2049   return TRUE;
2050 }
2051
2052 #ifndef GST_REMOVE_DEPRECATED
2053 /**
2054  * gst_vaapi_filter_set_skintone:
2055  * @filter: a #GstVaapiFilter
2056  * @enhance: %TRUE if enable the skin tone enhancement algorithm
2057  *
2058  * Applies the skin tone enhancement algorithm.
2059  *
2060  * Return value: %TRUE if the operation is supported, %FALSE
2061  * otherwise.
2062   **/
2063 gboolean
2064 gst_vaapi_filter_set_skintone (GstVaapiFilter * filter, gboolean enhance)
2065 {
2066   g_return_val_if_fail (filter != NULL, FALSE);
2067
2068   return op_set_skintone (filter,
2069       find_operation (filter, GST_VAAPI_FILTER_OP_SKINTONE), enhance);
2070 }
2071 #endif
2072
2073 /**
2074  * gst_vaapi_filter_set_skintone_level:
2075  * @filter: a #GstVaapiFilter
2076  * @value: the value if enable the skin tone enhancement algorithm
2077  *
2078  * Applies the skin tone enhancement algorithm with specifled value.
2079  *
2080  * Return value: %TRUE if the operation is supported, %FALSE
2081  * otherwise.
2082   **/
2083 gboolean
2084 gst_vaapi_filter_set_skintone_level (GstVaapiFilter * filter, guint value)
2085 {
2086   g_return_val_if_fail (filter != NULL, FALSE);
2087
2088   return op_set_skintone_level (filter,
2089       find_operation (filter, GST_VAAPI_FILTER_OP_SKINTONE_LEVEL), value);
2090 }
2091
2092 /**
2093  * gst_vaapi_filter_set_video_direction:
2094  * @filter: a #GstVaapiFilter
2095  * @method: the video direction (see #GstVideoOrientationMethod)
2096  *
2097  * Applies mirror/rotation to the video processing pipeline.
2098  *
2099  * Return value: %TRUE if the operation is supported, %FALSE otherwise.
2100  */
2101 gboolean
2102 gst_vaapi_filter_set_video_direction (GstVaapiFilter * filter,
2103     GstVideoOrientationMethod method)
2104 {
2105   g_return_val_if_fail (filter != NULL, FALSE);
2106
2107 #if VA_CHECK_VERSION(1,1,0)
2108   {
2109     guint32 va_mirror = VA_MIRROR_NONE;
2110     guint32 va_rotation = VA_ROTATION_NONE;
2111
2112     from_GstVideoOrientationMethod (method, &va_mirror, &va_rotation);
2113
2114     if (va_mirror != VA_MIRROR_NONE && !(filter->mirror_flags & va_mirror))
2115       return FALSE;
2116
2117     if (va_rotation != VA_ROTATION_NONE
2118         && !(filter->rotation_flags & (1 << va_rotation)))
2119       return FALSE;
2120   }
2121 #else
2122   return FALSE;
2123 #endif
2124
2125   filter->video_direction = method;
2126   return TRUE;
2127 }
2128
2129 /**
2130  * gst_vaapi_filter_get_video_direction:
2131  * @filter: a #GstVaapiFilter
2132  *
2133  * Return value: the currently applied video direction (see #GstVideoOrientationMethod)
2134  */
2135 GstVideoOrientationMethod
2136 gst_vaapi_filter_get_video_direction (GstVaapiFilter * filter)
2137 {
2138   g_return_val_if_fail (filter != NULL, GST_VIDEO_ORIENTATION_IDENTITY);
2139   return filter->video_direction;
2140 }
2141
2142 static inline gfloat
2143 op_get_float_default_value (GstVaapiFilter * filter,
2144     GstVaapiFilterOpData * op_data)
2145 {
2146   GParamSpecFloat *const pspec = G_PARAM_SPEC_FLOAT (op_data->pspec);
2147   return pspec->default_value;
2148 }
2149
2150 static inline gint
2151 op_get_enum_default_value (GstVaapiFilter * filter,
2152     GstVaapiFilterOpData * op_data)
2153 {
2154   GParamSpecEnum *const pspec = G_PARAM_SPEC_ENUM (op_data->pspec);
2155   return pspec->default_value;
2156 }
2157
2158 static inline guint
2159 op_get_uint_default_value (GstVaapiFilter * filter,
2160     GstVaapiFilterOpData * op_data)
2161 {
2162   GParamSpecUInt *const pspec = G_PARAM_SPEC_UINT (op_data->pspec);
2163   return pspec->default_value;
2164 }
2165
2166 static inline gboolean
2167 op_get_bool_default_value (GstVaapiFilter * filter,
2168     GstVaapiFilterOpData * op_data)
2169 {
2170   GParamSpecBoolean *const pspec = G_PARAM_SPEC_BOOLEAN (op_data->pspec);
2171   return pspec->default_value;
2172 }
2173
2174 gfloat
2175 gst_vaapi_filter_get_denoising_level_default (GstVaapiFilter * filter)
2176 {
2177   OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_DENOISE);
2178 }
2179
2180 gfloat
2181 gst_vaapi_filter_get_sharpening_level_default (GstVaapiFilter * filter)
2182 {
2183   OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_SHARPEN);
2184 }
2185
2186 gfloat
2187 gst_vaapi_filter_get_hue_default (GstVaapiFilter * filter)
2188 {
2189   OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_HUE);
2190 }
2191
2192 gfloat
2193 gst_vaapi_filter_get_saturation_default (GstVaapiFilter * filter)
2194 {
2195   OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_SATURATION);
2196 }
2197
2198 gfloat
2199 gst_vaapi_filter_get_brightness_default (GstVaapiFilter * filter)
2200 {
2201   OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_BRIGHTNESS);
2202 }
2203
2204 gfloat
2205 gst_vaapi_filter_get_contrast_default (GstVaapiFilter * filter)
2206 {
2207   OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_CONTRAST);
2208 }
2209
2210 GstVaapiScaleMethod
2211 gst_vaapi_filter_get_scaling_default (GstVaapiFilter * filter)
2212 {
2213   OP_RET_DEFAULT_VALUE (enum, filter, GST_VAAPI_FILTER_OP_SCALING);
2214 }
2215
2216 #ifndef GST_REMOVE_DEPRECATED
2217 gboolean
2218 gst_vaapi_filter_get_skintone_default (GstVaapiFilter * filter)
2219 {
2220   OP_RET_DEFAULT_VALUE (boolean, filter, GST_VAAPI_FILTER_OP_SKINTONE);
2221 }
2222 #endif
2223
2224 guint
2225 gst_vaapi_filter_get_skintone_level_default (GstVaapiFilter * filter)
2226 {
2227   OP_RET_DEFAULT_VALUE (uint, filter, GST_VAAPI_FILTER_OP_SKINTONE_LEVEL);
2228 }
2229
2230 GstVideoOrientationMethod
2231 gst_vaapi_filter_get_video_direction_default (GstVaapiFilter * filter)
2232 {
2233   OP_RET_DEFAULT_VALUE (boolean, filter, GST_VAAPI_FILTER_OP_VIDEO_DIRECTION);
2234 }