Add initial infrastructure for video processing.

Add initial API for video processing: only scaling and color format
conversion operations are supported.
This commit is contained in:
Gwenole Beauchesne 2013-07-23 15:52:45 +02:00
parent f34b6ffc60
commit f09008a8d1
8 changed files with 995 additions and 0 deletions

View file

@ -615,6 +615,31 @@ AC_CACHE_CHECK([for JPEG decoding API],
LIBS="$saved_LIBS" 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 dnl VA/Wayland API
if test "$enable_wayland" = "yes"; then if test "$enable_wayland" = "yes"; then
PKG_CHECK_MODULES([LIBVA_WAYLAND], [libva-wayland >= va_api_wld_version], 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 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, AC_DEFINE_UNQUOTED(USE_JPEG_DECODER, $USE_JPEG_DECODER,
[Defined to 1 if JPEG decoder is used]) [Defined to 1 if JPEG decoder is used])
AM_CONDITIONAL(USE_JPEG_DECODER, test $USE_JPEG_DECODER -eq 1) AM_CONDITIONAL(USE_JPEG_DECODER, test $USE_JPEG_DECODER -eq 1)

View file

@ -34,6 +34,7 @@
<xi:include href="xml/gstvaapidecoder_h264.xml"/> <xi:include href="xml/gstvaapidecoder_h264.xml"/>
<xi:include href="xml/gstvaapidecoder_vc1.xml"/> <xi:include href="xml/gstvaapidecoder_vc1.xml"/>
<xi:include href="xml/gstvaapisurfaceproxy.xml"/> <xi:include href="xml/gstvaapisurfaceproxy.xml"/>
<xi:include href="xml/gstvaapifilter.xml"/>
</chapter> </chapter>
<chapter id="object-tree"> <chapter id="object-tree">

View file

@ -373,3 +373,19 @@ gst_vaapi_surface_proxy_unref
<SUBSECTION Standard> <SUBSECTION Standard>
GST_VAAPI_SURFACE_PROXY_SURFACE GST_VAAPI_SURFACE_PROXY_SURFACE
</SECTION> </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>

View file

@ -55,6 +55,7 @@ libgstvaapi_source_c = \
gstvaapidecoder_vc1.c \ gstvaapidecoder_vc1.c \
gstvaapidisplay.c \ gstvaapidisplay.c \
gstvaapidisplaycache.c \ gstvaapidisplaycache.c \
gstvaapifilter.c \
gstvaapiimage.c \ gstvaapiimage.c \
gstvaapiimagepool.c \ gstvaapiimagepool.c \
gstvaapiminiobject.c \ gstvaapiminiobject.c \

View file

@ -684,6 +684,18 @@ gst_vaapi_display_create(GstVaapiDisplay *display,
} }
append_h263_config(priv->decoders); 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 */ /* VA display attributes */
display_attrs = display_attrs =
g_new(VADisplayAttribute, vaMaxNumDisplayAttributes(priv->display)); g_new(VADisplayAttribute, vaMaxNumDisplayAttributes(priv->display));

View file

@ -116,6 +116,16 @@ typedef void (*GstVaapiDisplayGetSizeMFunc)(GstVaapiDisplay *display,
#define GST_VAAPI_DISPLAY_TYPES(display) \ #define GST_VAAPI_DISPLAY_TYPES(display) \
gst_vaapi_display_get_display_types(GST_VAAPI_DISPLAY_CAST(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 { struct _GstVaapiDisplayPrivate {
GstVaapiDisplay *parent; GstVaapiDisplay *parent;
GRecMutex mutex; GRecMutex mutex;
@ -133,6 +143,7 @@ struct _GstVaapiDisplayPrivate {
GArray *subpicture_formats; GArray *subpicture_formats;
GArray *properties; GArray *properties;
guint use_foreign_display : 1; guint use_foreign_display : 1;
guint has_vpp : 1;
}; };
/** /**

View file

@ -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;
}

View file

@ -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 */