summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>2013-07-23 15:52:45 +0200
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>2013-08-23 19:00:38 +0200
commitf09008a8d147950aa31fb342b3b8a105eadcf9a6 (patch)
treeb45201e1c590021e499844d7a501b164ec981c7d
parentf34b6ffc60bfb87f03873c2d8ec2bebcfd3a5768 (diff)
Add initial infrastructure for video processing.
Add initial API for video processing: only scaling and color format conversion operations are supported.
-rw-r--r--configure.ac29
-rw-r--r--docs/reference/libs/libs-docs.xml.in1
-rw-r--r--docs/reference/libs/libs-sections.txt16
-rw-r--r--gst-libs/gst/vaapi/Makefile.am1
-rw-r--r--gst-libs/gst/vaapi/gstvaapidisplay.c12
-rw-r--r--gst-libs/gst/vaapi/gstvaapidisplay_priv.h11
-rw-r--r--gst-libs/gst/vaapi/gstvaapifilter.c821
-rw-r--r--gst-libs/gst/vaapi/gstvaapifilter.h104
8 files changed, 995 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 837ea106..66828fdc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -615,6 +615,31 @@ AC_CACHE_CHECK([for JPEG decoding API],
LIBS="$saved_LIBS"
])
+dnl Check for vpp (video post-processing) support
+USE_VA_VPP=0
+AC_CACHE_CHECK([for video post-postprocessing API],
+ ac_cv_have_va_vpp_api, [
+ saved_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $LIBVA_CFLAGS"
+ saved_LIBS="$LIBS"
+ LIBS="$LIBS $LIBVA_LIBS"
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <va/va.h>
+ #include <va/va_vpp.h>]],
+ [[VADisplay va_dpy;
+ VAContextID vpp_ctx;
+ VAProcFilterType filters[VAProcFilterCount];
+ unsigned int num_filters = VAProcFilterCount;
+ vaQueryVideoProcFilters(va_dpy, vpp_ctx, filters, &num_filters);
+ ]])],
+ [ac_cv_have_va_vpp_api="yes" USE_VA_VPP=1],
+ [ac_cv_have_va_vpp_api="no"]
+ )
+ CPPFLAGS="$saved_CPPFLAGS"
+ LIBS="$saved_LIBS"
+])
+
dnl VA/Wayland API
if test "$enable_wayland" = "yes"; then
PKG_CHECK_MODULES([LIBVA_WAYLAND], [libva-wayland >= va_api_wld_version],
@@ -633,6 +658,10 @@ case ":$USE_X11:$USE_GLX:$USE_WAYLAND:$USE_DRM:" in
;;
esac
+AC_DEFINE_UNQUOTED(USE_VA_VPP, $USE_VA_VPP,
+ [Defined to 1 if video post-processing is used])
+AM_CONDITIONAL(USE_VA_VPP, test $USE_VA_VPP -eq 1)
+
AC_DEFINE_UNQUOTED(USE_JPEG_DECODER, $USE_JPEG_DECODER,
[Defined to 1 if JPEG decoder is used])
AM_CONDITIONAL(USE_JPEG_DECODER, test $USE_JPEG_DECODER -eq 1)
diff --git a/docs/reference/libs/libs-docs.xml.in b/docs/reference/libs/libs-docs.xml.in
index 1f7f8409..45e05eab 100644
--- a/docs/reference/libs/libs-docs.xml.in
+++ b/docs/reference/libs/libs-docs.xml.in
@@ -34,6 +34,7 @@
<xi:include href="xml/gstvaapidecoder_h264.xml"/>
<xi:include href="xml/gstvaapidecoder_vc1.xml"/>
<xi:include href="xml/gstvaapisurfaceproxy.xml"/>
+ <xi:include href="xml/gstvaapifilter.xml"/>
</chapter>
<chapter id="object-tree">
diff --git a/docs/reference/libs/libs-sections.txt b/docs/reference/libs/libs-sections.txt
index 91796d9f..23a804f0 100644
--- a/docs/reference/libs/libs-sections.txt
+++ b/docs/reference/libs/libs-sections.txt
@@ -373,3 +373,19 @@ gst_vaapi_surface_proxy_unref
<SUBSECTION Standard>
GST_VAAPI_SURFACE_PROXY_SURFACE
</SECTION>
+
+<SECTION>
+<FILE>gstvaapifilter</FILE>
+<TITLE>GstVaapiFilter</TITLE>
+GstVaapiFilter
+gst_vaapi_filter_new
+gst_vaapi_filter_ref
+gst_vaapi_filter_unref
+gst_vaapi_filter_replace
+gst_vaapi_filter_get_operations
+gst_vaapi_filter_get_formats
+gst_vaapi_filter_set_operation
+gst_vaapi_filter_set_format
+<SUBSECTION Standard>
+GST_VAAPI_FILTER
+</SECTION>
diff --git a/gst-libs/gst/vaapi/Makefile.am b/gst-libs/gst/vaapi/Makefile.am
index 3e0a02a4..ab605e13 100644
--- a/gst-libs/gst/vaapi/Makefile.am
+++ b/gst-libs/gst/vaapi/Makefile.am
@@ -55,6 +55,7 @@ libgstvaapi_source_c = \
gstvaapidecoder_vc1.c \
gstvaapidisplay.c \
gstvaapidisplaycache.c \
+ gstvaapifilter.c \
gstvaapiimage.c \
gstvaapiimagepool.c \
gstvaapiminiobject.c \
diff --git a/gst-libs/gst/vaapi/gstvaapidisplay.c b/gst-libs/gst/vaapi/gstvaapidisplay.c
index 05833c8e..ca8c6cb0 100644
--- a/gst-libs/gst/vaapi/gstvaapidisplay.c
+++ b/gst-libs/gst/vaapi/gstvaapidisplay.c
@@ -684,6 +684,18 @@ gst_vaapi_display_create(GstVaapiDisplay *display,
}
append_h263_config(priv->decoders);
+ /* Video processing API */
+#if USE_VA_VPP
+ status = vaQueryConfigEntrypoints(priv->display, VAProfileNone,
+ entrypoints, &num_entrypoints);
+ if (vaapi_check_status(status, "vaQueryEntrypoints() [VAProfileNone]")) {
+ for (j = 0; j < num_entrypoints; j++) {
+ if (entrypoints[j] == VAEntrypointVideoProc)
+ priv->has_vpp = TRUE;
+ }
+ }
+#endif
+
/* VA display attributes */
display_attrs =
g_new(VADisplayAttribute, vaMaxNumDisplayAttributes(priv->display));
diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_priv.h
index 81768208..1f7f46ce 100644
--- a/gst-libs/gst/vaapi/gstvaapidisplay_priv.h
+++ b/gst-libs/gst/vaapi/gstvaapidisplay_priv.h
@@ -116,6 +116,16 @@ typedef void (*GstVaapiDisplayGetSizeMFunc)(GstVaapiDisplay *display,
#define GST_VAAPI_DISPLAY_TYPES(display) \
gst_vaapi_display_get_display_types(GST_VAAPI_DISPLAY_CAST(display))
+/**
+ * GST_VAAPI_DISPLAY_HAS_VPP:
+ * @display: a @GstVaapiDisplay
+ *
+ * Returns whether the @display supports video processing (VA/VPP)
+ */
+#undef GST_VAAPI_DISPLAY_HAS_VPP
+#define GST_VAAPI_DISPLAY_HAS_VPP(display) \
+ (GST_VAAPI_DISPLAY_GET_PRIVATE(display)->has_vpp)
+
struct _GstVaapiDisplayPrivate {
GstVaapiDisplay *parent;
GRecMutex mutex;
@@ -133,6 +143,7 @@ struct _GstVaapiDisplayPrivate {
GArray *subpicture_formats;
GArray *properties;
guint use_foreign_display : 1;
+ guint has_vpp : 1;
};
/**
diff --git a/gst-libs/gst/vaapi/gstvaapifilter.c b/gst-libs/gst/vaapi/gstvaapifilter.c
new file mode 100644
index 00000000..ce8556e0
--- /dev/null
+++ b/gst-libs/gst/vaapi/gstvaapifilter.c
@@ -0,0 +1,821 @@
+/*
+ * gstvaapifilter.c - Video processing abstraction
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include "gstvaapifilter.h"
+#include "gstvaapiutils.h"
+#include "gstvaapiminiobject.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapisurface_priv.h"
+
+#if USE_VA_VPP
+# include <va/va_vpp.h>
+#endif
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define GST_VAAPI_FILTER(obj) \
+ ((GstVaapiFilter *)(obj))
+
+typedef struct _GstVaapiFilterOpData GstVaapiFilterOpData;
+struct _GstVaapiFilterOpData {
+ GstVaapiFilterOp op;
+ GParamSpec *pspec;
+ volatile gint ref_count;
+ guint va_type;
+ guint va_subtype;
+ gpointer va_caps;
+ guint va_num_caps;
+ guint va_cap_size;
+ VABufferID va_buffer;
+ guint va_buffer_size;
+ guint is_enabled : 1;
+};
+
+struct _GstVaapiFilter {
+ /*< private >*/
+ GstVaapiMiniObject parent_instance;
+
+ GstVaapiDisplay *display;
+ VADisplay va_display;
+ VAConfigID va_config;
+ VAContextID va_context;
+ GPtrArray *operations;
+ GstVideoFormat format;
+ GArray *formats;
+};
+
+/* ------------------------------------------------------------------------- */
+/* --- VPP Helpers --- */
+/* ------------------------------------------------------------------------- */
+
+#if USE_VA_VPP
+static VAProcFilterType *
+vpp_get_filters_unlocked(GstVaapiFilter *filter, guint *num_filters_ptr)
+{
+ VAProcFilterType *filters = NULL;
+ guint num_filters = 0;
+ VAStatus va_status;
+
+ num_filters = VAProcFilterCount;
+ filters = g_malloc_n(num_filters, sizeof(*filters));
+ if (!filters)
+ goto error;
+
+ va_status = vaQueryVideoProcFilters(filter->va_display, filter->va_context,
+ filters, &num_filters);
+
+ // Try to reallocate to the expected number of filters
+ if (va_status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) {
+ VAProcFilterType * const new_filters =
+ g_try_realloc_n(filters, num_filters, sizeof(*new_filters));
+ if (!new_filters)
+ goto error;
+ filters = new_filters;
+
+ va_status = vaQueryVideoProcFilters(filter->va_display,
+ filter->va_context, filters, &num_filters);
+ }
+ if (!vaapi_check_status(va_status, "vaQueryVideoProcFilters()"))
+ goto error;
+
+ *num_filters_ptr = num_filters;
+ return filters;
+
+error:
+ g_free(filters);
+ return NULL;
+}
+
+static VAProcFilterType *
+vpp_get_filters(GstVaapiFilter *filter, guint *num_filters_ptr)
+{
+ VAProcFilterType *filters;
+
+ GST_VAAPI_DISPLAY_LOCK(filter->display);
+ filters = vpp_get_filters_unlocked(filter, num_filters_ptr);
+ GST_VAAPI_DISPLAY_UNLOCK(filter->display);
+ return filters;
+}
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* --- VPP Operations --- */
+/* ------------------------------------------------------------------------- */
+
+#if USE_VA_VPP
+#define DEFAULT_FORMAT GST_VIDEO_FORMAT_UNKNOWN
+
+enum {
+ PROP_0,
+
+ PROP_FORMAT = GST_VAAPI_FILTER_OP_FORMAT,
+
+ N_PROPERTIES
+};
+
+static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
+static gsize g_properties_initialized = FALSE;
+
+static void
+init_properties(void)
+{
+ /**
+ * GstVaapiFilter:format:
+ *
+ * The forced output pixel format, expressed as a #GstVideoFormat.
+ */
+ g_properties[PROP_FORMAT] =
+ g_param_spec_enum("format",
+ "Format",
+ "The forced output pixel format",
+ GST_TYPE_VIDEO_FORMAT,
+ DEFAULT_FORMAT,
+ G_PARAM_READWRITE);
+}
+
+static void
+ensure_properties(void)
+{
+ if (g_once_init_enter(&g_properties_initialized)) {
+ init_properties();
+ g_once_init_leave(&g_properties_initialized, TRUE);
+ }
+}
+
+static void
+op_data_free(GstVaapiFilterOpData *op_data)
+{
+ g_free(op_data->va_caps);
+ g_slice_free(GstVaapiFilterOpData, op_data);
+}
+
+static inline gpointer
+op_data_new(GstVaapiFilterOp op, GParamSpec *pspec)
+{
+ GstVaapiFilterOpData *op_data;
+
+ op_data = g_slice_new0(GstVaapiFilterOpData);
+ if (!op_data)
+ return NULL;
+
+ op_data->op = op;
+ op_data->pspec = pspec;
+ op_data->ref_count = 1;
+ op_data->va_buffer = VA_INVALID_ID;
+
+ switch (op) {
+ case GST_VAAPI_FILTER_OP_FORMAT:
+ op_data->va_type = VAProcFilterNone;
+ break;
+ default:
+ g_assert(0 && "unsupported operation");
+ goto error;
+ }
+ return op_data;
+
+error:
+ op_data_free(op_data);
+ return NULL;
+}
+
+static inline gpointer
+op_data_ref(gpointer data)
+{
+ GstVaapiFilterOpData * const op_data = data;
+
+ g_return_val_if_fail(op_data != NULL, NULL);
+
+ g_atomic_int_inc(&op_data->ref_count);
+ return op_data;
+}
+
+static void
+op_data_unref(gpointer data)
+{
+ GstVaapiFilterOpData * const op_data = data;
+
+ g_return_if_fail(op_data != NULL);
+ g_return_if_fail(op_data->ref_count > 0);
+
+ if (g_atomic_int_dec_and_test(&op_data->ref_count))
+ op_data_free(op_data);
+}
+
+/* Get default list of operations supported by the library */
+static GPtrArray *
+get_operations_default(void)
+{
+ GPtrArray *ops;
+ guint i;
+
+ ops = g_ptr_array_new_full(N_PROPERTIES, op_data_unref);
+ if (!ops)
+ return NULL;
+
+ ensure_properties();
+
+ for (i = 0; i < N_PROPERTIES; i++) {
+ GParamSpec * const pspec = g_properties[i];
+ if (!pspec)
+ continue;
+
+ GstVaapiFilterOpData * const op_data = op_data_new(i, pspec);
+ if (!op_data)
+ goto error;
+ g_ptr_array_add(ops, op_data);
+ }
+ return ops;
+
+error:
+ g_ptr_array_unref(ops);
+ return NULL;
+}
+
+/* Get the ordered list of operations, based on VA/VPP queries */
+static GPtrArray *
+get_operations_ordered(GstVaapiFilter *filter, GPtrArray *default_ops)
+{
+ GPtrArray *ops;
+ VAProcFilterType *filters;
+ guint i, j, num_filters;
+
+ ops = g_ptr_array_new_full(default_ops->len, op_data_unref);
+ if (!ops)
+ return NULL;
+
+ filters = vpp_get_filters(filter, &num_filters);
+ if (!filters)
+ goto error;
+
+ // Append virtual ops first, i.e. those without an associated VA filter
+ for (i = 0; i < default_ops->len; i++) {
+ GstVaapiFilterOpData * const op_data =
+ g_ptr_array_index(default_ops, i);
+ if (op_data->va_type == VAProcFilterNone)
+ g_ptr_array_add(ops, op_data_ref(op_data));
+ }
+
+ // Append ops, while preserving the VA filters ordering
+ for (i = 0; i < num_filters; i++) {
+ const VAProcFilterType va_type = filters[i];
+ if (va_type == VAProcFilterNone)
+ continue;
+
+ for (j = 0; j < default_ops->len; j++) {
+ GstVaapiFilterOpData * const op_data =
+ g_ptr_array_index(default_ops, j);
+ if (op_data->va_type != va_type)
+ continue;
+ g_ptr_array_add(ops, op_data_ref(op_data));
+ }
+ }
+
+ if (filter->operations)
+ g_ptr_array_unref(filter->operations);
+ filter->operations = g_ptr_array_ref(ops);
+
+ g_free(filters);
+ g_ptr_array_unref(default_ops);
+ return ops;
+
+error:
+ g_free(filters);
+ g_ptr_array_unref(ops);
+ g_ptr_array_unref(default_ops);
+ return NULL;
+}
+
+/* Determine the set of supported VPP operations by the specific
+ filter, or known to this library if filter is NULL */
+static GPtrArray *
+ensure_operations(GstVaapiFilter *filter)
+{
+ GPtrArray *ops;
+
+ if (filter && filter->operations)
+ return g_ptr_array_ref(filter->operations);
+
+ ops = get_operations_default();
+ if (!ops)
+ return NULL;
+ return filter ? get_operations_ordered(filter, ops) : ops;
+}
+#endif
+
+/* Find whether the VPP operation is supported or not */
+GstVaapiFilterOpData *
+find_operation(GstVaapiFilter *filter, GstVaapiFilterOp op)
+{
+ guint i;
+
+ if (!filter->operations)
+ return NULL;
+
+ for (i = 0; i < filter->operations->len; i++) {
+ GstVaapiFilterOpData * const op_data =
+ g_ptr_array_index(filter->operations, i);
+ if (op_data->op == op)
+ return op_data;
+ }
+ return NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Surface Formats --- */
+/* ------------------------------------------------------------------------- */
+
+static GArray *
+ensure_formats(GstVaapiFilter *filter)
+{
+ VASurfaceAttrib *surface_attribs = NULL;
+ guint i, num_surface_attribs = 0;
+ VAStatus va_status;
+
+ if (G_LIKELY(filter->formats))
+ return filter->formats;
+
+#if VA_CHECK_VERSION(0,34,0)
+ GST_VAAPI_DISPLAY_LOCK(filter->display);
+ va_status = vaQuerySurfaceAttributes(filter->va_display, filter->va_config,
+ NULL, &num_surface_attribs);
+ GST_VAAPI_DISPLAY_UNLOCK(filter->display);
+ if (!vaapi_check_status(va_status, "vaQuerySurfaceAttributes()"))
+ return NULL;
+
+ surface_attribs = g_malloc(num_surface_attribs * sizeof(*surface_attribs));
+ if (!surface_attribs)
+ return NULL;
+
+ GST_VAAPI_DISPLAY_LOCK(filter->display);
+ va_status = vaQuerySurfaceAttributes(filter->va_display, filter->va_config,
+ surface_attribs, &num_surface_attribs);
+ GST_VAAPI_DISPLAY_UNLOCK(filter->display);
+ if (!vaapi_check_status(va_status, "vaQuerySurfaceAttributes()"))
+ return NULL;
+
+ filter->formats = g_array_sized_new(FALSE, FALSE, sizeof(GstVideoFormat),
+ num_surface_attribs);
+ if (!filter->formats)
+ goto error;
+
+ for (i = 0; i < num_surface_attribs; i++) {
+ const VASurfaceAttrib * const surface_attrib = &surface_attribs[i];
+ GstVideoFormat format;
+
+ if (surface_attrib->type != VASurfaceAttribPixelFormat)
+ continue;
+ if (!(surface_attrib->flags & VA_SURFACE_ATTRIB_SETTABLE))
+ continue;
+
+ format = gst_vaapi_video_format_from_va_fourcc(
+ surface_attrib->value.value.i);
+ if (format == GST_VIDEO_FORMAT_UNKNOWN)
+ continue;
+ g_array_append_val(filter->formats, format);
+ }
+#endif
+
+ g_free(surface_attribs);
+ return filter->formats;
+
+error:
+ g_free(surface_attribs);
+ return NULL;
+}
+
+static inline gboolean
+is_special_format(GstVideoFormat format)
+{
+ return format == GST_VIDEO_FORMAT_UNKNOWN ||
+ format == GST_VIDEO_FORMAT_ENCODED;
+}
+
+static gboolean
+find_format(GstVaapiFilter *filter, GstVideoFormat format)
+{
+ guint i;
+
+ if (is_special_format(format) || !filter->formats)
+ return FALSE;
+
+ for (i = 0; i < filter->formats->len; i++) {
+ if (g_array_index(filter->formats, GstVideoFormat, i) == format)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Interface --- */
+/* ------------------------------------------------------------------------- */
+
+#if USE_VA_VPP
+static gboolean
+gst_vaapi_filter_init(GstVaapiFilter *filter, GstVaapiDisplay *display)
+{
+ VAStatus va_status;
+
+ filter->display = gst_vaapi_display_ref(display);
+ filter->va_display = GST_VAAPI_DISPLAY_VADISPLAY(display);
+ filter->va_config = VA_INVALID_ID;
+ filter->va_context = VA_INVALID_ID;
+ filter->format = DEFAULT_FORMAT;
+
+ if (!GST_VAAPI_DISPLAY_HAS_VPP(display))
+ return FALSE;
+
+ va_status = vaCreateConfig(filter->va_display, VAProfileNone,
+ VAEntrypointVideoProc, NULL, 0, &filter->va_config);
+ if (!vaapi_check_status(va_status, "vaCreateConfig() [VPP]"))
+ return FALSE;
+
+ va_status = vaCreateContext(filter->va_display, filter->va_config, 0, 0, 0,
+ NULL, 0, &filter->va_context);
+ if (!vaapi_check_status(va_status, "vaCreateContext() [VPP]"))
+ return FALSE;
+ return TRUE;
+}
+
+static void
+gst_vaapi_filter_finalize(GstVaapiFilter *filter)
+{
+ guint i;
+
+ GST_VAAPI_DISPLAY_LOCK(filter->display);
+ if (filter->operations) {
+ for (i = 0; i < filter->operations->len; i++) {
+ GstVaapiFilterOpData * const op_data =
+ g_ptr_array_index(filter->operations, i);
+ vaapi_destroy_buffer(filter->va_display, &op_data->va_buffer);
+ }
+ g_ptr_array_unref(filter->operations);
+ filter->operations = NULL;
+ }
+
+ if (filter->va_context != VA_INVALID_ID) {
+ vaDestroyContext(filter->va_display, filter->va_context);
+ filter->va_context = VA_INVALID_ID;
+ }
+
+ if (filter->va_config != VA_INVALID_ID) {
+ vaDestroyConfig(filter->va_display, filter->va_config);
+ filter->va_config = VA_INVALID_ID;
+ }
+ GST_VAAPI_DISPLAY_UNLOCK(filter->display);
+ gst_vaapi_display_replace(&filter->display, NULL);
+
+ if (filter->formats) {
+ g_array_unref(filter->formats);
+ filter->formats = NULL;
+ }
+}
+
+static inline const GstVaapiMiniObjectClass *
+gst_vaapi_filter_class(void)
+{
+ static const GstVaapiMiniObjectClass GstVaapiFilterClass = {
+ sizeof(GstVaapiFilter),
+ (GDestroyNotify)gst_vaapi_filter_finalize
+ };
+ return &GstVaapiFilterClass;
+}
+#endif
+
+/**
+ * gst_vaapi_filter_new:
+ * @display: a #GstVaapiDisplay
+ *
+ * Creates a new #GstVaapiFilter set up to operate in "identity"
+ * mode. This means that no other operation than scaling is performed.
+ *
+ * Return value: the newly created #GstVaapiFilter object
+ */
+GstVaapiFilter *
+gst_vaapi_filter_new(GstVaapiDisplay *display)
+{
+#if USE_VA_VPP
+ GstVaapiFilter *filter;
+
+ filter = (GstVaapiFilter *)
+ gst_vaapi_mini_object_new0(gst_vaapi_filter_class());
+ if (!filter)
+ return NULL;
+
+ if (!gst_vaapi_filter_init(filter, display))
+ goto error;
+ return filter;
+
+error:
+ gst_vaapi_filter_unref(filter);
+ return NULL;
+#else
+ GST_WARNING("video processing is not supported, "
+ "please consider an upgrade to VA-API >= 0.34");
+ return NULL;
+#endif
+}
+
+/**
+ * gst_vaapi_filter_ref:
+ * @filter: a #GstVaapiFilter
+ *
+ * Atomically increases the reference count of the given @filter by one.
+ *
+ * Returns: The same @filter argument
+ */
+GstVaapiFilter *
+gst_vaapi_filter_ref(GstVaapiFilter *filter)
+{
+ g_return_val_if_fail(filter != NULL, NULL);
+
+ return GST_VAAPI_FILTER(gst_vaapi_mini_object_ref(
+ GST_VAAPI_MINI_OBJECT(filter)));
+}
+
+/**
+ * gst_vaapi_filter_unref:
+ * @filter: a #GstVaapiFilter
+ *
+ * Atomically decreases the reference count of the @filter by one. If
+ * the reference count reaches zero, the filter will be free'd.
+ */
+void
+gst_vaapi_filter_unref(GstVaapiFilter *filter)
+{
+ g_return_if_fail(filter != NULL);
+
+ gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(filter));
+}
+
+/**
+ * gst_vaapi_filter_replace:
+ * @old_filter_ptr: a pointer to a #GstVaapiFilter
+ * @new_filter: a #GstVaapiFilter
+ *
+ * Atomically replaces the filter held in @old_filter_ptr with
+ * @new_filter. This means that @old_filter_ptr shall reference a
+ * valid filter. However, @new_filter can be NULL.
+ */
+void
+gst_vaapi_filter_replace(GstVaapiFilter **old_filter_ptr,
+ GstVaapiFilter *new_filter)
+{
+ g_return_if_fail(old_filter_ptr != NULL);
+
+ gst_vaapi_mini_object_replace((GstVaapiMiniObject **)old_filter_ptr,
+ GST_VAAPI_MINI_OBJECT(new_filter));
+}
+
+/**
+ * gst_vaapi_filter_get_operations:
+ * @filter: a #GstVaapiFilter, or %NULL
+ *
+ * Determines the set of supported operations for video processing.
+ * The caller owns an extra reference to the resulting array of
+ * #GstVaapiFilterOpInfo elements, so it shall be released with
+ * g_ptr_array_unref() after usage.
+ *
+ * If @filter is %NULL, then this function returns the video
+ * processing operations supported by this library.
+ *
+ * Return value: the set of supported operations, or %NULL if an error
+ * occurred.
+ */
+GPtrArray *
+gst_vaapi_filter_get_operations(GstVaapiFilter *filter)
+{
+#if USE_VA_VPP
+ return ensure_operations(filter);
+#else
+ return NULL;
+#endif
+}
+
+/**
+ * gst_vaapi_filter_set_operation:
+ * @filter: a #GstVaapiFilter
+ * @op: a #GstVaapiFilterOp
+ * @value: the @op settings
+ *
+ * Enable the specified operation @op to be performed during video
+ * processing, i.e. in gst_vaapi_filter_process(). The @value argument
+ * specifies the operation settings. e.g. deinterlacing method for
+ * deinterlacing, denoising level for noise reduction, etc.
+ *
+ * If @value is %NULL, then this function resets the operation
+ * settings to their default values.
+ *
+ * Return value: %TRUE if the specified operation may be supported,
+ * %FALSE otherwise
+ */
+gboolean
+gst_vaapi_filter_set_operation(GstVaapiFilter *filter, GstVaapiFilterOp op,
+ const GValue *value)
+{
+#if USE_VA_VPP
+ GstVaapiFilterOpData *op_data;
+
+ g_return_val_if_fail(filter != NULL, FALSE);
+
+ op_data = find_operation(filter, op);
+ if (!op_data)
+ return FALSE;
+
+ if (value && !G_VALUE_HOLDS(value, G_PARAM_SPEC_VALUE_TYPE(op_data->pspec)))
+ return FALSE;
+
+ switch (op) {
+ case GST_VAAPI_FILTER_OP_FORMAT:
+ return gst_vaapi_filter_set_format(filter, value ?
+ g_value_get_enum(value) : DEFAULT_FORMAT);
+ default:
+ break;
+ }
+#endif
+ return FALSE;
+}
+
+/**
+ * gst_vaapi_filter_process:
+ * @filter: a #GstVaapiFilter
+ * @src_surface: the source @GstVaapiSurface
+ * @dst_surface: the destination @GstVaapiSurface
+ * @flags: #GstVaapiSurfaceRenderFlags that apply to @src_surface
+ *
+ * Applies the operations currently defined in the @filter to
+ * @src_surface and return the output in @dst_surface. The order of
+ * operations is determined in a way that suits best the underlying
+ * hardware. i.e. the only guarantee held is the generated outcome,
+ * not any specific order of operations.
+ *
+ * Return value: a #GstVaapiFilterStatus
+ */
+static GstVaapiFilterStatus
+gst_vaapi_filter_process_unlocked(GstVaapiFilter *filter,
+ GstVaapiSurface *src_surface, GstVaapiSurface *dst_surface, guint flags)
+{
+#if USE_VA_VPP
+ VAProcPipelineParameterBuffer *pipeline_param = NULL;
+ VABufferID pipeline_param_buf_id;
+ VABufferID filters[N_PROPERTIES];
+ guint i, num_filters = 0;
+ VAStatus va_status;
+ VARectangle src_rect, dst_rect;
+
+ if (!ensure_operations(filter))
+ return GST_VAAPI_FILTER_STATUS_ERROR_ALLOCATION_FAILED;
+
+ src_rect.x = 0;
+ src_rect.y = 0;
+ src_rect.width = GST_VAAPI_SURFACE_WIDTH(src_surface);
+ src_rect.height = GST_VAAPI_SURFACE_HEIGHT(src_surface);
+
+ dst_rect.x = 0;
+ dst_rect.y = 0;
+ dst_rect.width = GST_VAAPI_SURFACE_WIDTH(dst_surface);
+ dst_rect.height = GST_VAAPI_SURFACE_HEIGHT(dst_surface);
+
+ for (i = 0, num_filters = 0; i < filter->operations->len; i++) {
+ GstVaapiFilterOpData * const op_data =
+ g_ptr_array_index(filter->operations, i);
+ if (!op_data->is_enabled)
+ continue;
+ if (op_data->va_buffer == VA_INVALID_ID) {
+ GST_ERROR("invalid VA buffer for operation %s",
+ g_param_spec_get_name(op_data->pspec));
+ goto error;
+ }
+ filters[num_filters++] = op_data->va_buffer;
+ }
+
+ if (!vaapi_create_buffer(filter->va_display, filter->va_context,
+ VAProcPipelineParameterBufferType, sizeof(*pipeline_param),
+ NULL, &pipeline_param_buf_id, (gpointer *)&pipeline_param))
+ goto error;
+
+ memset(pipeline_param, 0, sizeof(*pipeline_param));
+ pipeline_param->surface = GST_VAAPI_OBJECT_ID(src_surface);
+ pipeline_param->surface_region = &src_rect;
+ pipeline_param->surface_color_standard = VAProcColorStandardNone;
+ pipeline_param->output_region = &dst_rect;
+ pipeline_param->output_color_standard = VAProcColorStandardNone;
+ pipeline_param->output_background_color = 0xff000000;
+ pipeline_param->filter_flags = from_GstVaapiSurfaceRenderFlags(flags);
+ pipeline_param->filters = filters;
+ pipeline_param->num_filters = num_filters;
+
+ vaapi_unmap_buffer(filter->va_display, pipeline_param_buf_id, NULL);
+
+ va_status = vaBeginPicture(filter->va_display, filter->va_context,
+ GST_VAAPI_OBJECT_ID(dst_surface));
+ if (!vaapi_check_status(va_status, "vaBeginPicture()"))
+ goto error;
+
+ va_status = vaRenderPicture(filter->va_display, filter->va_context,
+ &pipeline_param_buf_id, 1);
+ if (!vaapi_check_status(va_status, "vaRenderPicture()"))
+ goto error;
+
+ va_status = vaEndPicture(filter->va_display, filter->va_context);
+ if (!vaapi_check_status(va_status, "vaEndPicture()"))
+ goto error;
+ return GST_VAAPI_FILTER_STATUS_SUCCESS;
+
+error:
+ vaDestroyBuffer(filter->va_display, pipeline_param_buf_id);
+ return GST_VAAPI_FILTER_STATUS_ERROR_OPERATION_FAILED;
+#endif
+ return GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_OPERATION;
+}
+
+GstVaapiFilterStatus
+gst_vaapi_filter_process(GstVaapiFilter *filter, GstVaapiSurface *src_surface,
+ GstVaapiSurface *dst_surface, guint flags)
+{
+ GstVaapiFilterStatus status;
+
+ g_return_val_if_fail(filter != NULL,
+ GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
+ g_return_val_if_fail(src_surface != NULL,
+ GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
+ g_return_val_if_fail(dst_surface != NULL,
+ GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
+
+ GST_VAAPI_DISPLAY_LOCK(filter->display);
+ status = gst_vaapi_filter_process_unlocked(filter,
+ src_surface, dst_surface, flags);
+ GST_VAAPI_DISPLAY_UNLOCK(filter->display);
+ return status;
+}
+
+/**
+ * gst_vaapi_filter_get_formats:
+ * @filter: a #GstVaapiFilter
+ *
+ * Determines the set of supported source or target formats for video
+ * processing. The caller owns an extra reference to the resulting
+ * array of #GstVideoFormat elements, so it shall be released with
+ * g_array_unref() after usage.
+ *
+ * Return value: the set of supported target formats for video processing.
+ */
+GArray *
+gst_vaapi_filter_get_formats(GstVaapiFilter *filter)
+{
+ g_return_val_if_fail(filter != NULL, NULL);
+
+ return ensure_formats(filter);
+}
+
+/**
+ * gst_vaapi_filter_set_format:
+ * @filter: a #GstVaapiFilter
+ * @format: the target surface format
+ *
+ * Sets the desired pixel format of the resulting video processing
+ * operations.
+ *
+ * If @format is #GST_VIDEO_FORMAT_UNKNOWN, the filter will assume iso
+ * format conversion, i.e. no color conversion at all and the target
+ * surface format shall match the source surface format.
+ *
+ * If @format is #GST_VIDEO_FORMAT_ENCODED, the filter will use the pixel
+ * format of the target surface passed to gst_vaapi_filter_process().
+ *
+ * Return value: %TRUE if the color conversion to the specified @format
+ * may be supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_format(GstVaapiFilter *filter, GstVideoFormat format)
+{
+ g_return_val_if_fail(filter != NULL, FALSE);
+
+ if (!ensure_formats(filter))
+ return FALSE;
+
+ if (!is_special_format(format) && !find_format(filter, format))
+ return FALSE;
+
+ filter->format = format;
+ return TRUE;
+}
diff --git a/gst-libs/gst/vaapi/gstvaapifilter.h b/gst-libs/gst/vaapi/gstvaapifilter.h
new file mode 100644
index 00000000..eb7d4f73
--- /dev/null
+++ b/gst-libs/gst/vaapi/gstvaapifilter.h
@@ -0,0 +1,104 @@
+/*
+ * gstvaapifilter.h - Video processing abstraction
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_FILTER_H
+#define GST_VAAPI_FILTER_H
+
+#include <gst/vaapi/gstvaapisurface.h>
+#include <gst/vaapi/video-format.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiFilter GstVaapiFilter;
+typedef struct _GstVaapiFilterOpInfo GstVaapiFilterOpInfo;
+
+/**
+ * @GST_VAAPI_FILTER_OP_FORMAT: Force output pixel format (#GstVideoFormat).
+ *
+ * The set of operations that could be applied to the filter.
+ */
+typedef enum {
+ GST_VAAPI_FILTER_OP_FORMAT = 1,
+} GstVaapiFilterOp;
+
+/**
+ * GstVaapiFilterOpInfo:
+ * @operation: the #GstVaapiFilterOp
+ * @pspec: the #GParamSpec describing the associated configurable value
+ *
+ * A #GstVaapiFilterOp descriptor.
+ */
+struct _GstVaapiFilterOpInfo {
+ const GstVaapiFilterOp op;
+ GParamSpec * const pspec;
+};
+
+/**
+ * GstVaapiFilterStatus:
+ * @GST_VAAPI_FILTER_STATUS_SUCCESS: Success.
+ * @GST_VAAPI_FILTER_STATUS_ERROR_ALLOCATION_FAILED: No memory left.
+ * @GST_VAAPI_FILTER_STATUS_ERROR_OPERATION_FAILED: Operation failed.
+ * @GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER: Invalid parameter.
+ * @GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_OPERATION: Unsupported operation.
+ * @GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_FORMAT: Unsupported target format.
+ *
+ * Video processing status for gst_vaapi_filter_process().
+ */
+typedef enum {
+ GST_VAAPI_FILTER_STATUS_SUCCESS = 0,
+ GST_VAAPI_FILTER_STATUS_ERROR_ALLOCATION_FAILED,
+ GST_VAAPI_FILTER_STATUS_ERROR_OPERATION_FAILED,
+ GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER,
+ GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_OPERATION,
+ GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_FORMAT,
+} GstVaapiFilterStatus;
+
+GstVaapiFilter *
+gst_vaapi_filter_new(GstVaapiDisplay *display);
+
+GstVaapiFilter *
+gst_vaapi_filter_ref(GstVaapiFilter *filter);
+
+void
+gst_vaapi_filter_unref(GstVaapiFilter *filter);
+
+void
+gst_vaapi_filter_replace(GstVaapiFilter **old_filter_ptr,
+ GstVaapiFilter *new_filter);
+
+GPtrArray *
+gst_vaapi_filter_get_operations(GstVaapiFilter *filter);
+
+gboolean
+gst_vaapi_filter_set_operation(GstVaapiFilter *filter, GstVaapiFilterOp op,
+ const GValue *value);
+
+GstVaapiFilterStatus
+gst_vaapi_filter_process(GstVaapiFilter *filter, GstVaapiSurface *src_surface,
+ GstVaapiSurface *dst_surface, guint flags);
+
+GArray *
+gst_vaapi_filter_get_formats(GstVaapiFilter *filter);
+
+gboolean
+gst_vaapi_filter_set_format(GstVaapiFilter *filter, GstVideoFormat format);
+
+#endif /* GST_VAAPI_FILTER_H */