From e263c9542c4c779fdbbfbcf1693980966efcc410 Mon Sep 17 00:00:00 2001 From: Florent Revest Date: Fri, 5 Aug 2016 12:23:15 +0200 Subject: [PATCH] Adds a sunxi-cedrus-drv-video libVA backend This VA backend uses v4l2's Frame API proposal to interface with the "sunxi-cedrus" video driver on Allwinner SoC. Only a few parts of the code are really dependent on sunxi-cedrus and this VA backend could be reused for other v4l drivers using the Frame API. --- .gitignore | 45 ++++++ AUTHORS | 1 + COPYING | 19 +++ Makefile.am | 9 ++ README.md | 12 ++ autogen.sh | 7 + configure.ac | 118 +++++++++++++++ src/Makefile.am | 40 +++++ src/buffer.c | 196 ++++++++++++++++++++++++ src/buffer.h | 69 +++++++++ src/context.c | 167 +++++++++++++++++++++ src/context.h | 64 ++++++++ src/image.c | 138 +++++++++++++++++ src/image.h | 66 ++++++++ src/object_heap.c | 255 +++++++++++++++++++++++++++++++ src/object_heap.h | 93 ++++++++++++ src/picture.c | 190 +++++++++++++++++++++++ src/picture.h | 41 +++++ src/subpicture.c | 75 ++++++++++ src/subpicture.h | 65 ++++++++ src/sunxi_cedrus_drv_video.c | 197 ++++++++++++++++++++++++ src/sunxi_cedrus_drv_video.h | 59 ++++++++ src/surface.c | 281 +++++++++++++++++++++++++++++++++++ src/surface.h | 77 ++++++++++ src/tiled_yuv.S | 185 +++++++++++++++++++++++ src/tiled_yuv.h | 30 ++++ src/va_config.c | 226 ++++++++++++++++++++++++++++ src/va_config.h | 80 ++++++++++ 28 files changed, 2805 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 Makefile.am create mode 100644 README.md create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 src/Makefile.am create mode 100644 src/buffer.c create mode 100644 src/buffer.h create mode 100644 src/context.c create mode 100644 src/context.h create mode 100644 src/image.c create mode 100644 src/image.h create mode 100644 src/object_heap.c create mode 100644 src/object_heap.h create mode 100644 src/picture.c create mode 100644 src/picture.h create mode 100644 src/subpicture.c create mode 100644 src/subpicture.h create mode 100644 src/sunxi_cedrus_drv_video.c create mode 100644 src/sunxi_cedrus_drv_video.h create mode 100644 src/surface.c create mode 100644 src/surface.h create mode 100644 src/tiled_yuv.S create mode 100644 src/tiled_yuv.h create mode 100644 src/va_config.c create mode 100644 src/va_config.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..87d78a7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,45 @@ +# Object files +*.o +*.ko + +# Libraries +*.lib +*.a +*.lo +*.la + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Misc +*~ +*.orig +*.rej +*.loT +*.bin +*.pc +*.g[4-7]s +.deps +.libs +install-sh +libtool +ltmain.sh +compile +missing +Makefile +Makefile.in +config.h +config.h.in +stamp-h1 +aclocal.m4 +autom4te.cache +config.guess +config.log +config.status +config.sub +configure +depcomp +TAGS diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..092893d --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Florent Revest diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..b10ba00 --- /dev/null +++ b/COPYING @@ -0,0 +1,19 @@ +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..099031a --- /dev/null +++ b/Makefile.am @@ -0,0 +1,9 @@ +AUTOMAKE_OPTIONS = foreign + +SUBDIRS = src + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = \ + aclocal.m4 compile config.guess config.sub \ + configure depcomp install-sh ltmain.sh \ + Makefile.in missing diff --git a/README.md b/README.md new file mode 100644 index 0000000..328225e --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +Sunxi Cedrus VA backend +======================= + +This libVA video driver is designed to work with the v4l2 "sunxi-cedrus" kernel +driver. However, the only sunxi-cedrus specific part is the format conversion +from tiled to planar, otherwise it would be generic enough to be used with other +v4l2 drivers using the "Frame API". + +You can try this driver with VLC but don't forget to tell libVA to use this +backend: + + export LIBVA_DRIVER_NAME=sunxi_cedrus diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..f5164d8 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,7 @@ +#! /bin/sh + +autoreconf -v --install + +if test -z "$NOCONFIGURE"; then + ./configure "$@" +fi diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..ef6b368 --- /dev/null +++ b/configure.ac @@ -0,0 +1,118 @@ +# intel-driver package version number +m4_define([sunxi_cedrus_major_version], [1]) +m4_define([sunxi_cedrus_minor_version], [0]) +m4_define([sunxi_cedrus_micro_version], [0]) +m4_define([sunxi_cedrus_pre_version], [0]) +m4_define([sunxi_cedrus_version], + [sunxi_cedrus_major_version.sunxi_cedrus_minor_version.sunxi_cedrus_micro_version]) +m4_if(sunxi_cedrus_pre_version, [0], [], [ +m4_append([sunxi_cedrus_version], sunxi_cedrus_pre_version, [.pre]) +]) + +# libva minimum version requirement +m4_define([libva_package_version], [1.2.2]) +m4_define([va_api_version], [0.34.0]) + +# libdrm minimum version requirement +m4_define([libdrm_version], [2.4.45]) + +AC_PREREQ([2.60]) +AC_INIT([liva_wrapper], [sunxi_cedrus_version], + [florent.revest@free-electrons.com], [sunxi_cedrus]) +AC_CONFIG_SRCDIR([Makefile.am]) +AM_INIT_AUTOMAKE([1.9 tar-ustar]) + +AC_CONFIG_HEADERS([src/config.h]) + +SUNXI_CEDRUS_MAJOR_VERSION=sunxi_cedrus_major_version +SUNXI_CEDRUS_MINOR_VERSION=sunxi_cedrus_minor_version +SUNXI_CEDRUS_MICRO_VERSION=sunxi_cedrus_micro_version +AC_DEFINE([SUNXI_CEDRUS_MAJOR_VERSION], [sunxi_cedrus_major_version], [Major version of the driver]) +AC_DEFINE([SUNXI_CEDRUS_MINOR_VERSION], [sunxi_cedrus_minor_version], [Minor version of the driver]) +AC_DEFINE([SUNXI_CEDRUS_MICRO_VERSION], [sunxi_cedrus_micro_version], [Micro version of the driver]) +AC_DEFINE([SUNXI_CEDRUS_PRE_VERSION], [sunxi_cedrus_pre_version], [Preversion of the driver]) + +SUNXI_CEDRUS_LT_LDFLAGS="-avoid-version" +AC_SUBST(SUNXI_CEDRUS_LT_LDFLAGS) + +dnl Use pretty build output with automake >= 1.11 +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])], [ + AM_DEFAULT_VERBOSITY=1 + AC_SUBST(AM_DEFAULT_VERBOSITY) +]) + +AC_DISABLE_STATIC +AC_PROG_LIBTOOL +AC_PROG_CC +AM_PROG_CC_C_O +AM_PROG_AS + +AC_C_BIGENDIAN +AC_HEADER_STDC +AC_SYS_LARGEFILE +AC_CHECK_LIB([m], [sin]) + +LIBVA_PACKAGE_VERSION=libva_package_version +AC_SUBST(LIBVA_PACKAGE_VERSION) + +dnl Check for recent enough DRM +LIBDRM_VERSION=libdrm_version +PKG_CHECK_MODULES([DRM], [libdrm >= $LIBDRM_VERSION]) +AC_SUBST(LIBDRM_VERSION) + +dnl Check for gen4asm +PKG_CHECK_MODULES(GEN4ASM, [intel-gen4asm >= 1.3], [gen4asm=yes], [gen4asm=no]) +AM_CONDITIONAL(HAVE_GEN4ASM, test x$gen4asm = xyes) +AC_PATH_PROG([GEN4ASM], [intel-gen4asm]) + +dnl Check for VA-API +PKG_CHECK_MODULES(LIBVA_DEPS, [libva >= va_api_version]) +PKG_CHECK_MODULES(X11_DEPS, [x11]) + +dnl Check for VA/DRM API +PKG_CHECK_MODULES(LIBVA_DRM_DEPS, [libva-drm], + [AC_DEFINE([HAVE_VA_DRM], [1], [Defined to 1 if VA/DRM API is enabled])], + [USE_DRM="no"]) + +# Check for +if test "$USE_DRM" = "yes"; then + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $DRM_CFLAGS" + AC_CHECK_HEADERS([drm_fourcc.h], [:], [USE_DRM="no"]) + CPPFLAGS="$saved_CPPFLAGS" +fi + +VA_VERSION=`$PKG_CONFIG --modversion libva` +VA_MAJOR_VERSION=`echo "$VA_VERSION" | cut -d'.' -f1` +VA_MINOR_VERSION=`echo "$VA_VERSION" | cut -d'.' -f2` +VA_MICRO_VERSION=`echo "$VA_VERSION" | cut -d'.' -f3` +VA_VERSION_STR="$VA_VERSION" + +va_full_version_int=`expr ${VA_MAJOR_VERSION:-0} "*" 1000000 + \ + ${VA_MINOR_VERSION:-0} "*" 10000 + \ + ${VA_MICRO_VERSION:-0} "*" 100 + \ + 0` +VA_DRIVER_INIT_FUNC="__vaDriverInit_${VA_MAJOR_VERSION}_${VA_MINOR_VERSION}" +AC_DEFINE_UNQUOTED([VA_DRIVER_INIT_FUNC], [$VA_DRIVER_INIT_FUNC], + [Define driver entry-point]) + +dnl Check for VA-API drivers path +AC_MSG_CHECKING([for VA drivers path]) +LIBVA_DRIVERS_PATH=`$PKG_CONFIG libva --variable driverdir` +if test -z "$LIBVA_DRIVERS_PATH"; then + LIBVA_DRIVERS_PATH="/usr/lib/dri/" +fi +AC_MSG_RESULT([$LIBVA_DRIVERS_PATH]) +AC_SUBST(LIBVA_DRIVERS_PATH) + +AC_OUTPUT([ + Makefile + src/Makefile +]) + +echo +echo $PACKAGE configuration summary: +echo +echo VA-API version ................... : $VA_VERSION_STR +echo VA-API drivers path .............. : $LIBVA_DRIVERS_PATH +echo diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..542702d --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,40 @@ +AM_CPPFLAGS = \ + -DPTHREADS \ + $(X11_DEPS_CFLAGS)\ + $(DRM_CFLAGS) \ + $(LIBVA_DEPS_CFLAGS) + +driver_cflags = \ + -Wall \ + -fvisibility=hidden + +driver_ldflags = \ + -module -avoid-version \ + -no-undefined \ + -Wl,--no-undefined + +driver_libs = \ + -lpthread -ldl \ + $(DRM_LIBS) \ + $(X11_DEPS_LIBS) \ + $(LIBVA_DEPS_LIBS) + +source_c = sunxi_cedrus_drv_video.c object_heap.c buffer.c va_config.c \ + context.c image.c picture.c subpicture.c surface.c + +source_s = \ + tiled_yuv.S + +source_h = sunxi_cedrus_drv_video.h object_heap.h buffer.h va_config.h \ + context.h image.h picture.h subpicture.h surface.h \ + tiled_yuv.h + +sunxi_cedrus_drv_video_la_LTLIBRARIES = sunxi_cedrus_drv_video.la +sunxi_cedrus_drv_video_ladir = $(LIBVA_DRIVERS_PATH) +sunxi_cedrus_drv_video_la_CFLAGS = $(driver_cflags) +sunxi_cedrus_drv_video_la_LDFLAGS = $(driver_ldflags) +sunxi_cedrus_drv_video_la_LIBADD = $(driver_libs) +sunxi_cedrus_drv_video_la_SOURCES = $(source_c) $(source_s) +noinst_HEADERS = $(source_h) + +MAINTAINERCLEANFILES = Makefile.in config.h.in diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 0000000..72a2b5d --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "sunxi_cedrus_drv_video.h" +#include "buffer.h" +#include "context.h" + +#include +#include +#include + +#include +#include + +#include + +/* + * A Buffer is a memory zone used to handle all kind of data, for example an IQ + * matrix or image buffer (which are allocated using realloc) or slice data + * (which are mmapped from v4l's kernel space) + */ + +VAStatus sunxi_cedrus_CreateBuffer(VADriverContextP ctx, VAContextID context, + VABufferType type, unsigned int size, unsigned int num_elements, + void *data, VABufferID *buf_id) +{ + INIT_DRIVER_DATA + VAStatus vaStatus = VA_STATUS_SUCCESS; + int bufferID; + struct v4l2_plane plane[1]; + object_buffer_p obj_buffer; + + /* Validate type */ + switch (type) + { + case VAPictureParameterBufferType: + case VAIQMatrixBufferType: /* Ignored */ + case VASliceParameterBufferType: + case VASliceDataBufferType: + case VAImageBufferType: + /* Ok */ + break; + default: + vaStatus = VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE; + return vaStatus; + } + + bufferID = object_heap_allocate(&driver_data->buffer_heap); + obj_buffer = BUFFER(bufferID); + if (NULL == obj_buffer) + { + vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED; + return vaStatus; + } + + obj_buffer->buffer_data = NULL; + obj_buffer->type = type; + + if(obj_buffer->type == VASliceDataBufferType) { + object_context_p obj_context; + + obj_context = CONTEXT(context); + assert(obj_context); + + struct v4l2_buffer buf; + memset(&(buf), 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = obj_context->num_rendered_surfaces%INPUT_BUFFERS_NB; + buf.length = 1; + buf.m.planes = plane; + + assert(ioctl(driver_data->mem2mem_fd, VIDIOC_QUERYBUF, &buf)==0); + + obj_buffer->buffer_data = mmap(NULL, size * num_elements, + PROT_READ | PROT_WRITE, MAP_SHARED, + driver_data->mem2mem_fd, buf.m.planes[0].m.mem_offset); + } else + obj_buffer->buffer_data = realloc(obj_buffer->buffer_data, size * num_elements); + + if (obj_buffer->buffer_data == NULL) + return VA_STATUS_ERROR_ALLOCATION_FAILED; + + if (VA_STATUS_SUCCESS == vaStatus) + { + obj_buffer->max_num_elements = num_elements; + obj_buffer->num_elements = num_elements; + obj_buffer->size = size; + + if (data) + memcpy(obj_buffer->buffer_data, data, + size * num_elements); + } + + if (VA_STATUS_SUCCESS == vaStatus) + *buf_id = bufferID; + + return vaStatus; +} + +VAStatus sunxi_cedrus_BufferSetNumElements(VADriverContextP ctx, + VABufferID buf_id, unsigned int num_elements) +{ + INIT_DRIVER_DATA + VAStatus vaStatus = VA_STATUS_SUCCESS; + object_buffer_p obj_buffer = BUFFER(buf_id); + assert(obj_buffer); + + if ((num_elements < 0) || (num_elements > obj_buffer->max_num_elements)) + vaStatus = VA_STATUS_ERROR_UNKNOWN; + if (VA_STATUS_SUCCESS == vaStatus) + obj_buffer->num_elements = num_elements; + + return vaStatus; +} + +VAStatus sunxi_cedrus_MapBuffer(VADriverContextP ctx, VABufferID buf_id, + void **pbuf) +{ + INIT_DRIVER_DATA + VAStatus vaStatus = VA_STATUS_ERROR_UNKNOWN; + object_buffer_p obj_buffer = BUFFER(buf_id); + assert(obj_buffer); + if (NULL == obj_buffer) + { + vaStatus = VA_STATUS_ERROR_INVALID_BUFFER; + return vaStatus; + } + + if (NULL != obj_buffer->buffer_data) + { + *pbuf = obj_buffer->buffer_data; + vaStatus = VA_STATUS_SUCCESS; + } + return vaStatus; +} + +VAStatus sunxi_cedrus_UnmapBuffer(VADriverContextP ctx, VABufferID buf_id) +{ + /* Do nothing */ + return VA_STATUS_SUCCESS; +} + +void sunxi_cedrus_destroy_buffer(struct sunxi_cedrus_driver_data *driver_data, + object_buffer_p obj_buffer) +{ + if (NULL != obj_buffer->buffer_data) + { + if(obj_buffer->type == VASliceDataBufferType) + munmap(obj_buffer->buffer_data, obj_buffer->size); + else + free(obj_buffer->buffer_data); + + obj_buffer->buffer_data = NULL; + } + + object_heap_free(&driver_data->buffer_heap, (object_base_p) obj_buffer); +} + +VAStatus sunxi_cedrus_DestroyBuffer(VADriverContextP ctx, VABufferID buffer_id) +{ + INIT_DRIVER_DATA + object_buffer_p obj_buffer = BUFFER(buffer_id); + assert(obj_buffer); + + sunxi_cedrus_destroy_buffer(driver_data, obj_buffer); + return VA_STATUS_SUCCESS; +} + +/* sunxi-cedrus doesn't support buffer info */ +VAStatus sunxi_cedrus_BufferInfo(VADriverContextP ctx, VABufferID buf_id, + VABufferType *type, unsigned int *size, + unsigned int *num_elements) +{ return VA_STATUS_ERROR_UNIMPLEMENTED; } diff --git a/src/buffer.h b/src/buffer.h new file mode 100644 index 0000000..e39c238 --- /dev/null +++ b/src/buffer.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _BUFFER_H_ +#define _BUFFER_H_ + +#include + +#include "object_heap.h" +#include "sunxi_cedrus_drv_video.h" + +#define BUFFER(id) ((object_buffer_p) object_heap_lookup(&driver_data->buffer_heap, id)) +#define BUFFER_ID_OFFSET 0x08000000 + +struct object_buffer { + struct object_base base; + void *buffer_data; + int max_num_elements; + int num_elements; + VABufferType type; + unsigned int size; +}; + +typedef struct object_buffer *object_buffer_p; + +VAStatus sunxi_cedrus_CreateBuffer(VADriverContextP ctx, VAContextID context, + VABufferType type, unsigned int size, unsigned int num_elements, + void *data, VABufferID *buf_id); + +VAStatus sunxi_cedrus_BufferSetNumElements(VADriverContextP ctx, + VABufferID buf_id, unsigned int num_elements); + +VAStatus sunxi_cedrus_MapBuffer(VADriverContextP ctx, VABufferID buf_id, + void **pbuf); + +VAStatus sunxi_cedrus_UnmapBuffer(VADriverContextP ctx, VABufferID buf_id); + +void sunxi_cedrus_destroy_buffer(struct sunxi_cedrus_driver_data *driver_data, + object_buffer_p obj_buffer); + +VAStatus sunxi_cedrus_DestroyBuffer(VADriverContextP ctx, VABufferID buffer_id); + +VAStatus sunxi_cedrus_BufferInfo(VADriverContextP ctx, VABufferID buf_id, + VABufferType *type, unsigned int *size, + unsigned int *num_elements); + +#endif /* _BUFFER_H_ */ diff --git a/src/context.c b/src/context.c new file mode 100644 index 0000000..1e149de --- /dev/null +++ b/src/context.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "sunxi_cedrus_drv_video.h" +#include "context.h" +#include "va_config.h" +#include "surface.h" + +#include +#include + +#include + +#include + +#include + +/* + * A Context is a global data structure used for rendering a video of a certain + * format. When a context is created, input buffers are created and v4l's output + * (which is the compressed data input queue, since capture is the real output) + * format is set. + */ + +VAStatus sunxi_cedrus_CreateContext(VADriverContextP ctx, VAConfigID config_id, + int picture_width, int picture_height, int flag, + VASurfaceID *render_targets, int num_render_targets, + VAContextID *context) +{ + INIT_DRIVER_DATA + VAStatus vaStatus = VA_STATUS_SUCCESS; + object_config_p obj_config; + int i; + struct v4l2_create_buffers create_bufs; + struct v4l2_format fmt; + enum v4l2_buf_type type; + + obj_config = CONFIG(config_id); + if (NULL == obj_config) + { + vaStatus = VA_STATUS_ERROR_INVALID_CONFIG; + return vaStatus; + } + + int contextID = object_heap_allocate(&driver_data->context_heap); + object_context_p obj_context = CONTEXT(contextID); + if (NULL == obj_context) + { + vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED; + return vaStatus; + } + + obj_context->context_id = contextID; + *context = contextID; + obj_context->current_render_target = -1; + obj_context->config_id = config_id; + obj_context->picture_width = picture_width; + obj_context->picture_height = picture_height; + obj_context->num_render_targets = num_render_targets; + obj_context->render_targets = (VASurfaceID *) malloc(num_render_targets * sizeof(VASurfaceID)); + obj_context->num_rendered_surfaces = 0; + + if (obj_context->render_targets == NULL) + { + vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED; + return vaStatus; + } + + for(i = 0; i < num_render_targets; i++) + { + if (NULL == SURFACE(render_targets[i])) + { + vaStatus = VA_STATUS_ERROR_INVALID_SURFACE; + break; + } + obj_context->render_targets[i] = render_targets[i]; + } + obj_context->flags = flag; + + /* Error recovery */ + if (VA_STATUS_SUCCESS != vaStatus) + { + obj_context->context_id = -1; + obj_context->config_id = -1; + free(obj_context->render_targets); + obj_context->render_targets = NULL; + obj_context->num_render_targets = 0; + obj_context->flags = 0; + object_heap_free(&driver_data->context_heap, (object_base_p) obj_context); + } + + memset(&(fmt), 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.width = picture_width; + fmt.fmt.pix_mp.height = picture_height; + fmt.fmt.pix_mp.plane_fmt[0].sizeimage = INPUT_BUFFER_MAX_SIZE; + switch(obj_config->profile) { + default: + vaStatus = VA_STATUS_ERROR_UNSUPPORTED_PROFILE; + return vaStatus; + break; + } + fmt.fmt.pix_mp.field = V4L2_FIELD_ANY; + fmt.fmt.pix_mp.num_planes = 1; + assert(ioctl(driver_data->mem2mem_fd, VIDIOC_S_FMT, &fmt)==0); + + memset (&create_bufs, 0, sizeof (struct v4l2_create_buffers)); + create_bufs.count = INPUT_BUFFERS_NB; + create_bufs.memory = V4L2_MEMORY_MMAP; + create_bufs.format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + assert(ioctl(driver_data->mem2mem_fd, VIDIOC_G_FMT, &create_bufs.format)==0); + assert(ioctl(driver_data->mem2mem_fd, VIDIOC_CREATE_BUFS, &create_bufs)==0); + + type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + assert(ioctl(driver_data->mem2mem_fd, VIDIOC_STREAMON, &type)==0); + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + assert(ioctl(driver_data->mem2mem_fd, VIDIOC_STREAMON, &type)==0); + + return vaStatus; +} + +VAStatus sunxi_cedrus_DestroyContext(VADriverContextP ctx, VAContextID context) +{ + INIT_DRIVER_DATA + object_context_p obj_context = CONTEXT(context); + assert(obj_context); + + obj_context->context_id = -1; + obj_context->config_id = -1; + obj_context->picture_width = 0; + obj_context->picture_height = 0; + if (obj_context->render_targets) + free(obj_context->render_targets); + obj_context->render_targets = NULL; + obj_context->num_render_targets = 0; + obj_context->flags = 0; + + obj_context->current_render_target = -1; + + object_heap_free(&driver_data->context_heap, (object_base_p) obj_context); + + return VA_STATUS_SUCCESS; +} + diff --git a/src/context.h b/src/context.h new file mode 100644 index 0000000..d4922b1 --- /dev/null +++ b/src/context.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _CONTEXT_H_ +#define _CONTEXT_H_ + +#include + +#include "object_heap.h" + +/* We can't dynamically call VIDIOC_REQBUFS for every MPEG slice we create. + * Indeed, the queue might be busy processing a previous buffer, so we need to + * pre-allocate a set of buffers with a max size */ +#define INPUT_BUFFER_MAX_SIZE 131072 +#define INPUT_BUFFERS_NB 4 + +#define CONTEXT(id) ((object_context_p) object_heap_lookup(&driver_data->context_heap, id)) +#define CONTEXT_ID_OFFSET 0x02000000 + +struct object_context { + struct object_base base; + VAContextID context_id; + VAConfigID config_id; + VASurfaceID current_render_target; + int picture_width; + int picture_height; + int num_render_targets; + int flags; + VASurfaceID *render_targets; + uint32_t num_rendered_surfaces; +}; + +typedef struct object_context *object_context_p; + +VAStatus sunxi_cedrus_CreateContext(VADriverContextP ctx, VAConfigID config_id, + int picture_width, int picture_height, int flag, + VASurfaceID *render_targets, int num_render_targets, + VAContextID *context); + +VAStatus sunxi_cedrus_DestroyContext(VADriverContextP ctx, VAContextID context); + +#endif /* _CONTEXT_H_ */ diff --git a/src/image.c b/src/image.c new file mode 100644 index 0000000..8528836 --- /dev/null +++ b/src/image.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "sunxi_cedrus_drv_video.h" +#include "image.h" +#include "surface.h" +#include "buffer.h" + +#include + +#include "tiled_yuv.h" + +/* + * An Image is a standard data structure containing rendered frames in a usable + * pixel format. Here we only use NV12 buffers which are converted from sunxi's + * proprietary tiled pixel format with tiled_yuv when deriving an Image from a + * Surface. + */ + +VAStatus sunxi_cedrus_QueryImageFormats(VADriverContextP ctx, + VAImageFormat *format_list, int *num_formats) +{ + format_list[0].fourcc = VA_FOURCC_NV12; + *num_formats = 1; + return VA_STATUS_SUCCESS; +} + +VAStatus sunxi_cedrus_CreateImage(VADriverContextP ctx, VAImageFormat *format, + int width, int height, VAImage *image) +{ + INIT_DRIVER_DATA + int sizeY, sizeUV; + object_image_p obj_img; + + image->format = *format; + image->buf = VA_INVALID_ID; + image->width = width; + image->height = height; + + sizeY = image->width * image->height; + sizeUV = ((image->width+1) * (image->height+1)/2); + + image->num_planes = 2; + image->pitches[0] = (image->width+31)&~31; + image->pitches[1] = (image->width+31)&~31; + image->offsets[0] = 0; + image->offsets[1] = sizeY; + image->data_size = sizeY + sizeUV; + + image->image_id = object_heap_allocate(&driver_data->image_heap); + if (image->image_id == VA_INVALID_ID) + return VA_STATUS_ERROR_ALLOCATION_FAILED; + obj_img = IMAGE(image->image_id); + + if (sunxi_cedrus_CreateBuffer(ctx, 0, VAImageBufferType, image->data_size, + 1, NULL, &image->buf) != VA_STATUS_SUCCESS) + return VA_STATUS_ERROR_ALLOCATION_FAILED; + obj_img->buf = image->buf; + + return VA_STATUS_SUCCESS; +} + +VAStatus sunxi_cedrus_DeriveImage(VADriverContextP ctx, VASurfaceID surface, + VAImage *image) +{ + INIT_DRIVER_DATA + object_surface_p obj_surface; + VAImageFormat fmt; + object_buffer_p obj_buffer; + VAStatus ret; + + obj_surface = SURFACE(surface); + fmt.fourcc = VA_FOURCC_NV12; + + ret = sunxi_cedrus_CreateImage(ctx, &fmt, obj_surface->width, + obj_surface->height, image); + if(ret != VA_STATUS_SUCCESS) + return ret; + + obj_buffer = BUFFER(image->buf); + if (NULL == obj_buffer) + return VA_STATUS_ERROR_ALLOCATION_FAILED; + + /* TODO: Use an appropriate DRM plane instead */ + tiled_to_planar(driver_data->luma_bufs[obj_surface->output_buf_index], obj_buffer->buffer_data, image->pitches[0], image->width, image->height); + tiled_to_planar(driver_data->chroma_bufs[obj_surface->output_buf_index], obj_buffer->buffer_data + image->width*image->height, image->pitches[1], image->width, image->height/2); + + return VA_STATUS_SUCCESS; +} + +VAStatus sunxi_cedrus_DestroyImage(VADriverContextP ctx, VAImageID image) +{ + INIT_DRIVER_DATA + object_image_p obj_img; + + obj_img = IMAGE(image); + assert(obj_img); + + sunxi_cedrus_DestroyBuffer(ctx, obj_img->buf); + return VA_STATUS_SUCCESS; +} + +VAStatus sunxi_cedrus_SetImagePalette(VADriverContextP ctx, VAImageID image, + unsigned char *palette) +{ return VA_STATUS_SUCCESS; } + +VAStatus sunxi_cedrus_GetImage(VADriverContextP ctx, VASurfaceID surface, + int x, int y, unsigned int width, unsigned int height, + VAImageID image) +{ return VA_STATUS_SUCCESS; } + +VAStatus sunxi_cedrus_PutImage(VADriverContextP ctx, VASurfaceID surface, + VAImageID image, int src_x, int src_y, unsigned int src_width, + unsigned int src_height, int dest_x, int dest_y, + unsigned int dest_width, unsigned int dest_height) +{ return VA_STATUS_SUCCESS; } diff --git a/src/image.h b/src/image.h new file mode 100644 index 0000000..def3ccb --- /dev/null +++ b/src/image.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _IMAGE_H_ +#define _IMAGE_H_ + +#include + +#include "object_heap.h" + +#define IMAGE(id) ((object_image_p) object_heap_lookup(&driver_data->image_heap, id)) +#define IMAGE_ID_OFFSET 0x10000000 + +struct object_image { + struct object_base base; + VABufferID buf; +}; + +typedef struct object_image *object_image_p; + +VAStatus sunxi_cedrus_QueryImageFormats(VADriverContextP ctx, + VAImageFormat *format_list, int *num_formats); + +VAStatus sunxi_cedrus_CreateImage(VADriverContextP ctx, VAImageFormat *format, + int width, int height, VAImage *image); + +VAStatus sunxi_cedrus_DeriveImage(VADriverContextP ctx, VASurfaceID surface, + VAImage *image); + +VAStatus sunxi_cedrus_DestroyImage(VADriverContextP ctx, VAImageID image); + +VAStatus sunxi_cedrus_SetImagePalette(VADriverContextP ctx, VAImageID image, + unsigned char *palette); + +VAStatus sunxi_cedrus_GetImage(VADriverContextP ctx, VASurfaceID surface, + int x, int y, unsigned int width, unsigned int height, + VAImageID image); + +VAStatus sunxi_cedrus_PutImage(VADriverContextP ctx, VASurfaceID surface, + VAImageID image, int src_x, int src_y, unsigned int src_width, + unsigned int src_height, int dest_x, int dest_y, + unsigned int dest_width, unsigned int dest_height); + +#endif /* _IMAGE_H_ */ diff --git a/src/object_heap.c b/src/object_heap.c new file mode 100644 index 0000000..bc5998f --- /dev/null +++ b/src/object_heap.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include "object_heap.h" + +#define ASSERT assert + +#define LAST_FREE -1 +#define ALLOCATED -2 + +/* + * Expands the heap + * Return 0 on success, -1 on error + */ +static int object_heap_expand(object_heap_p heap) +{ + int i; + void *new_heap_index; + int next_free; + int new_heap_size = heap->heap_size + heap->heap_increment; + int bucket_index = new_heap_size / heap->heap_increment - 1; + + if (bucket_index >= heap->num_buckets) { + int new_num_buckets = heap->num_buckets + 8; + void **new_bucket; + + new_bucket = realloc(heap->bucket, new_num_buckets * sizeof(void *)); + if (NULL == new_bucket) { + return -1; + } + + heap->num_buckets = new_num_buckets; + heap->bucket = new_bucket; + } + + new_heap_index = (void *) malloc(heap->heap_increment * heap->object_size); + if (NULL == new_heap_index) { + return -1; /* Out of memory */ + } + + heap->bucket[bucket_index] = new_heap_index; + next_free = heap->next_free; + for (i = new_heap_size; i-- > heap->heap_size;) { + object_base_p obj = (object_base_p)(new_heap_index + (i - heap->heap_size) * heap->object_size); + obj->id = i + heap->id_offset; + obj->next_free = next_free; + next_free = i; + } + heap->next_free = next_free; + heap->heap_size = new_heap_size; + return 0; /* Success */ +} + +/* + * Return 0 on success, -1 on error + */ +int object_heap_init(object_heap_p heap, int object_size, int id_offset) +{ + pthread_mutex_init(&heap->mutex, NULL); + heap->object_size = object_size; + heap->id_offset = id_offset & OBJECT_HEAP_OFFSET_MASK; + heap->heap_size = 0; + heap->heap_increment = 16; + heap->next_free = LAST_FREE; + heap->num_buckets = 0; + heap->bucket = NULL; + return object_heap_expand(heap); +} + +/* + * Allocates an object + * Returns the object ID on success, returns -1 on error + */ +static int object_heap_allocate_unlocked(object_heap_p heap) +{ + object_base_p obj; + int bucket_index, obj_index; + + if (LAST_FREE == heap->next_free) { + if (-1 == object_heap_expand(heap)) { + return -1; /* Out of memory */ + } + } + ASSERT(heap->next_free >= 0); + + bucket_index = heap->next_free / heap->heap_increment; + obj_index = heap->next_free % heap->heap_increment; + + obj = (object_base_p)(heap->bucket[bucket_index] + obj_index * heap->object_size); + heap->next_free = obj->next_free; + obj->next_free = ALLOCATED; + return obj->id; +} + +int object_heap_allocate(object_heap_p heap) +{ + int ret; + + pthread_mutex_lock(&heap->mutex); + ret = object_heap_allocate_unlocked(heap); + pthread_mutex_unlock(&heap->mutex); + return ret; +} + +/* + * Lookup an object by object ID + * Returns a pointer to the object on success, returns NULL on error + */ +static object_base_p object_heap_lookup_unlocked(object_heap_p heap, int id) +{ + object_base_p obj; + int bucket_index, obj_index; + + if ((id < heap->id_offset) || (id > (heap->heap_size + heap->id_offset))) { + return NULL; + } + id &= OBJECT_HEAP_ID_MASK; + bucket_index = id / heap->heap_increment; + obj_index = id % heap->heap_increment; + obj = (object_base_p)(heap->bucket[bucket_index] + obj_index * heap->object_size); + + /* Check if the object has in fact been allocated */ + if (obj->next_free != ALLOCATED) { + return NULL; + } + return obj; +} + +object_base_p object_heap_lookup(object_heap_p heap, int id) +{ + object_base_p obj; + + pthread_mutex_lock(&heap->mutex); + obj = object_heap_lookup_unlocked(heap, id); + pthread_mutex_unlock(&heap->mutex); + return obj; +} + +/* + * Iterate over all objects in the heap. + * Returns a pointer to the first object on the heap, returns NULL if heap is empty. + */ +object_base_p object_heap_first(object_heap_p heap, object_heap_iterator *iter) +{ + *iter = -1; + return object_heap_next(heap, iter); +} + +/* + * Iterate over all objects in the heap. + * Returns a pointer to the next object on the heap, returns NULL if heap is empty. + */ +static object_base_p object_heap_next_unlocked(object_heap_p heap, object_heap_iterator *iter) +{ + object_base_p obj; + int bucket_index, obj_index; + int i = *iter + 1; + + while (i < heap->heap_size) { + bucket_index = i / heap->heap_increment; + obj_index = i % heap->heap_increment; + + obj = (object_base_p)(heap->bucket[bucket_index] + obj_index * heap->object_size); + if (obj->next_free == ALLOCATED) { + *iter = i; + return obj; + } + i++; + } + *iter = i; + return NULL; +} + +object_base_p object_heap_next(object_heap_p heap, object_heap_iterator *iter) +{ + object_base_p obj; + + pthread_mutex_lock(&heap->mutex); + obj = object_heap_next_unlocked(heap, iter); + pthread_mutex_unlock(&heap->mutex); + return obj; +} + +/* + * Frees an object + */ +static void object_heap_free_unlocked(object_heap_p heap, object_base_p obj) +{ + /* Check if the object has in fact been allocated */ + ASSERT(obj->next_free == ALLOCATED); + + obj->next_free = heap->next_free; + heap->next_free = obj->id & OBJECT_HEAP_ID_MASK; +} + +void object_heap_free(object_heap_p heap, object_base_p obj) +{ + if (!obj) + return; + pthread_mutex_lock(&heap->mutex); + object_heap_free_unlocked(heap, obj); + pthread_mutex_unlock(&heap->mutex); +} + +/* + * Destroys a heap, the heap must be empty. + */ +void object_heap_destroy(object_heap_p heap) +{ + object_base_p obj; + int bucket_index, obj_index, i; + + /* Check if heap is empty */ + for (i = 0; i < heap->heap_size; i++) { + /* Check if object is not still allocated */ + bucket_index = i / heap->heap_increment; + obj_index = i % heap->heap_increment; + obj = (object_base_p)(heap->bucket[bucket_index] + obj_index * heap->object_size); + ASSERT(obj->next_free != ALLOCATED); + } + + for (i = 0; i < heap->heap_size / heap->heap_increment; i++) { + free(heap->bucket[i]); + } + + pthread_mutex_destroy(&heap->mutex); + + free(heap->bucket); + heap->bucket = NULL; + heap->heap_size = 0; + heap->next_free = LAST_FREE; +} diff --git a/src/object_heap.h b/src/object_heap.h new file mode 100644 index 0000000..adf2804 --- /dev/null +++ b/src/object_heap.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef OBJECT_HEAP_H +#define OBJECT_HEAP_H + +#include + +#define OBJECT_HEAP_OFFSET_MASK 0x7F000000 +#define OBJECT_HEAP_ID_MASK 0x00FFFFFF + +typedef struct object_base *object_base_p; +typedef struct object_heap *object_heap_p; + +struct object_base { + int id; + int next_free; +}; + +struct object_heap { + pthread_mutex_t mutex; + int object_size; + int id_offset; + int next_free; + int heap_size; + int heap_increment; + void **bucket; + int num_buckets; +}; + +typedef int object_heap_iterator; + +/* + * Return 0 on success, -1 on error + */ +int object_heap_init(object_heap_p heap, int object_size, int id_offset); + +/* + * Allocates an object + * Returns the object ID on success, returns -1 on error + */ +int object_heap_allocate(object_heap_p heap); + +/* + * Lookup an allocated object by object ID + * Returns a pointer to the object on success, returns NULL on error + */ +object_base_p object_heap_lookup(object_heap_p heap, int id); + +/* + * Iterate over all objects in the heap. + * Returns a pointer to the first object on the heap, returns NULL if heap is empty. + */ +object_base_p object_heap_first(object_heap_p heap, object_heap_iterator *iter); + +/* + * Iterate over all objects in the heap. + * Returns a pointer to the next object on the heap, returns NULL if heap is empty. + */ +object_base_p object_heap_next(object_heap_p heap, object_heap_iterator *iter); + +/* + * Frees an object + */ +void object_heap_free(object_heap_p heap, object_base_p obj); + +/* + * Destroys a heap, the heap must be empty. + */ +void object_heap_destroy(object_heap_p heap); + +#endif /* OBJECT_HEAP_H */ diff --git a/src/picture.c b/src/picture.c new file mode 100644 index 0000000..aa4d535 --- /dev/null +++ b/src/picture.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "sunxi_cedrus_drv_video.h" +#include "picture.h" +#include "buffer.h" +#include "context.h" +#include "surface.h" +#include "va_config.h" + +#include +#include + +#include + +#include + +#include + +/* + * A Picture is an encoded input frame made of several buffers. A single input + * can contain slice data, headers and IQ matrix. Each Picture is assigned a + * request ID when created and each corresponding buffer might be turned into a + * v4l buffers or extended control when rendered. Finally they are submitted to + * kernel space when reaching EndPicture. + */ + +VAStatus sunxi_cedrus_BeginPicture(VADriverContextP ctx, VAContextID context, + VASurfaceID render_target) +{ + INIT_DRIVER_DATA + VAStatus vaStatus = VA_STATUS_SUCCESS; + object_context_p obj_context; + object_surface_p obj_surface; + + obj_context = CONTEXT(context); + assert(obj_context); + + obj_surface = SURFACE(render_target); + assert(obj_surface); + + if(obj_surface->status == VASurfaceRendering) + sunxi_cedrus_SyncSurface(ctx, render_target); + + obj_surface->status = VASurfaceRendering; + obj_surface->request = (obj_context->num_rendered_surfaces)%INPUT_BUFFERS_NB+1; + obj_surface->input_buf_index = obj_context->num_rendered_surfaces%INPUT_BUFFERS_NB; + obj_context->num_rendered_surfaces ++; + + obj_context->current_render_target = obj_surface->base.id; + + return vaStatus; +} + +VAStatus sunxi_cedrus_RenderPicture(VADriverContextP ctx, VAContextID context, + VABufferID *buffers, int num_buffers) +{ + INIT_DRIVER_DATA + VAStatus vaStatus = VA_STATUS_SUCCESS; + object_context_p obj_context; + object_surface_p obj_surface; + object_config_p obj_config; + int i; + + obj_context = CONTEXT(context); + assert(obj_context); + + obj_config = CONFIG(obj_context->config_id); + if (NULL == obj_config) + { + vaStatus = VA_STATUS_ERROR_INVALID_CONFIG; + return vaStatus; + } + + obj_surface = SURFACE(obj_context->current_render_target); + assert(obj_surface); + + /* verify that we got valid buffer references */ + for(i = 0; i < num_buffers; i++) + { + object_buffer_p obj_buffer = BUFFER(buffers[i]); + assert(obj_buffer); + if (NULL == obj_buffer) + { + vaStatus = VA_STATUS_ERROR_INVALID_BUFFER; + break; + } + } + + return vaStatus; +} + +VAStatus sunxi_cedrus_EndPicture(VADriverContextP ctx, VAContextID context) +{ + INIT_DRIVER_DATA + VAStatus vaStatus = VA_STATUS_SUCCESS; + object_context_p obj_context; + object_surface_p obj_surface; + struct v4l2_buffer out_buf, cap_buf; + struct v4l2_plane plane[1]; + struct v4l2_plane planes[2]; + struct v4l2_ext_control ctrl; + struct v4l2_ext_controls extCtrls; + object_config_p obj_config; + + obj_context = CONTEXT(context); + assert(obj_context); + + obj_surface = SURFACE(obj_context->current_render_target); + assert(obj_surface); + + obj_config = CONFIG(obj_context->config_id); + if (NULL == obj_config) + { + vaStatus = VA_STATUS_ERROR_INVALID_CONFIG; + return vaStatus; + } + + memset(&(out_buf), 0, sizeof(out_buf)); + out_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + out_buf.memory = V4L2_MEMORY_MMAP; + out_buf.index = obj_surface->input_buf_index; + out_buf.length = 1; + out_buf.m.planes = plane; + out_buf.request = obj_surface->request; + + switch(obj_config->profile) { + default: + out_buf.m.planes[0].bytesused = 0; + ctrl.id = V4L2_CID_MPEG_VIDEO_MPEG2_FRAME_HDR; + ctrl.ptr = NULL; + ctrl.size = 0; + break; + } + + memset(&(cap_buf), 0, sizeof(cap_buf)); + cap_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + cap_buf.memory = V4L2_MEMORY_MMAP; + cap_buf.index = obj_surface->output_buf_index; + cap_buf.length = 2; + cap_buf.m.planes = planes; + + assert(ioctl(driver_data->mem2mem_fd, VIDIOC_QUERYBUF, &cap_buf)==0); + + extCtrls.controls = &ctrl; + extCtrls.count = 1; + extCtrls.request = obj_surface->request; + assert(ioctl(driver_data->mem2mem_fd, VIDIOC_S_EXT_CTRLS, &extCtrls)==0); + + if(ioctl(driver_data->mem2mem_fd, VIDIOC_QBUF, &cap_buf)) { + obj_surface->status = VASurfaceSkipped; + sunxi_cedrus_msg("Error when queuing output: %s\n", strerror(errno)); + return VA_STATUS_ERROR_UNKNOWN; + } + if(ioctl(driver_data->mem2mem_fd, VIDIOC_QBUF, &out_buf)) { + obj_surface->status = VASurfaceSkipped; + sunxi_cedrus_msg("Error when queuing input: %s\n", strerror(errno)); + ioctl(driver_data->mem2mem_fd, VIDIOC_DQBUF, &cap_buf); + return VA_STATUS_ERROR_UNKNOWN; + } + + /* For now, assume that we are done with rendering right away */ + obj_context->current_render_target = -1; + + return vaStatus; +} + + diff --git a/src/picture.h b/src/picture.h new file mode 100644 index 0000000..f864321 --- /dev/null +++ b/src/picture.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _PICTURE_H_ +#define _PICTURE_H_ + +#include + +#include "object_heap.h" + +VAStatus sunxi_cedrus_BeginPicture(VADriverContextP ctx, VAContextID context, + VASurfaceID render_target); + +VAStatus sunxi_cedrus_RenderPicture(VADriverContextP ctx, VAContextID context, + VABufferID *buffers, int num_buffers); + +VAStatus sunxi_cedrus_EndPicture(VADriverContextP ctx, VAContextID context); + +#endif /* _PICTURE_H_ */ diff --git a/src/subpicture.c b/src/subpicture.c new file mode 100644 index 0000000..ff57b20 --- /dev/null +++ b/src/subpicture.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "sunxi_cedrus_drv_video.h" +#include "subpicture.h" + +/* + * Subpictures aren't supported yet + */ + +VAStatus sunxi_cedrus_QuerySubpictureFormats(VADriverContextP ctx, + VAImageFormat *format_list, unsigned int *flags, + unsigned int *num_formats) +{ return VA_STATUS_SUCCESS; } + +VAStatus sunxi_cedrus_CreateSubpicture(VADriverContextP ctx, VAImageID image, + VASubpictureID *subpicture) +{ return VA_STATUS_SUCCESS; } + +VAStatus sunxi_cedrus_DestroySubpicture(VADriverContextP ctx, + VASubpictureID subpicture) +{ return VA_STATUS_SUCCESS; } + +VAStatus sunxi_cedrus_SetSubpictureImage(VADriverContextP ctx, + VASubpictureID subpicture, VAImageID image) +{ return VA_STATUS_SUCCESS; } + +VAStatus sunxi_cedrus_SetSubpicturePalette(VADriverContextP ctx, + VASubpictureID subpicture, unsigned char *palette) +{ return VA_STATUS_SUCCESS; } + +VAStatus sunxi_cedrus_SetSubpictureChromakey(VADriverContextP ctx, + VASubpictureID subpicture, unsigned int chromakey_min, + unsigned int chromakey_max, unsigned int chromakey_mask) +{ return VA_STATUS_SUCCESS; } + +VAStatus sunxi_cedrus_SetSubpictureGlobalAlpha(VADriverContextP ctx, + VASubpictureID subpicture, float global_alpha) +{ return VA_STATUS_SUCCESS; } + +VAStatus sunxi_cedrus_AssociateSubpicture(VADriverContextP ctx, + VASubpictureID subpicture, VASurfaceID *target_surfaces, + int num_surfaces, short src_x, short src_y, + unsigned short src_width, unsigned short src_height, + short dest_x, short dest_y, unsigned short dest_width, + unsigned short dest_height, unsigned int flags) +{ return VA_STATUS_SUCCESS; } + +VAStatus sunxi_cedrus_DeassociateSubpicture(VADriverContextP ctx, + VASubpictureID subpicture, VASurfaceID *target_surfaces, + int num_surfaces) +{ return VA_STATUS_SUCCESS; } + diff --git a/src/subpicture.h b/src/subpicture.h new file mode 100644 index 0000000..1e60266 --- /dev/null +++ b/src/subpicture.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _SUBPICTURE_H_ +#define _SUBPICTURE_H_ + +#include + +VAStatus sunxi_cedrus_QuerySubpictureFormats(VADriverContextP ctx, + VAImageFormat *format_list, unsigned int *flags, + unsigned int *num_formats); + +VAStatus sunxi_cedrus_CreateSubpicture(VADriverContextP ctx, VAImageID image, + VASubpictureID *subpicture); + +VAStatus sunxi_cedrus_DestroySubpicture(VADriverContextP ctx, + VASubpictureID subpicture); + +VAStatus sunxi_cedrus_SetSubpictureImage(VADriverContextP ctx, + VASubpictureID subpicture, VAImageID image); + +VAStatus sunxi_cedrus_SetSubpicturePalette(VADriverContextP ctx, + VASubpictureID subpicture, unsigned char *palette); + +VAStatus sunxi_cedrus_SetSubpictureChromakey(VADriverContextP ctx, + VASubpictureID subpicture, unsigned int chromakey_min, + unsigned int chromakey_max, unsigned int chromakey_mask); + +VAStatus sunxi_cedrus_SetSubpictureGlobalAlpha(VADriverContextP ctx, + VASubpictureID subpicture, float global_alpha); + +VAStatus sunxi_cedrus_AssociateSubpicture(VADriverContextP ctx, + VASubpictureID subpicture, VASurfaceID *target_surfaces, + int num_surfaces, short src_x, short src_y, + unsigned short src_width, unsigned short src_height, + short dest_x, short dest_y, unsigned short dest_width, + unsigned short dest_height, unsigned int flags); + +VAStatus sunxi_cedrus_DeassociateSubpicture(VADriverContextP ctx, + VASubpictureID subpicture, VASurfaceID *target_surfaces, + int num_surfaces); + +#endif /* _SUBPICTURE_H_ */ diff --git a/src/sunxi_cedrus_drv_video.c b/src/sunxi_cedrus_drv_video.c new file mode 100644 index 0000000..1c7b262 --- /dev/null +++ b/src/sunxi_cedrus_drv_video.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "buffer.h" +#include "context.h" +#include "image.h" +#include "picture.h" +#include "subpicture.h" +#include "surface.h" +#include "va_config.h" + +#include + +#include "sunxi_cedrus_drv_video.h" + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +/* We need to use stderr if we want to be heard */ +void sunxi_cedrus_msg(const char *msg, ...) +{ + va_list args; + + fprintf(stderr, "sunxi_cedrus_drv_video: "); + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); +} + +/* Free memory and close v4l device */ +VAStatus sunxi_cedrus_Terminate(VADriverContextP ctx) +{ + INIT_DRIVER_DATA + object_buffer_p obj_buffer; + object_config_p obj_config; + object_heap_iterator iter; + enum v4l2_buf_type type; + + type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + ioctl(driver_data->mem2mem_fd, VIDIOC_STREAMOFF, &type); + type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + ioctl(driver_data->mem2mem_fd, VIDIOC_STREAMOFF, &type); + + close(driver_data->mem2mem_fd); + + /* Clean up left over buffers */ + obj_buffer = (object_buffer_p) object_heap_first(&driver_data->buffer_heap, &iter); + while (obj_buffer) + { + sunxi_cedrus_msg("vaTerminate: bufferID %08x still allocated, destroying\n", obj_buffer->base.id); + sunxi_cedrus_destroy_buffer(driver_data, obj_buffer); + obj_buffer = (object_buffer_p) object_heap_next(&driver_data->buffer_heap, &iter); + } + + object_heap_destroy(&driver_data->buffer_heap); + object_heap_destroy(&driver_data->surface_heap); + object_heap_destroy(&driver_data->context_heap); + + /* Clean up configIDs */ + obj_config = (object_config_p) object_heap_first(&driver_data->config_heap, &iter); + while (obj_config) + { + object_heap_free(&driver_data->config_heap, (object_base_p) obj_config); + obj_config = (object_config_p) object_heap_next(&driver_data->config_heap, &iter); + } + object_heap_destroy(&driver_data->config_heap); + + free(ctx->pDriverData); + ctx->pDriverData = NULL; + + return VA_STATUS_SUCCESS; +} + +/* Only expose the init function */ +VAStatus __attribute__((visibility("default"))) +VA_DRIVER_INIT_FUNC(VADriverContextP ctx); + +/* Setup a bunch of function pointers for VA */ +VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP ctx) +{ + struct VADriverVTable * const vtable = ctx->vtable; + struct sunxi_cedrus_driver_data *driver_data; + struct v4l2_capability cap; + + ctx->version_major = VA_MAJOR_VERSION; + ctx->version_minor = VA_MINOR_VERSION; + ctx->max_profiles = SUNXI_CEDRUS_MAX_PROFILES; + ctx->max_entrypoints = SUNXI_CEDRUS_MAX_ENTRYPOINTS; + ctx->max_attributes = SUNXI_CEDRUS_MAX_CONFIG_ATTRIBUTES; + ctx->max_image_formats = SUNXI_CEDRUS_MAX_IMAGE_FORMATS; + ctx->max_subpic_formats = SUNXI_CEDRUS_MAX_SUBPIC_FORMATS; + ctx->max_display_attributes = SUNXI_CEDRUS_MAX_DISPLAY_ATTRIBUTES; + ctx->str_vendor = SUNXI_CEDRUS_STR_VENDOR; + + vtable->vaTerminate = sunxi_cedrus_Terminate; + vtable->vaQueryConfigEntrypoints = sunxi_cedrus_QueryConfigEntrypoints; + vtable->vaQueryConfigProfiles = sunxi_cedrus_QueryConfigProfiles; + vtable->vaQueryConfigEntrypoints = sunxi_cedrus_QueryConfigEntrypoints; + vtable->vaQueryConfigAttributes = sunxi_cedrus_QueryConfigAttributes; + vtable->vaCreateConfig = sunxi_cedrus_CreateConfig; + vtable->vaDestroyConfig = sunxi_cedrus_DestroyConfig; + vtable->vaGetConfigAttributes = sunxi_cedrus_GetConfigAttributes; + vtable->vaCreateSurfaces = sunxi_cedrus_CreateSurfaces; + vtable->vaDestroySurfaces = sunxi_cedrus_DestroySurfaces; + vtable->vaCreateContext = sunxi_cedrus_CreateContext; + vtable->vaDestroyContext = sunxi_cedrus_DestroyContext; + vtable->vaCreateBuffer = sunxi_cedrus_CreateBuffer; + vtable->vaBufferSetNumElements = sunxi_cedrus_BufferSetNumElements; + vtable->vaMapBuffer = sunxi_cedrus_MapBuffer; + vtable->vaUnmapBuffer = sunxi_cedrus_UnmapBuffer; + vtable->vaDestroyBuffer = sunxi_cedrus_DestroyBuffer; + vtable->vaBeginPicture = sunxi_cedrus_BeginPicture; + vtable->vaRenderPicture = sunxi_cedrus_RenderPicture; + vtable->vaEndPicture = sunxi_cedrus_EndPicture; + vtable->vaSyncSurface = sunxi_cedrus_SyncSurface; + vtable->vaQuerySurfaceStatus = sunxi_cedrus_QuerySurfaceStatus; + vtable->vaPutSurface = sunxi_cedrus_PutSurface; + vtable->vaQueryImageFormats = sunxi_cedrus_QueryImageFormats; + vtable->vaCreateImage = sunxi_cedrus_CreateImage; + vtable->vaDeriveImage = sunxi_cedrus_DeriveImage; + vtable->vaDestroyImage = sunxi_cedrus_DestroyImage; + vtable->vaSetImagePalette = sunxi_cedrus_SetImagePalette; + vtable->vaGetImage = sunxi_cedrus_GetImage; + vtable->vaPutImage = sunxi_cedrus_PutImage; + vtable->vaQuerySubpictureFormats = sunxi_cedrus_QuerySubpictureFormats; + vtable->vaCreateSubpicture = sunxi_cedrus_CreateSubpicture; + vtable->vaDestroySubpicture = sunxi_cedrus_DestroySubpicture; + vtable->vaSetSubpictureImage = sunxi_cedrus_SetSubpictureImage; + vtable->vaSetSubpictureChromakey = sunxi_cedrus_SetSubpictureChromakey; + vtable->vaSetSubpictureGlobalAlpha = sunxi_cedrus_SetSubpictureGlobalAlpha; + vtable->vaAssociateSubpicture = sunxi_cedrus_AssociateSubpicture; + vtable->vaDeassociateSubpicture = sunxi_cedrus_DeassociateSubpicture; + vtable->vaQueryDisplayAttributes = sunxi_cedrus_QueryDisplayAttributes; + vtable->vaGetDisplayAttributes = sunxi_cedrus_GetDisplayAttributes; + vtable->vaSetDisplayAttributes = sunxi_cedrus_SetDisplayAttributes; + vtable->vaLockSurface = sunxi_cedrus_LockSurface; + vtable->vaUnlockSurface = sunxi_cedrus_UnlockSurface; + vtable->vaBufferInfo = sunxi_cedrus_BufferInfo; + + driver_data = (struct sunxi_cedrus_driver_data *) malloc(sizeof(*driver_data)); + ctx->pDriverData = (void *) driver_data; + + assert(object_heap_init(&driver_data->config_heap, + sizeof(struct object_config), CONFIG_ID_OFFSET)==0); + assert(object_heap_init(&driver_data->context_heap, + sizeof(struct object_context), CONTEXT_ID_OFFSET)==0); + assert(object_heap_init(&driver_data->surface_heap, + sizeof(struct object_surface), SURFACE_ID_OFFSET)==0); + assert(object_heap_init(&driver_data->buffer_heap, + sizeof(struct object_buffer), BUFFER_ID_OFFSET)==0); + assert(object_heap_init(&driver_data->image_heap, + sizeof(struct object_image), IMAGE_ID_OFFSET)==0); + + driver_data->mem2mem_fd = open("/dev/video0", O_RDWR | O_NONBLOCK, 0); + assert(driver_data->mem2mem_fd >= 0); + + assert(ioctl(driver_data->mem2mem_fd, VIDIOC_QUERYCAP, &cap)==0); + if (!(cap.capabilities & V4L2_CAP_VIDEO_M2M_MPLANE)) + { + sunxi_cedrus_msg("/dev/video0 does not support m2m_mplane\n"); + return VA_STATUS_ERROR_OPERATION_FAILED; + } + + return VA_STATUS_SUCCESS; +} + diff --git a/src/sunxi_cedrus_drv_video.h b/src/sunxi_cedrus_drv_video.h new file mode 100644 index 0000000..4e5da2b --- /dev/null +++ b/src/sunxi_cedrus_drv_video.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _SUNXI_CEDRUS_DRV_VIDEO_H_ +#define _SUNXI_CEDRUS_DRV_VIDEO_H_ + +#include +#include "object_heap.h" + +#include + +#define INIT_DRIVER_DATA struct sunxi_cedrus_driver_data * const driver_data = (struct sunxi_cedrus_driver_data *) ctx->pDriverData; + +#define SUNXI_CEDRUS_STR_VENDOR "Sunxi Cedrus Driver 1.0" + +#define SUNXI_CEDRUS_MAX_PROFILES 11 +#define SUNXI_CEDRUS_MAX_ENTRYPOINTS 5 +#define SUNXI_CEDRUS_MAX_CONFIG_ATTRIBUTES 10 +#define SUNXI_CEDRUS_MAX_IMAGE_FORMATS 10 +#define SUNXI_CEDRUS_MAX_SUBPIC_FORMATS 4 +#define SUNXI_CEDRUS_MAX_DISPLAY_ATTRIBUTES 4 + +void sunxi_cedrus_msg(const char *msg, ...); + +struct sunxi_cedrus_driver_data { + struct object_heap config_heap; + struct object_heap context_heap; + struct object_heap surface_heap; + struct object_heap buffer_heap; + struct object_heap image_heap; + char *luma_bufs[VIDEO_MAX_FRAME]; + char *chroma_bufs[VIDEO_MAX_FRAME]; + unsigned int num_dst_bufs; + int mem2mem_fd; +}; + +#endif /* _SUNXI_CEDRUS_DRV_VIDEO_H_ */ diff --git a/src/surface.c b/src/surface.c new file mode 100644 index 0000000..86043e4 --- /dev/null +++ b/src/surface.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "sunxi_cedrus_drv_video.h" +#include "surface.h" + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +/* + * A Surface is an internal data structure never handled by the VA's user + * containing the output of a rendering. Usualy, a bunch of surfaces are created + * at the begining of decoding and they are then used alternatively. When + * created, a surface is assigned a corresponding v4l capture buffer and it is + * kept until the end of decoding. Syncing a surface waits for the v4l buffer to + * be available and then dequeue it. + * + * Note: since a Surface is kept private from the VA's user, it can ask to + * directly render a Surface on screen in an X Drawable. Some kind of + * implementation is available in PutSurface but this is only for development + * purpose. + */ + +VAStatus sunxi_cedrus_CreateSurfaces(VADriverContextP ctx, int width, + int height, int format, int num_surfaces, VASurfaceID *surfaces) +{ + INIT_DRIVER_DATA + VAStatus vaStatus = VA_STATUS_SUCCESS; + int i; + struct v4l2_buffer buf; + struct v4l2_plane planes[2]; + struct v4l2_create_buffers create_bufs; + struct v4l2_format fmt; + + /* We only support one format */ + if (VA_RT_FORMAT_YUV420 != format) + return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT; + + /* Set format for capture */ + memset(&(fmt), 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.width = width; + fmt.fmt.pix_mp.height = height; + fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_SUNXI; + fmt.fmt.pix_mp.field = V4L2_FIELD_ANY; + fmt.fmt.pix_mp.num_planes = 2; + assert(ioctl(driver_data->mem2mem_fd, VIDIOC_S_FMT, &fmt)==0); + + memset (&create_bufs, 0, sizeof (struct v4l2_create_buffers)); + create_bufs.count = num_surfaces; + create_bufs.memory = V4L2_MEMORY_MMAP; + create_bufs.format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + assert(ioctl(driver_data->mem2mem_fd, VIDIOC_G_FMT, &create_bufs.format)==0); + assert(ioctl(driver_data->mem2mem_fd, VIDIOC_CREATE_BUFS, &create_bufs)==0); + driver_data->num_dst_bufs = create_bufs.count; + + for (i = 0; i < create_bufs.count; i++) + { + int surfaceID = object_heap_allocate(&driver_data->surface_heap); + object_surface_p obj_surface = SURFACE(surfaceID); + if (NULL == obj_surface) + { + vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED; + break; + } + obj_surface->surface_id = surfaceID; + surfaces[i] = surfaceID; + + memset(&(buf), 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = create_bufs.index + i; + buf.length = 2; + buf.m.planes = planes; + + assert(ioctl(driver_data->mem2mem_fd, VIDIOC_QUERYBUF, &buf)==0); + + driver_data->luma_bufs[buf.index] = mmap(NULL, buf.m.planes[0].length, + PROT_READ | PROT_WRITE, MAP_SHARED, + driver_data->mem2mem_fd, buf.m.planes[0].m.mem_offset); + assert(driver_data->luma_bufs[buf.index] != MAP_FAILED); + + driver_data->chroma_bufs[buf.index] = mmap(NULL, buf.m.planes[1].length, + PROT_READ | PROT_WRITE, MAP_SHARED, + driver_data->mem2mem_fd, buf.m.planes[1].m.mem_offset); + assert(driver_data->chroma_bufs[buf.index] != MAP_FAILED); + + obj_surface->input_buf_index = 0; + obj_surface->output_buf_index = create_bufs.index + i; + + obj_surface->width = width; + obj_surface->height = height; + obj_surface->status = VASurfaceReady; + } + + /* Error recovery */ + if (VA_STATUS_SUCCESS != vaStatus) + { + /* surfaces[i-1] was the last successful allocation */ + for(; i--;) + { + object_surface_p obj_surface = SURFACE(surfaces[i]); + surfaces[i] = VA_INVALID_SURFACE; + assert(obj_surface); + object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface); + } + } + return vaStatus; +} + +VAStatus sunxi_cedrus_DestroySurfaces(VADriverContextP ctx, + VASurfaceID *surface_list, int num_surfaces) +{ + INIT_DRIVER_DATA + int i; + for(i = num_surfaces; i--;) + { + object_surface_p obj_surface = SURFACE(surface_list[i]); + assert(obj_surface); + object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface); + } + return VA_STATUS_SUCCESS; +} + +VAStatus sunxi_cedrus_SyncSurface(VADriverContextP ctx, + VASurfaceID render_target) +{ + INIT_DRIVER_DATA + object_surface_p obj_surface; + struct v4l2_buffer buf; + struct v4l2_plane plane[1]; + fd_set read_fds; + struct timeval tv = {0, 300000}; + + obj_surface = SURFACE(render_target); + assert(obj_surface); + + FD_ZERO(&read_fds); + FD_SET(driver_data->mem2mem_fd, &read_fds); + if(obj_surface->status != VASurfaceSkipped) + select(driver_data->mem2mem_fd + 1, &read_fds, NULL, NULL, &tv); + else + return VA_STATUS_ERROR_UNKNOWN; + + memset(&(buf), 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = obj_surface->input_buf_index; + buf.length = 1; + buf.m.planes = plane; + + if(ioctl(driver_data->mem2mem_fd, VIDIOC_DQBUF, &buf)) { + sunxi_cedrus_msg("Error when dequeuing input: %s\n", strerror(errno)); + return VA_STATUS_ERROR_UNKNOWN; + } + + memset(&(buf), 0, sizeof(buf)); + struct v4l2_plane planes[2]; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = obj_surface->output_buf_index; + buf.length = 2; + buf.m.planes = planes; + + obj_surface->status = VASurfaceReady; + + if(ioctl(driver_data->mem2mem_fd, VIDIOC_DQBUF, &buf)) { + sunxi_cedrus_msg("Error when dequeuing output: %s\n", strerror(errno)); + return VA_STATUS_ERROR_UNKNOWN; + } + + return VA_STATUS_SUCCESS; +} + +VAStatus sunxi_cedrus_QuerySurfaceStatus(VADriverContextP ctx, + VASurfaceID render_target, VASurfaceStatus *status) +{ + INIT_DRIVER_DATA + VAStatus vaStatus = VA_STATUS_SUCCESS; + object_surface_p obj_surface; + + obj_surface = SURFACE(render_target); + assert(obj_surface); + + *status = obj_surface->status; + + return vaStatus; +} + +/* WARNING: This is for development purpose only!!! */ +VAStatus sunxi_cedrus_PutSurface(VADriverContextP ctx, VASurfaceID surface, + void *draw, short srcx, short srcy, unsigned short srcw, + unsigned short srch, short destx, short desty, + unsigned short destw, unsigned short desth, + VARectangle *cliprects, unsigned int number_cliprects, + unsigned int flags) +{ + INIT_DRIVER_DATA + GC gc; + Display *display; + const XID xid = (XID)(uintptr_t)draw; + XColor xcolor; + int screen; + Colormap cm; + int colorratio = 65535 / 255; + int x, y; + object_surface_p obj_surface; + + obj_surface = SURFACE(surface); + assert(obj_surface); + + display = XOpenDisplay(getenv("DISPLAY")); + if (display == NULL) { + sunxi_cedrus_msg("Cannot connect to X server\n"); + exit(1); + } + + sunxi_cedrus_msg("warning: using vaPutSurface with sunxi-cedrus is not recommended\n"); + screen = DefaultScreen(display); + gc = XCreateGC(display, RootWindow(display, screen), 0, NULL); + XSync(display, False); + + cm = DefaultColormap(display, screen); + xcolor.flags = DoRed | DoGreen | DoBlue; + + for(x=destx; x < destx+destw; x++) { + for(y=desty; y < desty+desth; y++) { + char lum = driver_data->luma_bufs[obj_surface->output_buf_index][x+srcw*y]; + xcolor.red = xcolor.green = xcolor.blue = lum*colorratio; + XAllocColor(display, cm, &xcolor); + XSetForeground(display, gc, xcolor.pixel); + XDrawPoint(display, xid, gc, x, y); + } + } + + XFlush(display); + XCloseDisplay(display); + return VA_STATUS_SUCCESS; +} + +VAStatus sunxi_cedrus_LockSurface(VADriverContextP ctx, VASurfaceID surface, + unsigned int *fourcc, unsigned int *luma_stride, + unsigned int *chroma_u_stride, unsigned int *chroma_v_stride, + unsigned int *luma_offset, unsigned int *chroma_u_offset, + unsigned int *chroma_v_offset, unsigned int *buffer_name, + void **buffer) +{ return VA_STATUS_ERROR_UNIMPLEMENTED; } + +VAStatus sunxi_cedrus_UnlockSurface(VADriverContextP ctx, VASurfaceID surface) +{ return VA_STATUS_ERROR_UNIMPLEMENTED; } diff --git a/src/surface.h b/src/surface.h new file mode 100644 index 0000000..0785404 --- /dev/null +++ b/src/surface.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _SURFACES_H_ +#define _SURFACES_H_ + +#include + +#include "object_heap.h" + +#define SURFACE(id) ((object_surface_p) object_heap_lookup(&driver_data->surface_heap, id)) +#define SURFACE_ID_OFFSET 0x04000000 + +struct object_surface { + struct object_base base; + VASurfaceID surface_id; + uint32_t request; + uint32_t input_buf_index; + uint32_t output_buf_index; + int width; + int height; + VAStatus status; +}; + +typedef struct object_surface *object_surface_p; + +VAStatus sunxi_cedrus_CreateSurfaces(VADriverContextP ctx, int width, + int height, int format, int num_surfaces, VASurfaceID *surfaces); + +VAStatus sunxi_cedrus_DestroySurfaces(VADriverContextP ctx, + VASurfaceID *surface_list, int num_surfaces); + +VAStatus sunxi_cedrus_SyncSurface(VADriverContextP ctx, + VASurfaceID render_target); + +VAStatus sunxi_cedrus_QuerySurfaceStatus(VADriverContextP ctx, + VASurfaceID render_target, VASurfaceStatus *status); + +VAStatus sunxi_cedrus_PutSurface(VADriverContextP ctx, VASurfaceID surface, + void *draw, short srcx, short srcy, unsigned short srcw, + unsigned short srch, short destx, short desty, + unsigned short destw, unsigned short desth, + VARectangle *cliprects, unsigned int number_cliprects, + unsigned int flags); + +VAStatus sunxi_cedrus_LockSurface(VADriverContextP ctx, VASurfaceID surface, + unsigned int *fourcc, unsigned int *luma_stride, + unsigned int *chroma_u_stride, unsigned int *chroma_v_stride, + unsigned int *luma_offset, unsigned int *chroma_u_offset, + unsigned int *chroma_v_offset, unsigned int *buffer_name, + void **buffer); + +VAStatus sunxi_cedrus_UnlockSurface(VADriverContextP ctx, VASurfaceID surface); + +#endif /* _SURFACES_H_ */ diff --git a/src/tiled_yuv.S b/src/tiled_yuv.S new file mode 100644 index 0000000..52ff67f --- /dev/null +++ b/src/tiled_yuv.S @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2014 Jens Kuske + * + * 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 + * + */ + +/* + * The Sunxi Video Engine outputs buffers in a specific format similar to NV12 + * but with "tiles" of size 32x32. This code converts the data from this tiled + * format to two NV12 planes. + */ + +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack,"",%progbits /* mark stack as non-executable */ +#endif + +#ifndef __aarch64__ + +.text +.syntax unified +.arch armv7-a +.fpu neon +.thumb + +.macro thumb_function fname + .global \fname +#ifdef __ELF__ + .hidden \fname + .type \fname, %function +#endif + .thumb_func +\fname: +.endm + +.macro end_function fname +#ifdef __ELF__ + .size \fname, .-\fname +#endif +.endm + +SRC .req r0 +DST .req r1 +PITCH .req r2 +CNT .req r3 +TLINE .req r4 +HEIGHT .req r5 +REST .req r6 +NTILES .req r7 +TMPSRC .req r8 +DST2 .req r9 +TSIZE .req r12 +NEXTLIN .req lr + +thumb_function tiled_to_planar + push {r4, r5, r6, r7, r8, lr} + ldr HEIGHT, [sp, #24] + add NEXTLIN, r3, #31 + lsrs NTILES, r3, #5 + bic NEXTLIN, NEXTLIN, #31 + and REST, r3, #31 + lsl NEXTLIN, NEXTLIN, #5 + subs PITCH, r2, r3 + movs TLINE, #32 + rsb NEXTLIN, NEXTLIN, #32 + mov TSIZE, #1024 + + /* y loop */ +1: cbz NTILES, 3f + mov CNT, NTILES + + /* x loop complete tiles */ +2: pld [SRC, TSIZE] + vld1.8 {d0 - d3}, [SRC :256], TSIZE + subs CNT, #1 + vst1.8 {d0 - d3}, [DST]! + bne 2b + +3: cbnz REST, 4f + + /* fix up dest pointer if pitch != width */ +7: add DST, PITCH + + /* fix up src pointer at end of line */ + subs TLINE, #1 + itee ne + addne SRC, NEXTLIN + subeq SRC, #992 + moveq TLINE, #32 + + subs HEIGHT, #1 + bne 1b + pop {r4, r5, r6, r7, r8, pc} + + /* partly copy last tile of line */ +4: mov TMPSRC, SRC + tst REST, #16 + beq 5f + vld1.8 {d0 - d1}, [TMPSRC :128]! + vst1.8 {d0 - d1}, [DST]! +5: add SRC, TSIZE + ands CNT, REST, #15 + beq 7b +6: vld1.8 {d0[0]}, [TMPSRC]! + subs CNT, #1 + vst1.8 {d0[0]}, [DST]! + bne 6b + b 7b +end_function tiled_to_planar + +thumb_function tiled_deinterleave_to_planar + push {r4, r5, r6, r7, r8, r9, lr} + mov DST2, r2 + ldr HEIGHT, [sp, #32] + ldr r4, [sp, #28] + add NEXTLIN, r4, #31 + lsrs NTILES, r4, #5 + bic NEXTLIN, NEXTLIN, #31 + ubfx REST, r4, #1, #4 + lsl NEXTLIN, NEXTLIN, #5 + sub PITCH, r3, r4, lsr #1 + movs TLINE, #32 + rsb NEXTLIN, NEXTLIN, #32 + mov TSIZE, #1024 + + /* y loop */ +1: cbz NTILES, 3f + mov CNT, NTILES + + /* x loop complete tiles */ +2: pld [SRC, TSIZE] + vld2.8 {d0 - d3}, [SRC :256], TSIZE + subs CNT, #1 + vst1.8 {d0 - d1}, [DST]! + vst1.8 {d2 - d3}, [DST2]! + bne 2b + +3: cbnz REST, 4f + + /* fix up dest pointer if pitch != width */ +7: add DST, PITCH + add DST2, PITCH + + /* fix up src pointer at end of line */ + subs TLINE, #1 + itee ne + addne SRC, NEXTLIN + subeq SRC, #992 + moveq TLINE, #32 + + subs HEIGHT, #1 + bne 1b + pop {r4, r5, r6, r7, r8, r9, pc} + + /* partly copy last tile of line */ +4: mov TMPSRC, SRC + tst REST, #8 + beq 5f + vld2.8 {d0 - d1}, [TMPSRC :128]! + vst1.8 {d0}, [DST]! + vst1.8 {d1}, [DST2]! +5: add SRC, TSIZE + ands CNT, REST, #7 + beq 7b +6: vld2.8 {d0[0], d1[0]}, [TMPSRC]! + subs CNT, #1 + vst1.8 {d0[0]}, [DST]! + vst1.8 {d1[0]}, [DST2]! + bne 6b + b 7b +end_function tiled_deinterleave_to_planar + +#endif diff --git a/src/tiled_yuv.h b/src/tiled_yuv.h new file mode 100644 index 0000000..7a974d2 --- /dev/null +++ b/src/tiled_yuv.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2014 Jens Kuske + * + * 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 __TILED_YUV_H__ +#define __TILED_YUV_H__ + +void tiled_to_planar(void *src, void *dst, unsigned int dst_pitch, + unsigned int width, unsigned int height); + +void tiled_deinterleave_to_planar(void *src, void *dst1, void *dst2, + unsigned int dst_pitch, + unsigned int width, unsigned int height); + +#endif diff --git a/src/va_config.c b/src/va_config.c new file mode 100644 index 0000000..069e999 --- /dev/null +++ b/src/va_config.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "sunxi_cedrus_drv_video.h" +#include "va_config.h" + +#include +#include + +#include + +#include + +/* + * This file provides generalities to VA's user regarding the file formats + * supported by the v4l driver. It uses VIDIOC_ENUM_FMT to make the + * correspondence between v4l and VA video formats. + */ + +VAStatus sunxi_cedrus_QueryConfigProfiles(VADriverContextP ctx, + VAProfile *profile_list, int *num_profiles) +{ + INIT_DRIVER_DATA + int i = 0; + struct v4l2_fmtdesc vid_fmtdesc; + memset(&vid_fmtdesc, 0, sizeof(vid_fmtdesc)); + vid_fmtdesc.index = 0; + vid_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + + while(ioctl(driver_data->mem2mem_fd, VIDIOC_ENUM_FMT, &vid_fmtdesc) == 0) + { + vid_fmtdesc.index++; + } + + assert(i <= SUNXI_CEDRUS_MAX_PROFILES); + *num_profiles = i; + + return VA_STATUS_SUCCESS; +} + +VAStatus sunxi_cedrus_QueryConfigEntrypoints(VADriverContextP ctx, + VAProfile profile, VAEntrypoint *entrypoint_list, + int *num_entrypoints) +{ + switch (profile) { + default: + *num_entrypoints = 0; + break; + } + + assert(*num_entrypoints <= SUNXI_CEDRUS_MAX_ENTRYPOINTS); + return VA_STATUS_SUCCESS; +} + +VAStatus sunxi_cedrus_GetConfigAttributes(VADriverContextP ctx, + VAProfile profile, VAEntrypoint entrypoint, + VAConfigAttrib *attrib_list, int num_attribs) +{ + int i; + + for (i = 0; i < num_attribs; i++) + { + switch (attrib_list[i].type) + { + case VAConfigAttribRTFormat: + attrib_list[i].value = VA_RT_FORMAT_YUV420; + break; + + default: + /* Do nothing */ + attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED; + break; + } + } + + return VA_STATUS_SUCCESS; +} + +VAStatus sunxi_cedrus_update_attribute(object_config_p obj_config, + VAConfigAttrib *attrib) +{ + int i; + /* Check existing attributes */ + for(i = 0; obj_config->attrib_count < i; i++) + { + if (obj_config->attrib_list[i].type == attrib->type) + { + /* Update existing attribute */ + obj_config->attrib_list[i].value = attrib->value; + return VA_STATUS_SUCCESS; + } + } + if (obj_config->attrib_count < SUNXI_CEDRUS_MAX_CONFIG_ATTRIBUTES) + { + i = obj_config->attrib_count; + obj_config->attrib_list[i].type = attrib->type; + obj_config->attrib_list[i].value = attrib->value; + obj_config->attrib_count++; + return VA_STATUS_SUCCESS; + } + return VA_STATUS_ERROR_MAX_NUM_EXCEEDED; +} + +VAStatus sunxi_cedrus_CreateConfig(VADriverContextP ctx, VAProfile profile, + VAEntrypoint entrypoint, VAConfigAttrib *attrib_list, + int num_attribs, VAConfigID *config_id) +{ + INIT_DRIVER_DATA + VAStatus vaStatus; + int configID; + object_config_p obj_config; + int i; + + /* Validate profile & entrypoint */ + switch (profile) { + default: + vaStatus = VA_STATUS_ERROR_UNSUPPORTED_PROFILE; + break; + } + + if (VA_STATUS_SUCCESS != vaStatus) + return vaStatus; + + configID = object_heap_allocate(&driver_data->config_heap); + obj_config = CONFIG(configID); + if (NULL == obj_config) + { + vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED; + return vaStatus; + } + + obj_config->profile = profile; + obj_config->entrypoint = entrypoint; + obj_config->attrib_list[0].type = VAConfigAttribRTFormat; + obj_config->attrib_list[0].value = VA_RT_FORMAT_YUV420; + obj_config->attrib_count = 1; + + for(i = 0; i < num_attribs; i++) + { + vaStatus = sunxi_cedrus_update_attribute(obj_config, &(attrib_list[i])); + if (VA_STATUS_SUCCESS != vaStatus) + break; + } + + /* Error recovery */ + if (VA_STATUS_SUCCESS != vaStatus) + object_heap_free(&driver_data->config_heap, (object_base_p) obj_config); + else + *config_id = configID; + + return vaStatus; +} + +VAStatus sunxi_cedrus_DestroyConfig(VADriverContextP ctx, VAConfigID config_id) +{ + INIT_DRIVER_DATA + VAStatus vaStatus; + object_config_p obj_config; + + obj_config = CONFIG(config_id); + if (NULL == obj_config) + { + vaStatus = VA_STATUS_ERROR_INVALID_CONFIG; + return vaStatus; + } + + object_heap_free(&driver_data->config_heap, (object_base_p) obj_config); + return VA_STATUS_SUCCESS; +} + +VAStatus sunxi_cedrus_QueryConfigAttributes(VADriverContextP ctx, + VAConfigID config_id, VAProfile *profile, + VAEntrypoint *entrypoint, VAConfigAttrib *attrib_list, + int *num_attribs) +{ + INIT_DRIVER_DATA + VAStatus vaStatus = VA_STATUS_SUCCESS; + object_config_p obj_config; + int i; + + obj_config = CONFIG(config_id); + assert(obj_config); + + *profile = obj_config->profile; + *entrypoint = obj_config->entrypoint; + *num_attribs = obj_config->attrib_count; + for(i = 0; i < obj_config->attrib_count; i++) + attrib_list[i] = obj_config->attrib_list[i]; + + return vaStatus; +} + +/* sunxi-cedrus doesn't support display attributes */ +VAStatus sunxi_cedrus_QueryDisplayAttributes (VADriverContextP ctx, + VADisplayAttribute *attr_list, int *num_attributes) +{ return VA_STATUS_ERROR_UNKNOWN; } + +VAStatus sunxi_cedrus_GetDisplayAttributes (VADriverContextP ctx, + VADisplayAttribute *attr_list, int num_attributes) +{ return VA_STATUS_ERROR_UNKNOWN; } + +VAStatus sunxi_cedrus_SetDisplayAttributes (VADriverContextP ctx, + VADisplayAttribute *attr_list, int num_attributes) +{ return VA_STATUS_ERROR_UNKNOWN; } diff --git a/src/va_config.h b/src/va_config.h new file mode 100644 index 0000000..fb071d7 --- /dev/null +++ b/src/va_config.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016 Florent Revest, + * 2007 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#include + +#include "object_heap.h" + +#define CONFIG(id) ((object_config_p) object_heap_lookup(&driver_data->config_heap, id)) +#define CONFIG_ID_OFFSET 0x01000000 + +struct object_config { + struct object_base base; + VAProfile profile; + VAEntrypoint entrypoint; + VAConfigAttrib attrib_list[SUNXI_CEDRUS_MAX_CONFIG_ATTRIBUTES]; + int attrib_count; +}; + +typedef struct object_config *object_config_p; + +VAStatus sunxi_cedrus_QueryConfigProfiles(VADriverContextP ctx, + VAProfile *profile_list, int *num_profiles); + +VAStatus sunxi_cedrus_QueryConfigEntrypoints(VADriverContextP ctx, + VAProfile profile, VAEntrypoint *entrypoint_list, + int *num_entrypoints); + +VAStatus sunxi_cedrus_GetConfigAttributes(VADriverContextP ctx, + VAProfile profile, VAEntrypoint entrypoint, + VAConfigAttrib *attrib_list, int num_attribs); + +VAStatus sunxi_cedrus_update_attribute(object_config_p obj_config, + VAConfigAttrib *attrib); + +VAStatus sunxi_cedrus_CreateConfig(VADriverContextP ctx, VAProfile profile, + VAEntrypoint entrypoint, VAConfigAttrib *attrib_list, + int num_attribs, VAConfigID *config_id); + +VAStatus sunxi_cedrus_DestroyConfig(VADriverContextP ctx, VAConfigID config_id); + +VAStatus sunxi_cedrus_QueryConfigAttributes(VADriverContextP ctx, + VAConfigID config_id, VAProfile *profile, + VAEntrypoint *entrypoint, VAConfigAttrib *attrib_list, + int *num_attribs); + +VAStatus sunxi_cedrus_QueryDisplayAttributes (VADriverContextP ctx, + VADisplayAttribute *attr_list, int *num_attributes); + +VAStatus sunxi_cedrus_GetDisplayAttributes (VADriverContextP ctx, + VADisplayAttribute *attr_list, int num_attributes); + +VAStatus sunxi_cedrus_SetDisplayAttributes (VADriverContextP ctx, + VADisplayAttribute *attr_list, int num_attributes); + +#endif /* _CONFIG_H_ */