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