commit e263c9542c4c779fdbbfbcf1693980966efcc410 Author: Florent Revest Date: Fri Aug 5 12:23:15 2016 +0200 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. 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_ */