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