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