2 * gstvaapifilter.c - Video processing abstraction
4 * Copyright (C) 2013 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
23 #include "gstvaapifilter.h"
24 #include "gstvaapiutils.h"
25 #include "gstvaapivalue.h"
26 #include "gstvaapiminiobject.h"
27 #include "gstvaapidisplay_priv.h"
28 #include "gstvaapisurface_priv.h"
31 # include <va/va_vpp.h>
35 #include "gstvaapidebug.h"
37 #define GST_VAAPI_FILTER(obj) \
38 ((GstVaapiFilter *)(obj))
40 typedef struct _GstVaapiFilterOpData GstVaapiFilterOpData;
41 struct _GstVaapiFilterOpData {
44 volatile gint ref_count;
55 struct _GstVaapiFilter {
57 GstVaapiMiniObject parent_instance;
59 GstVaapiDisplay *display;
62 VAContextID va_context;
63 GPtrArray *operations;
64 GstVideoFormat format;
66 GstVaapiRectangle crop_rect;
67 guint use_crop_rect : 1;
70 /* ------------------------------------------------------------------------- */
71 /* --- VPP Helpers --- */
72 /* ------------------------------------------------------------------------- */
75 static VAProcFilterType *
76 vpp_get_filters_unlocked(GstVaapiFilter *filter, guint *num_filters_ptr)
78 VAProcFilterType *filters = NULL;
79 guint num_filters = 0;
82 num_filters = VAProcFilterCount;
83 filters = g_malloc_n(num_filters, sizeof(*filters));
87 va_status = vaQueryVideoProcFilters(filter->va_display, filter->va_context,
88 filters, &num_filters);
90 // Try to reallocate to the expected number of filters
91 if (va_status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) {
92 VAProcFilterType * const new_filters =
93 g_try_realloc_n(filters, num_filters, sizeof(*new_filters));
96 filters = new_filters;
98 va_status = vaQueryVideoProcFilters(filter->va_display,
99 filter->va_context, filters, &num_filters);
101 if (!vaapi_check_status(va_status, "vaQueryVideoProcFilters()"))
104 *num_filters_ptr = num_filters;
112 static VAProcFilterType *
113 vpp_get_filters(GstVaapiFilter *filter, guint *num_filters_ptr)
115 VAProcFilterType *filters;
117 GST_VAAPI_DISPLAY_LOCK(filter->display);
118 filters = vpp_get_filters_unlocked(filter, num_filters_ptr);
119 GST_VAAPI_DISPLAY_UNLOCK(filter->display);
124 vpp_get_filter_caps_unlocked(
125 GstVaapiFilter *filter, VAProcFilterType type,
126 guint cap_size, guint *num_caps_ptr)
132 caps = g_malloc(cap_size);
136 va_status = vaQueryVideoProcFilterCaps(filter->va_display,
137 filter->va_context, type, caps, &num_caps);
139 // Try to reallocate to the expected number of filters
140 if (va_status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) {
141 gpointer const new_caps = g_try_realloc_n(caps, num_caps, cap_size);
146 va_status = vaQueryVideoProcFilterCaps(filter->va_display,
147 filter->va_context, type, caps, &num_caps);
149 if (!vaapi_check_status(va_status, "vaQueryVideoProcFilterCaps()"))
152 *num_caps_ptr = num_caps;
161 vpp_get_filter_caps(GstVaapiFilter *filter, VAProcFilterType type,
162 guint cap_size, guint *num_caps_ptr)
166 GST_VAAPI_DISPLAY_LOCK(filter->display);
167 caps = vpp_get_filter_caps_unlocked(filter, type, cap_size, num_caps_ptr);
168 GST_VAAPI_DISPLAY_UNLOCK(filter->display);
173 /* ------------------------------------------------------------------------- */
174 /* --- VPP Operations --- */
175 /* ------------------------------------------------------------------------- */
178 #define DEFAULT_FORMAT GST_VIDEO_FORMAT_UNKNOWN
183 PROP_FORMAT = GST_VAAPI_FILTER_OP_FORMAT,
184 PROP_CROP = GST_VAAPI_FILTER_OP_CROP,
185 PROP_DENOISE = GST_VAAPI_FILTER_OP_DENOISE,
186 PROP_SHARPEN = GST_VAAPI_FILTER_OP_SHARPEN,
187 PROP_HUE = GST_VAAPI_FILTER_OP_HUE,
188 PROP_SATURATION = GST_VAAPI_FILTER_OP_SATURATION,
189 PROP_BRIGHTNESS = GST_VAAPI_FILTER_OP_BRIGHTNESS,
190 PROP_CONTRAST = GST_VAAPI_FILTER_OP_CONTRAST,
195 static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
196 static gsize g_properties_initialized = FALSE;
199 init_properties(void)
202 * GstVaapiFilter:format:
204 * The forced output pixel format, expressed as a #GstVideoFormat.
206 g_properties[PROP_FORMAT] =
207 g_param_spec_enum("format",
209 "The forced output pixel format",
210 GST_TYPE_VIDEO_FORMAT,
215 * GstVaapiFilter:crop-rect:
217 * The cropping rectangle, expressed as a #GstVaapiRectangle.
219 g_properties[PROP_CROP] =
220 g_param_spec_boxed("crop-rect",
221 "Cropping Rectangle",
222 "The cropping rectangle",
223 GST_VAAPI_TYPE_RECTANGLE,
227 * GstVaapiFilter:denoise:
229 * The level of noise reduction to apply.
231 g_properties[PROP_DENOISE] =
232 g_param_spec_float("denoise",
234 "The level of denoising to apply",
239 * GstVaapiFilter:sharpen:
241 * The level of sharpening to apply for positive values, or the
242 * level of blurring for negative values.
244 g_properties[PROP_SHARPEN] =
245 g_param_spec_float("sharpen",
247 "The level of sharpening/blurring to apply",
252 * GstVaapiFilter:hue:
254 * The color hue, expressed as a float value. Range is -180.0 to
255 * 180.0. Default value is 0.0 and represents no modification.
257 g_properties[PROP_HUE] =
258 g_param_spec_float("hue",
260 "The color hue value",
265 * GstVaapiFilter:saturation:
267 * The color saturation, expressed as a float value. Range is 0.0
268 * to 2.0. Default value is 1.0 and represents no modification.
270 g_properties[PROP_SATURATION] =
271 g_param_spec_float("saturation",
273 "The color saturation value",
278 * GstVaapiFilter:brightness:
280 * The color brightness, expressed as a float value. Range is -1.0
281 * to 1.0. Default value is 0.0 and represents no modification.
283 g_properties[PROP_BRIGHTNESS] =
284 g_param_spec_float("brightness",
286 "The color brightness value",
291 * GstVaapiFilter:contrast:
293 * The color contrast, expressed as a float value. Range is 0.0 to
294 * 2.0. Default value is 1.0 and represents no modification.
296 g_properties[PROP_CONTRAST] =
297 g_param_spec_float("contrast",
299 "The color contrast value",
305 ensure_properties(void)
307 if (g_once_init_enter(&g_properties_initialized)) {
309 g_once_init_leave(&g_properties_initialized, TRUE);
314 op_data_free(GstVaapiFilterOpData *op_data)
316 g_free(op_data->va_caps);
317 g_slice_free(GstVaapiFilterOpData, op_data);
320 static inline gpointer
321 op_data_new(GstVaapiFilterOp op, GParamSpec *pspec)
323 GstVaapiFilterOpData *op_data;
325 op_data = g_slice_new0(GstVaapiFilterOpData);
330 op_data->pspec = pspec;
331 op_data->ref_count = 1;
332 op_data->va_buffer = VA_INVALID_ID;
335 case GST_VAAPI_FILTER_OP_FORMAT:
336 case GST_VAAPI_FILTER_OP_CROP:
337 op_data->va_type = VAProcFilterNone;
339 case GST_VAAPI_FILTER_OP_DENOISE:
340 op_data->va_type = VAProcFilterNoiseReduction;
341 op_data->va_cap_size = sizeof(VAProcFilterCap);
342 op_data->va_buffer_size = sizeof(VAProcFilterParameterBuffer);
344 case GST_VAAPI_FILTER_OP_SHARPEN:
345 op_data->va_type = VAProcFilterSharpening;
346 op_data->va_cap_size = sizeof(VAProcFilterCap);
347 op_data->va_buffer_size = sizeof(VAProcFilterParameterBuffer);
349 case GST_VAAPI_FILTER_OP_HUE:
350 case GST_VAAPI_FILTER_OP_SATURATION:
351 case GST_VAAPI_FILTER_OP_BRIGHTNESS:
352 case GST_VAAPI_FILTER_OP_CONTRAST:
353 op_data->va_type = VAProcFilterColorBalance;
354 op_data->va_cap_size = sizeof(VAProcFilterCapColorBalance);
355 op_data->va_buffer_size = sizeof(VAProcFilterParameterBufferColorBalance);
358 g_assert(0 && "unsupported operation");
364 op_data_free(op_data);
368 static inline gpointer
369 op_data_ref(gpointer data)
371 GstVaapiFilterOpData * const op_data = data;
373 g_return_val_if_fail(op_data != NULL, NULL);
375 g_atomic_int_inc(&op_data->ref_count);
380 op_data_unref(gpointer data)
382 GstVaapiFilterOpData * const op_data = data;
384 g_return_if_fail(op_data != NULL);
385 g_return_if_fail(op_data->ref_count > 0);
387 if (g_atomic_int_dec_and_test(&op_data->ref_count))
388 op_data_free(op_data);
391 /* Ensure capability info is set up for the VA filter we are interested in */
393 op_data_ensure_caps(GstVaapiFilterOpData *op_data, gpointer filter_caps,
394 guint num_filter_caps)
396 guchar *filter_cap = filter_caps;
399 // Find the VA filter cap matching the op info sub-type
400 if (op_data->va_subtype) {
401 for (i = 0; i < num_filter_caps; i++) {
402 /* XXX: sub-type shall always be the first field */
403 if (op_data->va_subtype == *(guint *)filter_cap) {
407 filter_cap += op_data->va_cap_size;
409 if (i == num_filter_caps)
412 op_data->va_caps = g_memdup(filter_cap,
413 op_data->va_cap_size * num_filter_caps);
414 return op_data->va_caps != NULL;
417 /* Scale the filter value wrt. library spec and VA driver spec */
419 op_data_get_value_float(GstVaapiFilterOpData *op_data,
420 const VAProcFilterValueRange *range, gfloat value, gfloat *out_value_ptr)
422 GParamSpecFloat * const pspec = G_PARAM_SPEC_FLOAT(op_data->pspec);
425 g_return_val_if_fail(range != NULL, FALSE);
426 g_return_val_if_fail(out_value_ptr != NULL, FALSE);
428 if (value < pspec->minimum || value > pspec->maximum)
431 // Scale wrt. the medium ("default") value
432 out_value = range->default_value;
433 if (value > pspec->default_value)
434 out_value += ((value - pspec->default_value) /
435 (pspec->maximum - pspec->default_value) *
436 (range->max_value - range->default_value));
437 else if (value < pspec->default_value)
438 out_value -= ((pspec->default_value - value) /
439 (pspec->default_value - pspec->minimum) *
440 (range->default_value - range->min_value));
442 *out_value_ptr = out_value;
446 /* Get default list of operations supported by the library */
448 get_operations_default(void)
453 ops = g_ptr_array_new_full(N_PROPERTIES, op_data_unref);
459 for (i = 0; i < N_PROPERTIES; i++) {
460 GParamSpec * const pspec = g_properties[i];
464 GstVaapiFilterOpData * const op_data = op_data_new(i, pspec);
467 g_ptr_array_add(ops, op_data);
472 g_ptr_array_unref(ops);
476 /* Get the ordered list of operations, based on VA/VPP queries */
478 get_operations_ordered(GstVaapiFilter *filter, GPtrArray *default_ops)
481 VAProcFilterType *filters;
482 gpointer filter_caps = NULL;
483 guint i, j, num_filters, num_filter_caps = 0;
485 ops = g_ptr_array_new_full(default_ops->len, op_data_unref);
489 filters = vpp_get_filters(filter, &num_filters);
493 // Append virtual ops first, i.e. those without an associated VA filter
494 for (i = 0; i < default_ops->len; i++) {
495 GstVaapiFilterOpData * const op_data =
496 g_ptr_array_index(default_ops, i);
497 if (op_data->va_type == VAProcFilterNone)
498 g_ptr_array_add(ops, op_data_ref(op_data));
501 // Append ops, while preserving the VA filters ordering
502 for (i = 0; i < num_filters; i++) {
503 const VAProcFilterType va_type = filters[i];
504 if (va_type == VAProcFilterNone)
507 for (j = 0; j < default_ops->len; j++) {
508 GstVaapiFilterOpData * const op_data =
509 g_ptr_array_index(default_ops, j);
510 if (op_data->va_type != va_type)
514 filter_caps = vpp_get_filter_caps(filter, va_type,
515 op_data->va_cap_size, &num_filter_caps);
519 if (!op_data_ensure_caps(op_data, filter_caps, num_filter_caps))
521 g_ptr_array_add(ops, op_data_ref(op_data));
527 if (filter->operations)
528 g_ptr_array_unref(filter->operations);
529 filter->operations = g_ptr_array_ref(ops);
532 g_ptr_array_unref(default_ops);
538 g_ptr_array_unref(ops);
539 g_ptr_array_unref(default_ops);
543 /* Determine the set of supported VPP operations by the specific
544 filter, or known to this library if filter is NULL */
546 ensure_operations(GstVaapiFilter *filter)
550 if (filter && filter->operations)
551 return g_ptr_array_ref(filter->operations);
553 ops = get_operations_default();
556 return filter ? get_operations_ordered(filter, ops) : ops;
560 /* Find whether the VPP operation is supported or not */
561 GstVaapiFilterOpData *
562 find_operation(GstVaapiFilter *filter, GstVaapiFilterOp op)
566 if (!filter->operations)
569 for (i = 0; i < filter->operations->len; i++) {
570 GstVaapiFilterOpData * const op_data =
571 g_ptr_array_index(filter->operations, i);
572 if (op_data->op == op)
578 /* Ensure the operation's VA buffer is allocated */
579 static inline gboolean
580 op_ensure_buffer(GstVaapiFilter *filter, GstVaapiFilterOpData *op_data)
582 if (G_LIKELY(op_data->va_buffer != VA_INVALID_ID))
584 return vaapi_create_buffer(filter->va_display, filter->va_context,
585 VAProcFilterParameterBufferType, op_data->va_buffer_size, NULL,
586 &op_data->va_buffer, NULL);
589 /* Update a generic filter (float value) */
592 op_set_generic_unlocked(GstVaapiFilter *filter, GstVaapiFilterOpData *op_data,
595 VAProcFilterParameterBuffer *buf;
596 VAProcFilterCap *filter_cap;
599 if (!op_data || !op_ensure_buffer(filter, op_data))
602 op_data->is_enabled =
603 (value != G_PARAM_SPEC_FLOAT(op_data->pspec)->default_value);
604 if (!op_data->is_enabled)
607 filter_cap = op_data->va_caps;
608 if (!op_data_get_value_float(op_data, &filter_cap->range, value, &va_value))
611 buf = vaapi_map_buffer(filter->va_display, op_data->va_buffer);
615 buf->type = op_data->va_type;
616 buf->value = va_value;
617 vaapi_unmap_buffer(filter->va_display, op_data->va_buffer, NULL);
622 static inline gboolean
623 op_set_generic(GstVaapiFilter *filter, GstVaapiFilterOpData *op_data,
626 gboolean success = FALSE;
629 GST_VAAPI_DISPLAY_LOCK(filter->display);
630 success = op_set_generic_unlocked(filter, op_data, value);
631 GST_VAAPI_DISPLAY_UNLOCK(filter->display);
636 /* Update the color balance filter */
639 op_set_color_balance_unlocked(GstVaapiFilter *filter,
640 GstVaapiFilterOpData *op_data, gfloat value)
642 VAProcFilterParameterBufferColorBalance *buf;
643 VAProcFilterCapColorBalance *filter_cap;
646 if (!op_data || !op_ensure_buffer(filter, op_data))
649 op_data->is_enabled =
650 (value != G_PARAM_SPEC_FLOAT(op_data->pspec)->default_value);
651 if (!op_data->is_enabled)
654 filter_cap = op_data->va_caps;
655 if (!op_data_get_value_float(op_data, &filter_cap->range, value, &va_value))
658 buf = vaapi_map_buffer(filter->va_display, op_data->va_buffer);
662 buf->type = op_data->va_type;
663 buf->attrib = op_data->va_subtype;
664 buf->value = va_value;
665 vaapi_unmap_buffer(filter->va_display, op_data->va_buffer, NULL);
670 static inline gboolean
671 op_set_color_balance(GstVaapiFilter *filter, GstVaapiFilterOpData *op_data,
674 gboolean success = FALSE;
677 GST_VAAPI_DISPLAY_LOCK(filter->display);
678 success = op_set_color_balance_unlocked(filter, op_data, value);
679 GST_VAAPI_DISPLAY_UNLOCK(filter->display);
684 /* ------------------------------------------------------------------------- */
685 /* --- Surface Formats --- */
686 /* ------------------------------------------------------------------------- */
689 ensure_formats(GstVaapiFilter *filter)
691 VASurfaceAttrib *surface_attribs = NULL;
692 guint i, num_surface_attribs = 0;
695 if (G_LIKELY(filter->formats))
696 return filter->formats;
698 #if VA_CHECK_VERSION(0,34,0)
699 GST_VAAPI_DISPLAY_LOCK(filter->display);
700 va_status = vaQuerySurfaceAttributes(filter->va_display, filter->va_config,
701 NULL, &num_surface_attribs);
702 GST_VAAPI_DISPLAY_UNLOCK(filter->display);
703 if (!vaapi_check_status(va_status, "vaQuerySurfaceAttributes()"))
706 surface_attribs = g_malloc(num_surface_attribs * sizeof(*surface_attribs));
707 if (!surface_attribs)
710 GST_VAAPI_DISPLAY_LOCK(filter->display);
711 va_status = vaQuerySurfaceAttributes(filter->va_display, filter->va_config,
712 surface_attribs, &num_surface_attribs);
713 GST_VAAPI_DISPLAY_UNLOCK(filter->display);
714 if (!vaapi_check_status(va_status, "vaQuerySurfaceAttributes()"))
717 filter->formats = g_array_sized_new(FALSE, FALSE, sizeof(GstVideoFormat),
718 num_surface_attribs);
719 if (!filter->formats)
722 for (i = 0; i < num_surface_attribs; i++) {
723 const VASurfaceAttrib * const surface_attrib = &surface_attribs[i];
724 GstVideoFormat format;
726 if (surface_attrib->type != VASurfaceAttribPixelFormat)
728 if (!(surface_attrib->flags & VA_SURFACE_ATTRIB_SETTABLE))
731 format = gst_vaapi_video_format_from_va_fourcc(
732 surface_attrib->value.value.i);
733 if (format == GST_VIDEO_FORMAT_UNKNOWN)
735 g_array_append_val(filter->formats, format);
739 g_free(surface_attribs);
740 return filter->formats;
743 g_free(surface_attribs);
747 static inline gboolean
748 is_special_format(GstVideoFormat format)
750 return format == GST_VIDEO_FORMAT_UNKNOWN ||
751 format == GST_VIDEO_FORMAT_ENCODED;
755 find_format(GstVaapiFilter *filter, GstVideoFormat format)
759 if (is_special_format(format) || !filter->formats)
762 for (i = 0; i < filter->formats->len; i++) {
763 if (g_array_index(filter->formats, GstVideoFormat, i) == format)
769 /* ------------------------------------------------------------------------- */
770 /* --- Interface --- */
771 /* ------------------------------------------------------------------------- */
775 gst_vaapi_filter_init(GstVaapiFilter *filter, GstVaapiDisplay *display)
779 filter->display = gst_vaapi_display_ref(display);
780 filter->va_display = GST_VAAPI_DISPLAY_VADISPLAY(display);
781 filter->va_config = VA_INVALID_ID;
782 filter->va_context = VA_INVALID_ID;
783 filter->format = DEFAULT_FORMAT;
785 if (!GST_VAAPI_DISPLAY_HAS_VPP(display))
788 va_status = vaCreateConfig(filter->va_display, VAProfileNone,
789 VAEntrypointVideoProc, NULL, 0, &filter->va_config);
790 if (!vaapi_check_status(va_status, "vaCreateConfig() [VPP]"))
793 va_status = vaCreateContext(filter->va_display, filter->va_config, 0, 0, 0,
794 NULL, 0, &filter->va_context);
795 if (!vaapi_check_status(va_status, "vaCreateContext() [VPP]"))
801 gst_vaapi_filter_finalize(GstVaapiFilter *filter)
805 GST_VAAPI_DISPLAY_LOCK(filter->display);
806 if (filter->operations) {
807 for (i = 0; i < filter->operations->len; i++) {
808 GstVaapiFilterOpData * const op_data =
809 g_ptr_array_index(filter->operations, i);
810 vaapi_destroy_buffer(filter->va_display, &op_data->va_buffer);
812 g_ptr_array_unref(filter->operations);
813 filter->operations = NULL;
816 if (filter->va_context != VA_INVALID_ID) {
817 vaDestroyContext(filter->va_display, filter->va_context);
818 filter->va_context = VA_INVALID_ID;
821 if (filter->va_config != VA_INVALID_ID) {
822 vaDestroyConfig(filter->va_display, filter->va_config);
823 filter->va_config = VA_INVALID_ID;
825 GST_VAAPI_DISPLAY_UNLOCK(filter->display);
826 gst_vaapi_display_replace(&filter->display, NULL);
828 if (filter->formats) {
829 g_array_unref(filter->formats);
830 filter->formats = NULL;
834 static inline const GstVaapiMiniObjectClass *
835 gst_vaapi_filter_class(void)
837 static const GstVaapiMiniObjectClass GstVaapiFilterClass = {
838 sizeof(GstVaapiFilter),
839 (GDestroyNotify)gst_vaapi_filter_finalize
841 return &GstVaapiFilterClass;
846 * gst_vaapi_filter_new:
847 * @display: a #GstVaapiDisplay
849 * Creates a new #GstVaapiFilter set up to operate in "identity"
850 * mode. This means that no other operation than scaling is performed.
852 * Return value: the newly created #GstVaapiFilter object
855 gst_vaapi_filter_new(GstVaapiDisplay *display)
858 GstVaapiFilter *filter;
860 filter = (GstVaapiFilter *)
861 gst_vaapi_mini_object_new0(gst_vaapi_filter_class());
865 if (!gst_vaapi_filter_init(filter, display))
870 gst_vaapi_filter_unref(filter);
873 GST_WARNING("video processing is not supported, "
874 "please consider an upgrade to VA-API >= 0.34");
880 * gst_vaapi_filter_ref:
881 * @filter: a #GstVaapiFilter
883 * Atomically increases the reference count of the given @filter by one.
885 * Returns: The same @filter argument
888 gst_vaapi_filter_ref(GstVaapiFilter *filter)
890 g_return_val_if_fail(filter != NULL, NULL);
892 return GST_VAAPI_FILTER(gst_vaapi_mini_object_ref(
893 GST_VAAPI_MINI_OBJECT(filter)));
897 * gst_vaapi_filter_unref:
898 * @filter: a #GstVaapiFilter
900 * Atomically decreases the reference count of the @filter by one. If
901 * the reference count reaches zero, the filter will be free'd.
904 gst_vaapi_filter_unref(GstVaapiFilter *filter)
906 g_return_if_fail(filter != NULL);
908 gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(filter));
912 * gst_vaapi_filter_replace:
913 * @old_filter_ptr: a pointer to a #GstVaapiFilter
914 * @new_filter: a #GstVaapiFilter
916 * Atomically replaces the filter held in @old_filter_ptr with
917 * @new_filter. This means that @old_filter_ptr shall reference a
918 * valid filter. However, @new_filter can be NULL.
921 gst_vaapi_filter_replace(GstVaapiFilter **old_filter_ptr,
922 GstVaapiFilter *new_filter)
924 g_return_if_fail(old_filter_ptr != NULL);
926 gst_vaapi_mini_object_replace((GstVaapiMiniObject **)old_filter_ptr,
927 GST_VAAPI_MINI_OBJECT(new_filter));
931 * gst_vaapi_filter_get_operations:
932 * @filter: a #GstVaapiFilter, or %NULL
934 * Determines the set of supported operations for video processing.
935 * The caller owns an extra reference to the resulting array of
936 * #GstVaapiFilterOpInfo elements, so it shall be released with
937 * g_ptr_array_unref() after usage.
939 * If @filter is %NULL, then this function returns the video
940 * processing operations supported by this library.
942 * Return value: the set of supported operations, or %NULL if an error
946 gst_vaapi_filter_get_operations(GstVaapiFilter *filter)
949 return ensure_operations(filter);
956 * gst_vaapi_filter_set_operation:
957 * @filter: a #GstVaapiFilter
958 * @op: a #GstVaapiFilterOp
959 * @value: the @op settings
961 * Enable the specified operation @op to be performed during video
962 * processing, i.e. in gst_vaapi_filter_process(). The @value argument
963 * specifies the operation settings. e.g. deinterlacing method for
964 * deinterlacing, denoising level for noise reduction, etc.
966 * If @value is %NULL, then this function resets the operation
967 * settings to their default values.
969 * Return value: %TRUE if the specified operation may be supported,
973 gst_vaapi_filter_set_operation(GstVaapiFilter *filter, GstVaapiFilterOp op,
977 GstVaapiFilterOpData *op_data;
979 g_return_val_if_fail(filter != NULL, FALSE);
981 op_data = find_operation(filter, op);
985 if (value && !G_VALUE_HOLDS(value, G_PARAM_SPEC_VALUE_TYPE(op_data->pspec)))
989 case GST_VAAPI_FILTER_OP_FORMAT:
990 return gst_vaapi_filter_set_format(filter, value ?
991 g_value_get_enum(value) : DEFAULT_FORMAT);
992 case GST_VAAPI_FILTER_OP_CROP:
993 return gst_vaapi_filter_set_cropping_rectangle(filter, value ?
994 g_value_get_boxed(value) : NULL);
995 case GST_VAAPI_FILTER_OP_DENOISE:
996 case GST_VAAPI_FILTER_OP_SHARPEN:
997 return op_set_generic(filter, op_data,
998 (value ? g_value_get_float(value) :
999 G_PARAM_SPEC_FLOAT(op_data->pspec)->default_value));
1000 case GST_VAAPI_FILTER_OP_HUE:
1001 case GST_VAAPI_FILTER_OP_SATURATION:
1002 case GST_VAAPI_FILTER_OP_BRIGHTNESS:
1003 case GST_VAAPI_FILTER_OP_CONTRAST:
1004 return op_set_color_balance(filter, op_data,
1005 (value ? g_value_get_float(value) :
1006 G_PARAM_SPEC_FLOAT(op_data->pspec)->default_value));
1015 * gst_vaapi_filter_process:
1016 * @filter: a #GstVaapiFilter
1017 * @src_surface: the source @GstVaapiSurface
1018 * @dst_surface: the destination @GstVaapiSurface
1019 * @flags: #GstVaapiSurfaceRenderFlags that apply to @src_surface
1021 * Applies the operations currently defined in the @filter to
1022 * @src_surface and return the output in @dst_surface. The order of
1023 * operations is determined in a way that suits best the underlying
1024 * hardware. i.e. the only guarantee held is the generated outcome,
1025 * not any specific order of operations.
1027 * Return value: a #GstVaapiFilterStatus
1029 static GstVaapiFilterStatus
1030 gst_vaapi_filter_process_unlocked(GstVaapiFilter *filter,
1031 GstVaapiSurface *src_surface, GstVaapiSurface *dst_surface, guint flags)
1034 VAProcPipelineParameterBuffer *pipeline_param = NULL;
1035 VABufferID pipeline_param_buf_id;
1036 VABufferID filters[N_PROPERTIES];
1037 guint i, num_filters = 0;
1039 VARectangle src_rect, dst_rect;
1041 if (!ensure_operations(filter))
1042 return GST_VAAPI_FILTER_STATUS_ERROR_ALLOCATION_FAILED;
1044 if (filter->use_crop_rect) {
1045 const GstVaapiRectangle * const crop_rect = &filter->crop_rect;
1047 if ((crop_rect->x + crop_rect->width >
1048 GST_VAAPI_SURFACE_WIDTH(src_surface)) ||
1049 (crop_rect->y + crop_rect->height >
1050 GST_VAAPI_SURFACE_HEIGHT(src_surface)))
1053 src_rect.x = crop_rect->x;
1054 src_rect.y = crop_rect->y;
1055 src_rect.width = crop_rect->width;
1056 src_rect.height = crop_rect->height;
1061 src_rect.width = GST_VAAPI_SURFACE_WIDTH(src_surface);
1062 src_rect.height = GST_VAAPI_SURFACE_HEIGHT(src_surface);
1067 dst_rect.width = GST_VAAPI_SURFACE_WIDTH(dst_surface);
1068 dst_rect.height = GST_VAAPI_SURFACE_HEIGHT(dst_surface);
1070 for (i = 0, num_filters = 0; i < filter->operations->len; i++) {
1071 GstVaapiFilterOpData * const op_data =
1072 g_ptr_array_index(filter->operations, i);
1073 if (!op_data->is_enabled)
1075 if (op_data->va_buffer == VA_INVALID_ID) {
1076 GST_ERROR("invalid VA buffer for operation %s",
1077 g_param_spec_get_name(op_data->pspec));
1080 filters[num_filters++] = op_data->va_buffer;
1083 if (!vaapi_create_buffer(filter->va_display, filter->va_context,
1084 VAProcPipelineParameterBufferType, sizeof(*pipeline_param),
1085 NULL, &pipeline_param_buf_id, (gpointer *)&pipeline_param))
1088 memset(pipeline_param, 0, sizeof(*pipeline_param));
1089 pipeline_param->surface = GST_VAAPI_OBJECT_ID(src_surface);
1090 pipeline_param->surface_region = &src_rect;
1091 pipeline_param->surface_color_standard = VAProcColorStandardNone;
1092 pipeline_param->output_region = &dst_rect;
1093 pipeline_param->output_color_standard = VAProcColorStandardNone;
1094 pipeline_param->output_background_color = 0xff000000;
1095 pipeline_param->filter_flags = from_GstVaapiSurfaceRenderFlags(flags);
1096 pipeline_param->filters = filters;
1097 pipeline_param->num_filters = num_filters;
1099 vaapi_unmap_buffer(filter->va_display, pipeline_param_buf_id, NULL);
1101 va_status = vaBeginPicture(filter->va_display, filter->va_context,
1102 GST_VAAPI_OBJECT_ID(dst_surface));
1103 if (!vaapi_check_status(va_status, "vaBeginPicture()"))
1106 va_status = vaRenderPicture(filter->va_display, filter->va_context,
1107 &pipeline_param_buf_id, 1);
1108 if (!vaapi_check_status(va_status, "vaRenderPicture()"))
1111 va_status = vaEndPicture(filter->va_display, filter->va_context);
1112 if (!vaapi_check_status(va_status, "vaEndPicture()"))
1114 return GST_VAAPI_FILTER_STATUS_SUCCESS;
1117 vaDestroyBuffer(filter->va_display, pipeline_param_buf_id);
1118 return GST_VAAPI_FILTER_STATUS_ERROR_OPERATION_FAILED;
1120 return GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_OPERATION;
1123 GstVaapiFilterStatus
1124 gst_vaapi_filter_process(GstVaapiFilter *filter, GstVaapiSurface *src_surface,
1125 GstVaapiSurface *dst_surface, guint flags)
1127 GstVaapiFilterStatus status;
1129 g_return_val_if_fail(filter != NULL,
1130 GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
1131 g_return_val_if_fail(src_surface != NULL,
1132 GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
1133 g_return_val_if_fail(dst_surface != NULL,
1134 GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
1136 GST_VAAPI_DISPLAY_LOCK(filter->display);
1137 status = gst_vaapi_filter_process_unlocked(filter,
1138 src_surface, dst_surface, flags);
1139 GST_VAAPI_DISPLAY_UNLOCK(filter->display);
1144 * gst_vaapi_filter_get_formats:
1145 * @filter: a #GstVaapiFilter
1147 * Determines the set of supported source or target formats for video
1148 * processing. The caller owns an extra reference to the resulting
1149 * array of #GstVideoFormat elements, so it shall be released with
1150 * g_array_unref() after usage.
1152 * Return value: the set of supported target formats for video processing.
1155 gst_vaapi_filter_get_formats(GstVaapiFilter *filter)
1157 g_return_val_if_fail(filter != NULL, NULL);
1159 return ensure_formats(filter);
1163 * gst_vaapi_filter_set_format:
1164 * @filter: a #GstVaapiFilter
1165 * @format: the target surface format
1167 * Sets the desired pixel format of the resulting video processing
1170 * If @format is #GST_VIDEO_FORMAT_UNKNOWN, the filter will assume iso
1171 * format conversion, i.e. no color conversion at all and the target
1172 * surface format shall match the source surface format.
1174 * If @format is #GST_VIDEO_FORMAT_ENCODED, the filter will use the pixel
1175 * format of the target surface passed to gst_vaapi_filter_process().
1177 * Return value: %TRUE if the color conversion to the specified @format
1178 * may be supported, %FALSE otherwise.
1181 gst_vaapi_filter_set_format(GstVaapiFilter *filter, GstVideoFormat format)
1183 g_return_val_if_fail(filter != NULL, FALSE);
1185 if (!ensure_formats(filter))
1188 if (!is_special_format(format) && !find_format(filter, format))
1191 filter->format = format;
1196 * gst_vaapi_filter_set_cropping_rectangle:
1197 * @filter: a #GstVaapiFilter
1198 * @rect: the cropping region
1200 * Sets the source surface cropping rectangle to use during the video
1201 * processing. If @rect is %NULL, the whole source surface will be used.
1203 * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1206 gst_vaapi_filter_set_cropping_rectangle(GstVaapiFilter *filter,
1207 const GstVaapiRectangle *rect)
1209 g_return_val_if_fail(filter != NULL, FALSE);
1211 filter->use_crop_rect = rect != NULL;
1212 if (filter->use_crop_rect)
1213 filter->crop_rect = *rect;
1218 * gst_vaapi_filter_set_denoising_level:
1219 * @filter: a #GstVaapiFilter
1220 * @level: the level of noise reduction to apply
1222 * Sets the noise reduction level to apply. If @level is 0.0f, this
1223 * corresponds to disabling the noise reduction algorithm.
1225 * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1228 gst_vaapi_filter_set_denoising_level(GstVaapiFilter *filter, gfloat level)
1230 g_return_val_if_fail(filter != NULL, FALSE);
1232 return op_set_generic(filter,
1233 find_operation(filter, GST_VAAPI_FILTER_OP_DENOISE), level);
1237 * gst_vaapi_filter_set_sharpening_level:
1238 * @filter: a #GstVaapiFilter
1239 * @level: the sharpening factor
1241 * Enables noise reduction with the specified factor.
1243 * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1246 gst_vaapi_filter_set_sharpening_level(GstVaapiFilter *filter, gfloat level)
1248 g_return_val_if_fail(filter != NULL, FALSE);
1250 return op_set_generic(filter,
1251 find_operation(filter, GST_VAAPI_FILTER_OP_SHARPEN), level);
1255 * gst_vaapi_filter_set_hue:
1256 * @filter: a #GstVaapiFilter
1257 * @value: the color hue value
1259 * Enables color hue adjustment to the specified value.
1261 * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1264 gst_vaapi_filter_set_hue(GstVaapiFilter *filter, gfloat value)
1266 g_return_val_if_fail(filter != NULL, FALSE);
1268 return op_set_color_balance(filter,
1269 find_operation(filter, GST_VAAPI_FILTER_OP_HUE), value);
1273 * gst_vaapi_filter_set_saturation:
1274 * @filter: a #GstVaapiFilter
1275 * @value: the color saturation value
1277 * Enables color saturation adjustment to the specified value.
1279 * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1282 gst_vaapi_filter_set_saturation(GstVaapiFilter *filter, gfloat value)
1284 g_return_val_if_fail(filter != NULL, FALSE);
1286 return op_set_color_balance(filter,
1287 find_operation(filter, GST_VAAPI_FILTER_OP_SATURATION), value);
1291 * gst_vaapi_filter_set_brightness:
1292 * @filter: a #GstVaapiFilter
1293 * @value: the color brightness value
1295 * Enables color brightness adjustment to the specified value.
1297 * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1300 gst_vaapi_filter_set_brightness(GstVaapiFilter *filter, gfloat value)
1302 g_return_val_if_fail(filter != NULL, FALSE);
1304 return op_set_color_balance(filter,
1305 find_operation(filter, GST_VAAPI_FILTER_OP_BRIGHTNESS), value);
1309 * gst_vaapi_filter_set_contrast:
1310 * @filter: a #GstVaapiFilter
1311 * @value: the color contrast value
1313 * Enables color contrast adjustment to the specified value.
1315 * Return value: %TRUE if the operation is supported, %FALSE otherwise.
1318 gst_vaapi_filter_set_contrast(GstVaapiFilter *filter, gfloat value)
1320 g_return_val_if_fail(filter != NULL, FALSE);
1322 return op_set_color_balance(filter,
1323 find_operation(filter, GST_VAAPI_FILTER_OP_CONTRAST), value);