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