2 * Copyright (C) 2020 Igalia, S.L.
3 * Author: Víctor Jáquez <vjaquez@igalia.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
25 #include "gstvafilter.h"
27 #include <gst/va/gstvavideoformat.h>
28 #include <gst/va/vasurfaceimage.h>
29 #include <gst/video/video.h>
30 #include <va/va_drmcommon.h>
32 #include "gstvacaps.h"
33 #include "gstvadisplay_priv.h"
39 GstVaDisplay *display;
43 /* hardware constraints */
44 VAProcPipelineCaps pipeline_caps;
52 GArray *surface_formats;
53 GArray *image_formats;
55 GArray *available_filters;
57 /* stream information */
60 GstVideoOrientationMethod orientation;
64 gboolean crop_enabled;
66 VARectangle input_region;
67 VARectangle output_region;
69 VAProcColorStandardType input_color_standard;
70 VAProcColorProperties input_color_properties;
71 VAProcColorStandardType output_color_standard;
72 VAProcColorProperties output_color_properties;
77 GST_DEBUG_CATEGORY_STATIC (gst_va_filter_debug);
78 #define GST_CAT_DEFAULT gst_va_filter_debug
80 #define gst_va_filter_parent_class parent_class
81 G_DEFINE_TYPE_WITH_CODE (GstVaFilter, gst_va_filter, GST_TYPE_OBJECT,
82 GST_DEBUG_CATEGORY_INIT (gst_va_filter_debug, "vafilter", 0, "VA Filter"));
90 static GParamSpec *g_properties[N_PROPERTIES];
93 gst_va_filter_set_property (GObject * object, guint prop_id,
94 const GValue * value, GParamSpec * pspec)
96 GstVaFilter *self = GST_VA_FILTER (object);
100 g_assert (!self->display);
101 self->display = g_value_dup_object (value);
105 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
111 gst_va_filter_get_property (GObject * object, guint prop_id, GValue * value,
114 GstVaFilter *self = GST_VA_FILTER (object);
118 g_value_set_object (value, self->display);
121 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
127 gst_va_filter_dispose (GObject * object)
129 GstVaFilter *self = GST_VA_FILTER (object);
131 gst_va_filter_close (self);
133 g_clear_pointer (&self->available_filters, g_array_unref);
134 g_clear_pointer (&self->image_formats, g_array_unref);
135 g_clear_pointer (&self->surface_formats, g_array_unref);
136 gst_clear_object (&self->display);
138 G_OBJECT_CLASS (parent_class)->dispose (object);
142 gst_va_filter_class_init (GstVaFilterClass * klass)
144 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
146 gobject_class->set_property = gst_va_filter_set_property;
147 gobject_class->get_property = gst_va_filter_get_property;
148 gobject_class->dispose = gst_va_filter_dispose;
150 g_properties[PROP_DISPLAY] =
151 g_param_spec_object ("display", "GstVaDisplay", "GstVADisplay object",
153 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
155 g_object_class_install_properties (gobject_class, N_PROPERTIES, g_properties);
159 gst_va_filter_init (GstVaFilter * self)
161 self->config = VA_INVALID_ID;
162 self->context = VA_INVALID_ID;
164 self->min_height = 1;
165 self->max_height = G_MAXINT;
167 self->max_width = G_MAXINT;
171 gst_va_filter_new (GstVaDisplay * display)
173 g_return_val_if_fail (GST_IS_VA_DISPLAY (display), NULL);
175 return g_object_new (GST_TYPE_VA_FILTER, "display", display, NULL);
179 gst_va_filter_is_open (GstVaFilter * self)
183 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
185 GST_OBJECT_LOCK (self);
186 ret = (self->config != VA_INVALID_ID && self->context != VA_INVALID_ID);
187 GST_OBJECT_UNLOCK (self);
192 gst_va_filter_ensure_config_attributes (GstVaFilter * self,
193 guint32 * rt_formats_ptr)
195 VAConfigAttrib attribs[] = {
196 {.type = VAConfigAttribMaxPictureWidth,},
197 {.type = VAConfigAttribMaxPictureHeight,},
198 {.type = VAConfigAttribRTFormat,},
202 guint i, value, rt_formats = 0, max_width = 0, max_height = 0;
204 dpy = gst_va_display_get_va_dpy (self->display);
206 status = vaGetConfigAttributes (dpy, VAProfileNone, VAEntrypointVideoProc,
207 attribs, G_N_ELEMENTS (attribs));
208 if (status != VA_STATUS_SUCCESS) {
209 GST_ERROR_OBJECT (self, "vaGetConfigAttributes: %s", vaErrorStr (status));
213 for (i = 0; i < G_N_ELEMENTS (attribs); i++) {
214 value = attribs[i].value;
215 if (value == VA_ATTRIB_NOT_SUPPORTED)
217 switch (attribs[i].type) {
218 case VAConfigAttribMaxPictureHeight:
221 case VAConfigAttribMaxPictureWidth:
224 case VAConfigAttribRTFormat:
232 if (rt_formats_ptr && rt_formats != 0)
233 *rt_formats_ptr = rt_formats;
234 if (max_width > 0 && max_width < G_MAXINT)
235 self->max_width = max_width;
236 if (max_height > 0 && max_height < G_MAXINT)
237 self->max_height = max_height;
242 /* There are formats that are not handled correctly by driver */
244 format_is_accepted (GstVaFilter * self, GstVideoFormat format)
246 /* https://github.com/intel/media-driver/issues/690
247 * https://github.com/intel/media-driver/issues/644 */
248 if (!GST_VA_DISPLAY_IS_IMPLEMENTATION (self->display, INTEL_IHD))
252 case GST_VIDEO_FORMAT_ARGB:
253 case GST_VIDEO_FORMAT_xRGB:
254 case GST_VIDEO_FORMAT_ABGR:
255 case GST_VIDEO_FORMAT_xBGR:
265 gst_va_filter_ensure_surface_attributes (GstVaFilter * self)
267 GArray *surface_formats;
268 GstVideoFormat format;
269 VASurfaceAttrib *attribs;
270 guint i, attrib_count;
273 gst_va_get_surface_attribs (self->display, self->config, &attrib_count);
276 surface_formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
278 for (i = 0; i < attrib_count; i++) {
279 if (attribs[i].value.type != VAGenericValueTypeInteger)
281 switch (attribs[i].type) {
282 case VASurfaceAttribPixelFormat:
283 format = gst_va_video_format_from_va_fourcc (attribs[i].value.value.i);
284 if (format != GST_VIDEO_FORMAT_UNKNOWN
285 && format_is_accepted (self, format))
286 g_array_append_val (surface_formats, format);
288 case VASurfaceAttribMinWidth:
289 self->min_width = MAX (self->min_width, attribs[i].value.value.i);
291 case VASurfaceAttribMaxWidth:
292 if (self->max_width > 0)
293 self->max_width = MIN (self->max_width, attribs[i].value.value.i);
295 self->max_width = attribs[i].value.value.i;
297 case VASurfaceAttribMinHeight:
298 self->min_height = MAX (self->min_height, attribs[i].value.value.i);
300 case VASurfaceAttribMaxHeight:
301 if (self->max_height > 0)
302 self->max_height = MIN (self->max_height, attribs[i].value.value.i);
304 self->max_height = attribs[i].value.value.i;
306 case VASurfaceAttribMemoryType:
307 self->mem_types = attribs[i].value.value.i;
314 if (surface_formats->len == 0)
315 g_clear_pointer (&surface_formats, g_array_unref);
317 self->surface_formats = surface_formats;
325 gst_va_filter_ensure_pipeline_caps (GstVaFilter * self)
330 dpy = gst_va_display_get_va_dpy (self->display);
332 status = vaQueryVideoProcPipelineCaps (dpy, self->context, NULL, 0,
333 &self->pipeline_caps);
334 if (status != VA_STATUS_SUCCESS) {
335 GST_ERROR_OBJECT (self, "vaQueryVideoProcPipelineCaps: %s",
336 vaErrorStr (status));
343 /* Not thread-safe API */
345 gst_va_filter_open (GstVaFilter * self)
347 VAConfigAttrib attrib = {
348 .type = VAConfigAttribRTFormat,
353 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
355 if (gst_va_filter_is_open (self))
358 if (!gst_va_filter_ensure_config_attributes (self, &attrib.value))
361 if (!gst_va_filter_ensure_pipeline_caps (self))
364 self->image_formats = gst_va_display_get_image_formats (self->display);
365 if (!self->image_formats)
368 dpy = gst_va_display_get_va_dpy (self->display);
370 status = vaCreateConfig (dpy, VAProfileNone, VAEntrypointVideoProc, &attrib,
372 if (status != VA_STATUS_SUCCESS) {
373 GST_ERROR_OBJECT (self, "vaCreateConfig: %s", vaErrorStr (status));
377 if (!gst_va_filter_ensure_surface_attributes (self))
380 status = vaCreateContext (dpy, self->config, 0, 0, 0, NULL, 0,
382 if (status != VA_STATUS_SUCCESS) {
383 GST_ERROR_OBJECT (self, "vaCreateContext: %s", vaErrorStr (status));
391 status = vaDestroyConfig (dpy, self->config);
397 /* Not thread-safe API */
399 gst_va_filter_close (GstVaFilter * self)
404 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
406 if (!gst_va_filter_is_open (self))
409 dpy = gst_va_display_get_va_dpy (self->display);
411 if (self->context != VA_INVALID_ID) {
412 status = vaDestroyContext (dpy, self->context);
413 if (status != VA_STATUS_SUCCESS)
414 GST_ERROR_OBJECT (self, "vaDestroyContext: %s", vaErrorStr (status));
417 status = vaDestroyConfig (dpy, self->config);
418 if (status != VA_STATUS_SUCCESS) {
419 GST_ERROR_OBJECT (self, "vaDestroyConfig: %s", vaErrorStr (status));
423 g_clear_pointer (&self->available_filters, g_array_unref);
424 g_clear_pointer (&self->filters, g_array_unref);
426 gst_va_filter_init (self);
432 static const struct VaFilterCapMap {
433 VAProcFilterType type;
436 } filter_cap_map[] = {
437 #define F(name, count) { G_PASTE (VAProcFilter, name), count, G_STRINGIFY (name) }
438 F(NoiseReduction, 1),
439 F(Deinterlacing, VAProcDeinterlacingCount),
441 F(ColorBalance, VAProcColorBalanceCount),
442 F(SkinToneEnhancement, 1),
443 F(TotalColorCorrection, VAProcTotalColorCorrectionCount),
444 F(HVSNoiseReduction, 0),
445 F(HighDynamicRangeToneMapping, VAProcHighDynamicRangeMetadataTypeCount),
446 #if VA_CHECK_VERSION (1, 12, 0)
453 static const struct VaFilterCapMap *
454 gst_va_filter_get_filter_cap (VAProcFilterType type)
458 for (i = 0; i < G_N_ELEMENTS (filter_cap_map); i++) {
459 if (filter_cap_map[i].type == type)
460 return &filter_cap_map[i];
467 gst_va_filter_get_filter_cap_count (VAProcFilterType type)
469 const struct VaFilterCapMap *map = gst_va_filter_get_filter_cap (type);
470 return map ? map->count : 0;
475 VAProcFilterType type;
479 VAProcFilterCap simple;
480 VAProcFilterCapDeinterlacing deint[VAProcDeinterlacingCount];
481 VAProcFilterCapColorBalance cb[VAProcColorBalanceCount];
482 VAProcFilterCapTotalColorCorrection cc[VAProcTotalColorCorrectionCount];
483 VAProcFilterCapHighDynamicRange
484 hdr[VAProcHighDynamicRangeMetadataTypeCount];
485 #if VA_CHECK_VERSION (1, 12, 0)
486 VAProcFilterCap3DLUT lut[16];
492 gst_va_filter_ensure_filters (GstVaFilter * self)
496 VAProcFilterType *filter_types;
498 guint i, num = VAProcFilterCount;
499 gboolean ret = FALSE;
501 GST_OBJECT_LOCK (self);
502 if (self->available_filters) {
503 GST_OBJECT_UNLOCK (self);
506 GST_OBJECT_UNLOCK (self);
508 filter_types = g_malloc_n (num, sizeof (*filter_types));
510 dpy = gst_va_display_get_va_dpy (self->display);
512 status = vaQueryVideoProcFilters (dpy, self->context, filter_types, &num);
513 if (status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) {
514 filter_types = g_try_realloc_n (filter_types, num, sizeof (*filter_types));
515 status = vaQueryVideoProcFilters (dpy, self->context, filter_types, &num);
517 if (status != VA_STATUS_SUCCESS) {
518 GST_ERROR_OBJECT (self, "vaQueryVideoProcFilters: %s", vaErrorStr (status));
525 filters = g_array_sized_new (FALSE, FALSE, sizeof (struct VaFilter), num);
527 for (i = 0; i < num; i++) {
528 guint num_caps = gst_va_filter_get_filter_cap_count (filter_types[i]);
529 struct VaFilter filter = { filter_types[i], num_caps, {{{0,}}} };
532 status = vaQueryVideoProcFilterCaps (dpy, self->context, filter.type,
533 &filter.caps, &filter.num_caps);
534 if (status != VA_STATUS_SUCCESS) {
535 GST_WARNING_OBJECT (self, "vaQueryVideoProcFiltersCaps: %s",
536 vaErrorStr (status));
541 g_array_append_val (filters, filter);
544 GST_OBJECT_LOCK (self);
545 g_clear_pointer (&self->available_filters, g_array_unref);
546 self->available_filters = filters;
547 GST_OBJECT_UNLOCK (self);
552 g_free (filter_types);
558 static const struct _CBDesc {
563 } cb_desc[VAProcColorBalanceCount] = {
564 [VAProcColorBalanceHue] =
565 { "hue", "Hue", "Color hue value", GST_VA_FILTER_PROP_HUE },
566 [VAProcColorBalanceSaturation] =
567 { "saturation", "Saturation", "Color saturation value",
568 GST_VA_FILTER_PROP_SATURATION },
569 [VAProcColorBalanceBrightness] =
570 { "brightness", "Brightness", "Color brightness value",
571 GST_VA_FILTER_PROP_BRIGHTNESS },
572 [VAProcColorBalanceContrast] =
573 { "contrast", "Contrast", "Color contrast value",
574 GST_VA_FILTER_PROP_CONTRAST },
575 [VAProcColorBalanceAutoSaturation] =
576 { "auto-saturation", "Auto-Saturation", "Enable auto saturation",
577 GST_VA_FILTER_PROP_AUTO_SATURATION },
578 [VAProcColorBalanceAutoBrightness] =
579 { "auto-brightness", "Auto-Brightness", "Enable auto brightness",
580 GST_VA_FILTER_PROP_AUTO_BRIGHTNESS },
581 [VAProcColorBalanceAutoContrast] =
582 { "auto-contrast", "Auto-Contrast", "Enable auto contrast",
583 GST_VA_FILTER_PROP_AUTO_CONTRAST },
588 gst_va_filter_install_properties (GstVaFilter * self, GObjectClass * klass)
591 const GParamFlags common_flags = G_PARAM_READWRITE
592 | GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_STATIC_STRINGS
593 | GST_PARAM_MUTABLE_PLAYING | GST_PARAM_CONTROLLABLE;
595 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
597 if (!gst_va_filter_is_open (self))
600 if (!gst_va_filter_ensure_filters (self))
603 for (i = 0; i < self->available_filters->len; i++) {
604 const struct VaFilter *filter =
605 &g_array_index (self->available_filters, struct VaFilter, i);
607 switch (filter->type) {
608 case VAProcFilterNoiseReduction:{
609 const VAProcFilterCap *caps = &filter->caps.simple;
611 g_object_class_install_property (klass, GST_VA_FILTER_PROP_DENOISE,
612 g_param_spec_float ("denoise", "Noise reduction",
613 "Noise reduction factor", caps->range.min_value,
614 caps->range.max_value, caps->range.default_value,
618 case VAProcFilterSharpening:{
619 const VAProcFilterCap *caps = &filter->caps.simple;
621 g_object_class_install_property (klass, GST_VA_FILTER_PROP_SHARPEN,
622 g_param_spec_float ("sharpen", "Sharpening Level",
623 "Sharpening/blurring filter", caps->range.min_value,
624 caps->range.max_value, caps->range.default_value,
628 case VAProcFilterSkinToneEnhancement:{
629 const VAProcFilterCap *caps = &filter->caps.simple;
633 if (filter->num_caps == 0) {
634 pspec = g_param_spec_boolean ("skin-tone", "Skin Tone Enhancenment",
635 "Skin Tone Enhancenment filter", FALSE, common_flags);
637 pspec = g_param_spec_float ("skin-tone", "Skin Tone Enhancenment",
638 "Skin Tone Enhancenment filter", caps->range.min_value,
639 caps->range.max_value, caps->range.default_value, common_flags);
642 g_object_class_install_property (klass, GST_VA_FILTER_PROP_SKINTONE,
646 case VAProcFilterColorBalance:{
647 const VAProcFilterCapColorBalance *caps = filter->caps.cb;
651 for (j = 0; j < filter->num_caps; j++) {
653 if (caps[j].range.min_value < caps[j].range.max_value) {
654 pspec = g_param_spec_float (cb_desc[k].name, cb_desc[k].nick,
655 cb_desc[k].blurb, caps[j].range.min_value,
656 caps[j].range.max_value, caps[j].range.default_value,
659 pspec = g_param_spec_boolean (cb_desc[k].name, cb_desc[k].nick,
660 cb_desc[k].blurb, FALSE, common_flags);
663 g_object_class_install_property (klass, cb_desc[k].prop_id, pspec);
668 case VAProcFilterHighDynamicRangeToneMapping:{
670 for (j = 0; j < filter->num_caps; j++) {
671 const VAProcFilterCapHighDynamicRange *caps = &filter->caps.hdr[j];
672 if (caps->metadata_type == VAProcHighDynamicRangeMetadataHDR10
673 && (caps->caps_flag & VA_TONE_MAPPING_HDR_TO_SDR)) {
674 g_object_class_install_property (klass, GST_VA_FILTER_PROP_HDR,
675 g_param_spec_boolean ("hdr-tone-mapping", "HDR tone mapping",
676 "Enable HDR to SDR tone mapping", FALSE, common_flags));
686 if (self->pipeline_caps.mirror_flags != VA_MIRROR_NONE
687 || self->pipeline_caps.rotation_flags != VA_ROTATION_NONE) {
688 g_object_class_install_property (klass, GST_VA_FILTER_PROP_VIDEO_DIR,
689 g_param_spec_enum ("video-direction", "Video Direction",
690 "Video direction: rotation and flipping",
691 GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY,
699 * GstVaDeinterlaceMethods:
700 * @GST_VA_DEINTERLACE_BOB: Interpolating missing lines by using the
702 * @GST_VA_DEINTERLACE_WEAVE: Show both fields per frame. (don't use)
703 * @GST_VA_DEINTERLACE_ADAPTIVE: Interpolating missing lines by using
704 * spatial/temporal references.
705 * @GST_VA_DEINTERLACE_COMPENSATED: Recreating missing lines by using
711 static const GEnumValue di_desc[] = {
712 [GST_VA_DEINTERLACE_BOB] =
713 { VAProcDeinterlacingBob,
714 "Bob: Interpolating missing lines by using the adjacent lines.", "bob" },
715 [GST_VA_DEINTERLACE_WEAVE] =
716 { VAProcDeinterlacingWeave, "Weave: Show both fields per frame. (don't use)",
718 [GST_VA_DEINTERLACE_ADAPTIVE] =
719 { VAProcDeinterlacingMotionAdaptive,
720 "Adaptive: Interpolating missing lines by using spatial/temporal references.",
722 [GST_VA_DEINTERLACE_COMPENSATED] =
723 { VAProcDeinterlacingMotionCompensated,
724 "Compensation: Recreating missing lines by using motion vector.",
730 gst_va_deinterlace_methods_get_type (guint num_caps,
731 const VAProcFilterCapDeinterlacing * caps)
734 static GType deinterlace_methods_type = 0;
735 static GEnumValue methods_types[VAProcDeinterlacingCount];
737 if (deinterlace_methods_type > 0)
738 return deinterlace_methods_type;
740 for (i = 0; i < num_caps; i++) {
741 if (caps[i].type > VAProcDeinterlacingNone
742 && caps[i].type < VAProcDeinterlacingCount)
743 methods_types[j++] = di_desc[caps[i].type];
747 methods_types[j] = (GEnumValue) { 0, NULL, NULL };
750 deinterlace_methods_type = g_enum_register_static ("GstVaDeinterlaceMethods",
751 (const GEnumValue *) methods_types);
753 return deinterlace_methods_type;
757 gst_va_filter_install_deinterlace_properties (GstVaFilter * self,
758 GObjectClass * klass)
762 const GParamFlags common_flags = G_PARAM_READWRITE
763 | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_PLAYING;
765 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
767 if (!gst_va_filter_is_open (self))
770 if (!gst_va_filter_ensure_filters (self))
773 for (i = 0; i < self->available_filters->len; i++) {
774 const struct VaFilter *filter =
775 &g_array_index (self->available_filters, struct VaFilter, i);
777 if (filter->type == VAProcFilterDeinterlacing) {
778 guint i, default_method = 0;
779 const VAProcFilterCapDeinterlacing *caps = filter->caps.deint;
783 /* use the first method in the list as default */
784 for (i = 0; i < filter->num_caps; i++) {
785 if (caps[i].type > VAProcDeinterlacingNone
786 && caps[i].type < VAProcDeinterlacingCount) {
787 default_method = caps[i].type;
792 if (default_method == 0)
795 type = gst_va_deinterlace_methods_get_type (filter->num_caps, caps);
796 gst_type_mark_as_plugin_api (type, 0);
799 * GstVaDeinterlace:method
801 * Selects the different deinterlacing algorithms that can be used.
803 * It depends on the driver the number of available algorithms,
804 * and they provide different quality and different processing
809 g_object_class_install_property (klass,
810 GST_VA_FILTER_PROP_DEINTERLACE_METHOD,
811 g_param_spec_enum ("method", "Method", "Deinterlace Method",
812 type, default_method, common_flags));
822 gst_va_filter_has_filter (GstVaFilter * self, VAProcFilterType type)
826 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
828 if (!gst_va_filter_is_open (self))
831 if (!gst_va_filter_ensure_filters (self))
834 for (i = 0; i < self->available_filters->len; i++) {
835 const struct VaFilter *filter =
836 &g_array_index (self->available_filters, struct VaFilter, i);
838 if (filter->type == type)
846 gst_va_filter_get_filter_caps (GstVaFilter * self, VAProcFilterType type,
849 struct VaFilter *filter = NULL;
851 static const VAProcFilterCap i965_ste_caps = {
855 .default_value = 0.0,
863 if (!gst_va_filter_is_open (self))
866 if (!gst_va_filter_ensure_filters (self))
869 GST_OBJECT_LOCK (self);
870 for (i = 0; i < self->available_filters->len; i++) {
871 filter = &g_array_index (self->available_filters, struct VaFilter, i);
873 if (filter->type == type) {
874 if (filter->num_caps > 0)
876 else if (type == VAProcFilterSkinToneEnhancement && filter->num_caps == 0)
877 ret = (gpointer) & i965_ste_caps;
882 if (ret && filter && num_caps)
883 *num_caps = filter->num_caps;
884 GST_OBJECT_UNLOCK (self);
890 gst_va_filter_get_mem_types (GstVaFilter * self)
894 g_return_val_if_fail (GST_IS_VA_FILTER (self), 0);
896 GST_OBJECT_LOCK (self);
897 ret = self->mem_types;
898 GST_OBJECT_UNLOCK (self);
904 gst_va_filter_get_surface_formats (GstVaFilter * self)
908 g_return_val_if_fail (GST_IS_VA_FILTER (self), NULL);
910 GST_OBJECT_LOCK (self);
911 ret = self->surface_formats ? g_array_ref (self->surface_formats) : NULL;
912 GST_OBJECT_UNLOCK (self);
918 gst_va_filter_set_scale_method (GstVaFilter * self, guint32 method)
920 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
922 GST_OBJECT_LOCK (self);
923 self->scale_method = method;
924 GST_OBJECT_UNLOCK (self);
930 _from_video_orientation_method (GstVideoOrientationMethod orientation,
931 guint * mirror, guint * rotation)
933 switch (orientation) {
934 case GST_VIDEO_ORIENTATION_IDENTITY:
935 *mirror = VA_MIRROR_NONE;
936 *rotation = VA_ROTATION_NONE;
938 case GST_VIDEO_ORIENTATION_HORIZ:
939 *mirror = VA_MIRROR_HORIZONTAL;
940 *rotation = VA_ROTATION_NONE;
942 case GST_VIDEO_ORIENTATION_VERT:
943 *mirror = VA_MIRROR_VERTICAL;
944 *rotation = VA_ROTATION_NONE;
946 case GST_VIDEO_ORIENTATION_90R:
947 *mirror = VA_MIRROR_NONE;
948 *rotation = VA_ROTATION_90;
950 case GST_VIDEO_ORIENTATION_180:
951 *mirror = VA_MIRROR_NONE;
952 *rotation = VA_ROTATION_180;
954 case GST_VIDEO_ORIENTATION_90L:
955 *mirror = VA_MIRROR_NONE;
956 *rotation = VA_ROTATION_270;
958 case GST_VIDEO_ORIENTATION_UL_LR:
959 *mirror = VA_MIRROR_HORIZONTAL;
960 *rotation = VA_ROTATION_90;
962 case GST_VIDEO_ORIENTATION_UR_LL:
963 *mirror = VA_MIRROR_VERTICAL;
964 *rotation = VA_ROTATION_90;
975 gst_va_filter_set_orientation (GstVaFilter * self,
976 GstVideoOrientationMethod orientation)
978 guint32 mirror = VA_MIRROR_NONE, rotation = VA_ROTATION_NONE;
979 guint32 mirror_flags, rotation_flags;
981 if (!gst_va_filter_is_open (self))
984 if (!_from_video_orientation_method (orientation, &mirror, &rotation))
987 GST_OBJECT_LOCK (self);
988 mirror_flags = self->pipeline_caps.mirror_flags;
989 GST_OBJECT_UNLOCK (self);
991 if (mirror != VA_MIRROR_NONE && !(mirror_flags & mirror))
994 GST_OBJECT_LOCK (self);
995 rotation_flags = self->pipeline_caps.rotation_flags;
996 GST_OBJECT_UNLOCK (self);
998 if (rotation != VA_ROTATION_NONE && !(rotation_flags & (1 << rotation)))
1001 GST_OBJECT_LOCK (self);
1002 self->orientation = orientation;
1003 self->mirror = mirror;
1004 self->rotation = rotation;
1005 GST_OBJECT_UNLOCK (self);
1010 GstVideoOrientationMethod
1011 gst_va_filter_get_orientation (GstVaFilter * self)
1013 GstVideoOrientationMethod ret;
1015 GST_OBJECT_LOCK (self);
1016 ret = self->orientation;
1017 GST_OBJECT_UNLOCK (self);
1023 gst_va_filter_enable_cropping (GstVaFilter * self, gboolean cropping)
1025 GST_OBJECT_LOCK (self);
1026 if (cropping != self->crop_enabled)
1027 self->crop_enabled = cropping;
1028 GST_OBJECT_UNLOCK (self);
1031 static inline GstCaps *
1032 _create_base_caps (GstVaFilter * self)
1034 return gst_caps_new_simple ("video/x-raw", "width", GST_TYPE_INT_RANGE,
1035 self->min_width, self->max_width, "height", GST_TYPE_INT_RANGE,
1036 self->min_height, self->max_height, NULL);
1040 gst_va_filter_get_caps (GstVaFilter * self)
1042 GArray *surface_formats = NULL, *image_formats = NULL;
1043 GstCaps *caps, *base_caps, *feature_caps;
1044 GstCapsFeatures *features;
1047 g_return_val_if_fail (GST_IS_VA_FILTER (self), NULL);
1049 if (!gst_va_filter_is_open (self))
1052 surface_formats = gst_va_filter_get_surface_formats (self);
1053 if (!surface_formats)
1056 base_caps = _create_base_caps (self);
1058 if (!gst_caps_set_format_array (base_caps, surface_formats))
1061 g_array_unref (surface_formats);
1063 caps = gst_caps_new_empty ();
1065 mem_types = gst_va_filter_get_mem_types (self);
1067 if (mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_VA) {
1068 feature_caps = gst_caps_copy (base_caps);
1069 features = gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VA);
1070 gst_caps_set_features_simple (feature_caps, features);
1071 caps = gst_caps_merge (caps, feature_caps);
1073 if (mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME
1074 || mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2) {
1075 feature_caps = gst_caps_copy (base_caps);
1076 features = gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_DMABUF);
1077 gst_caps_set_features_simple (feature_caps, features);
1078 caps = gst_caps_merge (caps, feature_caps);
1081 gst_caps_unref (base_caps);
1083 base_caps = _create_base_caps (self);
1085 GST_OBJECT_LOCK (self);
1087 self->image_formats ? g_array_ref (self->image_formats) : NULL;
1088 GST_OBJECT_UNLOCK (self);
1090 if (image_formats) {
1091 if (!gst_caps_set_format_array (base_caps, image_formats))
1093 g_array_unref (image_formats);
1096 return gst_caps_merge (caps, base_caps);
1100 g_clear_pointer (&surface_formats, g_array_unref);
1101 g_clear_pointer (&image_formats, g_array_unref);
1102 gst_caps_unref (base_caps);
1109 static const struct ColorPropertiesMap
1111 VAProcColorStandardType standard;
1115 } color_properties_map[] = {
1116 { VAProcColorStandardBT601, 5, 6, 5 },
1117 { VAProcColorStandardBT601, 6, 6, 6 },
1118 { VAProcColorStandardBT709, 1, 1, 1 },
1119 { VAProcColorStandardBT470M, 4, 4, 4 },
1120 { VAProcColorStandardBT470BG, 5, 5, 5 },
1121 { VAProcColorStandardSMPTE170M, 6, 6, 6 },
1122 { VAProcColorStandardSMPTE240M, 7, 7, 7 },
1123 { VAProcColorStandardGenericFilm, 8, 1, 1 },
1124 { VAProcColorStandardSRGB, 1, 13, 0 },
1125 /* { VAProcColorStandardSTRGB, ?, ?, ? }, */
1126 { VAProcColorStandardXVYCC601, 1, 11, 5 },
1127 { VAProcColorStandardXVYCC709, 1, 11, 1 },
1128 { VAProcColorStandardBT2020, 9, 14, 9 },
1133 _get_chroma_siting (GstVideoChromaSite chrome_site)
1136 static const struct ChromaSiteMap {
1137 GstVideoChromaSite gst;
1139 } chroma_site_map[] = {
1140 { GST_VIDEO_CHROMA_SITE_UNKNOWN, VA_CHROMA_SITING_UNKNOWN },
1141 { GST_VIDEO_CHROMA_SITE_NONE, VA_CHROMA_SITING_VERTICAL_CENTER
1142 | VA_CHROMA_SITING_HORIZONTAL_CENTER },
1143 { GST_VIDEO_CHROMA_SITE_H_COSITED, VA_CHROMA_SITING_VERTICAL_CENTER
1144 | VA_CHROMA_SITING_HORIZONTAL_LEFT },
1145 { GST_VIDEO_CHROMA_SITE_V_COSITED, VA_CHROMA_SITING_VERTICAL_TOP
1146 | VA_CHROMA_SITING_VERTICAL_BOTTOM },
1147 { GST_VIDEO_CHROMA_SITE_COSITED, VA_CHROMA_SITING_VERTICAL_CENTER
1148 | VA_CHROMA_SITING_HORIZONTAL_LEFT
1149 | VA_CHROMA_SITING_VERTICAL_TOP
1150 | VA_CHROMA_SITING_VERTICAL_BOTTOM },
1151 { GST_VIDEO_CHROMA_SITE_JPEG, VA_CHROMA_SITING_VERTICAL_CENTER
1152 | VA_CHROMA_SITING_HORIZONTAL_CENTER },
1153 { GST_VIDEO_CHROMA_SITE_MPEG2, VA_CHROMA_SITING_VERTICAL_CENTER
1154 | VA_CHROMA_SITING_HORIZONTAL_LEFT },
1155 { GST_VIDEO_CHROMA_SITE_DV, VA_CHROMA_SITING_VERTICAL_TOP
1156 | VA_CHROMA_SITING_HORIZONTAL_LEFT },
1161 for (i = 0; i < G_N_ELEMENTS (chroma_site_map); i++) {
1162 if (chrome_site == chroma_site_map[i].gst)
1163 return chroma_site_map[i].va;
1166 return VA_CHROMA_SITING_UNKNOWN;
1170 _get_color_range (GstVideoColorRange range)
1173 static const struct ColorRangeMap {
1174 GstVideoColorRange gst;
1176 } color_range_map[] = {
1177 { GST_VIDEO_COLOR_RANGE_UNKNOWN, VA_SOURCE_RANGE_UNKNOWN },
1178 { GST_VIDEO_COLOR_RANGE_0_255, VA_SOURCE_RANGE_FULL },
1179 { GST_VIDEO_COLOR_RANGE_16_235, VA_SOURCE_RANGE_REDUCED },
1184 for (i = 0; i < G_N_ELEMENTS (color_range_map); i++) {
1185 if (range == color_range_map[i].gst)
1186 return color_range_map[i].va;
1189 return VA_SOURCE_RANGE_UNKNOWN;
1192 static VAProcColorStandardType
1193 _gst_video_colorimetry_to_va (const GstVideoColorimetry * const colorimetry)
1196 || colorimetry->primaries == GST_VIDEO_COLOR_PRIMARIES_UNKNOWN)
1197 return VAProcColorStandardNone;
1199 if (gst_video_colorimetry_matches (colorimetry, GST_VIDEO_COLORIMETRY_BT709))
1200 return VAProcColorStandardBT709;
1202 /* NOTE: VAProcColorStandardBT2020 in VAAPI is the same as
1203 * GST_VIDEO_COLORIMETRY_BT2020_10 in gstreamer. */
1204 if (gst_video_colorimetry_matches (colorimetry,
1205 GST_VIDEO_COLORIMETRY_BT2020_10) ||
1206 gst_video_colorimetry_matches (colorimetry, GST_VIDEO_COLORIMETRY_BT2020))
1207 return VAProcColorStandardBT2020;
1209 if (gst_video_colorimetry_matches (colorimetry, GST_VIDEO_COLORIMETRY_BT601))
1210 return VAProcColorStandardBT601;
1212 if (gst_video_colorimetry_matches (colorimetry,
1213 GST_VIDEO_COLORIMETRY_SMPTE240M))
1214 return VAProcColorStandardSMPTE240M;
1216 if (gst_video_colorimetry_matches (colorimetry, GST_VIDEO_COLORIMETRY_SRGB))
1217 return VAProcColorStandardSRGB;
1219 return VAProcColorStandardNone;
1223 _config_color_properties (VAProcColorStandardType * std,
1224 VAProcColorProperties * props, const GstVideoInfo * info,
1225 VAProcColorStandardType * standards, guint32 num_standards)
1227 GstVideoColorimetry colorimetry = GST_VIDEO_INFO_COLORIMETRY (info);
1228 VAProcColorStandardType best;
1229 gboolean has_explicit;
1231 gint score, bestscore = -1, worstscore;
1233 best = _gst_video_colorimetry_to_va (&colorimetry);
1235 has_explicit = FALSE;
1236 for (i = 0; i < num_standards; i++) {
1237 /* Find the exact match standard. */
1238 if (standards[i] != VAProcColorStandardNone && standards[i] == best)
1241 if (standards[i] == VAProcColorStandardExplicit)
1242 has_explicit = TRUE;
1245 if (i < num_standards) {
1247 goto set_properties;
1248 } else if (has_explicit) {
1249 *std = VAProcColorStandardExplicit;
1250 goto set_properties;
1253 worstscore = 4 * (colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN
1254 && colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB)
1255 + 2 * (colorimetry.transfer != GST_VIDEO_TRANSFER_UNKNOWN)
1256 + (colorimetry.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN);
1258 if (worstscore == 0) {
1259 /* No properties specified, there's not a useful choice. */
1260 *std = VAProcColorStandardNone;
1261 *props = (VAProcColorProperties) {
1267 best = VAProcColorStandardNone;
1269 for (i = 0; i < num_standards; i++) {
1270 for (j = 0; j < G_N_ELEMENTS (color_properties_map); j++) {
1271 if (color_properties_map[j].standard != standards[i])
1275 if (colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN
1276 && colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB)
1277 score += 4 * (colorimetry.matrix != color_properties_map[j].matrix);
1278 if (colorimetry.transfer != GST_VIDEO_TRANSFER_UNKNOWN)
1279 score += 2 * (colorimetry.transfer != color_properties_map[j].transfer);
1280 if (colorimetry.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN)
1281 score += (colorimetry.primaries != color_properties_map[j].primaries);
1283 if (score < worstscore && (bestscore == -1 || score < bestscore)) {
1285 best = color_properties_map[j].standard;
1291 if (best != VAProcColorStandardNone) {
1293 colorimetry.matrix = color_properties_map[k].matrix;
1294 colorimetry.transfer = color_properties_map[k].transfer;
1295 colorimetry.primaries = color_properties_map[k].primaries;
1300 *props = (VAProcColorProperties) {
1301 .chroma_sample_location =
1302 _get_chroma_siting (GST_VIDEO_INFO_CHROMA_SITE (info)),
1303 .color_range = _get_color_range (colorimetry.range),
1305 gst_video_color_primaries_to_iso (colorimetry.primaries),
1306 .transfer_characteristics =
1307 gst_video_transfer_function_to_iso (colorimetry.transfer),
1308 .matrix_coefficients =
1309 gst_video_color_matrix_to_iso (colorimetry.matrix),
1315 gst_va_filter_set_video_info (GstVaFilter * self, GstVideoInfo * in_info,
1316 GstVideoInfo * out_info)
1318 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
1319 g_return_val_if_fail (out_info && in_info, FALSE);
1321 if (!gst_va_filter_is_open (self))
1324 GST_OBJECT_LOCK (self);
1326 self->input_region = (VARectangle) {
1327 .width = GST_VIDEO_INFO_WIDTH (in_info),
1328 .height = GST_VIDEO_INFO_HEIGHT (in_info),
1331 self->output_region = (VARectangle) {
1332 .width = GST_VIDEO_INFO_WIDTH (out_info),
1333 .height = GST_VIDEO_INFO_HEIGHT (out_info),
1337 _config_color_properties (&self->input_color_standard,
1338 &self->input_color_properties, in_info,
1339 self->pipeline_caps.input_color_standards,
1340 self->pipeline_caps.num_input_color_standards);
1341 _config_color_properties (&self->output_color_standard,
1342 &self->output_color_properties, out_info,
1343 self->pipeline_caps.output_color_standards,
1344 self->pipeline_caps.num_output_color_standards);
1345 GST_OBJECT_UNLOCK (self);
1351 _query_pipeline_caps (GstVaFilter * self, GArray * filters,
1352 VAProcPipelineCaps * caps)
1354 VABufferID *va_filters = NULL;
1357 guint32 num_filters = 0;
1359 GST_OBJECT_LOCK (self);
1361 num_filters = filters->len;
1362 va_filters = (num_filters > 0) ? (VABufferID *) filters->data : NULL;
1364 GST_OBJECT_UNLOCK (self);
1366 dpy = gst_va_display_get_va_dpy (self->display);
1368 status = vaQueryVideoProcPipelineCaps (dpy, self->context, va_filters,
1371 if (status != VA_STATUS_SUCCESS) {
1372 GST_ERROR_OBJECT (self, "vaQueryVideoProcPipelineCaps: %s",
1373 vaErrorStr (status));
1381 gst_va_filter_add_deinterlace_buffer (GstVaFilter * self,
1382 VAProcDeinterlacingType method, guint32 * forward, guint32 * backward)
1384 GArray *filters = NULL;
1385 VAProcFilterParameterBufferDeinterlacing params = {
1386 .type = VAProcFilterDeinterlacing,
1387 .algorithm = method,
1389 VAProcPipelineCaps pipeline_caps = { 0, };
1392 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
1394 if (!gst_va_filter_is_open (self))
1397 if (!(method != VAProcDeinterlacingNone
1398 && method != VAProcDeinterlacingCount))
1401 if (!gst_va_filter_add_filter_buffer (self, ¶ms, sizeof (params), 1))
1404 GST_OBJECT_LOCK (self);
1406 filters = g_array_ref (self->filters);
1407 GST_OBJECT_UNLOCK (self);
1408 ret = _query_pipeline_caps (self, filters, &pipeline_caps);
1410 g_array_unref (filters);
1415 *forward = pipeline_caps.num_forward_references;
1417 *backward = pipeline_caps.num_backward_references;
1422 #ifndef GST_DISABLE_GST_DEBUG
1423 static const gchar *
1424 get_va_filter_name (gpointer data)
1426 VAProcFilterType type = ((VAProcFilterParameterBuffer *) data)->type;
1427 const struct VaFilterCapMap *m = gst_va_filter_get_filter_cap (type);
1429 return m ? m->name : "Unknown";
1434 gst_va_filter_add_filter_buffer (GstVaFilter * self, gpointer data, gsize size,
1441 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
1442 g_return_val_if_fail (data && size > 0, FALSE);
1444 if (!gst_va_filter_is_open (self))
1447 dpy = gst_va_display_get_va_dpy (self->display);
1448 status = vaCreateBuffer (dpy, self->context, VAProcFilterParameterBufferType,
1449 size, num, data, &buffer);
1450 if (status != VA_STATUS_SUCCESS) {
1451 GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
1455 GST_DEBUG_OBJECT (self, "Added filter: %s", get_va_filter_name (data));
1458 GST_OBJECT_LOCK (self);
1460 self->filters = g_array_sized_new (FALSE, FALSE, sizeof (VABufferID), 16);
1462 g_array_append_val (self->filters, buffer);
1463 GST_OBJECT_UNLOCK (self);
1469 _destroy_filters_unlocked (GstVaFilter * self)
1474 gboolean ret = TRUE;
1477 GST_TRACE_OBJECT (self, "Destroying %u filter buffers", self->filters->len);
1479 dpy = gst_va_display_get_va_dpy (self->display);
1481 for (i = 0; i < self->filters->len; i++) {
1482 buffer = g_array_index (self->filters, VABufferID, i);
1484 status = vaDestroyBuffer (dpy, buffer);
1485 if (status != VA_STATUS_SUCCESS) {
1487 GST_WARNING_OBJECT (self, "Failed to destroy filter buffer: %s",
1488 vaErrorStr (status));
1492 self->filters = g_array_set_size (self->filters, 0);
1498 gst_va_filter_drop_filter_buffers (GstVaFilter * self)
1500 gboolean ret = TRUE;
1502 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
1504 GST_OBJECT_LOCK (self);
1506 ret = _destroy_filters_unlocked (self);
1507 GST_OBJECT_UNLOCK (self);
1513 _get_surface_from_buffer (GstVaFilter * self, GstBuffer * buffer)
1515 VASurfaceID surface = VA_INVALID_ID;
1518 surface = gst_va_buffer_get_surface (buffer);
1520 if (surface != VA_INVALID_ID) {
1521 /* @FIXME: in gallium vaQuerySurfaceStatus only seems to work with
1522 * encoder's surfaces */
1523 if (!GST_VA_DISPLAY_IS_IMPLEMENTATION (self->display, MESA_GALLIUM))
1524 if (!va_check_surface (self->display, surface))
1525 surface = VA_INVALID_ID;
1532 _fill_va_sample (GstVaFilter * self, GstVaSample * sample,
1533 GstPadDirection direction)
1535 GstVideoCropMeta *crop = NULL;
1537 sample->surface = _get_surface_from_buffer (self, sample->buffer);
1538 if (sample->surface == VA_INVALID_ID)
1541 /* XXX: cropping occurs only in input frames */
1542 if (direction == GST_PAD_SRC) {
1543 GST_OBJECT_LOCK (self);
1544 sample->rect = self->output_region;
1545 sample->rect.x = sample->borders_w / 2;
1546 sample->rect.y = sample->borders_h / 2;
1547 sample->rect.width -= sample->borders_w;
1548 sample->rect.height -= sample->borders_h;
1549 GST_OBJECT_UNLOCK (self);
1554 /* if buffer has crop meta, its real size is in video meta */
1556 crop = gst_buffer_get_video_crop_meta (sample->buffer);
1558 GST_OBJECT_LOCK (self);
1559 if (crop && self->crop_enabled) {
1561 sample->rect = (VARectangle) {
1564 .width = crop->width,
1565 .height = crop->height
1569 sample->rect = self->input_region;
1571 GST_OBJECT_UNLOCK (self);
1577 _create_pipeline_buffer (GstVaFilter * self, GstVaSample * src,
1578 GstVaSample * dst, GArray * filters, VABufferID * buffer)
1582 VABufferID *va_filters = NULL;
1583 VAProcPipelineParameterBuffer params;
1584 guint32 num_filters = 0;
1586 GST_OBJECT_LOCK (self);
1590 num_filters = filters->len;
1591 va_filters = (num_filters > 0) ? (VABufferID *) filters->data : NULL;
1593 params = (VAProcPipelineParameterBuffer) {
1594 .surface = src->surface,
1595 .surface_region = &src->rect,
1596 .surface_color_standard = self->input_color_standard,
1597 .output_region = &dst->rect,
1598 .output_background_color = 0xff000000, /* ARGB black */
1599 .output_color_standard = self->output_color_standard,
1600 .filters = va_filters,
1601 .num_filters = num_filters,
1602 .forward_references = src->forward_references,
1603 .num_forward_references = src->num_forward_references,
1604 .backward_references = src->backward_references,
1605 .num_backward_references = src->num_backward_references,
1606 .rotation_state = self->rotation,
1607 .mirror_state = self->mirror,
1608 .input_surface_flag = src->flags,
1609 .output_surface_flag = dst->flags,
1610 .input_color_properties = self->input_color_properties,
1611 .output_color_properties = self->output_color_properties,
1612 .filter_flags = self->scale_method,
1614 .output_hdr_metadata = NULL,
1618 GST_OBJECT_UNLOCK (self);
1620 dpy = gst_va_display_get_va_dpy (self->display);
1621 status = vaCreateBuffer (dpy, self->context,
1622 VAProcPipelineParameterBufferType, sizeof (params), 1, ¶ms, buffer);
1623 if (status != VA_STATUS_SUCCESS) {
1624 GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
1628 GST_TRACE_OBJECT (self, "Created VABufferID %#x with %u filters: "
1629 "src %#x / dst %#x", *buffer, num_filters, src->surface, dst->surface);
1635 gst_va_filter_process (GstVaFilter * self, GstVaSample * src, GstVaSample * dst)
1637 GArray *filters = NULL;
1640 VAProcPipelineCaps pipeline_caps = { 0, };
1642 gboolean ret = FALSE;
1644 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
1645 g_return_val_if_fail (src, FALSE);
1646 g_return_val_if_fail (dst, FALSE);
1648 if (!gst_va_filter_is_open (self))
1651 if (!(_fill_va_sample (self, src, GST_PAD_SINK)
1652 && _fill_va_sample (self, dst, GST_PAD_SRC)))
1655 GST_OBJECT_LOCK (self);
1657 filters = g_array_ref (self->filters);
1658 GST_OBJECT_UNLOCK (self);
1660 if (!_query_pipeline_caps (self, filters, &pipeline_caps))
1663 if (!_create_pipeline_buffer (self, src, dst, filters, &buffer))
1667 g_array_unref (filters);
1669 dpy = gst_va_display_get_va_dpy (self->display);
1671 status = vaBeginPicture (dpy, self->context, dst->surface);
1672 if (status != VA_STATUS_SUCCESS) {
1673 GST_ERROR_OBJECT (self, "vaBeginPicture: %s", vaErrorStr (status));
1677 status = vaRenderPicture (dpy, self->context, &buffer, 1);
1678 if (status != VA_STATUS_SUCCESS) {
1679 GST_ERROR_OBJECT (self, "vaRenderPicture: %s with buffer %#x",
1680 vaErrorStr (status), buffer);
1684 status = vaEndPicture (dpy, self->context);
1685 if (status != VA_STATUS_SUCCESS) {
1686 GST_ERROR_OBJECT (self, "vaEndPicture: %s", vaErrorStr (status));
1693 status = vaDestroyBuffer (dpy, buffer);
1694 if (status != VA_STATUS_SUCCESS) {
1695 GST_WARNING_OBJECT (self, "Failed to destroy pipeline buffer: %s",
1696 vaErrorStr (status));
1703 status = vaEndPicture (dpy, self->context);
1704 if (status != VA_STATUS_SUCCESS)
1705 GST_ERROR_OBJECT (self, "vaEndPicture: %s", vaErrorStr (status));
1711 gst_va_filter_has_compose (GstVaFilter * self)
1713 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
1715 if (!gst_va_filter_is_open (self))
1718 /* HACK(uartie): i965 can't do composition */
1719 if (GST_VA_DISPLAY_IS_IMPLEMENTATION (self->display, INTEL_I965))
1722 /* some drivers can compose, but may not support blending (e.g. GALLIUM) */
1723 #ifndef GST_DISABLE_GST_DEBUG
1724 if (!(self->pipeline_caps.blend_flags & VA_BLEND_GLOBAL_ALPHA))
1725 GST_WARNING_OBJECT (self, "VPP does not support alpha blending");
1732 * gst_va_filter_compose:
1733 * @tx: the #GstVaComposeTransaction for input samples and output.
1735 * Iterates over all inputs via #GstVaComposeTransaction:next and composes
1736 * them onto the #GstVaComposeTransaction:output.
1738 * Only csc, scaling and blending filters are applied during composition.
1739 * All other filters are ignored here. Use #gst_va_filter_process to apply
1742 * Returns: TRUE on successful compose, FALSE otherwise.
1747 gst_va_filter_compose (GstVaFilter * self, GstVaComposeTransaction * tx)
1751 VASurfaceID out_surface;
1752 GstVaComposeSample *sample;
1754 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
1755 g_return_val_if_fail (tx, FALSE);
1756 g_return_val_if_fail (tx->next, FALSE);
1757 g_return_val_if_fail (tx->output, FALSE);
1759 if (!gst_va_filter_is_open (self))
1762 out_surface = _get_surface_from_buffer (self, tx->output);
1763 if (out_surface == VA_INVALID_ID)
1766 dpy = gst_va_display_get_va_dpy (self->display);
1768 status = vaBeginPicture (dpy, self->context, out_surface);
1769 if (status != VA_STATUS_SUCCESS) {
1770 GST_ERROR_OBJECT (self, "vaBeginPicture: %s", vaErrorStr (status));
1774 sample = tx->next (tx->user_data);
1775 for (; sample; sample = tx->next (tx->user_data)) {
1776 VAProcPipelineParameterBuffer params = { 0, };
1778 VASurfaceID in_surface;
1779 VABlendState blend = { 0, };
1781 in_surface = _get_surface_from_buffer (self, sample->buffer);
1782 if (in_surface == VA_INVALID_ID)
1785 /* (transfer full), unref it */
1786 gst_buffer_unref (sample->buffer);
1788 GST_OBJECT_LOCK (self);
1790 params = (VAProcPipelineParameterBuffer) {
1791 .surface = in_surface,
1792 .surface_region = &sample->input_region,
1793 .output_region = &sample->output_region,
1794 .output_background_color = 0xff000000,
1795 .filter_flags = self->scale_method,
1798 GST_OBJECT_UNLOCK (self);
1800 /* only send blend state when sample is not fully opaque */
1801 if ((self->pipeline_caps.blend_flags & VA_BLEND_GLOBAL_ALPHA)
1802 && sample->alpha < 1.0) {
1804 blend = (VABlendState) {
1805 .flags = VA_BLEND_GLOBAL_ALPHA,
1806 .global_alpha = sample->alpha,
1809 params.blend_state = &blend;
1812 status = vaCreateBuffer (dpy, self->context,
1813 VAProcPipelineParameterBufferType, sizeof (params), 1, ¶ms,
1815 if (status != VA_STATUS_SUCCESS) {
1816 GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
1820 status = vaRenderPicture (dpy, self->context, &buffer, 1);
1821 vaDestroyBuffer (dpy, buffer);
1822 if (status != VA_STATUS_SUCCESS) {
1823 GST_ERROR_OBJECT (self, "vaRenderPicture: %s", vaErrorStr (status));
1828 status = vaEndPicture (dpy, self->context);
1829 if (status != VA_STATUS_SUCCESS) {
1830 GST_ERROR_OBJECT (self, "vaEndPicture: %s", vaErrorStr (status));
1838 status = vaEndPicture (dpy, self->context);
1839 if (status != VA_STATUS_SUCCESS)
1840 GST_ERROR_OBJECT (self, "vaEndPicture: %s", vaErrorStr (status));
1846 * gst_va_buffer_get_surface_flags:
1847 * @buffer: the #GstBuffer to check.
1848 * @info: the #GstVideoInfo with info.
1850 * Gets the surface flags, related with interlace given @buffer and
1853 * Returns: VA surface flags.
1856 gst_va_buffer_get_surface_flags (GstBuffer * buffer, GstVideoInfo * info)
1858 guint32 surface_flags = 0;
1860 if (GST_VIDEO_INFO_INTERLACE_MODE (info) == GST_VIDEO_INTERLACE_MODE_MIXED
1861 || (GST_VIDEO_INFO_INTERLACE_MODE (info) ==
1862 GST_VIDEO_INTERLACE_MODE_INTERLEAVED
1863 && GST_VIDEO_INFO_FIELD_ORDER (info) ==
1864 GST_VIDEO_FIELD_ORDER_UNKNOWN)) {
1865 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_FLAG_INTERLACED)) {
1866 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_FLAG_TFF)) {
1867 surface_flags = VA_TOP_FIELD_FIRST;
1869 surface_flags = VA_BOTTOM_FIELD_FIRST;
1872 surface_flags = VA_FRAME_PICTURE;
1874 } else if (GST_VIDEO_INFO_FIELD_ORDER (info) ==
1875 GST_VIDEO_FIELD_ORDER_BOTTOM_FIELD_FIRST) {
1876 surface_flags = VA_BOTTOM_FIELD_FIRST;
1877 } else if (GST_VIDEO_INFO_FIELD_ORDER (info) ==
1878 GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST) {
1879 surface_flags = VA_TOP_FIELD_FIRST;
1882 return surface_flags;
1886 gst_va_filter_has_video_format (GstVaFilter * self, GstVideoFormat format,
1887 GstCapsFeatures * feature)
1892 g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
1893 g_return_val_if_fail (format != GST_VIDEO_FORMAT_UNKNOWN, FALSE);
1894 g_return_val_if_fail (GST_IS_CAPS_FEATURES (feature)
1895 && !gst_caps_features_is_any (feature), FALSE);
1898 GST_OBJECT_LOCK (self);
1899 for (i = 0; i < self->surface_formats->len; i++) {
1900 fmt = g_array_index (self->surface_formats, GstVideoFormat, i);
1901 if (format == fmt) {
1902 GST_OBJECT_UNLOCK (self);
1906 GST_OBJECT_UNLOCK (self);
1908 if (!gst_caps_features_is_equal (feature,
1909 GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY))
1912 GST_OBJECT_LOCK (self);
1913 for (i = 0; i < self->image_formats->len; i++) {
1914 fmt = g_array_index (self->image_formats, GstVideoFormat, i);
1915 if (format == fmt) {
1916 GST_OBJECT_UNLOCK (self);
1920 GST_OBJECT_UNLOCK (self);
1931 gst_va_scale_method_get_type (void)
1933 static gsize type = 0;
1934 static const GEnumValue values[] = {
1935 {VA_FILTER_SCALING_DEFAULT, "Default scaling method", "default"},
1936 {VA_FILTER_SCALING_FAST, "Fast scaling method", "fast"},
1937 {VA_FILTER_SCALING_HQ, "High quality scaling method", "hq"},
1941 if (g_once_init_enter (&type)) {
1942 const GType _type = g_enum_register_static ("GstVaScaleMethod", values);
1943 g_once_init_leave (&type, _type);