diff options
author | Gwenole Beauchesne <gwenole.beauchesne@intel.com> | 2013-07-23 15:52:45 +0200 |
---|---|---|
committer | Gwenole Beauchesne <gwenole.beauchesne@intel.com> | 2013-08-23 19:00:38 +0200 |
commit | f09008a8d147950aa31fb342b3b8a105eadcf9a6 (patch) | |
tree | b45201e1c590021e499844d7a501b164ec981c7d | |
parent | f34b6ffc60bfb87f03873c2d8ec2bebcfd3a5768 (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.ac | 29 | ||||
-rw-r--r-- | docs/reference/libs/libs-docs.xml.in | 1 | ||||
-rw-r--r-- | docs/reference/libs/libs-sections.txt | 16 | ||||
-rw-r--r-- | gst-libs/gst/vaapi/Makefile.am | 1 | ||||
-rw-r--r-- | gst-libs/gst/vaapi/gstvaapidisplay.c | 12 | ||||
-rw-r--r-- | gst-libs/gst/vaapi/gstvaapidisplay_priv.h | 11 | ||||
-rw-r--r-- | gst-libs/gst/vaapi/gstvaapifilter.c | 821 | ||||
-rw-r--r-- | gst-libs/gst/vaapi/gstvaapifilter.h | 104 |
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 */ |