Add initial infrastructure for video processing.
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Tue, 23 Jul 2013 13:52:45 +0000 (15:52 +0200)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Fri, 23 Aug 2013 17:00:38 +0000 (19:00 +0200)
Add initial API for video processing: only scaling and color format
conversion operations are supported.

configure.ac
docs/reference/libs/libs-docs.xml.in
docs/reference/libs/libs-sections.txt
gst-libs/gst/vaapi/Makefile.am
gst-libs/gst/vaapi/gstvaapidisplay.c
gst-libs/gst/vaapi/gstvaapidisplay_priv.h
gst-libs/gst/vaapi/gstvaapifilter.c [new file with mode: 0644]
gst-libs/gst/vaapi/gstvaapifilter.h [new file with mode: 0644]

index 837ea10..66828fd 100644 (file)
@@ -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)
index 1f7f840..45e05ea 100644 (file)
@@ -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">
index 91796d9..23a804f 100644 (file)
@@ -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>
index 3e0a02a..ab605e1 100644 (file)
@@ -55,6 +55,7 @@ libgstvaapi_source_c =                                \
        gstvaapidecoder_vc1.c                   \
        gstvaapidisplay.c                       \
        gstvaapidisplaycache.c                  \
+       gstvaapifilter.c                        \
        gstvaapiimage.c                         \
        gstvaapiimagepool.c                     \
        gstvaapiminiobject.c                    \
index 05833c8..ca8c6cb 100644 (file)
@@ -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));
index 8176820..1f7f46c 100644 (file)
@@ -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 (file)
index 0000000..ce8556e
--- /dev/null
@@ -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 (file)
index 0000000..eb7d4f7
--- /dev/null
@@ -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 */