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