diff options
author | Sejun Park <sejun79.park@samsung.com> | 2017-03-15 13:50:44 +0900 |
---|---|---|
committer | Sejun Park <sejun79.park@samsung.com> | 2017-03-16 13:24:12 +0900 |
commit | 825a2ef5c5394cda5191f38118238d7b74c2b1cc (patch) | |
tree | 3e85c28a14e963c47ab07b5c51f396928f166e30 | |
parent | 8c640ad377e054ceed527bf29397b982b054155b (diff) | |
download | libexynos-common-825a2ef5c5394cda5191f38118238d7b74c2b1cc.tar.gz libexynos-common-825a2ef5c5394cda5191f38118238d7b74c2b1cc.tar.bz2 libexynos-common-825a2ef5c5394cda5191f38118238d7b74c2b1cc.zip |
Initial version of libexynos-commonsubmit/tizen/20170404.094130accepted/tizen/unified/20170406.053550
Change-Id: Iee46e0c7bb5146ef516d9652c4c5634022cd4310
48 files changed, 17376 insertions, 0 deletions
@@ -0,0 +1,203 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + diff --git a/Makefile.am b/Makefile.am new file mode 100755 index 0000000..2bef805 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = libion libv4l2 libswconverter libcsc libgscaler + +pcfiles = exynoes-common.pc + @@ -0,0 +1,15 @@ + +1. "libtoolize" to install ltmain.sh +2. "aclocal" to generate m4 script for autoconf +3. "autoheader" to generate config.h +4. "autoconf" to generate configure script +5. "automake" with "--add-missing" optionto generate Makefile + +then assume that your compiler prefix is stored in ${CROSS_COMPILE}, +and your library prefix is ${PREFIX}, + +./configure --host=arm-linux-gnueabihf --prefix=${PREFIX} CC=${CROSS_COMPILE}gcc CXX=${CROSS_COMPILE}g++ + +(check your gcc prefix to find the host system it is assumed that "arm-linux-gnueabihf") + +then enjoy "make" and "make install" diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..30d679f --- /dev/null +++ b/autogen.sh @@ -0,0 +1,6 @@ +#! /bin/sh + +test -n "$srcdir" || srcdir=`dirname "$0"` +test -n "$srcdir" || srcdir=. +autoreconf --force --install --verbose "$srcdir" +test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" diff --git a/configure.ac b/configure.ac new file mode 100755 index 0000000..6adadc5 --- /dev/null +++ b/configure.ac @@ -0,0 +1,70 @@ +AC_PREREQ([2.60]) +AC_INIT([libexynos], + [1.0.0], + [https://www.tizen.org], + [libexynos]) + +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_SRCDIR([Makefile.am]) +AM_INIT_AUTOMAKE([1.10 foreign dist-bzip2]) +AM_MAINTAINER_MODE([enable]) +i +# Check for programs +AM_PROG_AS +AC_PROG_CC +AC_PROG_CXX + +AC_USE_SYSTEM_EXTENSIONS +AC_SYS_LARGEFILE +AC_FUNC_ALLOCA + +#AC_CONFIG_MACRO_DIR([m4]) + +LT_PREREQ([2.2]) +LT_INIT([disable-static]) + +# Enable quiet compiles on automake 1.11. +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +#PKG_CHECK_MODULES(TDM_EXYNOS, dlog) +#PKG_CHECK_MODULES(UDEV, libudev, [udev=yes], [udev=no]) +#if test x"$udev" = xyes; then +# AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection]) +#fi + +#AC_SUBST(DLOG_LIBS) + +# Initialize libtooldnl use dlog ------------------------------------------------------------------ +AC_ARG_ENABLE(dlog, AC_HELP_STRING([--enable-dlog], [using dlog]), + [ + case "${enableval}" in + yes) USE_DLOG=yes ;; + no) USE_DLOG=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-dlog) ;; + esac + ],[USE_DLOG=no]) + +if test "x$USE_DLOG" = "xyes"; then + PKG_CHECK_MODULES(DLOG, dlog) + AC_SUBST(DLOG_CFLAGS) + AC_SUBST(DLOG_LIBS) +fi +AM_CONDITIONAL(USE_DLOG, test "x$USE_DLOG" = "xyes") +dnl end ----------------------------------------------------------------------- + +# set the dir for the tbm module +DEFAULT_MODULE_PATH="${libdir}" + +# For enumerating devices in test case +AC_OUTPUT([ + Makefile + libv4l2/Makefile + libswconverter/Makefile + libcsc/Makefile + libgscaler/Makefile + libion/Makefile]) + +echo "" +echo "$PACKAGE_STRING will be compiled with:" +echo "" +echo "" diff --git a/exynos-common.pc b/exynos-common.pc new file mode 100755 index 0000000..d3e44ea --- /dev/null +++ b/exynos-common.pc @@ -0,0 +1,11 @@ +prefix=/usr +libdir=/usr/lib +includedir=/usr/include + +Name: Samsung exynos common package +Description: Samsung exynos common +Version: @VERSION@ +Requires: +Libs: -L${libdir} -lexynosv4l2 -lexynosgscaler -lcsc -lswconverter -lion +Cflags: -I${includedir}/libexynos-common + diff --git a/include/content_protect.h b/include/content_protect.h new file mode 100755 index 0000000..3cbf31f --- /dev/null +++ b/include/content_protect.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2012 Samsung Electronics Co., LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CONTENT_PROTECT_H__ +#define __CONTENT_PROTECT_H__ + +__BEGIN_DECLS + +typedef enum { + CP_SUCCESS = 0, + CP_ERROR_ENABLE_PATH_PROTECTION_FAILED, + CP_ERROR_DISABLE_PATH_PROTECTION_FAILED, +} cpResult_t; + + +/** + * protection IP + */ +#define CP_PROTECT_MFC (1 << 0) +#define CP_PROTECT_GSC0 (1 << 1) +#define CP_PROTECT_GSC3 (1 << 2) +#define CP_PROTECT_FIMD (1 << 3) +#define CP_PROTECT_MIXER (1 << 4) + +#define CP_PROTECT_MFC1 (1 << 5) +#define CP_PROTECT_GSC1 (1 << 6) +#define CP_PROTECT_GSC2 (1 << 7) +#define CP_PROTECT_HDMI (1 << 8) + +#if 0 +cpResult_t CP_Enable_Path_Protection(uint32_t); +cpResult_t CP_Disable_Path_Protection(uint32_t); +#else +static inline cpResult_t CP_Enable_Path_Protection(uint32_t) +{ + return CP_SUCCESS; +} +static inline cpResult_t CP_Disable_Path_Protection(uint32_t) +{ + return CP_SUCCESS; +} +#endif + +__END_DECLS + +#endif diff --git a/include/csc.h b/include/csc.h new file mode 100755 index 0000000..7f277d6 --- /dev/null +++ b/include/csc.h @@ -0,0 +1,562 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc.h + * + * @brief color space convertion abstract header + * + * @author Pyoungjae Jung (pjet.jung@samsung.com) + * + * @version 1.0 + * + * @history + * 2011.12.27 : Create + */ + +#ifndef CSC_H +#define CSC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define CSC_MAX_PLANES 3 + +typedef enum _CSC_ERRORCODE { + CSC_ErrorNone = 0, + CSC_Error, + CSC_ErrorNotInit, + CSC_ErrorInvalidAddress, + CSC_ErrorUnsupportFormat, + CSC_ErrorNotImplemented +} CSC_ERRORCODE; + +typedef enum _CSC_METHOD { + CSC_METHOD_SW = 0, + CSC_METHOD_HW +} CSC_METHOD; + +typedef enum _CSC_HW_PROPERTY_TYPE { + CSC_HW_PROPERTY_FIXED_NODE = 0, + CSC_HW_PROPERTY_MODE_DRM, +} CSC_HW_PROPERTY_TYPE; + +typedef enum _CSC_MEMTYPE { + CSC_MEMORY_MMAP = 1, + CSC_MEMORY_USERPTR, + CSC_MEMORY_OVERLAY, + CSC_MEMORY_DMABUF, + CSC_MEMORY_MFC, +} CSC_MEMTYPE; + +typedef enum _CSC_HW_ID { + CSC_HW_GSC0 = 0, + CSC_HW_GSC1, + CSC_HW_GSC2, + CSC_HW_GSC3, + CSC_HW_SC0, + CSC_HW_SC1, + CSC_HW_SC2, + CSC_HW_MAX, +} CSC_HW_ID; + +typedef enum _CSC_PLANE { + CSC_Y_PLANE = 0, + CSC_RGB_PLANE = 0, + CSC_U_PLANE = 1, + CSC_UV_PLANE = 1, + CSC_V_PLANE = 2 +} CSC_PLANE; + +typedef enum _CSC_HW_TYPE { + CSC_HW_TYPE_FIMC = 0, + CSC_HW_TYPE_GSCALER +} CSC_HW_TYPE; + +typedef enum _CSC_EQ_MODE { + CSC_EQ_MODE_USER = 0, + CSC_EQ_MODE_AUTO +} CSC_EQ_MODE; + +typedef enum _CSC_EQ_COLORSPACE { + CSC_EQ_COLORSPACE_SMPTE170M = 1, + CSC_EQ_COLORSPACE_SMPTE240M, + CSC_EQ_COLORSPACE_REC709, + CSC_EQ_COLORSPACE_BT878, + CSC_EQ_COLORSPACE_470_SYSTEM_M, + CSC_EQ_COLORSPACE_470_SYSTEM_BG +} CSC_EQ_COLORSPACE; + +typedef enum _CSC_EQ_RANGE { + CSC_EQ_RANGE_NARROW = 0, + CSC_EQ_RANGE_FULL +} CSC_EQ_RANGE; + +typedef enum _CSC_HW_FILTER { + CSC_FT_NONE = 0, + CSC_FT_BLUR, + CSC_FT_240, + CSC_FT_480, + CSC_FT_720, + CSC_FT_1080, + CSC_FT_MAX +} CSC_HW_FILTER; + +typedef struct _CSC_FORMAT { + unsigned int width; + unsigned int height; + unsigned int crop_left; + unsigned int crop_top; + unsigned int crop_width; + unsigned int crop_height; + unsigned int color_format; + unsigned int cacheable; + unsigned int mode_drm; +} CSC_FORMAT; + +typedef struct _CSC_BUFFER { + void *planes[CSC_MAX_PLANES]; + int mem_type; +} CSC_BUFFER; + +typedef struct _CSC_HW_PROPERTY { + int fixed_node; + int mode_drm; +} CSC_HW_PROPERTY; + +typedef struct _CSC_HANDLE { + CSC_FORMAT dst_format; + CSC_FORMAT src_format; + CSC_BUFFER dst_buffer; + CSC_BUFFER src_buffer; + CSC_METHOD csc_method; + CSC_HW_TYPE csc_hw_type; + void *csc_hw_handle; + CSC_HW_PROPERTY hw_property; + + /* CSC Equation */ + CSC_EQ_MODE csc_mode; + CSC_EQ_RANGE csc_range; + CSC_EQ_COLORSPACE colorspace; + + /* Denoising filter */ + CSC_HW_FILTER filter; +} CSC_HANDLE; + +/* + * change hal pixel format to omx pixel format + * + * @param hal_format + * hal pixel format[in] + * + * @return + * omx pixel format + */ +unsigned int hal_2_omx_pixel_format( + unsigned int hal_format); + +/* + * change omx pixel format to hal pixel format + * + * @param hal_format + * omx pixel format[in] + * + * @return + * hal pixel format + */ +unsigned int omx_2_hal_pixel_format( + unsigned int omx_format); + +/* + * Init CSC handle + * + * @return + * csc handle + */ +void *csc_init( + CSC_METHOD method); + +/* + * Deinit CSC handle + * + * @param handle + * CSC handle[in] + * + * @return + * error code + */ +CSC_ERRORCODE csc_deinit( + void *handle); + +/* + * get color space converter method + * + * @param handle + * CSC handle[in] + * + * @param method + * CSC method[out] + * + * @return + * error code + */ +CSC_ERRORCODE csc_get_method( + void *handle, + CSC_METHOD *method); + +/* + * set color space converter method + * + * @param handle + * CSC handle[in] + * + * @param method + * CSC method[in] + * + * @return + * error code + */ +CSC_ERRORCODE csc_set_method( + void *handle, + CSC_METHOD method); + +/* + * Set hw property + * + * @param handle + * CSC handle[in] + * + * @param property + * csc hw property[in] + * + * @param value + * csc hw property value[in] + * + * @return + * csc handle + */ +CSC_ERRORCODE csc_set_hw_property( + void *handle, + CSC_HW_PROPERTY_TYPE property, + int value); + +/* + * Get csc equation property. + * + * @param handle + * CSC handle[in] + * + * @param mode + * csc equation mode[out] + * + * @param colorspace + * csc color space[out] + * + * @param range + * csc equation range[out] + * + * @return + * error code + */ +CSC_ERRORCODE csc_get_eq_property( + void *handle, + CSC_EQ_MODE *csc_mode, + CSC_EQ_RANGE *csc_range, + CSC_EQ_COLORSPACE *colorspace); + +/* + * Set csc equation property. + * + * @param handle + * CSC handle[in] + * + * @param mode + * csc equation mode[in] + * + * @param colorspace + * csc color space[in] + * + * @param range + * csc equation range[in] + * + * @return + * error code + */ +CSC_ERRORCODE csc_set_eq_property( + void *handle, + CSC_EQ_MODE csc_mode, + CSC_EQ_RANGE csc_range, + CSC_EQ_COLORSPACE colorspace); + +/* + * Set csc filter property. + * + * @param handle + * CSC handle[in] + * + * @param filter + * csc filter info[in] + * + * @return + * error code + */ +CSC_ERRORCODE csc_set_filter_property( + void *handle, + CSC_HW_FILTER filter); + +/* + * Get source format. + * + * @param handle + * CSC handle[in] + * + * @param width + * address of image width[out] + * + * @param height + * address of image height[out] + * + * @param crop_left + * address of image left crop size[out] + * + * @param crop_top + * address of image top crop size[out] + * + * @param crop_width + * address of cropped image width[out] + * + * @param crop_height + * address of cropped image height[out] + * + * @param color_format + * address of source color format(HAL format)[out] + * + * @return + * error code + */ +CSC_ERRORCODE csc_get_src_format( + void *handle, + unsigned int *width, + unsigned int *height, + unsigned int *crop_left, + unsigned int *crop_top, + unsigned int *crop_width, + unsigned int *crop_height, + unsigned int *color_format, + unsigned int *cacheable); + +/* + * Set source format. + * Don't call each converting time. + * Pls call this function as below. + * 1. first converting time + * 2. format is changed + * + * @param handle + * CSC handle[in] + * + * @param width + * image width[in] + * + * @param height + * image height[in] + * + * @param crop_left + * image left crop size[in] + * + * @param crop_top + * image top crop size[in] + * + * @param crop_width + * cropped image width[in] + * + * @param crop_height + * cropped image height[in] + * + * @param color_format + * source color format(HAL format)[in] + * + * @return + * error code + */ +CSC_ERRORCODE csc_set_src_format( + void *handle, + unsigned int width, + unsigned int height, + unsigned int crop_left, + unsigned int crop_top, + unsigned int crop_width, + unsigned int crop_height, + unsigned int color_format, + unsigned int cacheable); + +/* + * Get destination format. + * + * @param handle + * CSC handle[in] + * + * @param width + * address of image width[out] + * + * @param height + * address of image height[out] + * + * @param crop_left + * address of image left crop size[out] + * + * @param crop_top + * address of image top crop size[out] + * + * @param crop_width + * address of cropped image width[out] + * + * @param crop_height + * address of cropped image height[out] + * + * @param color_format + * address of color format(HAL format)[out] + * + * @return + * error code + */ +CSC_ERRORCODE csc_get_dst_format( + void *handle, + unsigned int *width, + unsigned int *height, + unsigned int *crop_left, + unsigned int *crop_top, + unsigned int *crop_width, + unsigned int *crop_height, + unsigned int *color_format, + unsigned int *cacheable); + +/* + * Set destination format + * Don't call each converting time. + * Pls call this function as below. + * 1. first converting time + * 2. format is changed + * + * @param handle + * CSC handle[in] + * + * @param width + * image width[in] + * + * @param height + * image height[in] + * + * @param crop_left + * image left crop size[in] + * + * @param crop_top + * image top crop size[in] + * + * @param crop_width + * cropped image width[in] + * + * @param crop_height + * cropped image height[in] + * + * @param color_format + * destination color format(HAL format)[in] + * + * @return + * error code + */ +CSC_ERRORCODE csc_set_dst_format( + void *handle, + unsigned int width, + unsigned int height, + unsigned int crop_left, + unsigned int crop_top, + unsigned int crop_width, + unsigned int crop_height, + unsigned int color_format, + unsigned int cacheable); + +/* + * Setup source buffer + * set_format func should be called before this this func. + * + * @param handle + * CSC handle[in] + * + * @param src_buffer + * source buffer pointer array[in] + * + * @param y + * y or RGB destination pointer[in] + * + * @param u + * u or uv destination pointer[in] + * + * @param v + * v or none destination pointer[in] + * + * @return + * error code + */ +CSC_ERRORCODE csc_set_src_buffer( + void *handle, + void *addr[CSC_MAX_PLANES], + int mem_type); + +/* + * Setup destination buffer + * + * @param handle + * CSC handle[in] + * + * @param y + * y or RGB destination pointer[in] + * + * @param u + * u or uv destination pointer[in] + * + * @param v + * v or none destination pointer[in] + * + * @return + * error code + */ +CSC_ERRORCODE csc_set_dst_buffer( + void *handle, + void *addr[CSC_MAX_PLANES], + int mem_type); + +/* + * Convert color space with presetup color format + * + * @param handle + * CSC handle[in] + * + * @return + * error code + */ +CSC_ERRORCODE csc_convert( + void *handle); + +CSC_ERRORCODE csc_convert_with_rotation( + void *handle, int rotation, int flip_horizontal, int flip_vertical); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/exynos_format.h b/include/exynos_format.h new file mode 100755 index 0000000..23a0d0c --- /dev/null +++ b/include/exynos_format.h @@ -0,0 +1,224 @@ +/* + * Copyright@ Samsung Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#ifndef _EXYNOS_FORMAT_H_ +#define _EXYNOS_FORMAT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* HAL_PIXEL_FORMAT_YCbCr_422_P = 0x100, */ + HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M = 0x101, /* HAL_PIXEL_FORMAT_YCbCr_420_P */ + /* HAL_PIXEL_FORMAT_YCbCr_420_I = 0x102, */ + HAL_PIXEL_FORMAT_EXYNOS_CbYCrY_422_I = 0x103, /* HAL_PIXEL_FORMAT_CbYCrY_422_I */ + /* HAL_PIXEL_FORMAT_CbYCrY_420_I = 0x104, */ + HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M = 0x105, /* HAL_PIXEL_FORMAT_YCbCr_420_SP */ + HAL_PIXEL_FORMAT_EXYNOS_YCrCb_422_SP = 0x106, /* HAL_PIXEL_FORMAT_YCrCb_422_SP */ + HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_TILED= 0x107, /* HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED */ + HAL_PIXEL_FORMAT_EXYNOS_ARGB_8888 = 0x108, /* HAL_PIXEL_FORMAT_CUSTOM_ARGB_8888 */ + // support custom format for zero copy + /* HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP = 0x110 */ + /* HAL_PIXEL_FORMAT_CUSTOM_YCrCb_420_SP = 0x111, */ + /* HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP_TILED = 0x112, */ + /* HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_SP = 0x113, */ + /* HAL_PIXEL_FORMAT_CUSTOM_YCrCb_422_SP = 0x114, */ + /* HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_I = 0x115, */ + HAL_PIXEL_FORMAT_EXYNOS_YCrCb_422_I = 0x116, /* HAL_PIXEL_FORMAT_CUSTOM_YCrCb_422_I */ + /* HAL_PIXEL_FORMAT_CUSTOM_CbYCrY_422_I = 0x117, */ + HAL_PIXEL_FORMAT_EXYNOS_CrYCbY_422_I = 0x118, /* HAL_PIXEL_FORMAT_CUSTOM_CrYCbY_422_I */ + /* HAL_PIXEL_FORMAT_CUSTOM_CbYCr_422_I = 0x11B, */ + + HAL_PIXEL_FORMAT_EXYNOS_YV12_M = 0x11C, /* HAL_PIXEL_FORMAT_EXYNOS_YV12 */ + HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M = 0x11D, /* HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP */ + HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_FULL = 0x11E, /* HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_FULL */ + + /* newly added formats */ + HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P = 0x11F, + HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP = 0x120, + + /* Interlace EXYNOS_YCbCr_420_SP_M */ + HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_PRIV = 0x121, + + /* contiguous(single fd) custom formats */ + HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_PN = 0x122, + HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN = 0x123, + HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_TILED = 0x124, + + /* 10-bit format (8bit + separated 2bit) */ + HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_S10B = 0x125, + + /* 10-bit contiguous(single fd, 8bit + separated 2bit) custom formats */ + HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_S10B = 0x126, + + HAL_PIXEL_FORMAT_EXYNOS_MAX +}; + +/* for backward compatibility */ +#define HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M +#define HAL_PIXEL_FORMAT_CUSTOM_YCrCb_420_SP HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M + +// Gamut (colorspace range) +enum { + HAL_PIXEL_GAMUT_DEFAULT = 0, + // Values range 0-255 + HAL_PIXEL_GAMUT_WIDE_8, + // Values range 16-235 + HAL_PIXEL_GAMUT_NARROW_8 +}; + +// Chromaticities (colorspace parameters) +enum { + HAL_PIXEL_CHROMA_DEFAULT = 0, + // BT.601 "Standard Definition" color space + HAL_PIXEL_CHROMA_BT601_8, + // BT.709 "High Definition" color space + HAL_PIXEL_CHROMA_BT709_8 +}; + +struct ADDRS { + unsigned int addr_y; + unsigned int addr_cbcr; + unsigned int buf_idx; + unsigned int reserved; +}; + +/* 12 Y/CbCr 4:2:0 64x32 macroblocks */ +#define V4L2_PIX_FMT_NV12T v4l2_fourcc('T', 'V', '1', '2') + +#define ALIGN_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define ALIGN_DOWN(x, a) ((x) - (x % a)) +#ifndef ALIGN +#define ALIGN(x, a) ALIGN_UP(x, a) +#endif +#ifndef ALIGN_TO_32B +#define ALIGN_TO_32B(x) ((((x) + (1 << 5) - 1) >> 5) << 5) +#endif +#ifndef ALIGN_TO_128B +#define ALIGN_TO_128B(x) ((((x) + (1 << 7) - 1) >> 7) << 7) +#endif +#ifndef ALIGN_TO_8KB +#define ALIGN_TO_8KB(x) ((((x) + (1 << 13) - 1) >> 13) << 13) +#endif + +#define GET_32BPP_FRAME_SIZE(w, h) (((w) * (h)) << 2) +#define GET_24BPP_FRAME_SIZE(w, h) (((w) * (h)) * 3) +#define GET_16BPP_FRAME_SIZE(w, h) (((w) * (h)) << 1) + +/* + * Convert hal_pixel_format to v4l2_pixel_format. + * + * @param hal_pixel_format + * hal_pixel_format[in] + * + * @return + * v4l2_pixel_format + */ +int HAL_PIXEL_FORMAT_2_V4L2_PIX( + int hal_pixel_format); + +/* + * Convert v4l2_pixel_format to hal_pixel_format. + * + * @param v4l2_pixel_format + * v4l2_pixel_format[in] + * + * @return + * hal_pixel_format + */ +int V4L2_PIX_2_HAL_PIXEL_FORMAT( + int v4l2_pixel_format); + +/* + * Get frame_size of hal_pixel_format. + * + * @param hal_pixel_format + * hal_pixel_format[in] + * + * @param width + * width[in] + * + * @param height + * height[in] + * + * @return + * frame_size + */ +unsigned int FRAME_SIZE( + int hal_pixel_format, + int width, + int height); + +int PLANAR_FRAME_SIZE( + int hal_pixel_format, + int width, + int height, + unsigned int *luma_size, + unsigned int *chroma_size); + +int NUM_PLANES(int hal_pixel_format); + + +/* + * Get bpp and plane of v4l2_pixel_format. + * + * @param v4l2_pixel_format + * v4l2_pixel_format[in] + * + * @param bpp + * address of bpp[out] + * + * @param planes + * address of planes[out] + * + * @return + * error code + */ +int V4L2_PIX_2_YUV_INFO( + unsigned int v4l2_pixel_format, + unsigned int *bpp, + unsigned int *planes); + +/* + * Get bpp of v4l2_pixel_format. + * + * @param v4l2_pixel_format + * v4l2_pixel_format[in] + * + * @return + * bpp + */ +int get_yuv_bpp( + unsigned int v4l2_pixel_format); + +/* + * Get plane of v4l2_pixel_format. + * + * @param v4l2_pixel_format + * v4l2_pixel_format[in] + * + * @return + * num of plane + */ +int get_yuv_planes( + unsigned int v4l2_pixel_format); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/exynos_gscaler.h b/include/exynos_gscaler.h new file mode 100755 index 0000000..38b57a4 --- /dev/null +++ b/include/exynos_gscaler.h @@ -0,0 +1,519 @@ +/* + * + * Copyright 2012 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*! + * \file exynos_gscaler.h + * \brief header file for Gscaler HAL + * \author ShinWon Lee (shinwon.lee@samsung.com) + * \date 2012/01/09 + * + * <b>Revision History: </b> + * - 2012/01/09 : ShinWon Lee(shinwon.lee@samsung.com) \n + * Create + * + * - 2012/02/07 : ShinWon Lee(shinwon.lee@samsung.com) \n + * Change file name to exynos_gscaler.h + * + * - 2012/02/09 : Sangwoo, Parkk(sw5771.park@samsung.com) \n + * Use Multiple Gscaler by Multiple Process + * + * - 2012/02/20 : Sangwoo, Park(sw5771.park@samsung.com) \n + * Add exynos_gsc_set_rotation() API + * + * - 2012/02/20 : ShinWon Lee(shinwon.lee@samsung.com) \n + * Add size constrain + * + */ + +/*! + * \defgroup exynos_gscaler + * \brief API for gscaler + * \addtogroup Exynos + */ + +#ifndef EXYNOS_GSCALER_H_ +#define EXYNOS_GSCALER_H_ + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +//#define EXYNOS_GSC_TRACE 1 +#ifdef EXYNOS_GSC_TRACE +#define EXYNOS_GSC_LOG_TAG "Exynos_gscaler" +#define Exynos_gsc_In() Exynos_Log(EXYNOS_DEV_LOG_DEBUG, EXYNOS_GSC_LOG_TAG, "%s In , Line: %d", __FUNCTION__, __LINE__) +#define Exynos_gsc_Out() Exynos_Log(EXYNOS_DEV_LOG_DEBUG, EXYNOS_GSC_LOG_TAG, "%s Out , Line: %d", __FUNCTION__, __LINE__) +#else +#define Exynos_gsc_In() ((void *)0) +#define Exynos_gsc_Out() ((void *)0) +#endif + +typedef struct { + uint32_t x; + uint32_t y; + uint32_t w; + uint32_t h; + uint32_t fw; + uint32_t fh; + uint32_t format; + unsigned long yaddr; + unsigned long uaddr; + unsigned long vaddr; + uint32_t rot; + uint32_t cacheable; + uint32_t drmMode; + uint32_t narrowRgb; + int acquireFenceFd; + int releaseFenceFd; + int mem_type; + uint32_t pre_multi; +} exynos_mpp_img; + +enum SRC_BL_OP { + /* [0, 0] */ + SRC_BL_OP_CLR = 1, + /* [Sa, Sc] */ + SRC_BL_OP_SRC, + /* [Da, Dc] */ + SRC_BL_OP_DST, + /* [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */ + SRC_BL_OP_SRC_OVER, + /* [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */ + SRC_BL_OP_DST_OVER, + /* [Sa * Da, Sc * Da] */ + SRC_BL_OP_SRC_IN, + /* [Sa * Da, Sa * Dc] */ + SRC_BL_OP_DST_IN, + /* [Sa * (1 - Da), Sc * (1 - Da)] */ + SRC_BL_OP_SRC_OUT, + /* [Da * (1 - Sa), Dc * (1 - Sa)] */ + SRC_BL_OP_DST_OUT, + /* [Da, Sc * Da + (1 - Sa) * Dc] */ + SRC_BL_OP_SRC_ATOP, + /* [Sa, Sc * (1 - Da) + Sa * Dc ] */ + SRC_BL_OP_DST_ATOP, + /* [-(Sa * Da), Sc * (1 - Da) + (1 - Sa) * Dc] */ + SRC_BL_OP_XOR, + /* [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */ + SRC_BL_OP_DARKEN, + /* [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */ + SRC_BL_OP_LIGHTEN, + /** [Sa * Da, Sc * Dc] */ + SRC_BL_OP_MULTIPLY, + /* [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */ + SRC_BL_OP_SCREEN, + /* Saturate(S + D) */ + SRC_BL_OP_ADD +}; + +enum colorspace { + COLORSPACE_SMPTE170M, + COLORSPACE_SMPTE240M, + COLORSPACE_REC709, + COLORSPACE_BT878, + COLORSPACE_470_SYSTEM_M, + COLORSPACE_470_SYSTEM_BG, + COLORSPACE_JPEG, + COLORSPACE_SRGB, +}; + +struct SrcGlobalAlpha { + uint32_t enable; + unsigned int val; +}; + +struct CSC_Spec{ + uint32_t enable; // set 'true' for user-defined + enum colorspace space; + uint32_t wide; +}; + +struct SrcBlendInfo { + enum SRC_BL_OP blop; + unsigned int srcblendfmt; + unsigned int srcblendhpos; + unsigned int srcblendvpos; + unsigned int srcblendpremulti; + unsigned int srcblendstride; + unsigned int srcblendwidth; + unsigned int srcblendheight; + struct SrcGlobalAlpha globalalpha; + struct CSC_Spec cscspec; +}; + +/* + * Create libgscaler handle. + * Gscaler dev_num is dynamically changed. + * + * \ingroup exynos_gscaler + * + * \return + * libgscaler handle + */ +void *exynos_gsc_create( + void); + +/*! + * Create exclusive libgscaler handle. + * Other module can't use dev_num of Gscaler. + * + * \ingroup exynos_gscaler + * + * \param dev_num + * gscaler dev_num[in] + * \param gsc_mode + *It should be set to GSC_M2M_MODE or GSC_OUTPUT_MODE. + * + *\param out_mode + *It should be set to GSC_OUT_FIMD or GSC_OUT_TV. + * + * \return + * libgscaler handle + */ +void *exynos_gsc_create_exclusive( + int dev_num, + int gsc_mode, + int out_mode, + int allow_drm); + +/*! + * Destroy libgscaler handle + * + * \ingroup exynos_gscaler + * + * \param handle + * libgscaler handle[in] + */ +void exynos_gsc_destroy( + void *handle); + +/*! + * Set csc equation property + * + * \ingroup exynos_gscaler + * + * \param handle + * libgscaler handle[in] + * + * \param eq_auto + * csc mode (0: user, 1: auto)[in] + * + * \param range_full + * csc range (0: narrow, 1: full)[in] + * + * \param v4l2_colorspace + * ITU_R v4l2 colorspace(1: 601, 3: 709)[in] + */ +int exynos_gsc_set_csc_property( + void *handle, + unsigned int eq_auto, + unsigned int range_full, + unsigned int v4l2_colorspace); + +/*! + * Set source format. + * + * \ingroup exynos_gscaler + * + * \param handle + * libgscaler handle[in] + * + * \param width + * image width[in] + * + * \param height + * image height[in] + * + * \param crop_left + * image left crop size[in] + * + * \param crop_top + * image top crop size[in] + * + * \param crop_width + * cropped image width[in] + * + * \param crop_height + * cropped image height[in] + * + * \param v4l2_colorformat + * color format[in] + * + * \param cacheable + * ccacheable[in] + * + * \param mode_drm + * mode_drm[in] + * + * \return + * error code + */ +int exynos_gsc_set_src_format( + void *handle, + unsigned int width, + unsigned int height, + unsigned int crop_left, + unsigned int crop_top, + unsigned int crop_width, + unsigned int crop_height, + unsigned int v4l2_colorformat, + unsigned int cacheable, + unsigned int mode_drm); + +/*! + * Set destination format. + * + * \ingroup exynos_gscaler + * + * \param handle + * libgscaler handle[in] + * + * \param width + * image width[in] + * + * \param height + * image height[in] + * + * \param crop_left + * image left crop size[in] + * + * \param crop_top + * image top crop size[in] + * + * \param crop_width + * cropped image width[in] + * + * \param crop_height + * cropped image height[in] + * + * \param v4l2_colorformat + * color format[in] + * + * \param cacheable + * ccacheable[in] + * + * \param mode_drm + * mode_drm[in] + * + * \return + * error code + */ +int exynos_gsc_set_dst_format( + void *handle, + unsigned int width, + unsigned int height, + unsigned int crop_left, + unsigned int crop_top, + unsigned int crop_width, + unsigned int crop_height, + unsigned int v4l2_colorformat, + unsigned int cacheable, + unsigned int mode_drm); + +/*! + * Set rotation. + * + * \ingroup exynos_gscaler + * + * \param handle + * libgscaler handle[in] + * + * \param rotation + * image rotation. It should be multiple of 90[in] + * + * \param flip_horizontal + * image flip_horizontal[in] + * + * \param flip_vertical + * image flip_vertical[in] + * + * \return + * error code + */ +int exynos_gsc_set_rotation( + void *handle, + int rotation, + int flip_horizontal, + int flip_vertical); + +/*! + * Set source buffer + * + * \ingroup exynos_gscaler + * + * \param handle + * libgscaler handle[in] + * + * \param addr + * buffer pointer array[in] + * + * \param acquireFenceFd + * acquire fence fd for the buffer or -1[in] + * + * \return + * error code + */ +int exynos_gsc_set_src_addr( + void *handle, + void *addr[3], + int mem_type, + int acquireFenceFd); + +/*! + * Set destination buffer + * + * \param handle + * libgscaler handle[in] + * + * \param addr + * buffer pointer array[in] + * + * \param acquireFenceFd + * acquire fence fd for the buffer or -1[in] + * + * \return + * error code + */ +int exynos_gsc_set_dst_addr( + void *handle, + void *addr[3], + int mem_type, + int acquireFenceFd); + +/*! + * Convert color space with presetup color format + * + * \ingroup exynos_gscaler + * + * \param handle + * libgscaler handle[in] + * + * \return + * error code + */ +int exynos_gsc_convert( + void *handle); + +/* + * API for setting GSC subdev crop + * Used in OTF mode + */ +int exynos_gsc_subdev_s_crop( + void *handle, + exynos_mpp_img *src_img, + exynos_mpp_img *dst_img); + +/* +*api for setting the GSC config. +It configures the GSC for given config +*/ +int exynos_gsc_config_exclusive( + void *handle, + exynos_mpp_img *src_img, + exynos_mpp_img *dst_img); + +/* +*api for GSC-OUT run. +It queues the srcBuf to GSC and deques a buf from driver. +It should be called after configuring the GSC. +*/ +int exynos_gsc_run_exclusive( + void *handle, + exynos_mpp_img *src_img, + exynos_mpp_img *dst_img); + +/*! + * Create exclusive libgscaler blend handle. + * Other module can't use dev_num of Gscaler. + * + * \ingroup exynos_gscaler + * + * \param dev_num + * gscaler dev_num[in] + * \param gsc_mode + * \return + * libgscaler handle + */ +void *exynos_gsc_create_blend_exclusive( + int dev_num, + int gsc_mode, + int out_mode, + int allow_drm); + +/* +*api for setting the GSC blend config. +It configures the GSC for given config +*/ +int exynos_gsc_config_blend_exclusive( + void *handle, + exynos_mpp_img *src_img, + exynos_mpp_img *dst_img, + struct SrcBlendInfo *srcblendinfo); + +/* + * Blocks until the current frame is done processing. + */ +int exynos_gsc_wait_frame_done_exclusive +(void *handle); + +/* +*api for GSC stop. +It stops the GSC OUT streaming. +*/ +int exynos_gsc_stop_exclusive +(void *handle); + +/* +*api for GSC free_and_close. +*/ +int exynos_gsc_free_and_close +(void *handle); + +enum { + GSC_M2M_MODE = 0, + GSC_OUTPUT_MODE, + GSC_CAPTURE_MODE, + GSC_RESERVED_MODE, +}; + +/*flag info */ +enum { + GSC_DUMMY = 0, + GSC_OUT_FIMD, + GSC_OUT_TV, + GSC_RESERVED, +}; + +enum { + GSC_DONE_CNG_CFG = 0, + GSC_NEED_CNG_CFG, +}; + +enum { + GSC_MEM_MMAP = 1, + GSC_MEM_USERPTR, + GSC_MEM_OVERLAY, + GSC_MEM_DMABUF, +}; + +#ifdef __cplusplus +} +#endif + +#endif /*EXYNOS_GSCALER_H_*/ diff --git a/include/exynos_ion.h b/include/exynos_ion.h new file mode 100755 index 0000000..ed79198 --- /dev/null +++ b/include/exynos_ion.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIB_ION_H_ +#define _LIB_ION_H_ + +#define ION_HEAP_EXYNOS_CONTIG_MASK (1 << 4) +#define ION_EXYNOS_VIDEO_EXT_MASK (1 << 31) +#define ION_EXYNOS_VIDEO_EXT2_MASK (1 << 29) +#define ION_EXYNOS_FIMD_VIDEO_MASK (1 << 28) +#define ION_EXYNOS_GSC_MASK (1 << 27) +#define ION_EXYNOS_MFC_OUTPUT_MASK (1 << 26) +#define ION_EXYNOS_MFC_INPUT_MASK (1 << 25) +#define ION_EXYNOS_G2D_WFD_MASK (1 << 22) +#define ION_EXYNOS_VIDEO_MASK (1 << 21) + +enum { + ION_EXYNOS_HEAP_ID_CRYPTO = 1, + ION_EXYNOS_HEAP_ID_VIDEO_FW = 2, + ION_EXYNOS_HEAP_ID_VIDEO_STREAM = 3, + ION_EXYNOS_HEAP_ID_RESERVED = 4, + ION_EXYNOS_HEAP_ID_VIDEO_FRAME = 5, + ION_EXYNOS_HEAP_ID_VIDEO_SCALER = 6, + ION_EXYNOS_HEAP_ID_VIDEO_NFW = 7, + ION_EXYNOS_HEAP_ID_GPU_CRC = 8, + ION_EXYNOS_HEAP_ID_GPU_BUFFER = 9, + ION_EXYNOS_HEAP_ID_CAMERA = 10, +}; + +#define EXYNOS_ION_HEAP_CRYPTO_MASK (1 << ION_EXYNOS_HEAP_ID_CRYPTO) +#define EXYNOS_ION_HEAP_VIDEO_FW_MASK (1 << ION_EXYNOS_HEAP_ID_VIDEO_FW) +#define EXYNOS_ION_HEAP_VIDEO_STREAM_MASK (1 << ION_EXYNOS_HEAP_ID_VIDEO_STREAM) +#define EXYNOS_ION_HEAP_VIDEO_FRAME_MASK (1 << ION_EXYNOS_HEAP_ID_VIDEO_FRAME) +#define EXYNOS_ION_HEAP_VIDEO_SCALER_MASK (1 << ION_EXYNOS_HEAP_ID_VIDEO_SCALER) +#define EXYNOS_ION_HEAP_VIDEO_NFW_MASK (1 << ION_EXYNOS_HEAP_ID_VIDEO_NFW) +#define EXYNOS_ION_HEAP_GPU_CRC (1 << ION_EXYNOS_HEAP_ID_GPU_CRC) +#define EXYNOS_ION_HEAP_GPU_BUFFER (1 << ION_EXYNOS_HEAP_ID_GPU_BUFFER) +#define EXYNOS_ION_HEAP_CAMERA (1 << ION_EXYNOS_HEAP_ID_CAMERA) + +#endif /* _LIB_ION_H_ */ diff --git a/include/exynos_log.h b/include/exynos_log.h new file mode 100755 index 0000000..1b1faee --- /dev/null +++ b/include/exynos_log.h @@ -0,0 +1,56 @@ +#ifndef _EXYNOS_LOG_H_ +#define _EXYNOS_LOG_H_ + +#ifdef USE_DLOG +#include <dlog.h> + +static void __log_print(int level, const char *msg, ...) { + va_list argptr; + + va_start(argptr, msg); + + switch (level) { + case 1: + SLOG_VA(LOG_DEBUG, LOG_TAG, msg, argptr); + break; + case 2: + SLOG_VA(LOG_INFO, LOG_TAG, msg, argptr); + break; + case 3: + SLOG_VA(LOG_WARN, LOG_TAG, msg, argptr); + break; + case 4: + SLOG_VA(LOG_ERROR, LOG_TAG, msg, argptr); + break; + default: + SLOG_VA(LOG_DEBUG, LOG_TAG, msg, argptr); + break; + } + + va_end(argptr); +} + +#undef ALOGV +#undef ALOGD +#undef ALOGI +#undef ALOGW +#undef ALOGE + +#define ALOGV(...) __log_print(1, __VA_ARGS__) +#define ALOGD(...) __log_print(1, __VA_ARGS__) +#define ALOGI(...) __log_print(2, __VA_ARGS__) +#define ALOGW(...) __log_print(3, __VA_ARGS__) +#define ALOGE(...) __log_print(4, __VA_ARGS__) + +#else +#include <stdio.h> + +#define ALOGV(fmt, ...) printf("VERBOS: " fmt "\n", ##__VA_ARGS__) +#define ALOGD(fmt, ...) printf("DEBUG: " fmt "\n", ##__VA_ARGS__) +#define ALOGI(fmt, ...) printf("INFO: " fmt "\n", ##__VA_ARGS__) +#define ALOGW(fmt, ...) printf("WARNING: " fmt "\n", ##__VA_ARGS__) +#define ALOGE(fmt, ...) printf("ERROR: " fmt "\n", ##__VA_ARGS__) +#endif // USE_DLOG + +#endif // _LOG_H_ + diff --git a/include/exynos_scaler.h b/include/exynos_scaler.h new file mode 100755 index 0000000..1eea919 --- /dev/null +++ b/include/exynos_scaler.h @@ -0,0 +1,451 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * Copyright@ Samsung Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*! + * \file exynos_scaler.c + * \brief header file for Scaler HAL + * \author Sunyoung Kang (sy0816.kang@samsung.com) + * \date 2013/02/01 + * + * <b>Revision History: </b> + * - 2013.02.01 : Sunyoung Kang (sy0816.kang@samsung.com) \n + * Create + * + * - 2013.04.26 : Cho KyongHo (pullip.cho@samsung.com \n + * Library rewrite + * + */ + +#ifndef _EXYNOS_SCALER_H_ +#define _EXYNOS_SCALER_H_ + + +#include <linux/videodev2.h> +#include <linux/videodev2_exynos_media.h> +#include <stdbool.h> + +#include <exynos_format.h> +#include <exynos_v4l2.h> +#include <exynos_gscaler.h> + +#define SC_DEV_NODE "/dev/video" +#define SC_NODE(x) (50 + x) + +#define SC_NUM_OF_PLANES (3) + +#define V4L2_PIX_FMT_NV12_RGB32 v4l2_fourcc('N', 'V', '1', 'R') +#define V4L2_PIX_FMT_NV12N_RGB32 v4l2_fourcc('N', 'N', '1', 'R') +#define V4L2_PIX_FMT_NV12M_RGB32 v4l2_fourcc('N', 'V', 'R', 'G') +#define V4L2_PIX_FMT_NV12M_BGR32 v4l2_fourcc('N', 'V', 'B', 'G') +#define V4L2_PIX_FMT_NV12M_RGB565 v4l2_fourcc('N', 'V', 'R', '6') +#define V4L2_PIX_FMT_NV12M_RGB444 v4l2_fourcc('N', 'V', 'R', '4') +#define V4L2_PIX_FMT_NV12M_RGB555X v4l2_fourcc('N', 'V', 'R', '5') +#define V4L2_PIX_FMT_NV12MT_16X16_RGB32 v4l2_fourcc('V', 'M', 'R', 'G') + +#define V4L2_CID_2D_SRC_BLEND_SET_FMT (V4L2_CID_EXYNOS_BASE + 116) +#define V4L2_CID_2D_SRC_BLEND_SET_H_POS (V4L2_CID_EXYNOS_BASE + 117) +#define V4L2_CID_2D_SRC_BLEND_SET_V_POS (V4L2_CID_EXYNOS_BASE + 118) +#define V4L2_CID_2D_SRC_BLEND_FMT_PREMULTI (V4L2_CID_EXYNOS_BASE + 119) +#define V4L2_CID_2D_SRC_BLEND_SET_STRIDE (V4L2_CID_EXYNOS_BASE + 120) +#define V4L2_CID_2D_SRC_BLEND_SET_WIDTH (V4L2_CID_EXYNOS_BASE + 121) +#define V4L2_CID_2D_SRC_BLEND_SET_HEIGHT (V4L2_CID_EXYNOS_BASE + 122) + +#ifdef SCALER_USE_LOCAL_CID +#define V4L2_CID_GLOBAL_ALPHA (V4L2_CID_EXYNOS_BASE + 1) +#define V4L2_CID_2D_BLEND_OP (V4L2_CID_EXYNOS_BASE + 103) +#define V4L2_CID_2D_COLOR_FILL (V4L2_CID_EXYNOS_BASE + 104) +#define V4L2_CID_2D_DITH (V4L2_CID_EXYNOS_BASE + 105) +#define V4L2_CID_2D_FMT_PREMULTI (V4L2_CID_EXYNOS_BASE + 106) +#endif + +#define LIBSC_V4L2_CID_DNOISE_FT (V4L2_CID_EXYNOS_BASE + 150) +#define LIBSC_M2M1SHOT_OP_FILTER_SHIFT (28) +#define LIBSC_M2M1SHOT_OP_FILTER_MASK (0xf << 28) + +// libgscaler's internal use only +typedef enum _HW_SCAL_ID { + HW_SCAL0 = 4, + HW_SCAL1, + HW_SCAL2, + HW_SCAL_MAX, +} HW_SCAL_ID; + +// argument of non-blocking api +typedef exynos_mpp_img exynos_sc_img; + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * Create libscaler handle + * + * \ingroup exynos_scaler + * + * \param dev_num + * scaler dev_num[in] + * + * \return + * libscaler handle + */ +void *exynos_sc_create(int dev_num); + +/*! + * Destroy libscaler handle + * + * \ingroup exynos_scaler + * + * \param handle + * libscaler handle[in] + */ +int exynos_sc_destroy(void *handle); + +/*! + * Convert color space with presetup color format + * + * \ingroup exynos_scaler + * + * \param handle + * libscaler handle[in] + * + * \return + * error code + */ +int exynos_sc_convert(void *handle); + +/*! + * Convert color space with presetup color format + * + * \ingroup exynos_scaler + * + * \param handle + * libscaler handle + * + * \param csc_range + * csc narrow/wide property + * + * \param v4l2_colorspace + * csc equation property + * + * \param filter + * denoise filter info + * + * \return + * error code + */ +int exynos_sc_set_csc_property( + void *handle, + unsigned int csc_range, + unsigned int v4l2_colorspace, + unsigned int filter); + +/*! + * Set source format. + * + * \ingroup exynos_scaler + * + * \param handle + * libscaler handle[in] + * + * \param width + * image width[in] + * + * \param height + * image height[in] + * + * \param crop_left + * image left crop size[in] + * + * \param crop_top + * image top crop size[in] + * + * \param crop_width + * cropped image width[in] + * + * \param crop_height + * cropped image height[in] + * + * \param v4l2_colorformat + * color format[in] + * + * \param cacheable + * ccacheable[in] + * + * \param mode_drm + * mode_drm[in] + * + * \param premultiplied + * pre-multiplied format[in] + * + * \return + * error code + */ +int exynos_sc_set_src_format( + void *handle, + unsigned int width, + unsigned int height, + unsigned int crop_left, + unsigned int crop_top, + unsigned int crop_width, + unsigned int crop_height, + unsigned int v4l2_colorformat, + unsigned int cacheable, + unsigned int mode_drm, + unsigned int premultiplied); + +/*! + * Set destination format. + * + * \ingroup exynos_scaler + * + * \param handle + * libscaler handle[in] + * + * \param width + * image width[in] + * + * \param height + * image height[in] + * + * \param crop_left + * image left crop size[in] + * + * \param crop_top + * image top crop size[in] + * + * \param crop_width + * cropped image width[in] + * + * \param crop_height + * cropped image height[in] + * + * \param v4l2_colorformat + * color format[in] + * + * \param cacheable + * ccacheable[in] + * + * \param mode_drm + * mode_drm[in] + * + * \param premultiplied + * pre-multiplied format[in] + * + * \return + * error code + */ +int exynos_sc_set_dst_format( + void *handle, + unsigned int width, + unsigned int height, + unsigned int crop_left, + unsigned int crop_top, + unsigned int crop_width, + unsigned int crop_height, + unsigned int v4l2_colorformat, + unsigned int cacheable, + unsigned int mode_drm, + unsigned int premultiplied); + +/*! + * Set source buffer + * + * \ingroup exynos_scaler + * + * \param handle + * libscaler handle[in] + * + * \param addr + * buffer pointer array[in] + * + * \param mem_type + * memory type[in] + * + * \param acquireFenceFd + * acquire fence fd for the buffer or -1[in] + * + * \return + * error code + */ + +int exynos_sc_set_src_addr( + void *handle, + void *addr[SC_NUM_OF_PLANES], + int mem_type, + int acquireFenceFd); + +/*! + * Set destination buffer + * + * \param handle + * libscaler handle[in] + * + * \param addr + * buffer pointer array[in] + * + * \param mem_type + * memory type[in] + * + * \param acquireFenceFd + * acquire fence fd for the buffer or -1[in] + * + * \return + * error code + */ +int exynos_sc_set_dst_addr( + void *handle, + void *addr[SC_NUM_OF_PLANES], + int mem_type, + int acquireFenceFd); + +/*! + * Set rotation. + * + * \ingroup exynos_scaler + * + * \param handle + * libscaler handle[in] + * + * \param rot + * image rotation. It should be multiple of 90[in] + * + * \param flip_h + * image flip_horizontal[in] + * + * \param flip_v + * image flip_vertical[in] + * + * \return + * error code + */ +int exynos_sc_set_rotation( + void *handle, + int rot, + int flip_h, + int flip_v); + +////// non-blocking ///// + +void *exynos_sc_create_exclusive( + int dev_num, + int allow_drm); + +int exynos_sc_csc_exclusive(void *handle, + unsigned int range_full, + unsigned int v4l2_colorspace); + +int exynos_sc_config_exclusive( + void *handle, + exynos_sc_img *src_img, + exynos_sc_img *dst_img); + +int exynos_sc_run_exclusive( + void *handle, + exynos_sc_img *src_img, + exynos_sc_img *dst_img); + +void *exynos_sc_create_blend_exclusive( + int dev_num, + int allow_drm); + +int exynos_sc_config_blend_exclusive( + void *handle, + exynos_sc_img *src_img, + exynos_sc_img *dst_img, + struct SrcBlendInfo *srcblendinfo); + +int exynos_sc_wait_frame_done_exclusive +(void *handle); + +int exynos_sc_stop_exclusive +(void *handle); + +int exynos_sc_free_and_close +(void *handle); + + +/****************************************************************************** + ******** API for Copy Pixels between RGB data ******************************** + ******************************************************************************/ + +/*! + * Description of an image for both of the source and the destination. + * + * \ingroup exynos_scaler + */ +struct exynos_sc_pxinfo_img +{ + void *addr; + unsigned int width; + unsigned int height; + unsigned int crop_left; + unsigned int crop_top; + unsigned int crop_width; + unsigned int crop_height; + unsigned int pxfmt; // enum EXYNOS_SC_FMT_PXINFO +}; + +/*! + * Description of a pixel copy + * + * \ingroup exynos_scaler + */ +struct exynos_sc_pxinfo { + struct exynos_sc_pxinfo_img src; + struct exynos_sc_pxinfo_img dst; + unsigned short rotate; // 0 ~ 360 + char hflip; // non-zero value for hflip + char vflip; // non-zero value for vflip +}; + +/*! + * Pixel format definition for pixel copy + * + * \ingroup exynos_scaler + */ +enum SC_FMT_PXINFO { + EXYNOS_SC_FMT_RGB32 = 0x10, + EXYNOS_SC_FMT_BGR32, + EXYNOS_SC_FMT_RGB565, + EXYNOS_SC_FMT_RGB555X, + EXYNOS_SC_FMT_RGB444, +}; + +/*! + * Copy pixel data from RGB to RGB + * + * \ingroup exynos_scaler + * + * \param pxinfo + * information for pixel data copy [in] + * + * \param dev_num + * Scaler H/W instance number. Starts from 0 [in] + * + * \return + * true on success in copying pixel data. + * false on failure. + */ +bool exynos_sc_copy_pixels( + struct exynos_sc_pxinfo *pxinfo, + int dev_num); + +#ifdef __cplusplus +} +#endif + +#endif /* _EXYNOS_SCALER_H_ */ diff --git a/include/exynos_v4l2.h b/include/exynos_v4l2.h new file mode 100755 index 0000000..6320529 --- /dev/null +++ b/include/exynos_v4l2.h @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*! + * \file exynos_v4l2.h + * \brief header file for libv4l2 + * \author Jinsung Yang (jsgood.yang@samsung.com) + * \date 2011/12/15 + * + * <b>Revision History: </b> + * - 2011/12/15 : Jinsung Yang (jsgood.yang@samsung.com) \n + * Initial version + * + */ + +/*! + * \defgroup exynos_v4l2 + * \brief API for v4l2 + * \addtogroup Exynos + */ + +#ifndef __EXYNOS_LIB_V4L2_H__ +#define __EXYNOS_LIB_V4L2_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* V4L2 */ +#include <stdbool.h> +#include <linux/videodev2.h> /* vendor specific videodev2.h */ + +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_open(const char *filename, int oflag, ...); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_open_devname(const char *devname, int oflag, ...); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_close(int fd); +/*! \ingroup exynos_v4l2 */ +bool exynos_v4l2_enuminput(int fd, int index, char *input_name_buf); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_s_input(int fd, int index); +/*! \ingroup exynos_v4l2 */ +bool exynos_v4l2_querycap(int fd, unsigned int need_caps); +/*! \ingroup exynos_v4l2 */ +bool exynos_v4l2_enum_fmt(int fd, enum v4l2_buf_type type, unsigned int fmt); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_g_fmt(int fd, struct v4l2_format *fmt); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_s_fmt(int fd, struct v4l2_format *fmt); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_try_fmt(int fd, struct v4l2_format *fmt); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_reqbufs(int fd, struct v4l2_requestbuffers *req); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_querybuf(int fd, struct v4l2_buffer *buf); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_qbuf(int fd, struct v4l2_buffer *buf); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_dqbuf(int fd, struct v4l2_buffer *buf); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_streamon(int fd, enum v4l2_buf_type type); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_streamoff(int fd, enum v4l2_buf_type type); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_cropcap(int fd, struct v4l2_cropcap *crop); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_g_crop(int fd, struct v4l2_crop *crop); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_s_crop(int fd, struct v4l2_crop *crop); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_g_ctrl(int fd, unsigned int id, int *value); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_s_ctrl(int fd, unsigned int id, int value); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_prepare(int fd, struct v4l2_buffer *arg); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_g_parm(int fd, struct v4l2_streamparm *streamparm); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_s_parm(int fd, struct v4l2_streamparm *streamparm); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_g_ext_ctrl(int fd, struct v4l2_ext_controls *ctrl); +/*! \ingroup exynos_v4l2 */ +int exynos_v4l2_s_ext_ctrl(int fd, struct v4l2_ext_controls *ctrl); + +/* V4L2_SUBDEV */ +#include <linux/v4l2-subdev.h> + +/*! \ingroup exynos_v4l2 */ +int exynos_subdev_open(const char *filename, int oflag, ...); +/*! \ingroup exynos_v4l2 */ +int exynos_subdev_get_node_num(const char *devname, int oflag, ...); +/*! \ingroup exynos_v4l2 */ +int exynos_subdev_open_devname(const char *devname, int oflag, ...); +/*! \ingroup exynos_v4l2 */ +int exynos_subdev_close(int fd); +/*! \ingroup exynos_v4l2 */ +int exynos_subdev_enum_frame_size(int fd, struct v4l2_subdev_frame_size_enum *frame_size_enum); +/*! \ingroup exynos_v4l2 */ +int exynos_subdev_g_fmt(int fd, struct v4l2_subdev_format *fmt); +/*! \ingroup exynos_v4l2 */ +int exynos_subdev_s_fmt(int fd, struct v4l2_subdev_format *fmt); +/*! \ingroup exynos_v4l2 */ +int exynos_subdev_g_crop(int fd, struct v4l2_subdev_crop *crop); +/*! \ingroup exynos_v4l2 */ +int exynos_subdev_s_crop(int fd, struct v4l2_subdev_crop *crop); +/*! \ingroup exynos_v4l2 */ +int exynos_subdev_enum_frame_interval(int fd, struct v4l2_subdev_frame_interval_enum *frame_internval_enum); +/*! \ingroup exynos_v4l2 */ +int exynos_subdev_g_frame_interval(int fd, struct v4l2_subdev_frame_interval *frame_internval_enum); +/*! \ingroup exynos_v4l2 */ +int exynos_subdev_s_frame_interval(int fd, struct v4l2_subdev_frame_interval *frame_internval_enum); +/*! \ingroup exynos_v4l2 */ +int exynos_subdev_enum_mbus_code(int fd, struct v4l2_subdev_mbus_code_enum *mbus_code_enum); + +/* MEDIA CONTORLLER */ +#include "media.h" + +/*! media_link + * \ingroup exynos_v4l2 + */ +struct media_link { + struct media_pad *source; + struct media_pad *sink; + struct media_link *twin; + __u32 flags; + __u32 padding[3]; +}; + +/*! media_link + * \ingroup exynos_v4l2 + */ +struct media_pad { + struct media_entity *entity; + __u32 index; + __u32 flags; + __u32 padding[3]; +}; + +/*! media_link + * \ingroup exynos_v4l2 + */ +struct media_entity { + struct media_device *media; + struct media_entity_desc info; + struct media_pad *pads; + struct media_link *links; + unsigned int max_links; + unsigned int num_links; + + char devname[32]; + int fd; + __u32 padding[6]; +}; + +/*! media_link + * \ingroup exynos_v4l2 + */ +struct media_device { + int fd; + struct media_entity *entities; + unsigned int entities_count; + void (*debug_handler)(void *, ...); + void *debug_priv; + __u32 padding[6]; +}; + +/*! \ingroup exynos_v4l2 */ +struct media_device *exynos_media_open(const char *filename); +/*! \ingroup exynos_v4l2 */ +void exynos_media_close(struct media_device *media); +/*! \ingroup exynos_v4l2 */ +struct media_pad *exynos_media_entity_remote_source(struct media_pad *pad); +/*! \ingroup exynos_v4l2 */ +struct media_entity *exynos_media_get_entity_by_name(struct media_device *media, const char *name, size_t length); +/*! \ingroup exynos_v4l2 */ +struct media_entity *exynos_media_get_entity_by_id(struct media_device *media, __u32 id); +/*! \ingroup exynos_v4l2 */ +int exynos_media_setup_link(struct media_device *media, struct media_pad *source, struct media_pad *sink, __u32 flags); +/*! \ingroup exynos_v4l2 */ +int exynos_media_reset_links(struct media_device *media); +/*! \ingroup exynos_v4l2 */ +struct media_pad *exynos_media_parse_pad(struct media_device *media, const char *p, char **endp); +/*! \ingroup exynos_v4l2 */ +struct media_link *exynos_media_parse_link(struct media_device *media, const char *p, char **endp); +/*! \ingroup exynos_v4l2 */ +int exynos_media_parse_setup_link(struct media_device *media, const char *p, char **endp); +/*! \ingroup exynos_v4l2 */ +int exynos_media_parse_setup_links(struct media_device *media, const char *p); + +#ifdef __cplusplus +} +#endif + +#endif /* __EXYNOS_LIB_V4L2_H__ */ diff --git a/include/ion.h b/include/ion.h new file mode 100755 index 0000000..67161ca --- /dev/null +++ b/include/ion.h @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2012 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIB_ION_H_ +#define _LIB_ION_H_ + +#include <unistd.h> /* size_t */ + +#define ION_FLAG_CACHED 1 +#define ION_FLAG_CACHED_NEEDS_SYNC 2 +#define ION_FLAG_PRESERVE_KMAP 4 +#define ION_FLAG_NOZEROED 8 + +#define ION_HEAP_SYSTEM_MASK (1 << 0) +#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << 1) +#define ION_HEAP_EXYNOS_CONTIG_MASK (1 << 4) +#define ION_HEAP_EXYNOS_MASK (1 << 5) +#define ION_EXYNOS_VIDEO_MASK (1 << 21) +#define ION_EXYNOS_FIMD_VIDEO_MASK (1 << 28) +#define ION_EXYNOS_GSC_MASK (1 << 27) +#define ION_EXYNOS_MFC_OUTPUT_MASK (1 << 26) +#define ION_EXYNOS_MFC_INPUT_MASK (1 << 25) + + +/* ION_MSYNC_FLAGS + * values of @flags parameter to ion_msync() + * + * IMSYNC_DEV_TO_READ: Device only reads the buffer + * IMSYNC_DEV_TO_WRITE: Device may writes to the buffer + * IMSYNC_DEV_TO_RW: Device reads and writes to the buffer + * + * IMSYNC_SYNC_FOR_DEV: ion_msync() for device to access the buffer + * IMSYNC_SYNC_FOR_CPU: ion_msync() for CPU to access the buffer after device + * has accessed it. + * + * The values must be ORed with one of IMSYNC_DEV_* and one of IMSYNC_SYNC_*. + * Otherwise, ion_msync() will not effect. + */ +enum ION_MSYNC_FLAGS { + IMSYNC_DEV_TO_READ = 0, + IMSYNC_DEV_TO_WRITE = 1, + IMSYNC_DEV_TO_RW = 2, + IMSYNC_SYNC_FOR_DEV = 0x10000, + IMSYNC_SYNC_FOR_CPU = 0x20000, +}; + +struct ion_preload_object { + size_t len; + unsigned int count; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/* ion_client + * An ION client is an object or an entity that needs to use the service of + * ION and has unique address space. ion_client is an identifier of an ION + * client and it represents the ION client. + * All operations on ION needs a valid ion_client value and it can be obtained + * by ion_client_create(). + */ +typedef int ion_client; + +/* ion_buffer + * An identifier of a buffer allocated from ION. You must obtain to access + * a buffer allocated from ION. If you have an effective ion_buffer, you have + * three options to work with it. + * - To access the buffer, you can request an address (user virtual address) + * of the buffer with ion_map(). + * - To pass the buffer to the kernel, you can pass the ion_buffer to the + * kernel driver directly, if the kernel driver can work with ION. + * - To pass the buffer to other processes, you can pass the ion_buffer to + * other processes through RPC machanism such as socket communication or + * Android Binder because ion_buffer is actually an open file descripotor + * of the current process. + */ +typedef int ion_buffer; + +typedef unsigned int ion_handle; + +/* ion_client_create() + * @RETURN: new ion_client. + * netative value if creating new ion_client is failed. + * + * A call to ion_client_create() must be paired with ion_client_destroy(), + * symmetrically. ion_client_destroy() needs a valid ion_client that + * is returned by ion_client_create(). + */ +ion_client ion_client_create(void); + +/* ion_client_destroy() + * @client: An ion_client value to remove. + */ +void ion_client_destroy(ion_client client); + +/* ion_alloc() - Allocates new buffer from ION. + * @client: A valid ion_client value returned by ion_client_create(). + * @len: Size of a buffer required in bytes. + * @align: Alignment requirements of @len and the start address of the allocated + * buffer. If the @len is not aligned by @align, ION allocates a buffer + * that is aligned by @align and the size of the buffer will be larger + * than @len. + * @heap_mask: Mask of heaps which you want this allocation to be served from. + * @flags: Additional requirements about buffer. ION_FLAG_CACHED for a + * buffer you want to have a cached mapping of + * @RETURN: An ion_buffer that represents the buffer allocated. It is only + * unique in the context of the given client, @client. + * -error if the allocation failed. + * See the description of ion_buffer above for detailed information. + */ +ion_buffer ion_alloc(ion_client client, size_t len, size_t align, + unsigned int heap_mask, unsigned int flags); + +/* ion_free() - Frees an existing buffer that is allocated by ION + * @buffer: An ion_buffer of the buffer to be released. + */ +void ion_free(ion_buffer buffer); + +/* ion_map() - Obtains a virtual address of the buffer identied by @buffer + * @buffer: The buffer to map. The virtual address returned is allocated by the + * kernel. + * @len: The size of the buffer to map. This must not exceed the size of the + * buffer represented by @fd_buf. Thus you need to know the size of it + * before calling this function. If @len is less than the size of the + * buffer, this function just map just the size requested (@len) not the + * entire buffer. + * @offset: How many pages will be ignored while mapping.@offset number of + * pages from the start of the buffer will not be mapped. + * @RETURN: The start virtual addres mapped. + * MAP_FAILED if mapping fails. + * + * Note that @len + (@offset * PAGE_SIZE) must not exceed the size of the + * buffer. + */ +void *ion_map(ion_buffer buffer, size_t len, off_t offset); + +/* ion_unmap() - Frees the buffer mapped by ion_map() + * @addr: The address returned by ion_map(). + * @len: The size of the buffer mapped by ion_map(). + * @RETURN: 0 on success, and -1 on failure. + * errno is also set on failure. + */ +int ion_unmap(void *addr, size_t len); + +/* ion_msync() - Makes sure that data in the buffer are visible to H/W peri. + * @client: A valid ion_client value returned by ion_client_create(). + * @buffer: The buffer to perform ion_msync(). + * @flags: Direction of access of H/W peri and CPU. See the description of + * ION_MSYNC_FLAGS. + * @size: Size to ion_msync() in bytes. + * @offset: Where ion_msync() start in @buffer, size in bytes. + * @RETURN: 0 if successful. -error, otherwise. + * + * Note that @offset + @size must not exceed the size of @buffer. + */ +int ion_sync(ion_client client, ion_buffer buffer); + +/* ion_sync_range() - Make sure the specified range in the buffer are visible to H/W + * @client: A valid ion_client value returned by ion_client_create(). + * @sahre_fd: A valid file descriptor for the buffer(mostely returned by ion_alloc()) + * @addr: start address of the region to sync. + It must be the mapped address of the buffer specified by @dmabuf_fd. + * @size: size of the region to sync. + */ +int ion_sync_range(ion_client client, int dmabuf_fd, void *addr, size_t size); + +int ion_incRef(int fd, int share_fd, ion_handle *handle); + +int ion_decRef(int fd, ion_handle handle); + +#ifdef __cplusplus +} +#endif +#endif /* _LIB_ION_H_ */ diff --git a/include/linux/compiler.h b/include/linux/compiler.h new file mode 100755 index 0000000..9dd0d8a --- /dev/null +++ b/include/linux/compiler.h @@ -0,0 +1,95 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + *** To edit the content of this header, modify the corresponding + *** source file (e.g. under external/kernel-headers/original/) then + *** run bionic/libc/kernel/tools/update_all.py + *** + *** Any manual change here will be lost the next time this script will + *** be run. You've been warned! + *** + **************************************************************************** + ****************************************************************************/ +#ifndef __LINUX_COMPILER_H +#define __LINUX_COMPILER_H +#ifndef __ASSEMBLY__ +#define __user +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define __kernel +#define __safe +#define __force +#define __nocast +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define __iomem +#define __chk_user_ptr(x) (void) 0 +#define __chk_io_ptr(x) (void) 0 +#define __builtin_warning(x,y...) (1) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define __must_hold(x) +#define __acquires(x) +#define __releases(x) +#define __acquire(x) (void) 0 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define __release(x) (void) 0 +#define __cond_lock(x,c) (c) +#define __percpu +#define __rcu +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ___PASTE(a,b) a ##b +#define __PASTE(a,b) ___PASTE(a, b) +#endif +#ifndef __attribute_const__ +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define __attribute_const__ +#endif +#ifndef __cold +#define __cold +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#endif +#ifndef __section +#define __section(S) __attribute__((__section__(#S))) +#endif +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#ifndef __visible +#define __visible +#endif +#ifndef __same_type +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define __same_type(a,b) __builtin_types_compatible_p(typeof(a), typeof(b)) +#endif +#ifndef __native_word +#define __native_word(t) (sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long)) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#endif +#ifndef __compiletime_object_size +#define __compiletime_object_size(obj) - 1 +#endif +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#ifndef __compiletime_warning +#define __compiletime_warning(message) +#endif +#ifndef __compiletime_error +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define __compiletime_error(message) +#define __compiletime_error_fallback(condition) do { ((void) sizeof(char[1 - 2 * condition])); } while(0) +#endif +#ifndef __compiletime_error_fallback +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define __compiletime_error_fallback(condition) do { } while(0) +#endif +#define __compiletime_assert(condition,msg,prefix,suffix) do { bool __cond = ! (condition); extern void prefix ##suffix(void) __compiletime_error(msg); if(__cond) prefix ##suffix(); __compiletime_error_fallback(__cond); } while(0) +#define _compiletime_assert(condition,msg,prefix,suffix) __compiletime_assert(condition, msg, prefix, suffix) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define compiletime_assert(condition,msg) _compiletime_assert(condition, msg, __compiletime_assert_, __LINE__) +#define compiletime_assert_atomic_type(t) compiletime_assert(__native_word(t), "Need native word sized stores/loads for atomicity.") +#define ACCESS_ONCE(x) (* (volatile typeof(x) *) & (x)) +#define __kprobes +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define nokprobe_inline inline +#endif diff --git a/include/media.h b/include/media.h new file mode 100755 index 0000000..d627bef --- /dev/null +++ b/include/media.h @@ -0,0 +1,125 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + *** To edit the content of this header, modify the corresponding + *** source file (e.g. under external/kernel-headers/original/) then + *** run bionic/libc/kernel/tools/update_all.py + *** + *** Any manual change here will be lost the next time this script will + *** be run. You've been warned! + *** + **************************************************************************** + ****************************************************************************/ +#ifndef __LINUX_MEDIA_H +#define __LINUX_MEDIA_H +#include <linux/ioctl.h> +#include <linux/types.h> +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#include <linux/version.h> +#define MEDIA_API_VERSION KERNEL_VERSION(0, 1, 0) +struct media_device_info { + char driver[16]; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + char model[32]; + char serial[40]; + char bus_info[32]; + __u32 media_version; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + __u32 hw_revision; + __u32 driver_version; + __u32 reserved[31]; +}; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define MEDIA_ENT_ID_FLAG_NEXT (1 << 31) +#define MEDIA_ENT_TYPE_SHIFT 16 +#define MEDIA_ENT_TYPE_MASK 0x00ff0000 +#define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define MEDIA_ENT_T_DEVNODE (1 << MEDIA_ENT_TYPE_SHIFT) +#define MEDIA_ENT_T_DEVNODE_V4L (MEDIA_ENT_T_DEVNODE + 1) +#define MEDIA_ENT_T_DEVNODE_FB (MEDIA_ENT_T_DEVNODE + 2) +#define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENT_T_DEVNODE + 3) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENT_T_DEVNODE + 4) +#define MEDIA_ENT_T_V4L2_SUBDEV (2 << MEDIA_ENT_TYPE_SHIFT) +#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENT_T_V4L2_SUBDEV + 1) +#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH (MEDIA_ENT_T_V4L2_SUBDEV + 2) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define MEDIA_ENT_T_V4L2_SUBDEV_LENS (MEDIA_ENT_T_V4L2_SUBDEV + 3) +#define MEDIA_ENT_FL_DEFAULT (1 << 0) +struct media_entity_desc { + __u32 id; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + char name[32]; + __u32 type; + __u32 revision; + __u32 flags; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + __u32 group_id; + __u16 pads; + __u16 links; + __u32 reserved[4]; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + union { + struct { + __u32 major; + __u32 minor; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + } v4l; + struct { + __u32 major; + __u32 minor; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + } fb; + struct { + __u32 card; + __u32 device; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + __u32 subdevice; + } alsa; + int dvb; + __u8 raw[184]; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + }; +}; +#define MEDIA_PAD_FL_SINK (1 << 0) +#define MEDIA_PAD_FL_SOURCE (1 << 1) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +struct media_pad_desc { + __u32 entity; + __u16 index; + __u32 flags; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + __u32 reserved[2]; +}; +#define MEDIA_LNK_FL_ENABLED (1 << 0) +#define MEDIA_LNK_FL_IMMUTABLE (1 << 1) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define MEDIA_LNK_FL_DYNAMIC (1 << 2) +struct media_link_desc { + struct media_pad_desc source; + struct media_pad_desc sink; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + __u32 flags; + __u32 reserved[2]; +}; +struct media_links_enum { +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + __u32 entity; + struct media_pad_desc *pads; + struct media_link_desc *links; + __u32 reserved[4]; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +}; +#define MEDIA_IOC_DEVICE_INFO _IOWR('|', 0x00, struct media_device_info) +#define MEDIA_IOC_ENUM_ENTITIES _IOWR('|', 0x01, struct media_entity_desc) +#define MEDIA_IOC_ENUM_LINKS _IOWR('|', 0x02, struct media_links_enum) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define MEDIA_IOC_SETUP_LINK _IOWR('|', 0x03, struct media_link_desc) +#endif diff --git a/include/swconverter.h b/include/swconverter.h new file mode 100755 index 0000000..877e4ba --- /dev/null +++ b/include/swconverter.h @@ -0,0 +1,405 @@ +/* + * + * Copyright 2012 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file swconverter.h + * @brief Exynos_OMX specific define. It support MFC's tiled format. + * NV12T(tiled) layout: + * Each element is not pixel. + * MFC 5.x : It is 64x32 pixel block. + * MFC 6.x : It is 16x16 pixel block. + * uv pixel block is interleaved as u v u v u v ... + * y1 y2 y7 y8 y9 y10 y15 y16 + * y3 y4 y5 y6 y11 y12 y13 y14 + * y17 y18 y23 y24 y25 y26 y31 y32 + * y19 y20 y21 y22 y27 y28 y29 y30 + * uv1 uv2 uv7 uv8 uv9 uv10 uv15 uv16 + * uv3 uv4 uv5 uv6 uv11 uv12 uv13 uv14 + * YUV420Planar(linear) layout: + * Each element is not pixel. It is 64x32 pixel block. + * y1 y2 y3 y4 y5 y6 y7 y8 + * y9 y10 y11 y12 y13 y14 y15 y16 + * y17 y18 y19 y20 y21 y22 y23 y24 + * y25 y26 y27 y28 y29 y30 y31 y32 + * u1 u2 u3 u4 u5 u6 u7 u8 + * v1 v2 v3 v4 v5 v6 v7 v8 + * YUV420Semiplanar(linear) layout: + * Each element is not pixel. It is 64x32 pixel block. + * uv pixel block is interleaved as u v u v u v ... + * y1 y2 y3 y4 y5 y6 y7 y8 + * y9 y10 y11 y12 y13 y14 y15 y16 + * y17 y18 y19 y20 y21 y22 y23 y24 + * y25 y26 y27 y28 y29 y30 y31 y32 + * uv1 uv2 uv3 uv4 uv5 uv6 uv7 uv8 + * uv9 uv10 uv11 uv12 uv13 uv14 uv15 uv16 + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2012.02.01 : Create + */ + +#ifndef SW_CONVERTOR_H_ +#define SW_CONVERTOR_H_ + +/*--------------------------------------------------------------------------------*/ +/* Format Conversion API */ +/*--------------------------------------------------------------------------------*/ +/* + * C code only + * De-interleaves src to dest1, dest2 + * + * @param dest1 + * Address of de-interleaved data[out] + * + * @param dest2 + * Address of de-interleaved data[out] + * + * @param src + * Address of interleaved data[in] + * + * @param src_size + * Size of interleaved data[in] + */ +void csc_deinterleave_memcpy( + unsigned char *dest1, + unsigned char *dest2, + unsigned char *src, + unsigned int src_size); + +/* + * C code or Neon + * Interleaves src1, src2 to dest + * + * @param dest + * Address of interleaved data[out] + * + * @param src1 + * Address of de-interleaved data[in] + * + * @param src2 + * Address of de-interleaved data[in] + * + * @param src_size + * Size of de-interleaved data[in] + */ +void csc_interleave_memcpy( + unsigned char *dest, + unsigned char *src1, + unsigned char *src2, + unsigned int src_size); + +/* + * C code or Neon + * Converts tiled data to linear + * 1. y of nv12t to y of yuv420p + * 2. y of nv12t to y of yuv420s + * + * @param dst + * y address of yuv420[out] + * + * @param src + * y address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_tiled_to_linear_y( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height); + +/* + * C code or Neon + * Converts tiled data to linear + * 1. uv of nv12t to y of yuv420s + * + * @param dst + * uv address of yuv420s[out] + * + * @param src + * uv address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420s[in] + * + * @param yuv420_height + * real height of yuv420s[in] + * + */ +void csc_tiled_to_linear_uv( + unsigned char *uv_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height); + +/* + * C code or Neon + * Converts tiled data to linear + * 1. uv of nt12t to uv of yuv420p + * + * @param u_dst + * u address of yuv420p[out] + * + * @param v_dst + * v address of yuv420p[out] + * + * @param uv_src + * uv address of nt12t[in] + * + * @param yuv420_width + * real width of yuv420p[in] + * + * @param yuv420_height + * real height of yuv420p[in] + */ +void csc_tiled_to_linear_uv_deinterleave( + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height); + +/* + * Neon only + * Converts linear data to tiled + * 1. y of yuv420 to y of nv12t + * + * @param dst + * y address of nv12t[out] + * + * @param src + * y address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_linear_to_tiled_y( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height); + +/* + * Neon only + * Converts and interleaves linear data to tiled + * 1. uv of nv12t to uv of yuv420 + * + * @param dst + * uv address of nv12t[out] + * + * @param src + * u address of yuv420[in] + * + * @param src + * v address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * + * @param yuv420_height + * real height of yuv420[in] + * + */ +void csc_linear_to_tiled_uv( + unsigned char *uv_dst, + unsigned char *u_src, + unsigned char *v_src, + unsigned int width, + unsigned int height); + +/* + * C code only + * Converts RGB565 to YUV420P + * + * @param y_dst + * Y plane address of YUV420P[out] + * + * @param u_dst + * U plane address of YUV420P[out] + * + * @param v_dst + * V plane address of YUV420P[out] + * + * @param rgb_src + * Address of RGB565[in] + * + * @param width + * Width of RGB565[in] + * + * @param height + * Height of RGB565[in] + */ +void csc_RGB565_to_YUV420P( + unsigned char *y_dst, + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *rgb_src, + int width, + int height); + +/* + * C code only + * Converts RGB565 to YUV420SP + * + * @param y_dst + * Y plane address of YUV420SP[out] + * + * @param uv_dst + * UV plane address of YUV420SP[out] + * + * @param rgb_src + * Address of RGB565[in] + * + * @param width + * Width of RGB565[in] + * + * @param height + * Height of RGB565[in] + */ +void csc_RGB565_to_YUV420SP( + unsigned char *y_dst, + unsigned char *uv_dst, + unsigned char *rgb_src, + int width, + int height); + +/* + * C code only + * Converts BGRA8888 to YUV420P + * + * @param y_dst + * Y plane address of YUV420P[out] + * + * @param u_dst + * U plane address of YUV420P[out] + * + * @param v_dst + * V plane address of YUV420P[out] + * + * @param rgb_src + * Address of BGRA8888[in] + * + * @param width + * Width of BGRA8888[in] + * + * @param height + * Height of BGRA8888[in] + */ +void csc_BGRA8888_to_YUV420P( + unsigned char *y_dst, + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height); + +/* + * C code or Neon + * Converts BGRA8888 to YUV420SP + * + * @param y_dst + * Y plane address of YUV420SP[out] + * + * @param uv_dst + * UV plane address of YUV420SP[out] + * + * @param rgb_src + * Address of BGRA8888[in] + * + * @param width + * Width of BGRA8888[in] + * + * @param height + * Height of BGRA8888[in] + */ +void csc_BGRA8888_to_YUV420SP( + unsigned char *y_dst, + unsigned char *uv_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height); + +/* + * C code only + * Converts RGBA8888 to YUV420P + * + * @param y_dst + * Y plane address of YUV420P[out] + * + * @param u_dst + * U plane address of YUV420P[out] + * + * @param v_dst + * V plane address of YUV420P[out] + * + * @param rgb_src + * Address of RGBA8888[in] + * + * @param width + * Width of RGBA8888[in] + * + * @param height + * Height of RGBA8888[in] + */ +void csc_RGBA8888_to_YUV420P( + unsigned char *y_dst, + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height); + +/* + * C code or Neon + * Converts RGBA8888 to YUV420SP + * + * @param y_dst + * Y plane address of YUV420SP[out] + * + * @param uv_dst + * UV plane address of YUV420SP[out] + * + * @param rgb_src + * Address of RGBA8888[in] + * + * @param width + * Width of RGBA8888[in] + * + * @param height + * Height of RGBA8888[in] + */ +void csc_RGBA8888_to_YUV420SP( + unsigned char *y_dst, + unsigned char *uv_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height); + +#endif /*COLOR_SPACE_CONVERTOR_H_*/ diff --git a/include/system/graphics.h b/include/system/graphics.h new file mode 100755 index 0000000..afd9f7b --- /dev/null +++ b/include/system/graphics.h @@ -0,0 +1,763 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSTEM_CORE_INCLUDE_ANDROID_GRAPHICS_H +#define SYSTEM_CORE_INCLUDE_ANDROID_GRAPHICS_H + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * If the HAL needs to create service threads to handle graphics related + * tasks, these threads need to run at HAL_PRIORITY_URGENT_DISPLAY priority + * if they can block the main rendering thread in any way. + * + * the priority of the current thread can be set with: + * + * #include <sys/resource.h> + * setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); + * + */ + +#define HAL_PRIORITY_URGENT_DISPLAY (-8) + +/** + * pixel format definitions + */ + +enum { + /* + * "linear" color pixel formats: + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. + * + * The color space determines, for example, if the formats are linear or + * gamma-corrected; or whether any special operations are performed when + * reading or writing into a buffer in one of these formats. + */ + HAL_PIXEL_FORMAT_RGBA_8888 = 1, + HAL_PIXEL_FORMAT_RGBX_8888 = 2, + HAL_PIXEL_FORMAT_RGB_888 = 3, + HAL_PIXEL_FORMAT_RGB_565 = 4, + HAL_PIXEL_FORMAT_BGRA_8888 = 5, + + /* + * 0x100 - 0x1FF + * + * This range is reserved for pixel formats that are specific to the HAL + * implementation. Implementations can use any value in this range to + * communicate video pixel formats between their HAL modules. These formats + * must not have an alpha channel. Additionally, an EGLimage created from a + * gralloc buffer of one of these formats must be supported for use with the + * GL_OES_EGL_image_external OpenGL ES extension. + */ + + /* + * Android YUV format: + * + * This format is exposed outside of the HAL to software decoders and + * applications. EGLImageKHR must support it in conjunction with the + * OES_EGL_image_external extension. + * + * YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed + * by (W/2) x (H/2) Cr and Cb planes. + * + * This format assumes + * - an even width + * - an even height + * - a horizontal stride multiple of 16 pixels + * - a vertical stride equal to the height + * + * y_size = stride * height + * c_stride = ALIGN(stride/2, 16) + * c_size = c_stride * height/2 + * size = y_size + c_size * 2 + * cr_offset = y_size + * cb_offset = y_size + c_size + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. + */ + HAL_PIXEL_FORMAT_YV12 = 0x32315659, // YCrCb 4:2:0 Planar + + + /* + * Android Y8 format: + * + * This format is exposed outside of the HAL to the framework. + * The expected gralloc usage flags are SW_* and HW_CAMERA_*, + * and no other HW_ flags will be used. + * + * Y8 is a YUV planar format comprised of a WxH Y plane, + * with each pixel being represented by 8 bits. + * + * It is equivalent to just the Y plane from YV12. + * + * This format assumes + * - an even width + * - an even height + * - a horizontal stride multiple of 16 pixels + * - a vertical stride equal to the height + * + * size = stride * height + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. + */ + HAL_PIXEL_FORMAT_Y8 = 0x20203859, + + /* + * Android Y16 format: + * + * This format is exposed outside of the HAL to the framework. + * The expected gralloc usage flags are SW_* and HW_CAMERA_*, + * and no other HW_ flags will be used. + * + * Y16 is a YUV planar format comprised of a WxH Y plane, + * with each pixel being represented by 16 bits. + * + * It is just like Y8, but has double the bits per pixel (little endian). + * + * This format assumes + * - an even width + * - an even height + * - a horizontal stride multiple of 16 pixels + * - a vertical stride equal to the height + * - strides are specified in pixels, not in bytes + * + * size = stride * height * 2 + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer, except that dataSpace field + * HAL_DATASPACE_DEPTH indicates that this buffer contains a depth + * image where each sample is a distance value measured by a depth camera, + * plus an associated confidence value. + */ + HAL_PIXEL_FORMAT_Y16 = 0x20363159, + + /* + * Android RAW sensor format: + * + * This format is exposed outside of the camera HAL to applications. + * + * RAW16 is a single-channel, 16-bit, little endian format, typically + * representing raw Bayer-pattern images from an image sensor, with minimal + * processing. + * + * The exact pixel layout of the data in the buffer is sensor-dependent, and + * needs to be queried from the camera device. + * + * Generally, not all 16 bits are used; more common values are 10 or 12 + * bits. If not all bits are used, the lower-order bits are filled first. + * All parameters to interpret the raw data (black and white points, + * color space, etc) must be queried from the camera device. + * + * This format assumes + * - an even width + * - an even height + * - a horizontal stride multiple of 16 pixels + * - a vertical stride equal to the height + * - strides are specified in pixels, not in bytes + * + * size = stride * height * 2 + * + * This format must be accepted by the gralloc module when used with the + * following usage flags: + * - GRALLOC_USAGE_HW_CAMERA_* + * - GRALLOC_USAGE_SW_* + * - GRALLOC_USAGE_RENDERSCRIPT + * + * When used with ANativeWindow, the dataSpace should be + * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial + * extra metadata to define. + */ + HAL_PIXEL_FORMAT_RAW16 = 0x20, + + /* + * Android RAW10 format: + * + * This format is exposed outside of the camera HAL to applications. + * + * RAW10 is a single-channel, 10-bit per pixel, densely packed in each row, + * unprocessed format, usually representing raw Bayer-pattern images coming from + * an image sensor. + * + * In an image buffer with this format, starting from the first pixel of each + * row, each 4 consecutive pixels are packed into 5 bytes (40 bits). Each one + * of the first 4 bytes contains the top 8 bits of each pixel, The fifth byte + * contains the 2 least significant bits of the 4 pixels, the exact layout data + * for each 4 consecutive pixels is illustrated below (Pi[j] stands for the jth + * bit of the ith pixel): + * + * bit 7 bit 0 + * =====|=====|=====|=====|=====|=====|=====|=====| + * Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]| + * |-----|-----|-----|-----|-----|-----|-----|-----| + * Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]| + * |-----|-----|-----|-----|-----|-----|-----|-----| + * Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]| + * |-----|-----|-----|-----|-----|-----|-----|-----| + * Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]| + * |-----|-----|-----|-----|-----|-----|-----|-----| + * Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]| + * =============================================== + * + * This format assumes + * - a width multiple of 4 pixels + * - an even height + * - a vertical stride equal to the height + * - strides are specified in bytes, not in pixels + * + * size = stride * height + * + * When stride is equal to width * (10 / 8), there will be no padding bytes at + * the end of each row, the entire image data is densely packed. When stride is + * larger than width * (10 / 8), padding bytes will be present at the end of each + * row (including the last row). + * + * This format must be accepted by the gralloc module when used with the + * following usage flags: + * - GRALLOC_USAGE_HW_CAMERA_* + * - GRALLOC_USAGE_SW_* + * - GRALLOC_USAGE_RENDERSCRIPT + * + * When used with ANativeWindow, the dataSpace field should be + * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial + * extra metadata to define. + */ + HAL_PIXEL_FORMAT_RAW10 = 0x25, + + /* + * Android RAW12 format: + * + * This format is exposed outside of camera HAL to applications. + * + * RAW12 is a single-channel, 12-bit per pixel, densely packed in each row, + * unprocessed format, usually representing raw Bayer-pattern images coming from + * an image sensor. + * + * In an image buffer with this format, starting from the first pixel of each + * row, each two consecutive pixels are packed into 3 bytes (24 bits). The first + * and second byte contains the top 8 bits of first and second pixel. The third + * byte contains the 4 least significant bits of the two pixels, the exact layout + * data for each two consecutive pixels is illustrated below (Pi[j] stands for + * the jth bit of the ith pixel): + * + * bit 7 bit 0 + * ======|======|======|======|======|======|======|======| + * Byte 0: |P0[11]|P0[10]|P0[ 9]|P0[ 8]|P0[ 7]|P0[ 6]|P0[ 5]|P0[ 4]| + * |------|------|------|------|------|------|------|------| + * Byte 1: |P1[11]|P1[10]|P1[ 9]|P1[ 8]|P1[ 7]|P1[ 6]|P1[ 5]|P1[ 4]| + * |------|------|------|------|------|------|------|------| + * Byte 2: |P1[ 3]|P1[ 2]|P1[ 1]|P1[ 0]|P0[ 3]|P0[ 2]|P0[ 1]|P0[ 0]| + * ======================================================= + * + * This format assumes: + * - a width multiple of 4 pixels + * - an even height + * - a vertical stride equal to the height + * - strides are specified in bytes, not in pixels + * + * size = stride * height + * + * When stride is equal to width * (12 / 8), there will be no padding bytes at + * the end of each row, the entire image data is densely packed. When stride is + * larger than width * (12 / 8), padding bytes will be present at the end of + * each row (including the last row). + * + * This format must be accepted by the gralloc module when used with the + * following usage flags: + * - GRALLOC_USAGE_HW_CAMERA_* + * - GRALLOC_USAGE_SW_* + * - GRALLOC_USAGE_RENDERSCRIPT + * + * When used with ANativeWindow, the dataSpace field should be + * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial + * extra metadata to define. + */ + HAL_PIXEL_FORMAT_RAW12 = 0x26, + + /* + * Android opaque RAW format: + * + * This format is exposed outside of the camera HAL to applications. + * + * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an + * image sensor. The actual structure of buffers of this format is + * implementation-dependent. + * + * This format must be accepted by the gralloc module when used with the + * following usage flags: + * - GRALLOC_USAGE_HW_CAMERA_* + * - GRALLOC_USAGE_SW_* + * - GRALLOC_USAGE_RENDERSCRIPT + * + * When used with ANativeWindow, the dataSpace field should be + * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial + * extra metadata to define. + */ + HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24, + + /* + * Android binary blob graphics buffer format: + * + * This format is used to carry task-specific data which does not have a + * standard image structure. The details of the format are left to the two + * endpoints. + * + * A typical use case is for transporting JPEG-compressed images from the + * Camera HAL to the framework or to applications. + * + * Buffers of this format must have a height of 1, and width equal to their + * size in bytes. + * + * When used with ANativeWindow, the mapping of the dataSpace field to + * buffer contents for BLOB is as follows: + * + * dataSpace value | Buffer contents + * -------------------------------+----------------------------------------- + * HAL_DATASPACE_JFIF | An encoded JPEG image + * HAL_DATASPACE_DEPTH | An android_depth_points buffer + * Other | Unsupported + * + */ + HAL_PIXEL_FORMAT_BLOB = 0x21, + + /* + * Android format indicating that the choice of format is entirely up to the + * device-specific Gralloc implementation. + * + * The Gralloc implementation should examine the usage bits passed in when + * allocating a buffer with this format, and it should derive the pixel + * format from those usage flags. This format will never be used with any + * of the GRALLOC_USAGE_SW_* usage flags. + * + * If a buffer of this format is to be used as an OpenGL ES texture, the + * framework will assume that sampling the texture will always return an + * alpha value of 1.0 (i.e. the buffer contains only opaque pixel values). + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. + */ + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22, + + /* + * Android flexible YCbCr 4:2:0 formats + * + * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:0 + * buffer layout, while still describing the general format in a + * layout-independent manner. While called YCbCr, it can be + * used to describe formats with either chromatic ordering, as well as + * whole planar or semiplanar layouts. + * + * struct android_ycbcr (below) is the the struct used to describe it. + * + * This format must be accepted by the gralloc module when + * USAGE_SW_WRITE_* or USAGE_SW_READ_* are set. + * + * This format is locked for use by gralloc's (*lock_ycbcr) method, and + * locking with the (*lock) method will return an error. + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. + */ + HAL_PIXEL_FORMAT_YCbCr_420_888 = 0x23, + + /* + * Android flexible YCbCr 4:2:2 formats + * + * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:2 + * buffer layout, while still describing the general format in a + * layout-independent manner. While called YCbCr, it can be + * used to describe formats with either chromatic ordering, as well as + * whole planar or semiplanar layouts. + * + * This format is currently only used by SW readable buffers + * produced by MediaCodecs, so the gralloc module can ignore this format. + */ + HAL_PIXEL_FORMAT_YCbCr_422_888 = 0x27, + + /* + * Android flexible YCbCr 4:4:4 formats + * + * This format allows platforms to use an efficient YCbCr/YCrCb 4:4:4 + * buffer layout, while still describing the general format in a + * layout-independent manner. While called YCbCr, it can be + * used to describe formats with either chromatic ordering, as well as + * whole planar or semiplanar layouts. + * + * This format is currently only used by SW readable buffers + * produced by MediaCodecs, so the gralloc module can ignore this format. + */ + HAL_PIXEL_FORMAT_YCbCr_444_888 = 0x28, + + /* + * Android flexible RGB 888 formats + * + * This format allows platforms to use an efficient RGB/BGR/RGBX/BGRX + * buffer layout, while still describing the general format in a + * layout-independent manner. While called RGB, it can be + * used to describe formats with either color ordering and optional + * padding, as well as whole planar layout. + * + * This format is currently only used by SW readable buffers + * produced by MediaCodecs, so the gralloc module can ignore this format. + */ + HAL_PIXEL_FORMAT_FLEX_RGB_888 = 0x29, + + /* + * Android flexible RGBA 8888 formats + * + * This format allows platforms to use an efficient RGBA/BGRA/ARGB/ABGR + * buffer layout, while still describing the general format in a + * layout-independent manner. While called RGBA, it can be + * used to describe formats with any of the component orderings, as + * well as whole planar layout. + * + * This format is currently only used by SW readable buffers + * produced by MediaCodecs, so the gralloc module can ignore this format. + */ + HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 0x2A, + + /* Legacy formats (deprecated), used by ImageFormat.java */ + HAL_PIXEL_FORMAT_YCbCr_422_SP = 0x10, // NV16 + HAL_PIXEL_FORMAT_YCrCb_420_SP = 0x11, // NV21 + HAL_PIXEL_FORMAT_YCbCr_422_I = 0x14, // YUY2 +}; + +/* + * Structure for describing YCbCr formats for consumption by applications. + * This is used with HAL_PIXEL_FORMAT_YCbCr_*_888. + * + * Buffer chroma subsampling is defined in the format. + * e.g. HAL_PIXEL_FORMAT_YCbCr_420_888 has subsampling 4:2:0. + * + * Buffers must have a 8 bit depth. + * + * @y, @cb, and @cr point to the first byte of their respective planes. + * + * Stride describes the distance in bytes from the first value of one row of + * the image to the first value of the next row. It includes the width of the + * image plus padding. + * @ystride is the stride of the luma plane. + * @cstride is the stride of the chroma planes. + * + * @chroma_step is the distance in bytes from one chroma pixel value to the + * next. This is 2 bytes for semiplanar (because chroma values are interleaved + * and each chroma value is one byte) and 1 for planar. + */ + +struct android_ycbcr { + void *y; + void *cb; + void *cr; + size_t ystride; + size_t cstride; + size_t chroma_step; + + /** reserved for future use, set to 0 by gralloc's (*lock_ycbcr)() */ + uint32_t reserved[8]; +}; + +/** + * Structure used to define depth point clouds for format HAL_PIXEL_FORMAT_BLOB + * with dataSpace value of HAL_DATASPACE_DEPTH. + * When locking a native buffer of the above format and dataSpace value, + * the vaddr pointer can be cast to this structure. + * + * A variable-length list of (x,y,z, confidence) 3D points, as floats. (x, y, + * z) represents a measured point's position, with the coordinate system defined + * by the data source. Confidence represents the estimated likelihood that this + * measurement is correct. It is between 0.f and 1.f, inclusive, with 1.f == + * 100% confidence. + * + * @num_points is the number of points in the list + * + * @xyz_points is the flexible array of floating-point values. + * It contains (num_points) * 4 floats. + * + * For example: + * android_depth_points d = get_depth_buffer(); + * struct { + * float x; float y; float z; float confidence; + * } firstPoint, lastPoint; + * + * firstPoint.x = d.xyzc_points[0]; + * firstPoint.y = d.xyzc_points[1]; + * firstPoint.z = d.xyzc_points[2]; + * firstPoint.confidence = d.xyzc_points[3]; + * lastPoint.x = d.xyzc_points[(d.num_points - 1) * 4 + 0]; + * lastPoint.y = d.xyzc_points[(d.num_points - 1) * 4 + 1]; + * lastPoint.z = d.xyzc_points[(d.num_points - 1) * 4 + 2]; + * lastPoint.confidence = d.xyzc_points[(d.num_points - 1) * 4 + 3]; + */ + +struct android_depth_points { + uint32_t num_points; + + /** reserved for future use, set to 0 by gralloc's (*lock)() */ + uint32_t reserved[8]; + + float xyzc_points[]; +}; + +/** + * Transformation definitions + * + * IMPORTANT NOTE: + * HAL_TRANSFORM_ROT_90 is applied CLOCKWISE and AFTER HAL_TRANSFORM_FLIP_{H|V}. + * + */ + +enum { + /* flip source image horizontally (around the vertical axis) */ + HAL_TRANSFORM_FLIP_H = 0x01, + /* flip source image vertically (around the horizontal axis)*/ + HAL_TRANSFORM_FLIP_V = 0x02, + /* rotate source image 90 degrees clockwise */ + HAL_TRANSFORM_ROT_90 = 0x04, + /* rotate source image 180 degrees */ + HAL_TRANSFORM_ROT_180 = 0x03, + /* rotate source image 270 degrees clockwise */ + HAL_TRANSFORM_ROT_270 = 0x07, + /* don't use. see system/window.h */ + HAL_TRANSFORM_RESERVED = 0x08, +}; + +/** + * Dataspace Definitions + * ====================== + * + * Dataspace is the definition of how pixel values should be interpreted. + * + * For many formats, this is the colorspace of the image data, which includes + * primaries (including white point) and the transfer characteristic function, + * which describes both gamma curve and numeric range (within the bit depth). + * + * Other dataspaces include depth measurement data from a depth camera. + */ + +typedef enum android_dataspace { + /* + * Default-assumption data space, when not explicitly specified. + * + * It is safest to assume the buffer is an image with sRGB primaries and + * encoding ranges, but the consumer and/or the producer of the data may + * simply be using defaults. No automatic gamma transform should be + * expected, except for a possible display gamma transform when drawn to a + * screen. + */ + HAL_DATASPACE_UNKNOWN = 0x0, + + /* + * Arbitrary dataspace with manually defined characteristics. Definition + * for colorspaces or other meaning must be communicated separately. + * + * This is used when specifying primaries, transfer characteristics, + * etc. separately. + * + * A typical use case is in video encoding parameters (e.g. for H.264), + * where a colorspace can have separately defined primaries, transfer + * characteristics, etc. + */ + HAL_DATASPACE_ARBITRARY = 0x1, + + /* + * RGB Colorspaces + * ----------------- + * + * Primaries are given using (x,y) coordinates in the CIE 1931 definition + * of x and y specified by ISO 11664-1. + * + * Transfer characteristics are the opto-electronic transfer characteristic + * at the source as a function of linear optical intensity (luminance). + */ + + /* + * sRGB linear encoding: + * + * The red, green, and blue components are stored in sRGB space, but + * are linear, not gamma-encoded. + * The RGB primaries and the white point are the same as BT.709. + * + * The values are encoded using the full range ([0,255] for 8-bit) for all + * components. + */ + HAL_DATASPACE_SRGB_LINEAR = 0x200, + + /* + * sRGB gamma encoding: + * + * The red, green and blue components are stored in sRGB space, and + * converted to linear space when read, using the standard sRGB to linear + * equation: + * + * Clinear = Csrgb / 12.92 for Csrgb <= 0.04045 + * = (Csrgb + 0.055 / 1.055)^2.4 for Csrgb > 0.04045 + * + * When written the inverse transformation is performed: + * + * Csrgb = 12.92 * Clinear for Clinear <= 0.0031308 + * = 1.055 * Clinear^(1/2.4) - 0.055 for Clinear > 0.0031308 + * + * + * The alpha component, if present, is always stored in linear space and + * is left unmodified when read or written. + * + * The RGB primaries and the white point are the same as BT.709. + * + * The values are encoded using the full range ([0,255] for 8-bit) for all + * components. + * + */ + HAL_DATASPACE_SRGB = 0x201, + + /* + * YCbCr Colorspaces + * ----------------- + * + * Primaries are given using (x,y) coordinates in the CIE 1931 definition + * of x and y specified by ISO 11664-1. + * + * Transfer characteristics are the opto-electronic transfer characteristic + * at the source as a function of linear optical intensity (luminance). + */ + + /* + * JPEG File Interchange Format (JFIF) + * + * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255 + * + * Transfer characteristic curve: + * E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018 + * E = 4.500 L, 0.018 > L >= 0 + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + * + * Primaries: x y + * green 0.290 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + */ + HAL_DATASPACE_JFIF = 0x101, + + /* + * ITU-R Recommendation 601 (BT.601) - 625-line + * + * Standard-definition television, 625 Lines (PAL) + * + * For 8-bit-depth formats: + * Luma (Y) samples should range from 16 to 235, inclusive + * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive + * + * For 10-bit-depth formats: + * Luma (Y) samples should range from 64 to 940, inclusive + * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive + * + * Transfer characteristic curve: + * E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018 + * E = 4.500 L, 0.018 > L >= 0 + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + * + * Primaries: x y + * green 0.290 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + */ + HAL_DATASPACE_BT601_625 = 0x102, + + /* + * ITU-R Recommendation 601 (BT.601) - 525-line + * + * Standard-definition television, 525 Lines (NTSC) + * + * For 8-bit-depth formats: + * Luma (Y) samples should range from 16 to 235, inclusive + * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive + * + * For 10-bit-depth formats: + * Luma (Y) samples should range from 64 to 940, inclusive + * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive + * + * Transfer characteristic curve: + * E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018 + * E = 4.500 L, 0.018 > L >= 0 + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + * + * Primaries: x y + * green 0.310 0.595 + * blue 0.155 0.070 + * red 0.630 0.340 + * white (D65) 0.3127 0.3290 + */ + HAL_DATASPACE_BT601_525 = 0x103, + + /* + * ITU-R Recommendation 709 (BT.709) + * + * High-definition television + * + * For 8-bit-depth formats: + * Luma (Y) samples should range from 16 to 235, inclusive + * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive + * + * For 10-bit-depth formats: + * Luma (Y) samples should range from 64 to 940, inclusive + * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive + * + * Primaries: x y + * green 0.300 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + */ + HAL_DATASPACE_BT709 = 0x104, + + /* + * The buffer contains depth ranging measurements from a depth camera. + * This value is valid with formats: + * HAL_PIXEL_FORMAT_Y16: 16-bit samples, consisting of a depth measurement + * and an associated confidence value. The 3 MSBs of the sample make + * up the confidence value, and the low 13 LSBs of the sample make up + * the depth measurement. + * For the confidence section, 0 means 100% confidence, 1 means 0% + * confidence. The mapping to a linear float confidence value between + * 0.f and 1.f can be obtained with + * float confidence = (((depthSample >> 13) - 1) & 0x7) / 7.0f; + * The depth measurement can be extracted simply with + * uint16_t range = (depthSample & 0x1FFF); + * HAL_PIXEL_FORMAT_BLOB: A depth point cloud, as + * a variable-length float (x,y,z, confidence) coordinate point list. + * The point cloud will be represented with the android_depth_points + * structure. + */ + HAL_DATASPACE_DEPTH = 0x1000 + +} android_dataspace_t; + +#ifdef __cplusplus +} +#endif + +#endif /* SYSTEM_CORE_INCLUDE_ANDROID_GRAPHICS_H */ diff --git a/libcsc/Makefile.am b/libcsc/Makefile.am new file mode 100755 index 0000000..3293e20 --- /dev/null +++ b/libcsc/Makefile.am @@ -0,0 +1,11 @@ +lib_LTLIBRARIES = libcsc.la + +libcsc_la_SOURCES = csc.c +libcsc_la_CFLAGS = -I$(top_srcdir)/include -DLOG_TAG=\"LIBCSC\" +if USE_DLOG +libcsc_la_CFLAGS += $(DLOG_CFLAGS) -DUSE_DLOG +endif + +libcsc_la_LDFLAGS = -L$(top_srcdir)/libswconverter + +libcsc_la_LIBADD = -lswconverter $(DLOG_LIBS) diff --git a/libcsc/csc.c b/libcsc/csc.c new file mode 100755 index 0000000..d90968e --- /dev/null +++ b/libcsc/csc.c @@ -0,0 +1,1309 @@ +/* + * + * Copyright 2012 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc.c + * + * @brief color space convertion abstract source + * + * @author Pyoungjae Jung(pjet.jung@samsung.com) + * + * @version 1.0.0 + * + * @history + * 2012.1.11 : Create + */ +#include <exynos_log.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <system/graphics.h> + +#include <csc.h> +#include <exynos_format.h> +#include <swconverter.h> + +#ifdef USES_FIMC +#include "exynos_fimc.h" +#endif + +#ifdef USES_GSCALER +#include "exynos_gscaler.h" +#include "exynos_scaler.h" +#endif + +#define GSCALER_IMG_ALIGN 16 +#define FIMC_IMG_ALIGN_WIDTH 16 +#define FIMC_IMG_ALIGN_HEIGHT 2 +#define MFC_IMG_ALIGN_WIDTH 16 + +static CSC_ERRORCODE copy_mfc_data(CSC_HANDLE *handle) { + CSC_ERRORCODE ret = CSC_ErrorNone; + + int i; + char *pSrc = NULL; + char *pDst = NULL; + + ALOGV("%s: convert %x to %x", __FUNCTION__, handle->src_format.color_format, handle->dst_format.color_format); + + switch (handle->src_format.color_format) { + /* Multi FD to Single FD : decoder */ + /* remove a padding data */ + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_PN: + case HAL_PIXEL_FORMAT_EXYNOS_YV12_M: + pSrc = (char *)handle->src_buffer.planes[CSC_Y_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_Y_PLANE]; + for (i = 0; i < (int)handle->src_format.crop_height; i++) { + memcpy(pDst + (handle->src_format.crop_width * i), + pSrc + (handle->src_format.width * i), + handle->src_format.crop_width); + } + + pSrc = (char *)handle->src_buffer.planes[CSC_U_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_U_PLANE]; + for (i = 0; i < (int)(handle->src_format.crop_height >> 1); i++) { + memcpy(pDst + ((handle->src_format.crop_width >> 1) * i), + pSrc + (ALIGN((handle->src_format.crop_width >> 1), MFC_IMG_ALIGN_WIDTH) * i), + (handle->src_format.crop_width >> 1)); + } + + pSrc = (char *)handle->src_buffer.planes[CSC_V_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_V_PLANE]; + for (i = 0; i < (int)(handle->src_format.crop_height >> 1); i++) { + memcpy(pDst + ((handle->src_format.crop_width >> 1) * i), + pSrc + (ALIGN((handle->src_format.crop_width >> 1), MFC_IMG_ALIGN_WIDTH) * i), + (handle->src_format.crop_width >> 1)); + } + break; + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_PRIV: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_S10B: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN: + case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M: + pSrc = (char *)handle->src_buffer.planes[CSC_Y_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_Y_PLANE]; + for (i = 0; i < (int)handle->src_format.crop_height; i++) { + memcpy(pDst + (handle->src_format.crop_width * i), + pSrc + (handle->src_format.width * i), + handle->src_format.crop_width); + } + + pSrc = (char *)handle->src_buffer.planes[CSC_UV_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_UV_PLANE]; + for (i = 0; i < (int)(handle->src_format.crop_height >> 1); i++) { + memcpy(pDst + (handle->src_format.crop_width * i), + pSrc + (handle->src_format.width * i), + handle->src_format.crop_width); + } + break; + /* Single FD to Multi FD : encoder */ + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P: + case HAL_PIXEL_FORMAT_YV12: + /* adding a padding data for u/v plane : 420P */ + pSrc = (char *)handle->src_buffer.planes[CSC_Y_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_Y_PLANE]; + if (handle->src_format.width == handle->src_format.crop_width) { + memcpy(pDst, pSrc, (handle->src_format.width * handle->src_format.height)); + } else { + for (i = 0; i < (int)handle->src_format.height; i++) { + memcpy(pDst + (handle->src_format.width * i), + pSrc + (handle->src_format.crop_width * i), + handle->src_format.crop_width); + } + } + + pSrc = (char *)handle->src_buffer.planes[CSC_U_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_U_PLANE]; + for (i = 0; i < (int)(handle->src_format.height >> 1); i++) { + memcpy(pDst + (ALIGN((handle->src_format.width >> 1), MFC_IMG_ALIGN_WIDTH) * i), + pSrc + ((handle->src_format.crop_width >> 1) * i), + (handle->src_format.crop_width >> 1)); + } + + pSrc = (char *)handle->src_buffer.planes[CSC_V_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_V_PLANE]; + for (i = 0; i < (int)(handle->src_format.height >> 1); i++) { + memcpy(pDst + (ALIGN((handle->src_format.width >> 1), MFC_IMG_ALIGN_WIDTH) * i), + pSrc + ((handle->src_format.crop_width >> 1) * i), + (handle->src_format.crop_width >> 1)); + } + break; + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + if (handle->src_format.width == handle->src_format.crop_width) { + pSrc = (char *)handle->src_buffer.planes[CSC_Y_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_Y_PLANE]; + memcpy(pDst, pSrc, (handle->src_format.width * handle->src_format.height)); + + pSrc = (char *)handle->src_buffer.planes[CSC_UV_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_UV_PLANE]; + memcpy(pDst, pSrc, (handle->src_format.width * (handle->src_format.height >> 1))); + } else { + pSrc = (char *)handle->src_buffer.planes[CSC_Y_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_Y_PLANE]; + for (i = 0; i < (int)handle->src_format.height; i++) { + memcpy(pDst + (handle->src_format.width * i), + pSrc + (handle->src_format.crop_width * i), + handle->src_format.crop_width); + } + + pSrc = (char *)handle->src_buffer.planes[CSC_UV_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_UV_PLANE]; + memcpy(pDst, pSrc, (handle->src_format.width * (handle->src_format.height >> 1))); + for (i = 0; i < (int)(handle->src_format.height >> 1); i++) { + memcpy(pDst + (handle->src_format.width * i), + pSrc + (handle->src_format.crop_width * i), + handle->src_format.crop_width); + } + } + break; + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_EXYNOS_ARGB_8888: + pSrc = (char *)handle->src_buffer.planes[CSC_Y_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_Y_PLANE]; + memcpy(pDst, pSrc, (handle->src_format.width * handle->src_format.height * 4)); + break; + default: + ret = CSC_ErrorUnsupportFormat; + break; + } + + return ret; +} + +/* source is BRGA888 */ +static CSC_ERRORCODE conv_sw_src_argb888( + CSC_HANDLE *handle) +{ + CSC_ERRORCODE ret = CSC_ErrorNone; + + switch (handle->dst_format.color_format) { + case HAL_PIXEL_FORMAT_BGRA_8888: + if (handle->src_buffer.mem_type == CSC_MEMORY_MFC) { + ret = copy_mfc_data(handle); + } else { + ret = CSC_ErrorUnsupportFormat; + } + break; + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_PN: + csc_BGRA8888_to_YUV420P( + (unsigned char *)handle->dst_buffer.planes[CSC_Y_PLANE], + (unsigned char *)handle->dst_buffer.planes[CSC_U_PLANE], + (unsigned char *)handle->dst_buffer.planes[CSC_V_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_RGB_PLANE], + handle->src_format.width, + handle->src_format.height); + ret = CSC_ErrorNone; + break; + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN: + csc_BGRA8888_to_YUV420SP( + (unsigned char *)handle->dst_buffer.planes[CSC_Y_PLANE], + (unsigned char *)handle->dst_buffer.planes[CSC_UV_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_RGB_PLANE], + handle->src_format.width, + handle->src_format.height); + ret = CSC_ErrorNone; + break; + case HAL_PIXEL_FORMAT_YV12: + case HAL_PIXEL_FORMAT_EXYNOS_YV12_M: + csc_BGRA8888_to_YUV420P( + (unsigned char *)handle->dst_buffer.planes[CSC_Y_PLANE], + (unsigned char *)handle->dst_buffer.planes[CSC_V_PLANE], + (unsigned char *)handle->dst_buffer.planes[CSC_U_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_RGB_PLANE], + handle->src_format.width, + handle->src_format.height); + ret = CSC_ErrorNone; + break; + default: + ret = CSC_ErrorUnsupportFormat; + break; + } + + return ret; +} + +/* source is RGBA888 */ +static CSC_ERRORCODE conv_sw_src_rgba888( + CSC_HANDLE *handle) +{ + CSC_ERRORCODE ret = CSC_ErrorNone; + + switch (handle->dst_format.color_format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + if (handle->src_buffer.mem_type == CSC_MEMORY_MFC) { + ret = copy_mfc_data(handle); + } else { + ret = CSC_ErrorUnsupportFormat; + } + break; + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_PN: + csc_RGBA8888_to_YUV420P( + (unsigned char *)handle->dst_buffer.planes[CSC_Y_PLANE], + (unsigned char *)handle->dst_buffer.planes[CSC_U_PLANE], + (unsigned char *)handle->dst_buffer.planes[CSC_V_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_RGB_PLANE], + handle->src_format.width, + handle->src_format.height); + ret = CSC_ErrorNone; + break; + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN: + csc_RGBA8888_to_YUV420SP( + (unsigned char *)handle->dst_buffer.planes[CSC_Y_PLANE], + (unsigned char *)handle->dst_buffer.planes[CSC_UV_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_RGB_PLANE], + handle->src_format.width, + handle->src_format.height); + ret = CSC_ErrorNone; + break; + case HAL_PIXEL_FORMAT_YV12: + case HAL_PIXEL_FORMAT_EXYNOS_YV12_M: + csc_RGBA8888_to_YUV420P( + (unsigned char *)handle->dst_buffer.planes[CSC_Y_PLANE], + (unsigned char *)handle->dst_buffer.planes[CSC_V_PLANE], + (unsigned char *)handle->dst_buffer.planes[CSC_U_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_RGB_PLANE], + handle->src_format.width, + handle->src_format.height); + ret = CSC_ErrorNone; + break; + default: + ret = CSC_ErrorUnsupportFormat; + break; + } + + return ret; +} + + +/* source is NV12T */ +static CSC_ERRORCODE conv_sw_src_nv12t( + CSC_HANDLE *handle) +{ + CSC_ERRORCODE ret = CSC_ErrorNone; + + switch (handle->dst_format.color_format) { + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_PN: + csc_tiled_to_linear_y( + (unsigned char *)handle->dst_buffer.planes[CSC_Y_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_Y_PLANE], + handle->src_format.crop_width, + handle->src_format.crop_height); + csc_tiled_to_linear_uv_deinterleave( + (unsigned char *)handle->dst_buffer.planes[CSC_U_PLANE], + (unsigned char *)handle->dst_buffer.planes[CSC_V_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_UV_PLANE], + handle->src_format.crop_width, + handle->src_format.crop_height / 2); + ret = CSC_ErrorNone; + break; + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN: + csc_tiled_to_linear_y( + (unsigned char *)handle->dst_buffer.planes[CSC_Y_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_Y_PLANE], + handle->src_format.crop_width, + handle->src_format.crop_height); + csc_tiled_to_linear_uv( + (unsigned char *)handle->dst_buffer.planes[CSC_UV_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_UV_PLANE], + handle->src_format.crop_width, + handle->src_format.crop_height / 2); + ret = CSC_ErrorNone; + break; + default: + ret = CSC_ErrorUnsupportFormat; + break; + } + + return ret; +} + +/* source is YUV420P */ +static CSC_ERRORCODE conv_sw_src_yuv420p( + CSC_HANDLE *handle) +{ + CSC_ERRORCODE ret = CSC_ErrorNone; + + switch (handle->dst_format.color_format) { + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P: /* bypass */ + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_PN: + if (handle->src_buffer.mem_type == CSC_MEMORY_MFC) { + ret = copy_mfc_data(handle); + } else { + memcpy((unsigned char *)handle->dst_buffer.planes[CSC_Y_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_Y_PLANE], + handle->src_format.width * handle->src_format.height); + memcpy((unsigned char *)handle->dst_buffer.planes[CSC_U_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_U_PLANE], + (handle->src_format.width * handle->src_format.height) >> 2); + memcpy((unsigned char *)handle->dst_buffer.planes[CSC_V_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_V_PLANE], + (handle->src_format.width * handle->src_format.height) >> 2); + ret = CSC_ErrorNone; + } + break; + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN: + memcpy((unsigned char *)handle->dst_buffer.planes[CSC_Y_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_Y_PLANE], + handle->src_format.width * handle->src_format.height); + csc_interleave_memcpy( + (unsigned char *)handle->dst_buffer.planes[CSC_UV_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_U_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_V_PLANE], + (handle->src_format.width * handle->src_format.height) >> 2); + ret = CSC_ErrorNone; + break; + default: + ret = CSC_ErrorUnsupportFormat; + break; + } + + return ret; +} + +/* source is YVU420P */ +static CSC_ERRORCODE conv_sw_src_yvu420p( + CSC_HANDLE *handle) +{ + CSC_ERRORCODE ret = CSC_ErrorNone; + + switch (handle->dst_format.color_format) { + case HAL_PIXEL_FORMAT_YV12: /* bypass */ + case HAL_PIXEL_FORMAT_EXYNOS_YV12_M: + if (handle->src_buffer.mem_type == CSC_MEMORY_MFC) { + ret = copy_mfc_data(handle); + } else { + memcpy((unsigned char *)handle->dst_buffer.planes[CSC_Y_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_Y_PLANE], + handle->src_format.width * handle->src_format.height); + memcpy((unsigned char *)handle->dst_buffer.planes[CSC_U_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_U_PLANE], + (handle->src_format.width * handle->src_format.height) >> 2); + memcpy((unsigned char *)handle->dst_buffer.planes[CSC_V_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_V_PLANE], + (handle->src_format.width * handle->src_format.height) >> 2); + ret = CSC_ErrorNone; + } + break; + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN: + memcpy((unsigned char *)handle->dst_buffer.planes[CSC_Y_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_Y_PLANE], + handle->src_format.width * handle->src_format.height); + csc_interleave_memcpy( + (unsigned char *)handle->dst_buffer.planes[CSC_UV_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_V_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_U_PLANE], + (handle->src_format.width * handle->src_format.height) >> 2); + ret = CSC_ErrorNone; + break; + default: + ret = CSC_ErrorUnsupportFormat; + break; + } + + return ret; +} + +/* source is YUV420SP */ +static CSC_ERRORCODE conv_sw_src_yuv420sp( + CSC_HANDLE *handle) +{ + CSC_ERRORCODE ret = CSC_ErrorNone; + + char *pSrc = NULL; + char *pDst = NULL; + char *pDstU = NULL; + char *pDstV = NULL; + int srcOffset, dstOffset; + int i, j; + + switch (handle->dst_format.color_format) { + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP: /* bypass */ + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN: + if (handle->src_buffer.mem_type == CSC_MEMORY_MFC) { + ret = copy_mfc_data(handle); + } else { + memcpy((unsigned char *)handle->dst_buffer.planes[CSC_Y_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_Y_PLANE], + handle->src_format.width * handle->src_format.height); + memcpy((unsigned char *)handle->dst_buffer.planes[CSC_UV_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_UV_PLANE], + handle->src_format.width * handle->src_format.height >> 1); + ret = CSC_ErrorNone; + } + break; + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_PN: + { + pSrc = (char *)handle->src_buffer.planes[CSC_Y_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_Y_PLANE]; + for (i = 0; i < (int)handle->src_format.crop_height; i++) { + memcpy(pDst + (handle->src_format.crop_width * i), + pSrc + (handle->src_format.width * i), + handle->src_format.crop_width); + } + + pSrc = (char *)handle->src_buffer.planes[CSC_UV_PLANE]; + pDstU = (char *)handle->dst_buffer.planes[CSC_U_PLANE]; + pDstV = (char *)handle->dst_buffer.planes[CSC_V_PLANE]; + for (i = 0; i < (int)(handle->src_format.crop_height >> 1); i++) { + for (j = 0; j < (int)(handle->src_format.crop_width >> 1); j++) { + srcOffset = (i * handle->src_format.width) + (j * 2); + dstOffset = i * (handle->src_format.crop_width >> 1); + + pDstU[dstOffset + j] = pSrc[srcOffset]; + pDstV[dstOffset + j] = pSrc[srcOffset + 1]; + } + } + ret = CSC_ErrorNone; + } + break; + case HAL_PIXEL_FORMAT_YV12: + case HAL_PIXEL_FORMAT_EXYNOS_YV12_M: + pSrc = (char *)handle->src_buffer.planes[CSC_Y_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_Y_PLANE]; + for (i = 0; i < (int)handle->src_format.crop_height; i++) { + memcpy(pDst + (handle->src_format.crop_width * i), + pSrc + (handle->src_format.width * i), + handle->src_format.crop_width); + } + + pSrc = (char *)handle->src_buffer.planes[CSC_UV_PLANE]; + pDstU = (char *)handle->dst_buffer.planes[CSC_U_PLANE]; + pDstV = (char *)handle->dst_buffer.planes[CSC_V_PLANE]; + for (i = 0; i < (int)(handle->src_format.crop_height >> 1); i++) { + for (j = 0; j < (int)(handle->src_format.crop_width >> 1); j++) { + srcOffset = (i * handle->src_format.width) + (j * 2); + dstOffset = i * (handle->src_format.crop_width >> 1); + + pDstU[dstOffset + j] = pSrc[srcOffset + 1]; + pDstV[dstOffset + j] = pSrc[srcOffset]; + } + } + ret = CSC_ErrorNone; + break; + default: + ret = CSC_ErrorUnsupportFormat; + break; + } + + return ret; +} + +/* source is YVU420SP */ +static CSC_ERRORCODE conv_sw_src_yvu420sp( + CSC_HANDLE *handle) +{ + CSC_ERRORCODE ret = CSC_ErrorNone; + + char *pSrc = NULL; + char *pDst = NULL; + char *pDstU = NULL; + char *pDstV = NULL; + int srcOffset, dstOffset; + int i, j; + + switch (handle->dst_format.color_format) { + case HAL_PIXEL_FORMAT_YCrCb_420_SP: /* bypass */ + case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M: + if (handle->src_buffer.mem_type == CSC_MEMORY_MFC) { + ret = copy_mfc_data(handle); + } else { + memcpy((unsigned char *)handle->dst_buffer.planes[CSC_Y_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_Y_PLANE], + handle->src_format.width * handle->src_format.height); + memcpy((unsigned char *)handle->dst_buffer.planes[CSC_UV_PLANE], + (unsigned char *)handle->src_buffer.planes[CSC_UV_PLANE], + handle->src_format.width * handle->src_format.height >> 1); + ret = CSC_ErrorNone; + } + break; + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_PN: + pSrc = (char *)handle->src_buffer.planes[CSC_Y_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_Y_PLANE]; + for (i = 0; i < (int)handle->src_format.crop_height; i++) { + memcpy(pDst + (handle->src_format.crop_width * i), + pSrc + (handle->src_format.width * i), + handle->src_format.crop_width); + } + + pSrc = (char *)handle->src_buffer.planes[CSC_UV_PLANE]; + pDstU = (char *)handle->dst_buffer.planes[CSC_U_PLANE]; + pDstV = (char *)handle->dst_buffer.planes[CSC_V_PLANE]; + for (i = 0; i < (int)(handle->src_format.crop_height >> 1); i++) { + for (j = 0; j < (int)(handle->src_format.crop_width >> 1); j++) { + srcOffset = (i * handle->src_format.width) + (j * 2); + dstOffset = i * (handle->src_format.crop_width >> 1); + + pDstU[dstOffset + j] = pSrc[srcOffset + 1]; + pDstV[dstOffset + j] = pSrc[srcOffset]; + } + } + ret = CSC_ErrorNone; + break; + case HAL_PIXEL_FORMAT_YV12: + case HAL_PIXEL_FORMAT_EXYNOS_YV12_M: + pSrc = (char *)handle->src_buffer.planes[CSC_Y_PLANE]; + pDst = (char *)handle->dst_buffer.planes[CSC_Y_PLANE]; + for (i = 0; i < (int)handle->src_format.crop_height; i++) { + memcpy(pDst + (handle->src_format.crop_width * i), + pSrc + (handle->src_format.width * i), + handle->src_format.crop_width); + } + + pSrc = (char *)handle->src_buffer.planes[CSC_UV_PLANE]; + pDstU = (char *)handle->dst_buffer.planes[CSC_U_PLANE]; + pDstV = (char *)handle->dst_buffer.planes[CSC_V_PLANE]; + for (i = 0; i < (int)(handle->src_format.crop_height >> 1); i++) { + for (j = 0; j < (int)(handle->src_format.crop_width >> 1); j++) { + srcOffset = (i * handle->src_format.width) + (j * 2); + dstOffset = i * (handle->src_format.crop_width >> 1); + + pDstU[dstOffset + j] = pSrc[srcOffset]; + pDstV[dstOffset + j] = pSrc[srcOffset + 1]; + } + } + ret = CSC_ErrorNone; + break; + default: + ret = CSC_ErrorUnsupportFormat; + break; + } + + return ret; +} + +static CSC_ERRORCODE conv_sw( + CSC_HANDLE *handle) +{ + CSC_ERRORCODE ret = CSC_ErrorNone; + + switch (handle->src_format.color_format) { + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_TILED: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_TILED: + ret = conv_sw_src_nv12t(handle); + break; + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_PN: + ret = conv_sw_src_yuv420p(handle); + break; + case HAL_PIXEL_FORMAT_YV12: + case HAL_PIXEL_FORMAT_EXYNOS_YV12_M: + ret = conv_sw_src_yvu420p(handle); + break; + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_PRIV: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_S10B: + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN: + ret = conv_sw_src_yuv420sp(handle); + break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M: + ret = conv_sw_src_yvu420sp(handle); + break; + case HAL_PIXEL_FORMAT_BGRA_8888: + ret = conv_sw_src_argb888(handle); + break; + case HAL_PIXEL_FORMAT_RGBA_8888: + ret = conv_sw_src_rgba888(handle); + break; + case HAL_PIXEL_FORMAT_EXYNOS_ARGB_8888: + ret = copy_mfc_data(handle); + break; + default: + ret = CSC_ErrorUnsupportFormat; + break; + } + + return ret; +} + +static CSC_ERRORCODE conv_hw( + CSC_HANDLE *handle) +{ + CSC_ERRORCODE ret = CSC_ErrorNone; + switch (handle->csc_hw_type) { +#ifdef USES_FIMC + case CSC_HW_TYPE_FIMC: + if (exynos_fimc_convert(handle->csc_hw_handle) != 0) { + ALOGE("%s:: exynos_fimc_convert() fail", __func__); + ret = CSC_Error; + } + break; +#endif +#ifdef USES_GSCALER + case CSC_HW_TYPE_GSCALER: + if (handle->hw_property.fixed_node < CSC_HW_SC0) { + if (exynos_gsc_convert(handle->csc_hw_handle) != 0) { + ALOGE("%s:: exynos_gsc_convert() fail", __func__); + ret = CSC_Error; + } + } else { + if (exynos_sc_convert(handle->csc_hw_handle) != 0) { + ALOGE("%s:: exynos_sc_convert() fail", __func__); + ret = CSC_Error; + } + } + break; +#endif + default: + ALOGE("%s:: unsupported csc_hw_type(%d)", __func__, handle->csc_hw_type); + ret = CSC_ErrorNotImplemented; + break; + } + + return ret; +} + +static CSC_ERRORCODE csc_init_hw( + void *handle) +{ + CSC_HANDLE *csc_handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + csc_handle = (CSC_HANDLE *)handle; + if (csc_handle->csc_method == CSC_METHOD_HW) { +#ifdef USES_FIMC + csc_handle->csc_hw_type = CSC_HW_TYPE_FIMC; +#endif +#ifdef USES_GSCALER + csc_handle->csc_hw_type = CSC_HW_TYPE_GSCALER; +#endif + switch (csc_handle->csc_hw_type) { +#ifdef USES_FIMC + case CSC_HW_TYPE_FIMC: + if (csc_handle->hw_property.fixed_node >= 0) + csc_handle->csc_hw_handle = exynos_fimc_create_exclusive(csc_handle->hw_property.fixed_node, FIMC_M2M_MODE, 0, 0); + else + csc_handle->csc_hw_handle = exynos_fimc_create(); + ALOGV("%s:: CSC_HW_TYPE_FIMC", __func__); + break; +#endif +#ifdef USES_GSCALER + case CSC_HW_TYPE_GSCALER: + if (csc_handle->hw_property.fixed_node >= 0) { + if (csc_handle->hw_property.fixed_node < CSC_HW_SC0) + csc_handle->csc_hw_handle = exynos_gsc_create_exclusive(csc_handle->hw_property.fixed_node, GSC_M2M_MODE, 0, 0); + else if (csc_handle->hw_property.fixed_node < CSC_HW_MAX) + csc_handle->csc_hw_handle = exynos_sc_create(csc_handle->hw_property.fixed_node - CSC_HW_SC0); + else + csc_handle->csc_hw_handle = NULL; + } else { + csc_handle->csc_hw_handle = exynos_gsc_create(); + } + ALOGV("%s:: CSC_HW_TYPE_GSCALER", __func__); + break; +#endif + default: + ALOGE("%s:: unsupported csc_hw_type, csc use sw", __func__); + csc_handle->csc_hw_handle = NULL; + break; + } + } + + if (csc_handle->csc_method == CSC_METHOD_HW) { + if (csc_handle->csc_hw_handle == NULL) { + ALOGE("%s:: CSC_METHOD_HW can't open HW", __func__); + free(csc_handle); + csc_handle = NULL; + } + } + if (csc_handle) + ALOGV("%s:: CSC_METHOD=%d", __func__, csc_handle->csc_method); + + return ret; +} + +static CSC_ERRORCODE csc_set_format( + void *handle) +{ + CSC_HANDLE *csc_handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (handle == NULL) + return CSC_ErrorNotInit; + + csc_handle = (CSC_HANDLE *)handle; + if (csc_handle->csc_method == CSC_METHOD_HW) { + switch (csc_handle->csc_hw_type) { +#ifdef USES_FIMC + case CSC_HW_TYPE_FIMC: + exynos_fimc_set_src_format( + csc_handle->csc_hw_handle, + ALIGN(csc_handle->src_format.width, FIMC_IMG_ALIGN_WIDTH), + ALIGN(csc_handle->src_format.height, FIMC_IMG_ALIGN_HEIGHT), + csc_handle->src_format.crop_left, + csc_handle->src_format.crop_top, + csc_handle->src_format.crop_width, + csc_handle->src_format.crop_height, + HAL_PIXEL_FORMAT_2_V4L2_PIX(csc_handle->src_format.color_format), + csc_handle->src_format.cacheable, + csc_handle->hw_property.mode_drm); + + exynos_fimc_set_dst_format( + csc_handle->csc_hw_handle, + ALIGN(csc_handle->dst_format.width, FIMC_IMG_ALIGN_WIDTH), + ALIGN(csc_handle->dst_format.height, FIMC_IMG_ALIGN_HEIGHT), + csc_handle->dst_format.crop_left, + csc_handle->dst_format.crop_top, + csc_handle->dst_format.crop_width, + csc_handle->dst_format.crop_height, + HAL_PIXEL_FORMAT_2_V4L2_PIX(csc_handle->dst_format.color_format), + csc_handle->dst_format.cacheable, + csc_handle->hw_property.mode_drm, + 0); + break; +#endif +#ifdef USES_GSCALER + case CSC_HW_TYPE_GSCALER: + if (csc_handle->hw_property.fixed_node < CSC_HW_SC0) { + exynos_gsc_set_csc_property( + csc_handle->csc_hw_handle, + csc_handle->csc_mode, + csc_handle->csc_range, + csc_handle->colorspace); + + exynos_gsc_set_src_format( + csc_handle->csc_hw_handle, + csc_handle->src_format.width, + csc_handle->src_format.height, + csc_handle->src_format.crop_left, + csc_handle->src_format.crop_top, + csc_handle->src_format.crop_width, + csc_handle->src_format.crop_height, + HAL_PIXEL_FORMAT_2_V4L2_PIX(csc_handle->src_format.color_format), + csc_handle->src_format.cacheable, + csc_handle->hw_property.mode_drm); + + exynos_gsc_set_dst_format( + csc_handle->csc_hw_handle, + csc_handle->dst_format.width, + csc_handle->dst_format.height, + csc_handle->dst_format.crop_left, + csc_handle->dst_format.crop_top, + csc_handle->dst_format.crop_width, + csc_handle->dst_format.crop_height, + HAL_PIXEL_FORMAT_2_V4L2_PIX(csc_handle->dst_format.color_format), + csc_handle->dst_format.cacheable, + csc_handle->hw_property.mode_drm); + } else { + exynos_sc_set_csc_property( + csc_handle->csc_hw_handle, + csc_handle->csc_range, + csc_handle->colorspace, + csc_handle->filter); + + exynos_sc_set_src_format( + csc_handle->csc_hw_handle, + csc_handle->src_format.width, + csc_handle->src_format.height, + csc_handle->src_format.crop_left, + csc_handle->src_format.crop_top, + csc_handle->src_format.crop_width, + csc_handle->src_format.crop_height, + HAL_PIXEL_FORMAT_2_V4L2_PIX(csc_handle->src_format.color_format), + csc_handle->src_format.cacheable, + csc_handle->hw_property.mode_drm, + 1); + + exynos_sc_set_dst_format( + csc_handle->csc_hw_handle, + csc_handle->dst_format.width, + csc_handle->dst_format.height, + csc_handle->dst_format.crop_left, + csc_handle->dst_format.crop_top, + csc_handle->dst_format.crop_width, + csc_handle->dst_format.crop_height, + HAL_PIXEL_FORMAT_2_V4L2_PIX(csc_handle->dst_format.color_format), + csc_handle->dst_format.cacheable, + csc_handle->hw_property.mode_drm, + 1); + } + break; +#endif + default: + ALOGE("%s:: unsupported csc_hw_type", __func__); + break; + } + } + + return ret; +} + +static CSC_ERRORCODE csc_set_buffer( + void *handle) +{ + CSC_HANDLE *csc_handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (handle == NULL) + return CSC_ErrorNotInit; + + csc_handle = (CSC_HANDLE *)handle; + if (csc_handle->csc_method == CSC_METHOD_HW) { + switch (csc_handle->csc_hw_type) { +#ifdef USES_FIMC + case CSC_HW_TYPE_FIMC: + exynos_fimc_set_src_addr(csc_handle->csc_hw_handle, csc_handle->src_buffer.planes, csc_handle->src_buffer.mem_type, -1); + exynos_fimc_set_dst_addr(csc_handle->csc_hw_handle, csc_handle->dst_buffer.planes, csc_handle->dst_buffer.mem_type, -1); + break; +#endif +#ifdef USES_GSCALER + case CSC_HW_TYPE_GSCALER: + if (csc_handle->hw_property.fixed_node < CSC_HW_SC0) { + exynos_gsc_set_src_addr(csc_handle->csc_hw_handle, csc_handle->src_buffer.planes, csc_handle->src_buffer.mem_type, -1); + exynos_gsc_set_dst_addr(csc_handle->csc_hw_handle, csc_handle->dst_buffer.planes, csc_handle->dst_buffer.mem_type, -1); + } else { + exynos_sc_set_src_addr(csc_handle->csc_hw_handle, csc_handle->src_buffer.planes, csc_handle->src_buffer.mem_type, -1); + exynos_sc_set_dst_addr(csc_handle->csc_hw_handle, csc_handle->dst_buffer.planes, csc_handle->dst_buffer.mem_type, -1); + } + break; +#endif + default: + ALOGE("%s:: unsupported csc_hw_type", __func__); + break; + } + } + + return ret; +} + +void *csc_init( + CSC_METHOD method) +{ + CSC_HANDLE *csc_handle; + csc_handle = (CSC_HANDLE *)malloc(sizeof(CSC_HANDLE)); + if (csc_handle == NULL) + return NULL; + + memset(csc_handle, 0, sizeof(CSC_HANDLE)); +#ifdef USES_DEFAULT_CSC_HW_SCALER + csc_handle->hw_property.fixed_node = DEFAULT_CSC_HW; /* CSC_HW_SC1 == 5 */ +#else + csc_handle->hw_property.fixed_node = -1; +#endif + csc_handle->hw_property.mode_drm = 0; + csc_handle->csc_method = method; + + return (void *)csc_handle; +} + +CSC_ERRORCODE csc_deinit( + void *handle) +{ + CSC_ERRORCODE ret = CSC_ErrorNone; + CSC_HANDLE *csc_handle; + + if (handle == NULL) + return ret; + + csc_handle = (CSC_HANDLE *)handle; + if (csc_handle->csc_method == CSC_METHOD_HW) { + switch (csc_handle->csc_hw_type) { +#ifdef USES_FIMC + case CSC_HW_TYPE_FIMC: + exynos_fimc_destroy(csc_handle->csc_hw_handle); + break; +#endif +#ifdef USES_GSCALER + case CSC_HW_TYPE_GSCALER: + if (csc_handle->hw_property.fixed_node < CSC_HW_SC0) + exynos_gsc_destroy(csc_handle->csc_hw_handle); + else + exynos_sc_destroy(csc_handle->csc_hw_handle); + break; +#endif + default: + ALOGE("%s:: unsupported csc_hw_type", __func__); + break; + } + } + + free(csc_handle); + ret = CSC_ErrorNone; + + return ret; +} + +CSC_ERRORCODE csc_get_method( + void *handle, + CSC_METHOD *method) +{ + CSC_HANDLE *csc_handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (handle == NULL) + return CSC_ErrorNotInit; + + csc_handle = (CSC_HANDLE *)handle; + *method = csc_handle->csc_method; + + return ret; +} + +CSC_ERRORCODE csc_set_method( + void *handle, + CSC_METHOD method) +{ + CSC_HANDLE *csc_handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (handle == NULL) + return CSC_ErrorNotInit; + csc_handle = (CSC_HANDLE *)handle; + + switch (method) { + case CSC_METHOD_SW: + case CSC_METHOD_HW: + csc_handle->csc_method = method; + break; + default: + ret = CSC_Error; + break; + } + + return ret; +} + +CSC_ERRORCODE csc_set_hw_property( + void *handle, + CSC_HW_PROPERTY_TYPE property, + int value) +{ + CSC_HANDLE *csc_handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (handle == NULL) + return CSC_ErrorNotInit; + + csc_handle = (CSC_HANDLE *)handle; + switch (property) { + case CSC_HW_PROPERTY_FIXED_NODE: + csc_handle->hw_property.fixed_node = value; + break; + case CSC_HW_PROPERTY_MODE_DRM: + csc_handle->hw_property.mode_drm = value; + break; + default: + ALOGE("%s:: not supported hw property", __func__); + ret = CSC_ErrorUnsupportFormat; + } + + return ret; +} + +CSC_ERRORCODE csc_get_eq_property( + void *handle, + CSC_EQ_MODE *csc_mode, + CSC_EQ_RANGE *csc_range, + CSC_EQ_COLORSPACE *colorspace) +{ + CSC_HANDLE *csc_handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (handle == NULL) + return CSC_ErrorNotInit; + + csc_handle = (CSC_HANDLE *)handle; + *csc_mode = csc_handle->csc_mode; + *csc_range = csc_handle->csc_range; + *colorspace = csc_handle->colorspace; + + return ret; +} + +CSC_ERRORCODE csc_set_eq_property( + void *handle, + CSC_EQ_MODE csc_mode, + CSC_EQ_RANGE csc_range, + CSC_EQ_COLORSPACE colorspace) +{ + CSC_HANDLE *csc_handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (handle == NULL) + return CSC_Error; + + csc_handle = (CSC_HANDLE *)handle; + csc_handle->csc_mode = csc_mode; + csc_handle->csc_range = csc_range; + csc_handle->colorspace = colorspace; + + return ret; +} + +CSC_ERRORCODE csc_set_filter_property( + void *handle, + CSC_HW_FILTER filter) +{ + CSC_HANDLE *csc_handle; + + if (handle == NULL) + return CSC_Error; + + csc_handle = (CSC_HANDLE *)handle; + if (filter >= CSC_FT_MAX) + return CSC_Error; + + csc_handle->filter = filter; + csc_handle->hw_property.fixed_node = CSC_HW_SC1; + + return 0; +} + +CSC_ERRORCODE csc_get_src_format( + void *handle, + unsigned int *width, + unsigned int *height, + unsigned int *crop_left, + unsigned int *crop_top, + unsigned int *crop_width, + unsigned int *crop_height, + unsigned int *color_format, + unsigned int *cacheable) +{ + CSC_HANDLE *csc_handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (handle == NULL) + return CSC_ErrorNotInit; + + csc_handle = (CSC_HANDLE *)handle; + *width = csc_handle->src_format.width; + *height = csc_handle->src_format.height; + *crop_left = csc_handle->src_format.crop_left; + *crop_top = csc_handle->src_format.crop_top; + *crop_width = csc_handle->src_format.crop_width; + *crop_height = csc_handle->src_format.crop_height; + *color_format = csc_handle->src_format.color_format; + *cacheable = csc_handle->src_format.cacheable; + + return ret; +} + +CSC_ERRORCODE csc_set_src_format( + void *handle, + unsigned int width, + unsigned int height, + unsigned int crop_left, + unsigned int crop_top, + unsigned int crop_width, + unsigned int crop_height, + unsigned int color_format, + unsigned int cacheable) +{ + CSC_HANDLE *csc_handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (handle == NULL) + return CSC_ErrorNotInit; + + csc_handle = (CSC_HANDLE *)handle; + csc_handle->src_format.width = width; + csc_handle->src_format.height = height; + csc_handle->src_format.crop_left = crop_left; + csc_handle->src_format.crop_top = crop_top; + csc_handle->src_format.crop_width = crop_width; + csc_handle->src_format.crop_height = crop_height; + csc_handle->src_format.color_format = color_format; + csc_handle->src_format.cacheable = cacheable; + + return ret; +} + +CSC_ERRORCODE csc_get_dst_format( + void *handle, + unsigned int *width, + unsigned int *height, + unsigned int *crop_left, + unsigned int *crop_top, + unsigned int *crop_width, + unsigned int *crop_height, + unsigned int *color_format, + unsigned int *cacheable) +{ + CSC_HANDLE *csc_handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (handle == NULL) + return CSC_ErrorNotInit; + + csc_handle = (CSC_HANDLE *)handle; + *width = csc_handle->dst_format.width; + *height = csc_handle->dst_format.height; + *crop_left = csc_handle->dst_format.crop_left; + *crop_top = csc_handle->dst_format.crop_top; + *crop_width = csc_handle->dst_format.crop_width; + *crop_height = csc_handle->dst_format.crop_height; + *color_format = csc_handle->dst_format.color_format; + *cacheable = csc_handle->dst_format.cacheable; + + return ret; +} + +CSC_ERRORCODE csc_set_dst_format( + void *handle, + unsigned int width, + unsigned int height, + unsigned int crop_left, + unsigned int crop_top, + unsigned int crop_width, + unsigned int crop_height, + unsigned int color_format, + unsigned int cacheable) +{ + CSC_HANDLE *csc_handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (handle == NULL) + return CSC_ErrorNotInit; + + csc_handle = (CSC_HANDLE *)handle; + csc_handle->dst_format.width = width; + csc_handle->dst_format.height = height; + csc_handle->dst_format.crop_left = crop_left; + csc_handle->dst_format.crop_top = crop_top; + csc_handle->dst_format.crop_width = crop_width; + csc_handle->dst_format.crop_height = crop_height; + csc_handle->dst_format.color_format = color_format; + csc_handle->dst_format.cacheable = cacheable; + + return ret; +} + +CSC_ERRORCODE csc_set_src_buffer( + void *handle, + void *addr[3], + int mem_type) +{ + CSC_HANDLE *csc_handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (handle == NULL) + return CSC_ErrorNotInit; + + csc_handle = (CSC_HANDLE *)handle; + csc_handle->src_buffer.planes[CSC_Y_PLANE] = addr[0]; + csc_handle->src_buffer.planes[CSC_U_PLANE] = addr[1]; + csc_handle->src_buffer.planes[CSC_V_PLANE] = addr[2]; + csc_handle->src_buffer.mem_type = mem_type; + + return ret; +} + +CSC_ERRORCODE csc_set_dst_buffer( + void *handle, + void *addr[3], + int mem_type) +{ + CSC_HANDLE *csc_handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (handle == NULL) + return CSC_ErrorNotInit; + + csc_handle = (CSC_HANDLE *)handle; + csc_handle->dst_buffer.planes[CSC_Y_PLANE] = addr[0]; + csc_handle->dst_buffer.planes[CSC_U_PLANE] = addr[1]; + csc_handle->dst_buffer.planes[CSC_V_PLANE] = addr[2]; + csc_handle->dst_buffer.mem_type = mem_type; + + return ret; +} + +CSC_ERRORCODE csc_convert( + void *handle) +{ + CSC_HANDLE *csc_handle = (CSC_HANDLE *)handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (csc_handle == NULL) + return CSC_ErrorNotInit; + + if ((csc_handle->csc_method == CSC_METHOD_HW) && + (csc_handle->csc_hw_handle == NULL)) + csc_init_hw(handle); + + csc_set_format(csc_handle); + csc_set_buffer(csc_handle); + + if (csc_handle->csc_method == CSC_METHOD_HW) + ret = conv_hw(csc_handle); + else + ret = conv_sw(csc_handle); + + return ret; +} + +CSC_ERRORCODE csc_convert_with_rotation( + void *handle, int rotation, int flip_horizontal, int flip_vertical) +{ + CSC_HANDLE *csc_handle = (CSC_HANDLE *)handle; + CSC_ERRORCODE ret = CSC_ErrorNone; + + if (csc_handle == NULL) + return CSC_ErrorNotInit; + + if ((csc_handle->csc_method == CSC_METHOD_HW) && + (csc_handle->csc_hw_handle == NULL)) + csc_init_hw(handle); + + csc_set_format(csc_handle); + csc_set_buffer(csc_handle); + +#ifdef USES_FIMC + exynos_fimc_set_rotation(csc_handle->csc_hw_handle, rotation, flip_horizontal, flip_vertical); +#endif +#ifdef USES_GSCALER + if (csc_handle->hw_property.fixed_node < CSC_HW_SC0) + exynos_gsc_set_rotation(csc_handle->csc_hw_handle, rotation, flip_horizontal, flip_vertical); + else + exynos_sc_set_rotation(csc_handle->csc_hw_handle, rotation, flip_horizontal, flip_vertical); +#endif + + if (csc_handle->csc_method == CSC_METHOD_HW) + ret = conv_hw(csc_handle); + else + ret = conv_sw(csc_handle); + + return ret; +} diff --git a/libexynos-common.manifest b/libexynos-common.manifest new file mode 100755 index 0000000..a76fdba --- /dev/null +++ b/libexynos-common.manifest @@ -0,0 +1,5 @@ +<manifest> + <request> + <domain name="_" /> + </request> +</manifest> diff --git a/libgscaler/Makefile.am b/libgscaler/Makefile.am new file mode 100755 index 0000000..afe91ef --- /dev/null +++ b/libgscaler/Makefile.am @@ -0,0 +1,7 @@ +lib_LTLIBRARIES = libexynosgscaler.la + +libexynosgscaler_la_SOURCES = libgscaler_obj.cpp libgscaler.cpp +libexynosgscaler_la_CFLAGS = -DLOG_TAG=\"LIBEXYNOSGSCALER\" -I$(top_srcdir)/include +libexynosgscaler_la_CXXFLAGS = $(libexynosgscaler_la_CFLAGS) +libexynosgscaler_la_LDFLAGS = -L$(top_srcdir)/libcsc +libexynosgscaler_la_LIBADD = -lcsc $(DLOG_LIBS) diff --git a/libgscaler/libgscaler.cpp b/libgscaler/libgscaler.cpp new file mode 100755 index 0000000..8073e80 --- /dev/null +++ b/libgscaler/libgscaler.cpp @@ -0,0 +1,646 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * Copyright@ Samsung Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*! + * \file libgscaler.cpp + * \brief source file for Gscaler HAL + * \author Sungchun Kang (sungchun.kang@samsung.com) + * \date 2013/06/01 + * + * <b>Revision History: </b> + * - 2013.06.01 : Sungchun Kang (sungchun.kang@samsung.com) \n + * Create + */ + +#include "libgscaler_obj.h" + +void *exynos_gsc_create(void) +{ + CGscaler *gsc = new CGscaler(GSC_M2M_MODE); + if (!gsc) { + ALOGE("%s:: failed to allocate Gscaler handle", __func__); + return NULL; + } + if (gsc->m_gsc_find_and_create(gsc) == false) { + ALOGE("%s::m_exynos_gsc_find_and_create() fail", __func__); + delete gsc; + return NULL; + } + + return reinterpret_cast<void *>(gsc); +} + +void *exynos_gsc_create_exclusive( + int dev_num, + int mode, + int out_mode, + int allow_drm) +{ + int i = 0; + int op_id = 0; + unsigned int total_sleep_time = 0; + int ret = 0; + + Exynos_gsc_In(); + + if ((dev_num < 0) || (dev_num >= HW_SCAL_MAX)) { + ALOGE("%s::fail:: dev_num is not valid(%d) ", __func__, dev_num); + return NULL; + } + + if ((dev_num >= NUM_OF_GSC_HW) && (dev_num < HW_SCAL_MAX)) { + CGscaler *gsc = new CGscaler(mode, out_mode, dev_num, allow_drm); + if (!gsc) { + ALOGE("%s:: failed to allocate Gscaler handle", __func__); + return NULL; + } + + gsc->scaler = exynos_sc_create_exclusive(dev_num - HW_SCAL0, + allow_drm); + if (!gsc->scaler) { + delete(gsc); + ALOGE("%s::exynos_sc_create fail", __func__); + return NULL; + } + Exynos_gsc_Out(); + return reinterpret_cast<void *>(gsc); + } + + if ((mode < 0) || (mode >= NUM_OF_GSC_HW)) { + ALOGE("%s::fail:: mode is not valid(%d) ", __func__, mode); + return NULL; + } + + CGscaler *gsc = new CGscaler(mode, out_mode, dev_num, allow_drm); + if (!gsc) { + ALOGE("%s:: failed to allocate Gscaler handle", __func__); + return NULL; + } + + if (mode == GSC_M2M_MODE) { + gsc->gsc_fd = gsc->m_gsc_m2m_create(dev_num); + if (gsc->gsc_fd < 0) { + ALOGE("%s::m_gsc_m2m_create(%i) fail", __func__, dev_num); + goto err; + } + } else if (mode == GSC_OUTPUT_MODE) { + ret = gsc->m_gsc_output_create(gsc, dev_num, out_mode); + if (ret < 0) { + ALOGE("%s::m_gsc_output_create(%i) fail", __func__, dev_num); + goto err; + } + } else if (mode == GSC_CAPTURE_MODE) { + ret = gsc->m_gsc_capture_create(gsc, dev_num, out_mode); + if (ret < 0) { + ALOGE("%s::m_gsc_capture_create(%i) fail", __func__, dev_num); + goto err; + } + } else { + ALOGE("%s::Unsupported Mode(%i) fail", __func__, dev_num); + goto err; + } + + Exynos_gsc_Out(); + + return reinterpret_cast<void *>(gsc); +err: + switch (mode) { + case GSC_M2M_MODE: + gsc->m_gsc_m2m_destroy(gsc); + break; + case GSC_OUTPUT_MODE: + gsc->m_gsc_out_destroy(gsc); + break; + case GSC_CAPTURE_MODE: + gsc->m_gsc_cap_destroy(gsc); + break; + } + + delete(gsc); + + Exynos_gsc_Out(); + + return NULL; +} + +void exynos_gsc_destroy(void *handle) +{ + Exynos_gsc_In(); + + int i = 0; + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return; + } + + if (gsc->mode == GSC_OUTPUT_MODE) + gsc->m_gsc_out_destroy(gsc); + else if (gsc->mode ==GSC_CAPTURE_MODE) + gsc->m_gsc_cap_destroy(gsc); + else + gsc->m_gsc_m2m_destroy(gsc); + + delete(gsc); + + Exynos_gsc_Out(); +} + +int exynos_gsc_set_csc_property( + void *handle, + unsigned int eq_auto, + unsigned int range_full, + unsigned int v4l2_colorspace) +{ + Exynos_gsc_In(); + + CGscaler *gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + if (gsc->gsc_id >= HW_SCAL0) { + int ret; + ret = exynos_sc_csc_exclusive(gsc->scaler, + range_full, v4l2_colorspace); + Exynos_gsc_Out(); + return ret; + } + gsc->eq_auto = eq_auto; + gsc->range_full = range_full; + gsc->v4l2_colorspace = v4l2_colorspace; + + Exynos_gsc_Out(); + + return 0; +} + +int exynos_gsc_set_src_format( + void *handle, + unsigned int width, + unsigned int height, + unsigned int crop_left, + unsigned int crop_top, + unsigned int crop_width, + unsigned int crop_height, + unsigned int v4l2_colorformat, + unsigned int cacheable, + unsigned int mode_drm) +{ + Exynos_gsc_In(); + + CGscaler *gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + gsc->src_info.width = width; + gsc->src_info.height = height; + gsc->src_info.crop_left = crop_left; + gsc->src_info.crop_top = crop_top; + gsc->src_info.crop_width = crop_width; + gsc->src_info.crop_height = crop_height; + gsc->src_info.v4l2_colorformat = v4l2_colorformat; + gsc->src_info.cacheable = cacheable; + gsc->src_info.mode_drm = mode_drm; + gsc->src_info.dirty = true; + + Exynos_gsc_Out(); + + return 0; +} + +int exynos_gsc_set_dst_format( + void *handle, + unsigned int width, + unsigned int height, + unsigned int crop_left, + unsigned int crop_top, + unsigned int crop_width, + unsigned int crop_height, + unsigned int v4l2_colorformat, + unsigned int cacheable, + unsigned int mode_drm) +{ + Exynos_gsc_In(); + + CGscaler *gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + gsc->dst_info.width = width; + gsc->dst_info.height = height; + gsc->dst_info.crop_left = crop_left; + gsc->dst_info.crop_top = crop_top; + gsc->dst_info.crop_width = crop_width; + gsc->dst_info.crop_height = crop_height; + gsc->dst_info.v4l2_colorformat = v4l2_colorformat; + gsc->dst_info.dirty = true; + gsc->dst_info.cacheable = cacheable; + gsc->dst_info.mode_drm = mode_drm; + + Exynos_gsc_Out(); + + return 0; +} + +int exynos_gsc_set_rotation( + void *handle, + int rotation, + int flip_horizontal, + int flip_vertical) +{ + CGscaler *gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + int new_rotation = rotation % 360; + + if (new_rotation % 90 != 0) { + ALOGE("%s::rotation(%d) cannot be acceptable fail", __func__, + rotation); + return -1; + } + + if(new_rotation < 0) + new_rotation = -new_rotation; + + gsc->dst_info.rotation = new_rotation; + gsc->dst_info.flip_horizontal = flip_horizontal; + gsc->dst_info.flip_vertical = flip_vertical; + + return 0; +} + +int exynos_gsc_set_src_addr( + void *handle, + void *addr[3], + int mem_type, + int acquireFenceFd) +{ + Exynos_gsc_In(); + + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + gsc->src_info.buf.addr[0] = addr[0]; + gsc->src_info.buf.addr[1] = addr[1]; + gsc->src_info.buf.addr[2] = addr[2]; + gsc->src_info.acquireFenceFd = acquireFenceFd; + gsc->src_info.buf.mem_type = (enum v4l2_memory)mem_type; + + Exynos_gsc_Out(); + + return 0; +} + +int exynos_gsc_set_dst_addr( + void *handle, + void *addr[3], + int mem_type, + int acquireFenceFd) +{ + Exynos_gsc_In(); + + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + gsc->dst_info.buf.addr[0] = addr[0]; + gsc->dst_info.buf.addr[1] = addr[1]; + gsc->dst_info.buf.addr[2] = addr[2]; + gsc->dst_info.acquireFenceFd = acquireFenceFd; + gsc->dst_info.buf.mem_type = (enum v4l2_memory)mem_type; + + Exynos_gsc_Out(); + + return 0; +} + +int exynos_gsc_convert(void *handle) +{ + Exynos_gsc_In(); + + int ret = -1; + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return ret; + } + + if (gsc->m_gsc_m2m_run_core(handle) < 0) { + ALOGE("%s::exynos_gsc_run_core fail", __func__); + goto done; + } + + if (gsc->m_gsc_m2m_wait_frame_done(handle) < 0) { + ALOGE("%s::exynos_gsc_m2m_wait_frame_done", __func__); + goto done; + } + + if (gsc->src_info.releaseFenceFd >= 0) { + close(gsc->src_info.releaseFenceFd); + gsc->src_info.releaseFenceFd = -1; + } + + if (gsc->dst_info.releaseFenceFd >= 0) { + close(gsc->dst_info.releaseFenceFd); + gsc->dst_info.releaseFenceFd = -1; + } + + if (gsc->m_gsc_m2m_stop(handle) < 0) { + ALOGE("%s::m_gsc_m2m_stop", __func__); + goto done; + } + + ret = 0; + +done: + Exynos_gsc_Out(); + + return ret; +} + +int exynos_gsc_subdev_s_crop(void *handle, + exynos_mpp_img *src_img, exynos_mpp_img *dst_img) +{ + struct v4l2_subdev_crop sd_crop; + CGscaler *gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + sd_crop.pad = GSCALER_SUBDEV_PAD_SOURCE; + sd_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_crop.rect.left = dst_img->x; + sd_crop.rect.top = dst_img->y; + sd_crop.rect.width = dst_img->w; + sd_crop.rect.height = dst_img->h; + + return exynos_subdev_s_crop(gsc->mdev.gsc_sd_entity->fd, &sd_crop); +} + +int exynos_gsc_config_exclusive(void *handle, + exynos_mpp_img *src_img, exynos_mpp_img *dst_img) +{ + Exynos_gsc_In(); + + int ret = 0; + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + if (gsc->gsc_id >= HW_SCAL0) { + ret = exynos_sc_config_exclusive(gsc->scaler, + (exynos_sc_img *)src_img, (exynos_sc_img *)dst_img); + Exynos_gsc_Out(); + return ret; + } + + switch (gsc->mode) { + case GSC_M2M_MODE: + ret = gsc->m_gsc_m2m_config(handle, src_img, dst_img); + break; + case GSC_OUTPUT_MODE: + ret = gsc->m_gsc_out_config(handle, src_img, dst_img); + break; + case GSC_CAPTURE_MODE: + ret = gsc->m_gsc_cap_config(handle, src_img, dst_img); + break; + default: + break; + } + + Exynos_gsc_Out(); + + return ret; +} + +int exynos_gsc_run_exclusive(void *handle, + exynos_mpp_img *src_img, exynos_mpp_img *dst_img) +{ + Exynos_gsc_In(); + + int ret = 0; + CGscaler* gsc = GetGscaler(handle); + if (handle == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + if (gsc->gsc_id >= HW_SCAL0) { + ret = exynos_sc_run_exclusive(gsc->scaler, + (exynos_sc_img *)src_img, (exynos_sc_img *)dst_img); + Exynos_gsc_Out(); + return ret; + } + + switch (gsc->mode) { + case GSC_M2M_MODE: + ret = gsc->m_gsc_m2m_run(handle, src_img, dst_img); + break; + case GSC_OUTPUT_MODE: + ret = gsc->m_gsc_out_run(handle, src_img); + break; + case GSC_CAPTURE_MODE: + ret = gsc->m_gsc_cap_run(handle, dst_img); + break; + default: + break; + } + + Exynos_gsc_Out(); + + return ret; +} + +void *exynos_gsc_create_blend_exclusive(int dev_num, int mode, int out_mode, + int allow_drm) +{ + int i = 0; + int op_id = 0; + unsigned int total_sleep_time = 0; + int ret = 0; + + Exynos_gsc_In(); + + if ((dev_num < 0) || (dev_num >= HW_SCAL_MAX)) { + ALOGE("%s::fail:: dev_num is not valid(%d) ", __func__, dev_num); + return NULL; + } + + if ((dev_num >= NUM_OF_GSC_HW) && (dev_num < HW_SCAL_MAX)) { + CGscaler *gsc = new CGscaler(mode, out_mode, dev_num, allow_drm); + if (!gsc) { + ALOGE("%s:: failed to allocate Gscaler handle", __func__); + return NULL; + } + + gsc->scaler = exynos_sc_create_blend_exclusive(dev_num - HW_SCAL0, allow_drm); + if (!gsc->scaler) { + Exynos_gsc_Out(); + delete(gsc); + ALOGE("%s::exynos_sc_create_blend_exclusive failed", __func__); + return NULL; + } + Exynos_gsc_Out(); + + return reinterpret_cast<void *>(gsc); + } + + Exynos_gsc_Out(); + + return NULL; +} + +int exynos_gsc_config_blend_exclusive(void *handle, + exynos_mpp_img *src_img, exynos_mpp_img *dst_img, + struct SrcBlendInfo *srcblendinfo) +{ + Exynos_gsc_In(); + + int ret = 0; + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + if (gsc->gsc_id >= HW_SCAL0) { + ret = exynos_sc_config_blend_exclusive(gsc->scaler, + (exynos_sc_img *)src_img, + (exynos_sc_img *)dst_img, + srcblendinfo); + Exynos_gsc_Out(); + return ret; + } + Exynos_gsc_Out(); + return ret; +} + +int exynos_gsc_wait_frame_done_exclusive(void *handle) +{ + Exynos_gsc_In(); + + int ret = 0; + CGscaler* gsc = GetGscaler(handle); + if (handle == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + if (gsc->gsc_id >= HW_SCAL0) { + ret = exynos_sc_wait_frame_done_exclusive(gsc->scaler); + Exynos_gsc_Out(); + return ret; + } + + if (gsc->mode == GSC_M2M_MODE) + ret = gsc->m_gsc_m2m_wait_frame_done(handle); + + Exynos_gsc_Out(); + + return ret; +} + +int exynos_gsc_stop_exclusive(void *handle) +{ + Exynos_gsc_In(); + + int ret = 0; + CGscaler* gsc = GetGscaler(handle); + if (handle == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + if (gsc->gsc_id >= HW_SCAL0) { + ret = exynos_sc_stop_exclusive(gsc->scaler); + Exynos_gsc_Out(); + return ret; + } + + switch (gsc->mode) { + case GSC_M2M_MODE: + ret = gsc->m_gsc_m2m_stop(handle); + break; + case GSC_OUTPUT_MODE: + ret = gsc->m_gsc_out_stop(handle); + break; + case GSC_CAPTURE_MODE: + ret = gsc->m_gsc_cap_stop(handle); + break; + default: + break; + } + + Exynos_gsc_Out(); + + return ret; +} + +int exynos_gsc_free_and_close(void *handle) +{ + Exynos_gsc_In(); + + struct v4l2_requestbuffers reqbuf; + struct v4l2_buffer buf; + struct v4l2_plane planes[NUM_OF_GSC_PLANES]; + int ret = 0; + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + + if (gsc->gsc_id >= HW_SCAL0) { + ret = exynos_sc_free_and_close(gsc->scaler); + Exynos_gsc_Out(); + return ret; + } + + memset(&reqbuf, 0, sizeof(struct v4l2_requestbuffers)); + if (gsc->mode == GSC_OUTPUT_MODE) + reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + else + reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + reqbuf.memory = V4L2_MEMORY_DMABUF; + reqbuf.count = 0; + + if (exynos_v4l2_reqbufs(gsc->mdev.gsc_vd_entity->fd, &reqbuf) < 0) { + ALOGE("%s::request buffers failed", __func__); + return -1; + } + + exynos_gsc_destroy(gsc); + Exynos_gsc_Out(); + + return 0; +} diff --git a/libgscaler/libgscaler_obj.cpp b/libgscaler/libgscaler_obj.cpp new file mode 100755 index 0000000..58b88e0 --- /dev/null +++ b/libgscaler/libgscaler_obj.cpp @@ -0,0 +1,2074 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * Copyright@ Samsung Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*! + * \file libgscaler_obj.cpp + * \brief source file for Gscaler HAL + * \author Sungchun Kang (sungchun.kang@samsung.com) + * \date 2013/06/01 + * + * <b>Revision History: </b> + * - 2013.06.01 : Sungchun Kang (sungchun.kang@samsung.com) \n + * Create + */ + +#include <cerrno> +#include "libgscaler_obj.h" +#include <system/graphics.h> +#include <content_protect.h> + +int CGscaler::m_gsc_output_create(void *handle, int dev_num, int out_mode) +{ + Exynos_gsc_In(); + + struct media_device *media0; + struct media_entity *gsc_sd_entity; + struct media_entity *gsc_vd_entity; + struct media_entity *sink_sd_entity; + char node[32]; + char devname[32]; + unsigned int cap; + int i; + int fd = 0; + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + if ((out_mode != GSC_OUT_FIMD) && + (out_mode != GSC_OUT_TV)) + return -1; + + gsc->out_mode = out_mode; + /* GSCX => FIMD_WINX : arbitrary linking is not allowed */ + if ((out_mode == GSC_OUT_FIMD) && +#ifndef USES_ONLY_GSC0_GSC1 + (dev_num > 2)) +#else + (dev_num > 1)) +#endif + return -1; + + /* media0 */ + snprintf(node, sizeof(node), "%s%d", PFX_NODE_MEDIADEV, 0); + media0 = exynos_media_open(node); + if (media0 == NULL) { + ALOGE("%s::exynos_media_open failed (node=%s)", __func__, node); + return false; + } + gsc->mdev.media0 = media0; + + /* Get the sink subdev entity by name and make the node of sink subdev*/ + if (out_mode == GSC_OUT_FIMD) + snprintf(devname, sizeof(devname), PFX_FIMD_ENTITY, dev_num); + else + snprintf(devname, sizeof(devname), PFX_MXR_ENTITY, 0); + + sink_sd_entity = exynos_media_get_entity_by_name(media0, devname, + strlen(devname)); + if (!sink_sd_entity) { + ALOGE("%s:: failed to get the sink sd entity", __func__); + goto gsc_output_err; + } + gsc->mdev.sink_sd_entity = sink_sd_entity; + + sink_sd_entity->fd = exynos_subdev_open_devname(devname, O_RDWR); + if (sink_sd_entity->fd < 0) { + ALOGE("%s:: failed to open sink subdev node", __func__); + goto gsc_output_err; + } + + /* get GSC video dev & sub dev entity by name*/ +#if defined(USES_DT) + switch (dev_num) { + case 0: + snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY0); + break; + case 1: + snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY1); + break; + case 2: + snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY2); + break; + } +#else + snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY, dev_num); +#endif + gsc_vd_entity = exynos_media_get_entity_by_name(media0, devname, + strlen(devname)); + if (!gsc_vd_entity) { + ALOGE("%s:: failed to get the gsc vd entity", __func__); + goto gsc_output_err; + } + gsc->mdev.gsc_vd_entity = gsc_vd_entity; + + snprintf(devname, sizeof(devname), PFX_GSC_SUBDEV_ENTITY, dev_num); + gsc_sd_entity = exynos_media_get_entity_by_name(media0, devname, + strlen(devname)); + if (!gsc_sd_entity) { + ALOGE("%s:: failed to get the gsc sd entity", __func__); + goto gsc_output_err; + } + gsc->mdev.gsc_sd_entity = gsc_sd_entity; + + /* gsc sub-dev open */ + snprintf(devname, sizeof(devname), PFX_GSC_SUBDEV_ENTITY, dev_num); + gsc_sd_entity->fd = exynos_subdev_open_devname(devname, O_RDWR); + if (gsc_sd_entity->fd < 0) { + ALOGE("%s: gsc sub-dev open fail", __func__); + goto gsc_output_err; + } + + /* gsc video-dev open */ +#if defined(USES_DT) + switch (dev_num) { + case 0: + snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY0); + break; + case 1: + snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY1); + break; + case 2: + snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY2); + break; + } +#else + snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY, dev_num); +#endif + gsc_vd_entity->fd = exynos_v4l2_open_devname(devname, O_RDWR | O_NONBLOCK); + if (gsc_vd_entity->fd < 0) { + ALOGE("%s: gsc video-dev open fail", __func__); + goto gsc_output_err; + } + + cap = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT_MPLANE; + + if (exynos_v4l2_querycap(gsc_vd_entity->fd, cap) == false) { + ALOGE("%s::exynos_v4l2_querycap() fail", __func__); + goto gsc_output_err; + } + + Exynos_gsc_Out(); + + return 0; + +gsc_output_err: + gsc->m_gsc_out_destroy(handle); + + return -1; +} + +int CGscaler::m_gsc_capture_create(void *handle, int dev_num, int out_mode) +{ + Exynos_gsc_In(); + + struct media_device *media1; + struct media_entity *gsc_sd_entity; + struct media_entity *gsc_vd_entity; + struct media_entity *sink_sd_entity; + struct media_link *links; + char node[32]; + char devname[32]; + unsigned int cap; + int i; + int fd = 0; + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + gsc->out_mode = out_mode; + + if (dev_num != 2) + return -1; + + /* media1 */ + snprintf(node, sizeof(node), "%s%d", PFX_NODE_MEDIADEV, 1); + media1 = exynos_media_open(node); + if (media1 == NULL) { + ALOGE("%s::exynos_media_open failed (node=%s)", __func__, node); + return false; + } + gsc->mdev.media1 = media1; + + /* DECON-TV sub-device Open */ + snprintf(devname, sizeof(devname), DEX_WB_SD_NAME); + + sink_sd_entity = exynos_media_get_entity_by_name(media1, devname, + strlen(devname)); + if (!sink_sd_entity) { + ALOGE("%s:: failed to get the sink sd entity", __func__); + goto gsc_cap_err; + } + gsc->mdev.sink_sd_entity = sink_sd_entity; + + sink_sd_entity->fd = exynos_subdev_open_devname(devname, O_RDWR); + if (sink_sd_entity->fd < 0) { + ALOGE("%s:: failed to open sink subdev node", __func__); + goto gsc_cap_err; + } + + /* Gscaler2 capture video-device Open */ + snprintf(devname, sizeof(devname), PFX_GSC_CAPTURE_ENTITY); + gsc_vd_entity = exynos_media_get_entity_by_name(media1, devname, + strlen(devname)); + if (!gsc_vd_entity) { + ALOGE("%s:: failed to get the gsc vd entity", __func__); + goto gsc_cap_err; + } + gsc->mdev.gsc_vd_entity = gsc_vd_entity; + + gsc_vd_entity->fd = exynos_v4l2_open_devname(devname, O_RDWR); + if (gsc_vd_entity->fd < 0) { + ALOGE("%s: gsc video-dev open fail", __func__); + goto gsc_cap_err; + } + + /* Gscaler2 capture sub-device Open */ + snprintf(devname, sizeof(devname), GSC_WB_SD_NAME); + gsc_sd_entity = exynos_media_get_entity_by_name(media1, devname, + strlen(devname)); + if (!gsc_sd_entity) { + ALOGE("%s:: failed to get the gsc sd entity", __func__); + goto gsc_cap_err; + } + gsc->mdev.gsc_sd_entity = gsc_sd_entity; + + gsc_sd_entity->fd = exynos_subdev_open_devname(devname, O_RDWR); + if (gsc_sd_entity->fd < 0) { + ALOGE("%s: gsc sub-dev open fail", __func__); + goto gsc_cap_err; + } + + if (exynos_media_setup_link(media1, sink_sd_entity->pads, + gsc_sd_entity->pads, MEDIA_LNK_FL_ENABLED) < 0) { + ALOGE("%s::exynos_media_setup_link failed", __func__); + goto gsc_cap_err; + } + + cap = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE; + + if (exynos_v4l2_querycap(gsc_vd_entity->fd, cap) == false) { + ALOGE("%s::exynos_v4l2_querycap() fail", __func__); + goto gsc_cap_err; + } + + Exynos_gsc_Out(); + + return 0; + +gsc_cap_err: + gsc->m_gsc_cap_destroy(handle); + + return -1; +} + +int CGscaler::m_gsc_out_stop(void *handle) +{ + Exynos_gsc_In(); + + struct v4l2_requestbuffers reqbuf; + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + if (gsc->src_info.stream_on == false) { + /* to handle special scenario.*/ + gsc->src_info.qbuf_cnt = 0; + ALOGD("%s::GSC is already stopped", __func__); + goto SKIP_STREAMOFF; + } + gsc->src_info.qbuf_cnt = 0; + gsc->src_info.stream_on = false; + + if (exynos_v4l2_streamoff(gsc->mdev.gsc_vd_entity->fd, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) < 0) { + ALOGE("%s::stream off failed", __func__); + return -1; + } + +SKIP_STREAMOFF: + Exynos_gsc_Out(); + + return 0; +} + +int CGscaler::m_gsc_cap_stop(void *handle) +{ + Exynos_gsc_In(); + + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + if (gsc->dst_info.stream_on == false) { + /* to handle special scenario.*/ + gsc->dst_info.qbuf_cnt = 0; + ALOGD("%s::GSC is already stopped", __func__); + goto SKIP_STREAMOFF; + } + gsc->dst_info.qbuf_cnt = 0; + gsc->dst_info.stream_on = false; + + if (exynos_v4l2_streamoff(gsc->mdev.gsc_vd_entity->fd, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) < 0) { + ALOGE("%s::stream off failed", __func__); + return -1; + } + +SKIP_STREAMOFF: + Exynos_gsc_Out(); + + return 0; +} + +bool CGscaler::m_gsc_out_destroy(void *handle) +{ + Exynos_gsc_In(); + + int i; + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return false; + } + + if (gsc->src_info.stream_on == true) { + if (gsc->m_gsc_out_stop(gsc) < 0) + ALOGE("%s::m_gsc_out_stop() fail", __func__); + + gsc->src_info.stream_on = false; + } + + if (gsc->mdev.gsc_vd_entity && gsc->mdev.gsc_vd_entity->fd > 0) { + close(gsc->mdev.gsc_vd_entity->fd); + gsc->mdev.gsc_vd_entity->fd = -1; + } + + if (gsc->mdev.gsc_sd_entity && gsc->mdev.gsc_sd_entity->fd > 0) { + close(gsc->mdev.gsc_sd_entity->fd); + gsc->mdev.gsc_sd_entity->fd = -1; + } + + if (gsc->mdev.sink_sd_entity && gsc->mdev.sink_sd_entity->fd > 0) { + close(gsc->mdev.sink_sd_entity->fd); + gsc->mdev.sink_sd_entity->fd = -1; + } + + if (gsc->mdev.media0) + exynos_media_close(gsc->mdev.media0); + + gsc->mdev.media0 = NULL; + gsc->mdev.gsc_sd_entity = NULL; + gsc->mdev.gsc_vd_entity = NULL; + gsc->mdev.sink_sd_entity = NULL; + + Exynos_gsc_Out(); + return true; +} + +bool CGscaler::m_gsc_cap_destroy(void *handle) +{ + Exynos_gsc_In(); + + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return false; + } + + if (gsc->dst_info.stream_on == true) { + if (gsc->m_gsc_cap_stop(gsc) < 0) + ALOGE("%s::m_gsc_cap_stop() fail", __func__); + + gsc->dst_info.stream_on = false; + } + + if (!gsc->mdev.media1 || !gsc->mdev.gsc_sd_entity || + !gsc->mdev.gsc_vd_entity || !gsc->mdev.sink_sd_entity) { + ALOGE("%s::gsc->mdev information is null", __func__); + return false; + } + + if (exynos_media_setup_link(gsc->mdev.media1, + gsc->mdev.sink_sd_entity->pads, + gsc->mdev.gsc_sd_entity->pads, 0) < 0) { + ALOGE("%s::exynos_media_setup_unlin failed", __func__); + } + + if (gsc->mdev.gsc_vd_entity && gsc->mdev.gsc_vd_entity->fd > 0) { + close(gsc->mdev.gsc_vd_entity->fd); + gsc->mdev.gsc_vd_entity->fd = -1; + } + + if (gsc->mdev.gsc_sd_entity && gsc->mdev.gsc_sd_entity->fd > 0) { + close(gsc->mdev.gsc_sd_entity->fd); + gsc->mdev.gsc_sd_entity->fd = -1; + } + + if (gsc->mdev.sink_sd_entity && gsc->mdev.sink_sd_entity->fd > 0) { + close(gsc->mdev.sink_sd_entity->fd); + gsc->mdev.sink_sd_entity->fd = -1; + } + + if (gsc->mdev.media1) + exynos_media_close(gsc->mdev.media1); + + gsc->mdev.media1 = NULL; + gsc->mdev.gsc_sd_entity = NULL; + gsc->mdev.gsc_vd_entity = NULL; + gsc->mdev.sink_sd_entity = NULL; + + Exynos_gsc_Out(); + return true; +} + +int CGscaler::m_gsc_m2m_create(int dev) +{ + Exynos_gsc_In(); + + int fd = 0; + int video_node_num; + unsigned int cap; + char node[32]; + + switch(dev) { + case 0: + video_node_num = NODE_NUM_GSC_0; + break; + case 1: + video_node_num = NODE_NUM_GSC_1; + break; +#ifndef USES_ONLY_GSC0_GSC1 + case 2: + video_node_num = NODE_NUM_GSC_2; + break; + case 3: + video_node_num = NODE_NUM_GSC_3; + break; +#endif + default: + ALOGE("%s::unexpected dev(%d) fail", __func__, dev); + return -1; + break; + } + + snprintf(node, sizeof(node), "%s%d", PFX_NODE_GSC, video_node_num); + fd = exynos_v4l2_open(node, O_RDWR); + if (fd < 0) { + ALOGE("%s::exynos_v4l2_open(%s) fail", __func__, node); + return -1; + } + + cap = V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_CAPTURE_MPLANE; + + if (exynos_v4l2_querycap(fd, cap) == false) { + ALOGE("%s::exynos_v4l2_querycap() fail", __func__); + close(fd); + fd = 0; + return -1; + } + + Exynos_gsc_Out(); + + return fd; +} + +bool CGscaler::m_gsc_find_and_create(void *handle) +{ + Exynos_gsc_In(); + + int i = 0; + bool flag_find_new_gsc = false; + unsigned int total_sleep_time = 0; + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return false; + } + + do { + for (i = 0; i < NUM_OF_GSC_HW; i++) { +#ifndef USES_ONLY_GSC0_GSC1 + if (i == 0 || i == 3) +#else + if (i == 0) +#endif + continue; + + gsc->gsc_id = i; + gsc->gsc_fd = gsc->m_gsc_m2m_create(i); + if (gsc->gsc_fd < 0) { + gsc->gsc_fd = 0; + continue; + } + + flag_find_new_gsc = true; + break; + } + + if (flag_find_new_gsc == false) { + usleep(GSC_WAITING_TIME_FOR_TRYLOCK); + total_sleep_time += GSC_WAITING_TIME_FOR_TRYLOCK; + ALOGV("%s::waiting for the gscaler availability", __func__); + } + + } while(flag_find_new_gsc == false + && total_sleep_time < MAX_GSC_WAITING_TIME_FOR_TRYLOCK); + + if (flag_find_new_gsc == false) + ALOGE("%s::we don't have any available gsc.. fail", __func__); + + Exynos_gsc_Out(); + + return flag_find_new_gsc; +} + +bool CGscaler::m_gsc_m2m_destroy(void *handle) +{ + Exynos_gsc_In(); + + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return false; + } + + /* + * just in case, we call stop here because we cannot afford to leave + * secure side protection on if things failed. + */ + gsc->m_gsc_m2m_stop(handle); + + if (gsc->gsc_id >= HW_SCAL0) { + bool ret = exynos_sc_free_and_close(gsc->scaler); + Exynos_gsc_Out(); + return ret; + } + + if (0 < gsc->gsc_fd) + close(gsc->gsc_fd); + gsc->gsc_fd = 0; + + Exynos_gsc_Out(); + + return true; +} + +int CGscaler::m_gsc_m2m_stop(void *handle) +{ + Exynos_gsc_In(); + + struct v4l2_requestbuffers req_buf; + int ret = 0; + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + if (!gsc->src_info.stream_on && !gsc->dst_info.stream_on) { + /* wasn't streaming, return success */ + return 0; + } else if (gsc->src_info.stream_on != gsc->dst_info.stream_on) { + ALOGE("%s: invalid state, queue stream state doesn't match \ + (%d != %d)", __func__, gsc->src_info.stream_on, + gsc->dst_info.stream_on); + ret = -1; + } + + /* + * we need to plow forward on errors below to make sure that if we had + * turned on content protection on secure side, we turn it off. + * + * also, if we only failed to turn on one of the streams, we'll turn + * the other one off correctly. + */ + if (gsc->src_info.stream_on == true) { + if (exynos_v4l2_streamoff(gsc->gsc_fd, + gsc->src_info.buf.buf_type) < 0) { + ALOGE("%s::exynos_v4l2_streamoff(src) fail", __func__); + ret = -1; + } + gsc->src_info.stream_on = false; + } + + if (gsc->dst_info.stream_on == true) { + if (exynos_v4l2_streamoff(gsc->gsc_fd, + gsc->dst_info.buf.buf_type) < 0) { + ALOGE("%s::exynos_v4l2_streamoff(dst) fail", __func__); + ret = -1; + } + gsc->dst_info.stream_on = false; + } + + /* if drm is enabled */ + if (gsc->allow_drm && gsc->protection_enabled) { + unsigned int protect_id = 0; + + if (gsc->gsc_id == 0) + protect_id = CP_PROTECT_GSC0; + else if (gsc->gsc_id == 1) + protect_id = CP_PROTECT_GSC1; + else if (gsc->gsc_id == 2) + protect_id = CP_PROTECT_GSC2; + else if (gsc->gsc_id == 3) + protect_id = CP_PROTECT_GSC3; + + /* CP_Disable_Path_Protection(protect_id); */ + gsc->protection_enabled = false; + } + + if (exynos_v4l2_s_ctrl(gsc->gsc_fd, + V4L2_CID_CONTENT_PROTECTION, 0) < 0) { + ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CONTENT_PROTECTION) fail", + __func__); + ret = -1; + } + + /* src: clear_buf */ + req_buf.count = 0; + req_buf.type = gsc->src_info.buf.buf_type; + req_buf.memory = gsc->src_info.buf.mem_type; + if (exynos_v4l2_reqbufs(gsc->gsc_fd, &req_buf) < 0) { + ALOGE("%s::exynos_v4l2_reqbufs():src: fail", __func__); + ret = -1; + } + + /* dst: clear_buf */ + req_buf.count = 0; + req_buf.type = gsc->dst_info.buf.buf_type; + req_buf.memory = gsc->dst_info.buf.mem_type;; + if (exynos_v4l2_reqbufs(gsc->gsc_fd, &req_buf) < 0) { + ALOGE("%s::exynos_v4l2_reqbufs():dst: fail", __func__); + ret = -1; + } + + Exynos_gsc_Out(); + + return ret; +} + +int CGscaler::m_gsc_m2m_run_core(void *handle) +{ + Exynos_gsc_In(); + + unsigned int rotate, hflip, vflip; + bool is_dirty; + bool is_drm; + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + is_dirty = gsc->src_info.dirty || gsc->dst_info.dirty; + is_drm = gsc->src_info.mode_drm; + + if (is_dirty && (gsc->src_info.mode_drm != gsc->dst_info.mode_drm)) { + ALOGE("%s: drm mode mismatch between src and dst, \ + gsc%d (s=%d d=%d)", __func__, gsc->gsc_id, + gsc->src_info.mode_drm, gsc->dst_info.mode_drm); + return -1; + } else if (is_drm && !gsc->allow_drm) { + ALOGE("%s: drm mode is not supported on gsc%d", __func__, + gsc->gsc_id); + return -1; + } + + CGscaler::rotateValueHAL2GSC(gsc->dst_img.rot, &rotate, &hflip, &vflip); + + if (CGscaler::m_gsc_check_src_size(&gsc->src_info.width, + &gsc->src_info.height, &gsc->src_info.crop_left, + &gsc->src_info.crop_top, &gsc->src_info.crop_width, + &gsc->src_info.crop_height, gsc->src_info.v4l2_colorformat, + (rotate == 90 || rotate == 270)) == false) { + ALOGE("%s::m_gsc_check_src_size() fail", __func__); + return -1; + } + + if (CGscaler::m_gsc_check_dst_size(&gsc->dst_info.width, + &gsc->dst_info.height, &gsc->dst_info.crop_left, + &gsc->dst_info.crop_top, &gsc->dst_info.crop_width, + &gsc->dst_info.crop_height, gsc->dst_info.v4l2_colorformat, + gsc->dst_info.rotation) == false) { + ALOGE("%s::m_gsc_check_dst_size() fail", __func__); + return -1; + } + + /* dequeue buffers from previous work if necessary */ + if (gsc->src_info.stream_on == true) { + if (gsc->m_gsc_m2m_wait_frame_done(handle) < 0) { + ALOGE("%s::exynos_gsc_m2m_wait_frame_done fail", __func__); + return -1; + } + } + + /* + * need to set the content protection flag before doing reqbufs + * in set_format + */ + if (is_dirty && gsc->allow_drm && is_drm) { + if (exynos_v4l2_s_ctrl(gsc->gsc_fd, + V4L2_CID_CONTENT_PROTECTION, is_drm) < 0) { + ALOGE("%s::exynos_v4l2_s_ctrl() fail", __func__); + return -1; + } + } + + /* + * from this point on, we have to ensure to call stop to clean up + * whatever state we have set. + */ + + if (gsc->src_info.dirty) { + if (CGscaler::m_gsc_set_format(gsc->gsc_fd, &gsc->src_info) == false) { + ALOGE("%s::m_gsc_set_format(src) fail", __func__); + goto done; + } + gsc->src_info.dirty = false; + } + + if (gsc->dst_info.dirty) { + if (CGscaler::m_gsc_set_format(gsc->gsc_fd, &gsc->dst_info) == false) { + ALOGE("%s::m_gsc_set_format(dst) fail", __func__); + goto done; + } + gsc->dst_info.dirty = false; + } + + /* + * set up csc equation property + */ + if (is_dirty) { + if (exynos_v4l2_s_ctrl(gsc->gsc_fd, + V4L2_CID_CSC_EQ_MODE, gsc->eq_auto) < 0) { + ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CSC_EQ_MODE) fail", __func__); + return -1; + } + + if (exynos_v4l2_s_ctrl(gsc->gsc_fd, + V4L2_CID_CSC_EQ, gsc->v4l2_colorspace) < 0) { + ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CSC_EQ) fail", __func__); + return -1; + } + + if (exynos_v4l2_s_ctrl(gsc->gsc_fd, + V4L2_CID_CSC_RANGE, gsc->range_full) < 0) { + ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CSC_RANGE) fail", __func__); + return -1; + } + } + + /* if we are enabling drm, make sure to enable hw protection. + * Need to do this before queuing buffers so that the mmu is reserved + * and power domain is kept on. + */ + if (is_dirty && gsc->allow_drm && is_drm) { + unsigned int protect_id = 0; + + if (gsc->gsc_id == 0) { + protect_id = CP_PROTECT_GSC0; + } else if (gsc->gsc_id == 1) { + protect_id = CP_PROTECT_GSC1; + } else if (gsc->gsc_id == 2) { + protect_id = CP_PROTECT_GSC2; + } else if (gsc->gsc_id == 3) { + protect_id = CP_PROTECT_GSC3; + } else { + ALOGE("%s::invalid gscaler id %d for content protection", + __func__, gsc->gsc_id); + goto done; + } + + /* if (CP_Enable_Path_Protection(protect_id) != 0) { + ALOGE("%s::CP_Enable_Path_Protection failed", __func__); + goto done; + } */ + gsc->protection_enabled = true; + } + + if (gsc->m_gsc_set_addr(gsc->gsc_fd, &gsc->src_info) == false) { + ALOGE("%s::m_gsc_set_addr(src) fail", __func__); + goto done; + } + + if (gsc->m_gsc_set_addr(gsc->gsc_fd, &gsc->dst_info) == false) { + ALOGE("%s::m_gsc_set_addr(dst) fail", __func__); + goto done; + } + + if (gsc->src_info.stream_on == false) { + if (exynos_v4l2_streamon(gsc->gsc_fd, gsc->src_info.buf.buf_type) < 0) { + ALOGE("%s::exynos_v4l2_streamon(src) fail", __func__); + goto done; + } + gsc->src_info.stream_on = true; + } + + if (gsc->dst_info.stream_on == false) { + if (exynos_v4l2_streamon(gsc->gsc_fd, gsc->dst_info.buf.buf_type) < 0) { + ALOGE("%s::exynos_v4l2_streamon(dst) fail", __func__); + goto done; + } + gsc->dst_info.stream_on = true; + } + + Exynos_gsc_Out(); + + return 0; + +done: + gsc->m_gsc_m2m_stop(handle); + return -1; +} + +bool CGscaler::m_gsc_check_src_size( + unsigned int *w, unsigned int *h, + unsigned int *crop_x, unsigned int *crop_y, + unsigned int *crop_w, unsigned int *crop_h, + int v4l2_colorformat, bool rotation) +{ + unsigned int minWidth, minHeight, shift = 0; + if (v4l2_colorformat == V4L2_PIX_FMT_RGB32 || v4l2_colorformat == V4L2_PIX_FMT_RGB565) + shift = 1; + if (rotation) { + minWidth = GSC_MIN_SRC_H_SIZE >> shift; + minHeight = GSC_MIN_SRC_W_SIZE >> shift; + } else { + minWidth = GSC_MIN_SRC_W_SIZE >> shift; + minHeight = GSC_MIN_SRC_H_SIZE >> shift; + } + + if (*w < minWidth || *h < minHeight) { + ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)", + __func__, GSC_MIN_SRC_W_SIZE, *w, GSC_MIN_SRC_H_SIZE, *h); + return false; + } + + if (*crop_w < minWidth || *crop_h < minHeight) { + ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)", + __func__, GSC_MIN_SRC_W_SIZE,* crop_w, GSC_MIN_SRC_H_SIZE, *crop_h); + return false; + } + + return true; +} + +bool CGscaler::m_gsc_check_dst_size( + unsigned int *w, unsigned int *h, + unsigned int *crop_x, unsigned int *crop_y, + unsigned int *crop_w, unsigned int *crop_h, + int v4l2_colorformat, + int rotation) +{ + if (*w < GSC_MIN_DST_W_SIZE || *h < GSC_MIN_DST_H_SIZE) { + ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)", + __func__, GSC_MIN_DST_W_SIZE, *w, GSC_MIN_DST_H_SIZE, *h); + return false; + } + + if (*crop_w < GSC_MIN_DST_W_SIZE || *crop_h < GSC_MIN_DST_H_SIZE) { + ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)", + __func__, GSC_MIN_DST_W_SIZE,* crop_w, GSC_MIN_DST_H_SIZE, *crop_h); + return false; + } + + return true; +} + + +int CGscaler::m_gsc_multiple_of_n(int number, int N) +{ + int result = number; + switch (N) { + case 1: + case 2: + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + case 256: + result = (number - (number & (N-1))); + break; + default: + result = number - (number % N); + break; + } + return result; +} + +int CGscaler::m_gsc_m2m_wait_frame_done(void *handle) +{ + Exynos_gsc_In(); + + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + if ((gsc->src_info.stream_on == false) || + (gsc->dst_info.stream_on == false)) { + ALOGE("%s:: src_strean_on or dst_stream_on are false", __func__); + return -1; + } + + if (gsc->src_info.buf.buffer_queued) { + if (exynos_v4l2_dqbuf(gsc->gsc_fd, &gsc->src_info.buf.buffer) < 0) { + ALOGE("%s::exynos_v4l2_dqbuf(src) fail", __func__); + return -1; + } + gsc->src_info.buf.buffer_queued = false; + } + + if (gsc->dst_info.buf.buffer_queued) { + if (exynos_v4l2_dqbuf(gsc->gsc_fd, &gsc->dst_info.buf.buffer) < 0) { + ALOGE("%s::exynos_v4l2_dqbuf(dst) fail", __func__); + return -1; + } + gsc->dst_info.buf.buffer_queued = false; + } + + Exynos_gsc_Out(); + + return 0; +} + +bool CGscaler::m_gsc_set_format(int fd, GscInfo *info) +{ + Exynos_gsc_In(); + + struct v4l2_requestbuffers req_buf; + int plane_count; + + plane_count = m_gsc_get_plane_count(info->v4l2_colorformat); + if (plane_count < 0) { + ALOGE("%s::not supported v4l2_colorformat", __func__); + return false; + } + + if (exynos_v4l2_s_ctrl(fd, V4L2_CID_ROTATE, info->rotation) < 0) { + ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_ROTATE) fail", __func__); + return false; + } + + if (exynos_v4l2_s_ctrl(fd, V4L2_CID_VFLIP, info->flip_horizontal) < 0) { + ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_VFLIP) fail", __func__); + return false; + } + + if (exynos_v4l2_s_ctrl(fd, V4L2_CID_HFLIP, info->flip_vertical) < 0) { + ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_HFLIP) fail", __func__); + return false; + } + + info->format.type = info->buf.buf_type; + info->format.fmt.pix_mp.width = info->width; + info->format.fmt.pix_mp.height = info->height; + info->format.fmt.pix_mp.pixelformat = info->v4l2_colorformat; + info->format.fmt.pix_mp.field = V4L2_FIELD_ANY; + info->format.fmt.pix_mp.num_planes = plane_count; + + if (exynos_v4l2_s_fmt(fd, &info->format) < 0) { + ALOGE("%s::exynos_v4l2_s_fmt() fail", __func__); + return false; + } + + info->crop.type = info->buf.buf_type; + info->crop.c.left = info->crop_left; + info->crop.c.top = info->crop_top; + info->crop.c.width = info->crop_width; + info->crop.c.height = info->crop_height; + + if (exynos_v4l2_s_crop(fd, &info->crop) < 0) { + ALOGE("%s::exynos_v4l2_s_crop() fail", __func__); + return false; + } + + if (exynos_v4l2_s_ctrl(fd, V4L2_CID_CACHEABLE, info->cacheable) < 0) { + ALOGE("%s::exynos_v4l2_s_ctrl() fail", __func__); + return false; + } + + req_buf.count = 1; + req_buf.type = info->buf.buf_type; + req_buf.memory = info->buf.mem_type; + if (exynos_v4l2_reqbufs(fd, &req_buf) < 0) { + ALOGE("%s::exynos_v4l2_reqbufs() fail", __func__); + return false; + } + + Exynos_gsc_Out(); + + return true; +} + +unsigned int CGscaler::m_gsc_get_plane_count(int v4l_pixel_format) +{ + int plane_count = 0; + + switch (v4l_pixel_format) { + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_RGB444: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_YUV422P: + plane_count = 1; + break; + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV12MT_16X16: + case V4L2_PIX_FMT_NV21M: + plane_count = 2; + break; + case V4L2_PIX_FMT_YVU420M: + case V4L2_PIX_FMT_YUV420M: + plane_count = 3; + break; + default: + ALOGE("%s::unmatched v4l_pixel_format color_space(0x%x)\n", + __func__, v4l_pixel_format); + plane_count = -1; + break; + } + + return plane_count; +} + +bool CGscaler::m_gsc_set_addr(int fd, GscInfo *info) +{ + unsigned int i; + unsigned int plane_size[NUM_OF_GSC_PLANES]; + + CGscaler::m_gsc_get_plane_size(plane_size, info->width, + info->height, info->v4l2_colorformat); + + info->buf.buffer.index = 0; + info->buf.buffer.flags = V4L2_BUF_FLAG_USE_SYNC; + info->buf.buffer.type = info->buf.buf_type; + info->buf.buffer.memory = info->buf.mem_type; + info->buf.buffer.m.planes = info->buf.planes; + info->buf.buffer.length = info->format.fmt.pix_mp.num_planes; + info->buf.buffer.reserved = info->acquireFenceFd; + + for (i = 0; i < info->format.fmt.pix_mp.num_planes; i++) { + if (info->buf.buffer.memory == V4L2_MEMORY_DMABUF) + info->buf.buffer.m.planes[i].m.fd = (long)info->buf.addr[i]; + else + info->buf.buffer.m.planes[i].m.userptr = + (unsigned long)info->buf.addr[i]; + info->buf.buffer.m.planes[i].length = plane_size[i]; + info->buf.buffer.m.planes[i].bytesused = 0; + } + + if (exynos_v4l2_qbuf(fd, &info->buf.buffer) < 0) { + ALOGE("%s::exynos_v4l2_qbuf() fail", __func__); + return false; + } + info->buf.buffer_queued = true; + + info->releaseFenceFd = info->buf.buffer.reserved; + + return true; +} + +unsigned int CGscaler::m_gsc_get_plane_size( + unsigned int *plane_size, + unsigned int width, + unsigned int height, + int v4l_pixel_format) +{ + switch (v4l_pixel_format) { + /* 1 plane */ + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_BGR32: + plane_size[0] = width * height * 4; + plane_size[1] = 0; + plane_size[2] = 0; + break; + case V4L2_PIX_FMT_RGB24: + plane_size[0] = width * height * 3; + plane_size[1] = 0; + plane_size[2] = 0; + break; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_RGB444: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + plane_size[0] = width * height * 2; + plane_size[1] = 0; + plane_size[2] = 0; + break; + /* 2 planes */ + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV21M: + plane_size[0] = width * height; + plane_size[1] = width * (height / 2); + plane_size[2] = 0; + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + plane_size[0] = width * height * 3 / 2; + plane_size[1] = 0; + plane_size[2] = 0; + break; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_YUV422P: + plane_size[0] = width * height * 2; + plane_size[1] = 0; + plane_size[2] = 0; + break; + case V4L2_PIX_FMT_NV12MT_16X16: + plane_size[0] = ALIGN(width, 16) * ALIGN(height, 16); + plane_size[1] = ALIGN(width, 16) * ALIGN(height / 2, 8); + plane_size[2] = 0; + break; + /* 3 planes */ + case V4L2_PIX_FMT_YUV420M: + plane_size[0] = width * height; + plane_size[1] = (width / 2) * (height / 2); + plane_size[2] = (width / 2) * (height / 2); + break; + case V4L2_PIX_FMT_YVU420: + plane_size[0] = ALIGN(width, 16) * height + ALIGN(width / 2, 16) * height; + plane_size[1] = 0; + plane_size[2] = 0; + break; + case V4L2_PIX_FMT_YUV420: + plane_size[0] = width * height * 3 / 2; + plane_size[1] = 0; + plane_size[2] = 0; + break; + case V4L2_PIX_FMT_YVU420M: + plane_size[0] = ALIGN(width, 16) * height; + plane_size[1] = ALIGN(width / 2, 16) * (height / 2); + plane_size[2] = plane_size[1]; + break; + default: + ALOGE("%s::unmatched v4l_pixel_format color_space(0x%x)\n", + __func__, v4l_pixel_format); + return -1; + } + + return 0; +} + +int CGscaler::m_gsc_m2m_config(void *handle, + exynos_mpp_img *src_img, exynos_mpp_img *dst_img) +{ + Exynos_gsc_In(); + + int32_t src_color_space; + int32_t dst_color_space; + int ret; + unsigned int rotate; + unsigned int hflip; + unsigned int vflip; + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + if ((src_img->drmMode && !gsc->allow_drm) || + (src_img->drmMode != dst_img->drmMode)) { + ALOGE("%s::invalid drm state request for gsc%d (s=%d d=%d)", + __func__, gsc->gsc_id, src_img->drmMode, dst_img->drmMode); + return -1; + } + + src_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(src_img->format); + dst_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(dst_img->format); + CGscaler::rotateValueHAL2GSC(dst_img->rot, &rotate, &hflip, &vflip); + exynos_gsc_set_rotation(gsc, rotate, hflip, vflip); + + ret = exynos_gsc_set_src_format(gsc, src_img->fw, src_img->fh, + src_img->x, src_img->y, src_img->w, src_img->h, + src_color_space, src_img->cacheable, src_img->drmMode); + if (ret < 0) { + ALOGE("%s: fail: exynos_gsc_set_src_format \ + [fw %d fh %d x %d y %d w %d h %d f %x rot %d]", + __func__, src_img->fw, src_img->fh, src_img->x, src_img->y, + src_img->w, src_img->h, src_color_space, src_img->rot); + return -1; + } + + ret = exynos_gsc_set_dst_format(gsc, dst_img->fw, dst_img->fh, + dst_img->x, dst_img->y, dst_img->w, dst_img->h, + dst_color_space, dst_img->cacheable, dst_img->drmMode); + if (ret < 0) { + ALOGE("%s: fail: exynos_gsc_set_dst_format \ + [fw %d fh %d x %d y %d w %d h %d f %x rot %d]", + __func__, dst_img->fw, dst_img->fh, dst_img->x, dst_img->y, + dst_img->w, dst_img->h, src_color_space, dst_img->rot); + return -1; + } + + Exynos_gsc_Out(); + + return 0; +} + +int CGscaler::m_gsc_out_config(void *handle, + exynos_mpp_img *src_img, exynos_mpp_img *dst_img) +{ + Exynos_gsc_In(); + + struct v4l2_format fmt; + struct v4l2_crop crop; + struct v4l2_requestbuffers reqbuf; + struct v4l2_subdev_format sd_fmt; + struct v4l2_subdev_crop sd_crop; + int i; + unsigned int rotate; + unsigned int hflip; + unsigned int vflip; + unsigned int plane_size[NUM_OF_GSC_PLANES]; + bool rgb; + + struct v4l2_rect dst_rect; + int32_t src_color_space; + int32_t dst_color_space; + int32_t src_planes; + + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + if (gsc->src_info.stream_on != false) { + ALOGE("Error: Src is already streamed on !!!!"); + return -1; + } + + memcpy(&gsc->src_img, src_img, sizeof(exynos_mpp_img)); + memcpy(&gsc->dst_img, dst_img, sizeof(exynos_mpp_img)); + src_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(src_img->format); + dst_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(dst_img->format); + src_planes = m_gsc_get_plane_count(src_color_space); + src_planes = (src_planes == -1) ? 1 : src_planes; + rgb = get_yuv_planes(dst_color_space) == -1; + CGscaler::rotateValueHAL2GSC(dst_img->rot, &rotate, &hflip, &vflip); + + if (CGscaler::m_gsc_check_src_size(&gsc->src_img.fw, + &gsc->src_img.fh, &gsc->src_img.x, &gsc->src_img.y, + &gsc->src_img.w, &gsc->src_img.h, src_color_space, + (rotate == 90 || rotate == 270)) == false) { + ALOGE("%s::m_gsc_check_src_size() fail", __func__); + return -1; + } + + /*set: src v4l2_buffer*/ + gsc->src_info.buf.buf_idx = 0; + gsc->src_info.qbuf_cnt = 0; + /* set format: src pad of GSC sub-dev*/ + sd_fmt.pad = GSCALER_SUBDEV_PAD_SOURCE; + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + if (gsc->out_mode == GSC_OUT_FIMD) { + sd_fmt.format.width = gsc->dst_img.fw; + sd_fmt.format.height = gsc->dst_img.fh; + } else { + sd_fmt.format.width = gsc->dst_img.w; + sd_fmt.format.height = gsc->dst_img.h; + } + sd_fmt.format.code = rgb ? V4L2_MBUS_FMT_RGB666_1X18 : + V4L2_MBUS_FMT_YDYUYDYV8_1X16; + if (exynos_subdev_s_fmt(gsc->mdev.gsc_sd_entity->fd, &sd_fmt) < 0) { + ALOGE("%s::GSC subdev set format failed", __func__); + return -1; + } + + /* set crop: src crop of GSC sub-dev*/ + sd_crop.pad = GSCALER_SUBDEV_PAD_SOURCE; + sd_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE; + if (gsc->out_mode == GSC_OUT_FIMD) { + sd_crop.rect.left = gsc->dst_img.x; + sd_crop.rect.top = gsc->dst_img.y; + sd_crop.rect.width = gsc->dst_img.w; + sd_crop.rect.height = gsc->dst_img.h; + } else { + sd_crop.rect.left = 0; + sd_crop.rect.top = 0; + sd_crop.rect.width = gsc->dst_img.w; + sd_crop.rect.height = gsc->dst_img.h; + } + + /* sink pad is connected to GSC out */ + /* set format: sink sub-dev */ + if (gsc->out_mode == GSC_OUT_FIMD) { + sd_fmt.pad = FIMD_SUBDEV_PAD_SINK; + sd_fmt.format.width = gsc->dst_img.w; + sd_fmt.format.height = gsc->dst_img.h; + } else { + sd_fmt.pad = MIXER_V_SUBDEV_PAD_SINK; + sd_fmt.format.width = gsc->dst_img.w + gsc->dst_img.x*2; + sd_fmt.format.height = gsc->dst_img.h + gsc->dst_img.y*2; + } + + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.format.code = rgb ? V4L2_MBUS_FMT_RGB666_1X18 : + V4L2_MBUS_FMT_YDYUYDYV8_1X16; + if (exynos_subdev_s_fmt(gsc->mdev.sink_sd_entity->fd, &sd_fmt) < 0) { + ALOGE("%s::sink:set format failed (PAD=%d)", __func__, + sd_fmt.pad); + return -1; + } + + /* set crop: sink sub-dev */ + if (gsc->out_mode == GSC_OUT_FIMD) + sd_crop.pad = FIMD_SUBDEV_PAD_SINK; + else + sd_crop.pad = MIXER_V_SUBDEV_PAD_SINK; + + sd_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE; + if (gsc->out_mode == GSC_OUT_FIMD) { + sd_crop.rect.left = gsc->dst_img.x; + sd_crop.rect.top = gsc->dst_img.y; + sd_crop.rect.width = gsc->dst_img.w; + sd_crop.rect.height = gsc->dst_img.h; + } else { + sd_crop.rect.left = 0; + sd_crop.rect.top = 0; + sd_crop.rect.width = gsc->dst_img.w; + sd_crop.rect.height = gsc->dst_img.h; + } + + if (gsc->out_mode != GSC_OUT_FIMD) { + sd_fmt.pad = MIXER_V_SUBDEV_PAD_SOURCE; + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.format.width = gsc->dst_img.w + gsc->dst_img.x*2; + sd_fmt.format.height = gsc->dst_img.h + gsc->dst_img.y*2; + sd_fmt.format.code = V4L2_MBUS_FMT_RGB666_1X18; + if (exynos_subdev_s_fmt(gsc->mdev.sink_sd_entity->fd, &sd_fmt) < 0) { + ALOGE("%s::sink:set format failed (PAD=%d)", __func__, + sd_fmt.pad); + return -1; + } + + sd_fmt.pad = MIXER_V_SUBDEV_PAD_SOURCE; + sd_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_crop.rect.left = gsc->dst_img.x; + sd_crop.rect.top = gsc->dst_img.y; + sd_crop.rect.width = gsc->dst_img.w; + sd_crop.rect.height = gsc->dst_img.h; + if (exynos_subdev_s_crop(gsc->mdev.sink_sd_entity->fd, &sd_crop) < 0) { + ALOGE("%s::sink: subdev set crop failed(PAD=%d)", __func__, + sd_crop.pad); + return -1; + } + } + + /*set GSC ctrls */ + if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, V4L2_CID_ROTATE, + rotate) < 0) { + ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_ROTATE: %d) failed", + __func__, rotate); + return -1; + } + + if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, V4L2_CID_HFLIP, + vflip) < 0) { + ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_HFLIP: %d) failed", + __func__, vflip); + return -1; + } + + if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, V4L2_CID_VFLIP, + hflip) < 0) { + ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_VFLIP: %d) failed", + __func__, hflip); + return -1; + } + + if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, + V4L2_CID_CACHEABLE, 1) < 0) { + ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_CACHEABLE: 1) failed", + __func__); + return -1; + } + + if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, + V4L2_CID_CONTENT_PROTECTION, gsc->src_img.drmMode) < 0) { + ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CONTENT_PROTECTION) fail", + __func__); + return -1; + } + + if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, + V4L2_CID_CSC_EQ_MODE, gsc->eq_auto) < 0) { + ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CSC_EQ_MODE) fail", __func__); + return -1; + } + + if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, + V4L2_CID_CSC_EQ, gsc->v4l2_colorspace) < 0) { + ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CSC_EQ) fail", __func__); + return -1; + } + + if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, + V4L2_CID_CSC_RANGE, gsc->range_full) < 0) { + ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CSC_RANGE) fail", __func__); + return -1; + } + + /* set src format :GSC video dev*/ + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt.fmt.pix_mp.width = gsc->src_img.fw; + fmt.fmt.pix_mp.height = gsc->src_img.fh; + fmt.fmt.pix_mp.pixelformat = src_color_space; + fmt.fmt.pix_mp.field = V4L2_FIELD_NONE; + fmt.fmt.pix_mp.num_planes = src_planes; + + if (exynos_v4l2_s_fmt(gsc->mdev.gsc_vd_entity->fd, &fmt) < 0) { + ALOGE("%s::videodev set format failed", __func__); + return -1; + } + + /* set src crop info :GSC video dev*/ + crop.type = fmt.type; + crop.c.left = gsc->src_img.x; + crop.c.top = gsc->src_img.y; + crop.c.width = gsc->src_img.w; + crop.c.height = gsc->src_img.h; + + if (exynos_v4l2_s_crop(gsc->mdev.gsc_vd_entity->fd, &crop) < 0) { + ALOGE("%s::videodev set crop failed", __func__); + return -1; + } + + reqbuf.type = fmt.type; + reqbuf.memory = V4L2_MEMORY_DMABUF; + reqbuf.count = MAX_BUFFERS_GSCALER_OUT; + + if (exynos_v4l2_reqbufs(gsc->mdev.gsc_vd_entity->fd, &reqbuf) < 0) { + ALOGE("%s::request buffers failed", __func__); + return -1; + } + + Exynos_gsc_Out(); + + return 0; +} + +int CGscaler::m_gsc_cap_config(void *handle, + exynos_mpp_img *src_img, exynos_mpp_img *dst_img) +{ + Exynos_gsc_In(); + + struct v4l2_format fmt; + struct v4l2_crop crop; + struct v4l2_requestbuffers reqbuf; + struct v4l2_subdev_format sd_fmt; + struct v4l2_subdev_crop sd_crop; + int i; + unsigned int rotate; + unsigned int hflip; + unsigned int vflip; + unsigned int plane_size[NUM_OF_GSC_PLANES]; + bool rgb; + + struct v4l2_rect dst_rect; + int32_t src_color_space; + int32_t dst_color_space; + int32_t dst_planes; + + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + memcpy(&gsc->src_img, src_img, sizeof(exynos_mpp_img)); + memcpy(&gsc->dst_img, dst_img, sizeof(exynos_mpp_img)); + src_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(src_img->format); + dst_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(dst_img->format); + dst_planes = m_gsc_get_plane_count(dst_color_space); + dst_planes = (dst_planes == -1) ? 1 : dst_planes; + rgb = get_yuv_planes(src_color_space) == -1; + CGscaler::rotateValueHAL2GSC(src_img->rot, &rotate, &hflip, &vflip); + + if (CGscaler::m_gsc_check_src_size(&gsc->src_img.fw, + &gsc->src_img.fh, &gsc->src_img.x, &gsc->src_img.y, + &gsc->src_img.w, &gsc->src_img.h, src_color_space, + (rotate == 90 || rotate == 270)) == false) { + ALOGE("%s::m_gsc_check_src_size() fail", __func__); + return -1; + } + + /*set GSC ctrls */ + if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, V4L2_CID_ROTATE, + rotate) < 0) { + ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_ROTATE: %d) failed", + __func__, rotate); + return -1; + } + if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, V4L2_CID_HFLIP, + vflip) < 0) { + ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_HFLIP: %d) failed", + __func__, vflip); + return -1; + } + if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, V4L2_CID_VFLIP, + hflip) < 0) { + ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_VFLIP: %d) failed", + __func__, hflip); + return -1; + } + if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, + V4L2_CID_CACHEABLE, 1) < 0) { + ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_CACHEABLE: 1) failed", + __func__); + return -1; + } + if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, + V4L2_CID_CONTENT_PROTECTION, gsc->src_img.drmMode) < 0) { + ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CONTENT_PROTECTION) fail", + __func__); + return -1; + } + if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, + V4L2_CID_CSC_RANGE, gsc->range_full)) { + ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CSC_RANGE: %d) fail", + __func__, gsc->range_full); + return -1; + } + /* set format: source pad of Decon-TV sub-dev*/ + sd_fmt.pad = DECON_TV_WB_PAD; + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.format.width = gsc->src_img.w; + sd_fmt.format.height = gsc->src_img.h; + sd_fmt.format.code = WB_PATH_FORMAT; + if (exynos_subdev_s_fmt(gsc->mdev.sink_sd_entity->fd, &sd_fmt) < 0) { + ALOGE("%s::Decon-TV subdev set format failed", __func__); + return -1; + } + + if (!gsc->dst_info.stream_on) { + /* set src format: GSC video dev*/ + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt.fmt.pix_mp.width = gsc->dst_img.fw; + fmt.fmt.pix_mp.height = gsc->dst_img.fh; + fmt.fmt.pix_mp.pixelformat = dst_color_space; + fmt.fmt.pix_mp.field = V4L2_FIELD_NONE; + fmt.fmt.pix_mp.num_planes = dst_planes; + + if (exynos_v4l2_s_fmt(gsc->mdev.gsc_vd_entity->fd, &fmt) < 0) { + ALOGE("%s::videodev set format failed", __func__); + return -1; + } + gsc->dst_info.buf.buf_idx = 0; + gsc->dst_info.qbuf_cnt = 0; + } + + /* set format: sink pad of GSC sub-dev*/ + sd_fmt.pad = GSCALER_SUBDEV_PAD_SINK; + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.format.width = gsc->src_img.w; + sd_fmt.format.height = gsc->src_img.h; + sd_fmt.format.code = WB_PATH_FORMAT; + if (exynos_subdev_s_fmt(gsc->mdev.gsc_sd_entity->fd, &sd_fmt) < 0) { + ALOGE("%s::GSC subdev set format failed", __func__); + return -1; + } + + /* set src crop info :GSC video dev*/ + crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + crop.c.left = gsc->dst_img.x; + crop.c.top = gsc->dst_img.y; + crop.c.width = gsc->dst_img.w; + crop.c.height = gsc->dst_img.h; + if (exynos_v4l2_s_crop(gsc->mdev.gsc_vd_entity->fd, &crop) < 0) { + ALOGE("%s::videodev set crop failed", __func__); + return -1; + } + + /* set crop: src crop of GSC sub-dev*/ + sd_crop.pad = GSCALER_SUBDEV_PAD_SINK; + sd_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_crop.rect.left = 0; + sd_crop.rect.top = 0; + sd_crop.rect.width = gsc->src_img.w; + sd_crop.rect.height = gsc->src_img.h; + + if (exynos_subdev_s_crop(gsc->mdev.gsc_sd_entity->fd, &sd_crop) < 0) { + ALOGE("%s::GSC subdev set crop failed(PAD=%d)", __func__, + sd_crop.pad); + return -1; + } + reqbuf.type = fmt.type; + reqbuf.memory = V4L2_MEMORY_DMABUF; + reqbuf.count = MAX_BUFFERS_GSCALER_CAP; + + if (!gsc->dst_info.stream_on) { + if (exynos_v4l2_reqbufs(gsc->mdev.gsc_vd_entity->fd, &reqbuf) < 0) { + ALOGE("%s::request buffers failed", __func__); + return -1; + } + } + + Exynos_gsc_Out(); + + return 0; +} + + +void CGscaler::rotateValueHAL2GSC(unsigned int transform, + unsigned int *rotate, unsigned int *hflip, unsigned int *vflip) +{ + int rotate_flag = transform & 0x7; + *rotate = 0; + *hflip = 0; + *vflip = 0; + + switch (rotate_flag) { + case HAL_TRANSFORM_ROT_90: + *rotate = 90; + break; + case HAL_TRANSFORM_ROT_180: + *rotate = 180; + break; + case HAL_TRANSFORM_ROT_270: + *rotate = 270; + break; + case HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90: + *rotate = 90; + *vflip = 1; /* set vflip to compensate the rot & flip order. */ + break; + case HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90: + *rotate = 90; + *hflip = 1; /* set hflip to compensate the rot & flip order. */ + break; + case HAL_TRANSFORM_FLIP_H: + *hflip = 1; + break; + case HAL_TRANSFORM_FLIP_V: + *vflip = 1; + break; + default: + break; + } +} + +int CGscaler::m_gsc_m2m_run(void *handle, + exynos_mpp_img *src_img, exynos_mpp_img *dst_img) +{ + Exynos_gsc_In(); + + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + void *addr[3] = {NULL, NULL, NULL}; + int ret = 0; + + addr[0] = (void *)src_img->yaddr; + addr[1] = (void *)src_img->uaddr; + addr[2] = (void *)src_img->vaddr; + ret = exynos_gsc_set_src_addr(handle, addr, src_img->mem_type, + src_img->acquireFenceFd); + if (ret < 0) { + ALOGE("%s::fail: exynos_gsc_set_src_addr[%p %p %p]", __func__, + addr[0], addr[1], addr[2]); + return -1; + } + + addr[0] = (void *)dst_img->yaddr; + addr[1] = (void *)dst_img->uaddr; + addr[2] = (void *)dst_img->vaddr; + ret = exynos_gsc_set_dst_addr(handle, addr, dst_img->mem_type, + dst_img->acquireFenceFd); + if (ret < 0) { + ALOGE("%s::fail: exynos_gsc_set_dst_addr[%p %p %p]", __func__, + addr[0], addr[1], addr[2]); + return -1; + } + + ret = gsc->m_gsc_m2m_run_core(handle); + if (ret < 0) { + ALOGE("%s::fail: m_gsc_m2m_run_core", __func__); + return -1; + } + + if (src_img->acquireFenceFd >= 0) { + close(src_img->acquireFenceFd); + src_img->acquireFenceFd = -1; + } + + if (dst_img->acquireFenceFd >= 0) { + close(dst_img->acquireFenceFd); + dst_img->acquireFenceFd = -1; + } + + src_img->releaseFenceFd = gsc->src_info.releaseFenceFd; + dst_img->releaseFenceFd = gsc->dst_info.releaseFenceFd; + + Exynos_gsc_Out(); + + return 0; +} + +int CGscaler::m_gsc_out_run(void *handle, exynos_mpp_img *src_img) +{ + struct v4l2_plane planes[NUM_OF_GSC_PLANES]; + struct v4l2_buffer buf; + int32_t src_color_space; + int32_t src_planes; + unsigned int i; + unsigned int plane_size[NUM_OF_GSC_PLANES]; + int ret = 0; + unsigned int dq_retry_cnt = 0; + + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + /* All buffers have been queued, dequeue one */ + if (gsc->src_info.qbuf_cnt == MAX_BUFFERS_GSCALER_OUT) { + memset(&buf, 0, sizeof(struct v4l2_buffer)); + for (i = 0; i < NUM_OF_GSC_PLANES; i++) + memset(&planes[i], 0, sizeof(struct v4l2_plane)); + + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.memory = V4L2_MEMORY_DMABUF; + buf.m.planes = planes; + + src_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(gsc->src_img.format); + src_planes = m_gsc_get_plane_count(src_color_space); + src_planes = (src_planes == -1) ? 1 : src_planes; + buf.length = src_planes; + + + do { + ret = exynos_v4l2_dqbuf(gsc->mdev.gsc_vd_entity->fd, &buf); + if (ret == -EAGAIN) { + ALOGE("%s::Retry DQbuf(index=%d)", __func__, buf.index); + usleep(10000); + dq_retry_cnt++; + continue; + } + break; + } while (dq_retry_cnt <= 10); + + if (ret < 0) { + ALOGE("%s::dq buffer failed (index=%d)", __func__, buf.index); + return -1; + } + gsc->src_info.qbuf_cnt--; + } + + memset(&buf, 0, sizeof(struct v4l2_buffer)); + for (i = 0; i < NUM_OF_GSC_PLANES; i++) + memset(&planes[i], 0, sizeof(struct v4l2_plane)); + + src_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(gsc->src_img.format); + src_planes = m_gsc_get_plane_count(src_color_space); + src_planes = (src_planes == -1) ? 1 : src_planes; + + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + buf.memory = V4L2_MEMORY_DMABUF; + buf.flags = 0; + buf.length = src_planes; + buf.index = gsc->src_info.buf.buf_idx; + buf.m.planes = planes; + buf.reserved = -1; + + gsc->src_info.buf.addr[0] = (void*)src_img->yaddr; + gsc->src_info.buf.addr[1] = (void*)src_img->uaddr; + gsc->src_info.buf.addr[2] = (void*)src_img->vaddr; + + if (CGscaler::tmp_get_plane_size(src_color_space, plane_size, + gsc->src_img.fw, gsc->src_img.fh, src_planes) != true) { + ALOGE("%s:get_plane_size:fail", __func__); + return -1; + } + + for (i = 0; i < buf.length; i++) { + buf.m.planes[i].m.fd = (long)gsc->src_info.buf.addr[i]; + buf.m.planes[i].length = plane_size[i]; + buf.m.planes[i].bytesused = plane_size[i]; + } + + /* Queue the buf */ + if (exynos_v4l2_qbuf(gsc->mdev.gsc_vd_entity->fd, &buf) < 0) { + ALOGE("%s::queue buffer failed (index=%d)(mSrcBufNum=%d)", + __func__, gsc->src_info.buf.buf_idx, + MAX_BUFFERS_GSCALER_OUT); + return -1; + } + gsc->src_info.buf.buf_idx++; + gsc->src_info.buf.buf_idx = + gsc->src_info.buf.buf_idx % MAX_BUFFERS_GSCALER_OUT; + gsc->src_info.qbuf_cnt++; + + if (gsc->src_info.stream_on == false) { + if (exynos_v4l2_streamon(gsc->mdev.gsc_vd_entity->fd, + (v4l2_buf_type)buf.type) < 0) { + ALOGE("%s::stream on failed", __func__); + return -1; + } + gsc->src_info.stream_on = true; + } + + return 0; +} + +int CGscaler::m_gsc_cap_run(void *handle, exynos_mpp_img *dst_img) +{ + struct v4l2_plane planes[NUM_OF_GSC_PLANES]; + struct v4l2_buffer buf; + int32_t dst_color_space; + int32_t dst_planes; + unsigned int i; + unsigned int plane_size[NUM_OF_GSC_PLANES]; + CGscaler* gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + /* All buffers have been queued, dequeue one */ + if (gsc->dst_info.qbuf_cnt == MAX_BUFFERS_GSCALER_CAP) { + memset(&buf, 0, sizeof(struct v4l2_buffer)); + for (i = 0; i < NUM_OF_GSC_PLANES; i++) + memset(&planes[i], 0, sizeof(struct v4l2_plane)); + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_DMABUF; + buf.m.planes = planes; + + dst_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(gsc->dst_img.format); + dst_planes = m_gsc_get_plane_count(dst_color_space); + dst_planes = (dst_planes == -1) ? 1 : dst_planes; + buf.length = dst_planes; + + + if (exynos_v4l2_dqbuf(gsc->mdev.gsc_vd_entity->fd, &buf) < 0) { + ALOGE("%s::dequeue buffer failed (index=%d)(mSrcBufNum=%d)", + __func__, gsc->src_info.buf.buf_idx, + MAX_BUFFERS_GSCALER_CAP); + return -1; + } + gsc->dst_info.qbuf_cnt--; + } + + memset(&buf, 0, sizeof(struct v4l2_buffer)); + for (i = 0; i < NUM_OF_GSC_PLANES; i++) + memset(&planes[i], 0, sizeof(struct v4l2_plane)); + + dst_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(gsc->dst_img.format); + dst_planes = m_gsc_get_plane_count(dst_color_space); + dst_planes = (dst_planes == -1) ? 1 : dst_planes; + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_DMABUF; + buf.flags = V4L2_BUF_FLAG_USE_SYNC; + buf.length = dst_planes; + buf.index = gsc->dst_info.buf.buf_idx; + buf.m.planes = planes; + buf.reserved = dst_img->acquireFenceFd; + + gsc->dst_info.buf.addr[0] = (void*)dst_img->yaddr; + gsc->dst_info.buf.addr[1] = (void*)dst_img->uaddr; + gsc->dst_info.buf.addr[2] = (void*)dst_img->vaddr; + + if (CGscaler::tmp_get_plane_size(dst_color_space, plane_size, + gsc->dst_img.fw, gsc->dst_img.fh, dst_planes) != true) { + ALOGE("%s:get_plane_size:fail", __func__); + return -1; + } + + for (i = 0; i < buf.length; i++) { + buf.m.planes[i].m.fd = (int)(long)gsc->dst_info.buf.addr[i]; + buf.m.planes[i].length = plane_size[i]; + buf.m.planes[i].bytesused = plane_size[i]; + } + + /* Queue the buf */ + if (exynos_v4l2_qbuf(gsc->mdev.gsc_vd_entity->fd, &buf) < 0) { + ALOGE("%s::queue buffer failed (index=%d)(mDstBufNum=%d)", + __func__, gsc->dst_info.buf.buf_idx, + MAX_BUFFERS_GSCALER_CAP); + return -1; + } + + gsc->dst_info.buf.buf_idx++; + gsc->dst_info.buf.buf_idx = + gsc->dst_info.buf.buf_idx % MAX_BUFFERS_GSCALER_CAP; + gsc->dst_info.qbuf_cnt++; + + if (gsc->dst_info.stream_on == false) { + if (exynos_v4l2_streamon(gsc->mdev.gsc_vd_entity->fd, + (v4l2_buf_type)buf.type) < 0) { + ALOGE("%s::stream on failed", __func__); + return -1; + } + gsc->dst_info.stream_on = true; + } + + dst_img->releaseFenceFd = buf.reserved; + return 0; +} + +bool CGscaler::tmp_get_plane_size(int V4L2_PIX, + unsigned int * size, unsigned int width, unsigned int height, int src_planes) +{ + unsigned int frame_ratio = 1; + int src_bpp = get_yuv_bpp(V4L2_PIX); + unsigned int frame_size = width * height; + + src_planes = (src_planes == -1) ? 1 : src_planes; + frame_ratio = 8 * (src_planes -1) / (src_bpp - 8); + + switch (src_planes) { + case 1: + switch (V4L2_PIX) { + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB32: + size[0] = frame_size << 2; + break; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YVYU: + size[0] = frame_size << 1; + break; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV21M: + size[0] = (frame_size * 3) >> 1; + break; + case V4L2_PIX_FMT_YVU420: + size[0] = frame_size + (ALIGN((width >> 1), 16) * ((height >> 1) * 2)); + break; + default: + ALOGE("%s::invalid color type (%x)", __func__, V4L2_PIX); + return false; + break; + } + size[1] = 0; + size[2] = 0; + break; + case 2: + size[0] = frame_size; + size[1] = frame_size / frame_ratio; + size[2] = 0; + break; + case 3: + size[0] = frame_size; + size[1] = frame_size / frame_ratio; + size[2] = frame_size / frame_ratio; + break; + default: + ALOGE("%s::invalid color foarmt", __func__); + return false; + break; + } + + return true; +} + +int CGscaler::ConfigMpp(void *handle, exynos_mpp_img *src, + exynos_mpp_img *dst) +{ + return exynos_gsc_config_exclusive(handle, src, dst); +} + +int CGscaler::ConfigBlendMpp(void *handle, exynos_mpp_img *src, + exynos_mpp_img *dst, + SrcBlendInfo *srcblendinfo) +{ + return exynos_gsc_config_blend_exclusive(handle, src, dst, srcblendinfo); +} + +int CGscaler::RunMpp(void *handle, exynos_mpp_img *src, + exynos_mpp_img *dst) +{ + return exynos_gsc_run_exclusive(handle, src, dst); +} + +int CGscaler::StopMpp(void *handle) +{ + return exynos_gsc_stop_exclusive(handle); +} + +void CGscaler::DestroyMpp(void *handle) +{ + return exynos_gsc_destroy(handle); +} + +int CGscaler::SetCSCProperty(void *handle, unsigned int eqAuto, + unsigned int fullRange, unsigned int colorspace) +{ + return exynos_gsc_set_csc_property(handle, eqAuto, fullRange, + colorspace); +} + +int CGscaler::FreeMpp(void *handle) +{ + return exynos_gsc_free_and_close(handle); +} + +int CGscaler::SetInputCrop(void *handle, + exynos_mpp_img *src_img, exynos_mpp_img *dst_img) +{ + struct v4l2_crop crop; + int ret = 0; + CGscaler *gsc = GetGscaler(handle); + if (gsc == NULL) { + ALOGE("%s::handle == NULL() fail", __func__); + return -1; + } + + crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + crop.c.left = src_img->x; + crop.c.top = src_img->y; + crop.c.width = src_img->w; + crop.c.height = src_img->h; + + return exynos_v4l2_s_crop(gsc->mdev.gsc_vd_entity->fd, &crop); +} diff --git a/libgscaler/libgscaler_obj.h b/libgscaler/libgscaler_obj.h new file mode 100755 index 0000000..e36e397 --- /dev/null +++ b/libgscaler/libgscaler_obj.h @@ -0,0 +1,265 @@ +/* + * Copyright@ Samsung Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#ifndef LIBGSCALER_OBJ_H_ +#define LIBGSCALER_OBJ_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <linux/videodev2.h> +#include <fcntl.h> +#include <stdbool.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <linux/videodev2_exynos_media.h> +#include <exynos_gscaler.h> + +#include <exynos_format.h> +#include <exynos_v4l2.h> + +#include <exynos_scaler.h> +#include <exynos_log.h> + +#define NUM_OF_GSC_PLANES (3) +#define MAX_BUFFERS_GSCALER_OUT (10) +#define MAX_BUFFERS_GSCALER_CAP (1) +#define GSCALER_SUBDEV_PAD_SINK (0) +#define GSCALER_SUBDEV_PAD_SOURCE (1) +#define MIXER_V_SUBDEV_PAD_SINK (0) +#define MIXER_V_SUBDEV_PAD_SOURCE (3) +#define FIMD_SUBDEV_PAD_SINK (0) +#define DECON_TV_WB_PAD (0) +#define MAX_BUFFERS (6) + +#define NUM_OF_GSC_HW (4) +#define NODE_NUM_GSC_0 (23) +#define NODE_NUM_GSC_1 (26) +#define NODE_NUM_GSC_2 (29) +#define NODE_NUM_GSC_3 (32) + +#define PFX_NODE_GSC "/dev/video" +#define PFX_NODE_MEDIADEV "/dev/media" +#define PFX_MXR_ENTITY "s5p-mixer%d" +#define PFX_FIMD_ENTITY "s3c-fb-window%d" +#if defined(USES_DT) +#define PFX_GSC_VIDEODEV_ENTITY0 "13c00000.gsc.output" +#define PFX_GSC_VIDEODEV_ENTITY1 "13c10000.gsc.output" +#define PFX_GSC_VIDEODEV_ENTITY2 "13c20000.gsc.output" +#else +#define PFX_GSC_VIDEODEV_ENTITY "exynos-gsc.%d.output" +#endif +#define PFX_GSC_CAPTURE_ENTITY "13c20000.gsc.capture" +#define PFX_GSC_SUBDEV_ENTITY "exynos-gsc-sd.%d" +#define PFX_SUB_DEV "/dev/v4l-subdev%d" +#define GSC_WB_SD_NAME "gsc-wb-sd" +#define DEX_WB_SD_NAME "dex-wb-sd" +#define GSC_VD_PAD_SOURCE 0 +#define GSC_SD_PAD_SINK 0 +#define GSC_SD_PAD_SOURCE 1 +#define GSC_OUT_PAD_SINK 0 +#define WB_PATH_FORMAT 0x100D; + +#define GSC_MIN_SRC_W_SIZE (64) +#define GSC_MIN_SRC_H_SIZE (32) +#define GSC_MIN_DST_W_SIZE (32) +#define GSC_MIN_DST_H_SIZE (16) + +#define MAX_GSC_WAITING_TIME_FOR_TRYLOCK (16000) // 16msec +#define GSC_WAITING_TIME_FOR_TRYLOCK (8000) // 8msec + +typedef struct GscalerInfo { + unsigned int width; + unsigned int height; + unsigned int crop_left; + unsigned int crop_top; + unsigned int crop_width; + unsigned int crop_height; + unsigned int v4l2_colorformat; + unsigned int mode_drm; + unsigned int cacheable; + int rotation; + int flip_horizontal; + int flip_vertical; + int qbuf_cnt; + int acquireFenceFd; + int releaseFenceFd; + bool stream_on; + bool dirty; + struct v4l2_format format; + struct v4l2_crop crop; + struct Buffer_Info { + enum v4l2_memory mem_type; + enum v4l2_buf_type buf_type; + void *addr[NUM_OF_GSC_PLANES]; + struct v4l2_plane planes[NUM_OF_GSC_PLANES]; + bool buffer_queued; + struct v4l2_buffer buffer; + int buf_idx; + }buf; +}GscInfo; + +struct MediaDevice { + struct media_device *media0; + struct media_device *media1; + struct media_entity *gsc_sd_entity; + struct media_entity *gsc_vd_entity; + struct media_entity *sink_sd_entity; +}; + +class CGscaler { +public: + GscInfo src_info; + GscInfo dst_info; + exynos_mpp_img src_img; + exynos_mpp_img dst_img; + MediaDevice mdev; + int out_mode; + int gsc_id; + bool allow_drm; + bool protection_enabled; + int gsc_fd; + int mode; + unsigned int eq_auto; /* 0: user, 1: auto */ + unsigned int range_full; /* 0: narrow, 1: full */ + unsigned int v4l2_colorspace; /* 1: 601, 3: 709, see csc.h or videodev2.h */ + void *scaler; + + void __InitMembers(int __mode, int __out_mode, int __gsc_id,int __allow_drm) + { + memset(&mdev, 0, sizeof(mdev)); + scaler = NULL; + + mode = __mode; + out_mode = __out_mode; + gsc_id = __gsc_id; + allow_drm = __allow_drm; + } + + CGscaler(int __mode) + { + memset(&src_info, 0, sizeof(GscInfo)); + memset(&dst_info, 0, sizeof(GscInfo)); + memset(&src_img, 0, sizeof(exynos_mpp_img)); + memset(&dst_img, 0, sizeof(exynos_mpp_img)); + mode = __mode; + protection_enabled = false; + gsc_fd = -1; + src_info.buf.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + dst_info.buf.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + eq_auto = 0; /* user mode */ + range_full = 0; /* narrow */ + v4l2_colorspace = 1; /* SMPTE170M (601) */ + __InitMembers(__mode, 0, 0, 0); + } + CGscaler(int __mode, int __out_mode, int __gsc_id, int __allow_drm) + { + memset(&src_info, 0, sizeof(GscInfo)); + memset(&dst_info, 0, sizeof(GscInfo)); + memset(&src_img, 0, sizeof(exynos_mpp_img)); + memset(&dst_img, 0, sizeof(exynos_mpp_img)); + protection_enabled = false; + gsc_fd = -1; + src_info.buf.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + dst_info.buf.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + eq_auto = 0; /* user mode */ + range_full = 0; /* narrow */ + v4l2_colorspace = 1; /* SMPTE170M (601) */ + __InitMembers(__mode, __out_mode, __gsc_id, __allow_drm); + } + + ~CGscaler() + { + ALOGD("%s", __func__); + } + virtual int ConfigMpp(void *handle, exynos_mpp_img *src, + exynos_mpp_img *dst); + virtual int ConfigBlendMpp(void *handle, exynos_mpp_img *src, + exynos_mpp_img *dst, + SrcBlendInfo *srcblendinfo); + virtual int RunMpp(void *handle, exynos_mpp_img *src, + exynos_mpp_img *dst); + virtual int StopMpp(void *handle); + virtual void DestroyMpp(void *handle); + virtual int SetCSCProperty(void *handle, unsigned int eqAuto, + unsigned int fullRange, unsigned int colorspace); + virtual int FreeMpp(void *handle); + virtual int SetInputCrop(void *handle, exynos_mpp_img *src, exynos_mpp_img *dst); + bool m_gsc_find_and_create(void *handle); + bool m_gsc_out_destroy(void *handle); + bool m_gsc_cap_destroy(void *handle); + bool m_gsc_m2m_destroy(void *handle); + int m_gsc_m2m_create(int dev); + int m_gsc_output_create(void *handle, int dev_num, int out_mode); + int m_gsc_capture_create(void *handle, int dev_num, int out_mode); + int m_gsc_out_stop(void *handle); + int m_gsc_cap_stop(void *handle); + int m_gsc_m2m_stop(void *handle); + int m_gsc_m2m_run_core(void *handle); + int m_gsc_m2m_wait_frame_done(void *handle); + int m_gsc_m2m_config(void *handle, + exynos_mpp_img *src_img, exynos_mpp_img *dst_img); + int m_gsc_out_config(void *handle, + exynos_mpp_img *src_img, exynos_mpp_img *dst_img); + int m_gsc_cap_config(void *handle, + exynos_mpp_img *src_img, exynos_mpp_img *dst_img); + int m_gsc_m2m_run(void *handle, + exynos_mpp_img *src_img, exynos_mpp_img *dst_img); + int m_gsc_out_run(void *handle, exynos_mpp_img *src_img); + int m_gsc_cap_run(void *handle, exynos_mpp_img *dst_img); + static bool m_gsc_set_format(int fd, GscInfo *info); + static unsigned int m_gsc_get_plane_count(int v4l_pixel_format); + static bool m_gsc_set_addr(int fd, GscInfo *info); + static unsigned int m_gsc_get_plane_size( + unsigned int *plane_size, unsigned int width, + unsigned int height, int v4l_pixel_format); + static bool m_gsc_check_src_size(unsigned int *w, unsigned int *h, + unsigned int *crop_x, unsigned int *crop_y, + unsigned int *crop_w, unsigned int *crop_h, + int v4l2_colorformat, bool rotation); + static bool m_gsc_check_dst_size(unsigned int *w, unsigned int *h, + unsigned int *crop_x, unsigned int *crop_y, + unsigned int *crop_w, unsigned int *crop_h, + int v4l2_colorformat, int rotation); + static int m_gsc_multiple_of_n(int number, int N); + static void rotateValueHAL2GSC(unsigned int transform, + unsigned int *rotate, unsigned int *hflip, unsigned int *vflip); + static bool tmp_get_plane_size(int V4L2_PIX, + unsigned int * size, unsigned int width, unsigned int height, int src_planes); +}; + +inline CGscaler *GetGscaler(void* handle) +{ + if (handle == NULL) { + ALOGE("%s::NULL Scaler handle", __func__); + return NULL; + } + + CGscaler *gsc = reinterpret_cast<CGscaler *>(handle); + + return gsc; +} +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libion/Makefile.am b/libion/Makefile.am new file mode 100755 index 0000000..80234e9 --- /dev/null +++ b/libion/Makefile.am @@ -0,0 +1,12 @@ +lib_LTLIBRARIES = libion.la + +libion_la_SOURCES = ion.c +libion_la_CFLAGS = -I$(CURDIR)/include \ + -I$(CURDIR)/kernel-headers \ + -I$(top_srcdir)/include +libion_la_CFLAGS += -DLOG_TAG=\"LIBION\" +if USE_DLOG +libion_la_CFLAGS += $(DLOG_CFLAGS) -DUSE_DLOG +endif + +libion_la_LIBADD = $(DLOG_LIBS) diff --git a/libion/include/ion/ion.h b/libion/include/ion/ion.h new file mode 100755 index 0000000..6b847e0 --- /dev/null +++ b/libion/include/ion/ion.h @@ -0,0 +1,47 @@ +/* + * ion.c + * + * Memory Allocator functions for ion + * + * Copyright 2011 Google, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SYS_CORE_ION_H +#define __SYS_CORE_ION_H + +#include <sys/types.h> +#include <linux/ion.h> + +__BEGIN_DECLS + +struct ion_handle; + +int ion_open(); +int ion_close(int fd); +int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask, + unsigned int flags, ion_user_handle_t *handle); +int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask, + unsigned int flags, int *handle_fd); +int ion_sync_fd(int fd, int handle_fd); +int ion_sync_fd_partial(int fd, int handle_fd, off_t offset, size_t len); +int ion_free(int fd, ion_user_handle_t handle); +int ion_map(int fd, ion_user_handle_t handle, size_t length, int prot, + int flags, off_t offset, unsigned char **ptr, int *map_fd); +int ion_share(int fd, ion_user_handle_t handle, int *share_fd); +int ion_import(int fd, int share_fd, ion_user_handle_t *handle); + +__END_DECLS + +#endif /* __SYS_CORE_ION_H */ diff --git a/libion/ion.c b/libion/ion.c new file mode 100755 index 0000000..403a585 --- /dev/null +++ b/libion/ion.c @@ -0,0 +1,190 @@ +/* + * ion.c + * + * Memory Allocator functions for ion + * + * Copyright 2011 Google, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#include <cutils/log.h> +//#define ENABLE_DEBUG_LOG +#include <exynos_log.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/types.h> + +#include <linux/ion.h> +#include <ion/ion.h> + +int ion_open() +{ + int fd = open("/dev/ion", O_RDWR); + if (fd < 0) + ALOGE("open /dev/ion failed!\n"); + return fd; +} + +int ion_close(int fd) +{ + int ret = close(fd); + if (ret < 0) + return -errno; + return ret; +} + +static int ion_ioctl(int fd, int req, void *arg) +{ + int ret = ioctl(fd, req, arg); + if (ret < 0) { + ALOGE("ioctl %x failed with code %d: %s\n", req, + ret, strerror(errno)); + return -errno; + } + return ret; +} + +int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask, + unsigned int flags, ion_user_handle_t *handle) +{ + int ret; + struct ion_allocation_data data = { + .len = len, + .align = align, + .heap_id_mask = heap_mask, + .flags = flags, + }; + + if (handle == NULL) + return -EINVAL; + + ret = ion_ioctl(fd, ION_IOC_ALLOC, &data); + if (ret < 0) + return ret; + *handle = data.handle; + return ret; +} + +int ion_free(int fd, ion_user_handle_t handle) +{ + struct ion_handle_data data = { + .handle = handle, + }; + return ion_ioctl(fd, ION_IOC_FREE, &data); +} + +int ion_map(int fd, ion_user_handle_t handle, size_t length, int prot, + int flags, off_t offset, unsigned char **ptr, int *map_fd) +{ + int ret; + unsigned char *tmp_ptr; + struct ion_fd_data data = { + .handle = handle, + }; + + if (map_fd == NULL) + return -EINVAL; + if (ptr == NULL) + return -EINVAL; + + ret = ion_ioctl(fd, ION_IOC_MAP, &data); + if (ret < 0) + return ret; + if (data.fd < 0) { + ALOGE("map ioctl returned negative fd\n"); + return -EINVAL; + } + tmp_ptr = mmap(NULL, length, prot, flags, data.fd, offset); + if (tmp_ptr == MAP_FAILED) { + ALOGE("mmap failed: %s\n", strerror(errno)); + return -errno; + } + *map_fd = data.fd; + *ptr = tmp_ptr; + return ret; +} + +int ion_share(int fd, ion_user_handle_t handle, int *share_fd) +{ + int ret; + struct ion_fd_data data = { + .handle = handle, + }; + + if (share_fd == NULL) + return -EINVAL; + + ret = ion_ioctl(fd, ION_IOC_SHARE, &data); + if (ret < 0) + return ret; + if (data.fd < 0) { + ALOGE("share ioctl returned negative fd\n"); + return -EINVAL; + } + *share_fd = data.fd; + return ret; +} + +int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask, + unsigned int flags, int *handle_fd) { + ion_user_handle_t handle; + int ret; + + ret = ion_alloc(fd, len, align, heap_mask, flags, &handle); + if (ret < 0) + return ret; + ret = ion_share(fd, handle, handle_fd); + ion_free(fd, handle); + return ret; +} + +int ion_import(int fd, int share_fd, ion_user_handle_t *handle) +{ + int ret; + struct ion_fd_data data = { + .fd = share_fd, + }; + + if (handle == NULL) + return -EINVAL; + + ret = ion_ioctl(fd, ION_IOC_IMPORT, &data); + if (ret < 0) + return ret; + *handle = data.handle; + return ret; +} + +int ion_sync_fd(int fd, int handle_fd) +{ + struct ion_fd_data data = { + .fd = handle_fd, + }; + return ion_ioctl(fd, ION_IOC_SYNC, &data); +} + +int ion_sync_fd_partial(int fd, int handle_fd, off_t offset, size_t len) +{ + struct ion_fd_partial_data data = { + .fd = handle_fd, + .offset = offset, + .len = len, + }; + return ion_ioctl(fd, ION_IOC_SYNC_PARTIAL, &data); +} diff --git a/libion/kernel-headers/linux/ion.h b/libion/kernel-headers/linux/ion.h new file mode 100755 index 0000000..bb145d1 --- /dev/null +++ b/libion/kernel-headers/linux/ion.h @@ -0,0 +1,106 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + *** To edit the content of this header, modify the corresponding + *** source file (e.g. under external/kernel-headers/original/) then + *** run bionic/libc/kernel/tools/update_all.py + *** + *** Any manual change here will be lost the next time this script will + *** be run. You've been warned! + *** + **************************************************************************** + ****************************************************************************/ +#ifndef _UAPI_LINUX_ION_H +#define _UAPI_LINUX_ION_H +#include <linux/ioctl.h> +#include <linux/types.h> +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +typedef int ion_user_handle_t; +enum ion_heap_type { + ION_HEAP_TYPE_SYSTEM, + ION_HEAP_TYPE_SYSTEM_CONTIG, +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + ION_HEAP_TYPE_CARVEOUT, + ION_HEAP_TYPE_CHUNK, + ION_HEAP_TYPE_DMA, + ION_HEAP_TYPE_CUSTOM, +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + ION_NUM_HEAPS = 16, +}; +#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM) +#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT) +#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA) +#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8 +#define ION_FLAG_CACHED 1 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ION_FLAG_CACHED_NEEDS_SYNC 2 +#define ION_FLAG_PRESERVE_KMAP 4 +#define ION_FLAG_NOZEROED 8 +#define ION_FLAG_PROTECTED 16 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ION_FLAG_SYNC_FORCE 32 +struct ion_allocation_data { + size_t len; + size_t align; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + unsigned int heap_id_mask; + unsigned int flags; + ion_user_handle_t handle; +}; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +struct ion_fd_data { + ion_user_handle_t handle; + int fd; +}; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +struct ion_fd_partial_data { + ion_user_handle_t handle; + int fd; + off_t offset; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + size_t len; +}; +struct ion_handle_data { + ion_user_handle_t handle; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +}; +struct ion_custom_data { + unsigned int cmd; + unsigned long arg; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +}; +struct ion_preload_object { + size_t len; + unsigned int count; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +}; +struct ion_preload_data { + unsigned int heap_id_mask; + unsigned int flags; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + unsigned int count; + struct ion_preload_object *obj; +}; +#define ION_IOC_MAGIC 'I' +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, struct ion_allocation_data) +#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data) +#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data) +#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data) +#define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data) +#define ION_IOC_SYNC_PARTIAL _IOWR(ION_IOC_MAGIC, 9, struct ion_fd_partial_data) +#define ION_IOC_PRELOAD_ALLOC _IOW(ION_IOC_MAGIC, 8, struct ion_preload_data) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data) +#endif +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ diff --git a/libswconverter/Makefile.am b/libswconverter/Makefile.am new file mode 100755 index 0000000..2a98d0e --- /dev/null +++ b/libswconverter/Makefile.am @@ -0,0 +1,24 @@ +lib_LTLIBRARIES = libswconverter.la + +libswconverter_la_SOURCES = swconvertor.c \ + csc_BGRA8888_to_RGBA8888_NEON.s \ + csc_BGRA8888_to_YUV420SP_NEON.s \ + csc_RGBA8888_to_YUV420SP_NEON.s \ + csc_interleave_memcpy_neon.s \ + csc_linear_to_tiled_crop_neon.s \ + csc_linear_to_tiled_interleave_crop_neon.s \ + csc_tiled_to_linear_crop_neon.s \ + csc_tiled_to_linear_deinterleave_crop_neon.s \ + csc_tiled_to_linear_uv_deinterleave_neon.s \ + csc_tiled_to_linear_uv_neon.s \ + csc_tiled_to_linear_y_neon.s + +libswconverter_la_CFLAGS = -I$(top_srcdir)/include +libswconverter_la_CFLAGS += -Wno-unused-variable -Wno-unused-function +libswconverter_la_CFLAGS += -DLOG_TAG=\"LIBSWCONVERTER\" + +libswconverter_la_CCASFLAGS = -march=armv7-a -mfpu=neon-vfpv4 + +libswconverter_la_LDFLAGS = "-Wl,-z,noexecstack" + +libswconverter_la_LIBADD = $(DLOG_LIBS) diff --git a/libswconverter/csc_BGRA8888_to_RGBA8888_NEON.s b/libswconverter/csc_BGRA8888_to_RGBA8888_NEON.s new file mode 100755 index 0000000..0f4b45b --- /dev/null +++ b/libswconverter/csc_BGRA8888_to_RGBA8888_NEON.s @@ -0,0 +1,112 @@ +/* + * + * Copyright 2013 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_BGRA8888_to_RGBA8888.s + * @brief color format converter + * @author Hyungdeok Lee (hd0408.lee@samsung.com) + * @version 1.0 + * @history + * 2013.02.28 : Create + */ + +/* + * Source BGRA8888 copy to Dest RGBA8888. + * Use neon interleaved load instruction, easly swap R ch to B ch. + * + * @param dest + * dst address[out] + * + * @param src + * src address[in] + * + * @param width + * line width [in] + * + * @param bpp + * bpp only concerned about 4 + */ + + .arch armv7-a + .text + .global csc_BGRA8888_RGBA8888_NEON + .type csc_BGRA8888_RGBA8888_NEON, %function +csc_BGRA8888_RGBA8888_NEON: + .fnstart + + @r0 dest + @r1 src + @r2 width + @r3 bpp + @r4 + @r5 + @r6 + @r7 + @r8 temp1 + @r9 temp2 + @r10 dest_addr + @r11 src_addr + @r12 temp_width + @r14 i + + stmfd sp!, {r4-r12,r14} @ backup registers + + mov r10, r0 + mov r11, r1 + mov r9, r2, lsr #5 @ r9 = r2 >> 5 (32) + and r14, r9, #3 @ r14 = r9 & 3 + mov r12, r2, lsr #7 @ r12 = r2 >> 7 (128) + + cmp r12, #0 + beq LESS_THAN_128 + +@ Process d0 to d3 at once. 4 times same operation. := 8 byte * 4 * 4 = 128 byte loop. +LOOP_128: + @pld [r11] @ cache line fill. use this for r11 region set by cachable. + vld4.8 {d0, d1, d2, d3}, [r11]! + vswp d0, d2 + vst4.8 {d0, d1, d2, d3}, [r10]! + + vld4.8 {d0, d1, d2, d3}, [r11]! + vswp d0, d2 + vst4.8 {d0, d1, d2, d3}, [r10]! + + vld4.8 {d0, d1, d2, d3}, [r11]! + vswp d0, d2 + vst4.8 {d0, d1, d2, d3}, [r10]! + + vld4.8 {d0, d1, d2, d3}, [r11]! + vswp d0, d2 + vst4.8 {d0, d1, d2, d3}, [r10]! + + subs r12, #1 + bne LOOP_128 + +LESS_THAN_128: + cmp r14, #0 + beq END + +LOOP_32: + vld4.8 {d0, d1, d2, d3}, [r11]! + vswp d0, d2 + vst4.8 {d0, d1, d2, d3}, [r10]! + subs r14, #1 + bne LOOP_32 + +END: + ldmfd sp!, {r4-r12,r15} @ restore registers + .fnend diff --git a/libswconverter/csc_BGRA8888_to_YUV420SP_NEON.s b/libswconverter/csc_BGRA8888_to_YUV420SP_NEON.s new file mode 100755 index 0000000..956f553 --- /dev/null +++ b/libswconverter/csc_BGRA8888_to_YUV420SP_NEON.s @@ -0,0 +1,365 @@ + + .arch armv7-a + .text + .global csc_BGRA8888_to_YUV420SP_NEON + .type csc_BGRA8888_to_YUV420SP_NEON, %function +csc_BGRA8888_to_YUV420SP_NEON: + .fnstart + + @r0 pDstY + @r1 pDstUV + @r2 pSrcRGB + @r3 nWidth + @r4 pDstY2 = pDstY + nWidth + @r5 pSrcRGB2 = pSrcRGB + nWidthx2 + @r6 temp7, nWidth16m + @r7 temp6, accumilator + @r8 temp5, nWidthTemp + @r9 temp4, Raw RGB565 + @r10 temp3, r,g,b + @r11 temp2, immediate operand + @r12 temp1, nHeight + @r14 temp0, debugging pointer + + .equ CACHE_LINE_SIZE, 32 + .equ PRE_LOAD_OFFSET, 6 + + stmfd sp!, {r4-r12,r14} @ backup registers + ldr r12, [sp, #40] @ load nHeight + @ldr r14, [sp, #44] @ load pTest + add r4, r0, r3 @r4: pDstY2 = pDstY + nWidth + add r5, r2, r3, lsl #2 @r5: pSrcRGB2 = tmpSrcRGB + nWidthx4 + sub r8, r3, #16 @r8: nWidthTmp = nWidth -16 + + @q0: temp1, R + @q1: temp2, GB + @q2: R + @q3: G + @q4: B + @q5: temp3, output + + + vmov.u16 q6, #66 @coefficient assignment + vmov.u16 q7, #129 + vmov.u16 q8, #25 + vmov.u16 q9, #0x8080 @ 128<<8 + 128 + + vmov.u16 q10, #0x1000 @ 16<<8 + 128 + vorr.u16 q10, #0x0080 + + vmov.u16 q11, #38 @#-38 + vmov.u16 q12, #74 @#-74 + vmov.u16 q13, #112 + vmov.u16 q14, #94 @#-94 + vmov.u16 q15, #18 @#-18 + + + + +LOOP_NHEIGHT2: + stmfd sp!, {r12} @ backup registers + +LOOP_NWIDTH16: + pld [r2, #(CACHE_LINE_SIZE*PRE_LOAD_OFFSET)] + @-------------------------------------------YUV ------------------------------------------ + vmov.u16 q14, #94 @#94 + vmov.u16 q15, #18 @#18 + vld4.8 {d0,d1,d2,d3}, [r2]! @loadRGB interleavely + vld4.8 {d4,d5,d6,d7}, [r2]! @loadRGB interleavely + + + vmov.u16 d8,d2 + vmov.u16 d9,d6 + vmov.u16 d10,d1 + vmov.u16 d11,d5 + vmov.u16 d12,d0 + vmov.u16 d13,d4 + + vand.u16 q4,#0x00FF @R + vand.u16 q5,#0x00FF @G + vand.u16 q6,#0x00FF @B + + vmov.u16 q8,q9 @ CalcU() + vmla.u16 q8,q6,q13 @112 * B[k] + vmls.u16 q8,q4,q11 @q0:U -(38 * R[k]) @128<<6+ 32 + u>>2 + vmls.u16 q8,q5,q12 @-(74 * G[k]) + vshr.u16 q8,q8, #8 @(128<<8+ 128 + u)>>8 + + vmov.u16 q7,q9 @CalcV() + vmla.u16 q7,q4,q13 @112 * R[k] + vmls.u16 q7,q5,q14 @q0:U -(94 * G[k]) @128<<6+ 32 + v>>2 + vmls.u16 q7,q6,q15 @-(18 * B[k]) + vshr.u16 q7,q7, #8 @(128<<8+ 128 + v)>>8 + + + vtrn.8 q8,q7 + vst1.8 {q8}, [r1]! @write UV component to yuv420_buffer+linear_ylanesiez + + @-------------------------------------------Y ------------------------------------------ + + vmov.u16 q14, #66 @#66 + vmov.u16 q15, #129 @#129 + vmov.u16 q8, #25 @#25 + + @CalcY_Y() + + vmul.u16 q7,q4,q14 @q0 = 66 *R[k] + vmla.u16 q7,q5,q15 @q0 += 129 *G[k] + vmla.u16 q7,q6,q8 @q0 += 25 *B[k] + + vadd.u16 q7,q7,q10 + vshr.u16 q7,q7, #8 + + vmov.u16 d8,d2 + vmov.u16 d9,d6 + vmov.u16 d10,d1 + vmov.u16 d11,d5 + vmov.u16 d12,d0 + vmov.u16 d13,d4 + + vshr.u16 q4,q4,#8 @R + vshr.u16 q5,q5,#8 @G + vshr.u16 q6,q6,#8 @B + + vmul.u16 q0,q4,q14 @q0 = 66 *R[k] + vmla.u16 q0,q5,q15 @q0 += 129 *G[k] + vmla.u16 q0,q6,q8 @q0 += 25 *B[k] + vadd.u16 q0,q0,q10 + vshr.u16 q0,q0, #8 + + vtrn.8 q7,q0 + vst1.8 {q7}, [r0]!@write to Y to yuv420_buffer + + + + @-------------------------------------------Y ------------------------------------------ + + @---------------------------------------------Y1------------------------------------------- + + pld [r5, #(CACHE_LINE_SIZE*PRE_LOAD_OFFSET)] + vld4.8 {d0,d1,d2,d3}, [r5]! @loadRGB interleavely + vld4.8 {d4,d5,d6,d7}, [r5]! @loadRGB interleavely + + vmov.u16 d8,d2 + vmov.u16 d9,d6 + vmov.u16 d10,d1 + vmov.u16 d11,d5 + vmov.u16 d12,d0 + vmov.u16 d13,d4 + + + vand.u16 q4,#0x00FF @R + vand.u16 q5,#0x00FF @G + vand.u16 q6,#0x00FF @B + + + + vmul.u16 q7,q4,q14 @q0 = 66 *R[k] + vmla.u16 q7,q5,q15 @q0 += 129 *G[k] + vmla.u16 q7,q6,q8 @q0 += 25 *B[k] + vadd.u16 q7,q7,q10 + vshr.u16 q7,q7, #8 + + vmov.u16 d8,d2 + vmov.u16 d9,d6 + vmov.u16 d10,d1 + vmov.u16 d11,d5 + vmov.u16 d12,d0 + vmov.u16 d13,d4 + + vshr.u16 q4,q4,#8 @R + vshr.u16 q5,q5,#8 @G + vshr.u16 q6,q6,#8 @B + + vmul.u16 q0,q4,q14 @q0 = 66 *R[k] + vmla.u16 q0,q5,q15 @q0 += 129 *G[k] + vmla.u16 q0,q6,q8 @q0 += 25 *B[k] + vadd.u16 q0,q0,q10 + vshr.u16 q0,q0, #8 + + vtrn.8 q7,q0 + vst1.8 {q7}, [r4]!@write to Y to yuv420_buffer + + subs r8,r8,#16 @nWidth16-- + BPL LOOP_NWIDTH16 @if nWidth16>0 + @-----------------------------------unaligned --------------------------------------- + + adds r8,r8,#16 @ + 16 - 2 + BEQ NO_UNALIGNED @in case that nWidht is multiple of 16 +LOOP_NWIDTH2: + @----------------------------------pDstRGB1--Y------------------------------------------ + @stmfd sp!, {r14} @backup r14 + + + ldr r9, [r2], #4 @loadRGB int + ldr r12, [r2], #4 @loadRGB int + + mov r10, r9,lsr #16 @copy to r10 + mov r14, r12 @copy to r10 + + ldr r6, =0x000000FF + and r10, r10, r6 @R: (rgbIn[k] & 0xF800) >> 10; + ldr r6, =0x00FF0000 + and r14, r14, r6 @R: (rgbIn[k] & 0xF800) >> 10; + add r10,r10,r14 + + mov r11, #66 @accumilator += R*66 + mul r7, r10, r11 + + mov r10, r9,lsr #8 @copy to r10 + mov r14, r12,lsl #8 @copy to r10 + + ldr r6, =0x000000FF + and r10, r10, r6 @G: + ldr r6, =0x00FF0000 + and r14, r14, r6 @G: + add r10,r10,r14 + + mov r11, #129 @accumilator += G *129 + mla r7, r10, r11, r7 + + mov r10, r9 @copy to r10 + mov r14, r12,lsl #16 @copy to r10 + + ldr r6, =0x000000FF + and r10, r10, r6 @B + ldr r6, =0x00FF0000 + and r14, r14, r6 @B + add r10,r10,r14 + + mov r11, #25 @accumilator 1 -= B *25 + mla r7, r10, r11, r7 + + ldr r6, =0x10801080 + add r7, r6 + + lsr r7, #8 + strb r7, [r0],#1 + lsr r7,#16 + strb r7, [r0],#1 + @ldmfd sp!, {r14} @load r14 + + + @----------------------------------pDstRGB2--UV------------------------------------------ + + mov r10, r9 @copy to r10 + ldr r7,=0x00008080 + mov r12,r7 + + ldr r6, =0x000000FF + and r10, r10, r6 @B: + + mov r11, #112 @accumilator += B*112 + mla r7, r10, r11, r7 + + + mov r11, #18 @accumilator -= B*18 + mul r11, r10, r11 + sub r12, r12, r11 + + + + + mov r10, r9, lsr #16 @copy to r10 + ldr r6, =0x000000FF + and r10, r10, r6 @R: (rgbIn[k] & 0xF800) >> 10; + + mov r11, #38 @accumilator -= R *38 + mul r11, r10, r11 + sub r7, r7, r11 + + mov r11, #112 @accumilator = R *112 + mla r12, r10, r11, r12 + + mov r10, r9,lsr #8 @copy to r10 + ldr r6, =0x000000FF + and r10, r10, r6 @G: (rgbIn[k] & 0x07E0) >> 5; + + mov r11, #74 @accumilator -= G*74 + mul r11, r10, r11 + sub r7, r7, r11 + + mov r11, #94 @accumilator -= G*94 + mul r11, r10, r11 + sub r12, r12, r11 + + lsr r7, #8 @ >>8 + strb r7, [r1],#1 + lsr r12, #8 @ >>8 + strb r12, [r1],#1 + + @----------------------------------pDstRGB2--Y------------------------------------------ + @stmfd sp!, {r14} @backup r14 + + + ldr r9, [r5], #4 @loadRGB int + ldr r12, [r5], #4 @loadRGB int + + mov r10, r9,lsr #16 @copy to r10 + mov r14, r12 @copy to r10 + + ldr r6, =0x000000FF + and r10, r10, r6 @R: (rgbIn[k] & 0xF800) >> 10; + ldr r6, =0x00FF0000 + and r14, r14, r6 @R: (rgbIn[k] & 0xF800) >> 10; + add r10,r10,r14 + + mov r11, #66 @accumilator += R*66 + mul r7, r10, r11 + + mov r10, r9,lsr #8 @copy to r10 + mov r14, r12,lsl #8 @copy to r10 + + ldr r6, =0x000000FF + and r10, r10, r6 @G: + ldr r6, =0x00FF0000 + and r14, r14, r6 @G: + add r10,r10,r14 + + mov r11, #129 @accumilator += G *129 + mla r7, r10, r11, r7 + + mov r10, r9 @copy to r10 + mov r14, r12,lsl #16 @copy to r10 + + ldr r6, =0x000000FF + and r10, r10, r6 @B + ldr r6, =0x00FF0000 + and r14, r14, r6 @B + add r10,r10,r14 + + + + + mov r11, #25 @accumilator 1 -= B *25 + mla r7, r10, r11, r7 + + ldr r6, =0x10801080 + add r7, r6 + lsr r7, #8 + + strb r7, [r4],#1 + lsr r7,#16 + strb r7, [r4],#1 + @ldmfd sp!, {r14} @load r14 + + + subs r8,r8,#2 @ nWidth2 -= 2 + BGT LOOP_NWIDTH2 @ if nWidth2>0 + + +NO_UNALIGNED: @in case that nWidht is multiple of 16 + + @----------------------------------------------------------------------------- + sub r8, r3, #16 @r8: nWidthTmp = nWidth -16 + add r0, r0, r3 @pDstY + nwidth + add r2, r2, r3, lsl #2 @pSrcRGB + nwidthx4 + add r4, r4, r3 @pDstY2 + nwidth + add r5, r5, r3, lsl #2 @pSrcRGB2 + nwidthx4 + + ldmfd sp!, {r12} + subs r12,r12,#2 @nHeight -=2 + BGT LOOP_NHEIGHT2 @if nHeight2>0 + + ldmfd sp!, {r4-r12,pc} @ backup registers + .fnend diff --git a/libswconverter/csc_RGBA8888_to_YUV420SP_NEON.s b/libswconverter/csc_RGBA8888_to_YUV420SP_NEON.s new file mode 100755 index 0000000..92c2d58 --- /dev/null +++ b/libswconverter/csc_RGBA8888_to_YUV420SP_NEON.s @@ -0,0 +1,388 @@ + + .arch armv7-a + .text + .global csc_RGBA8888_to_YUV420SP_NEON + .type csc_RGBA8888_to_YUV420SP_NEON, %function +csc_RGBA8888_to_YUV420SP_NEON: + .fnstart + + @r0 pDstY + @r1 pDstUV + @r2 pSrcRGB + @r3 nWidth + @r4 pDstY2 = pDstY + nWidth + @r5 pSrcRGB2 = pSrcRGB + nWidthx2 + @r6 temp7, nWidth16m + @r7 temp6, accumilator + @r8 temp5, nWidthTemp + @r9 temp4, Raw RGB565 + @r10 temp3, r,g,b + @r11 temp2, immediate operand + @r12 temp1, nHeight + @r14 temp0, debugging pointer + + .equ CACHE_LINE_SIZE, 32 + .equ PRE_LOAD_OFFSET, 6 + + stmfd sp!, {r4-r12,r14} @ backup registers + ldr r12, [sp, #40] @ load nHeight + @ldr r14, [sp, #44] @ load pTest + add r4, r0, r3 @r4: pDstY2 = pDstY + nWidth + add r5, r2, r3, lsl #2 @r5: pSrcRGB2 = tmpSrcRGB + nWidthx4 + sub r8, r3, #16 @r8: nWidthTmp = nWidth -16 + + @q0: temp1, R + @q1: temp2, GB + @q2: R + @q3: G + @q4: B + @q5: temp3, output + + + vmov.u16 q6, #66 @coefficient assignment + vmov.u16 q7, #129 + vmov.u16 q8, #25 + vmov.u16 q9, #0x8080 @ 128<<8 + 128 + + vmov.u16 q10, #0x1000 @ 16<<8 + 128 + vorr.u16 q10, #0x0080 + + vmov.u16 q11, #38 @#-38 + vmov.u16 q12, #74 @#-74 + vmov.u16 q13, #112 + vmov.u16 q14, #94 @#-94 + vmov.u16 q15, #18 @#-18 + + + + +LOOP_NHEIGHT2: + stmfd sp!, {r12} @ backup registers + +LOOP_NWIDTH16: + pld [r2, #(CACHE_LINE_SIZE*PRE_LOAD_OFFSET)] + @-------------------------------------------YUV ------------------------------------------ + vmov.u16 q14, #94 @#94 + vmov.u16 q15, #18 @#18 + vld4.8 {d0,d1,d2,d3}, [r2]! @loadRGB interleavely + vld4.8 {d4,d5,d6,d7}, [r2]! @loadRGB interleavely + + + @vmov.u16 d8,d2 + @vmov.u16 d9,d6 + @vmov.u16 d10,d1 + @vmov.u16 d11,d5 + @vmov.u16 d12,d0 + @vmov.u16 d13,d4 + vmov.u16 d8,d0 + vmov.u16 d9,d4 + vmov.u16 d10,d1 + vmov.u16 d11,d5 + vmov.u16 d12,d2 + vmov.u16 d13,d6 + + vand.u16 q4,#0x00FF @R + vand.u16 q5,#0x00FF @G + vand.u16 q6,#0x00FF @B + + vmov.u16 q8,q9 @ CalcU() + vmla.u16 q8,q6,q13 @112 * B[k] + vmls.u16 q8,q4,q11 @q0:U -(38 * R[k]) @128<<6+ 32 + u>>2 + vmls.u16 q8,q5,q12 @-(74 * G[k]) + vshr.u16 q8,q8, #8 @(128<<8+ 128 + u)>>8 + + vmov.u16 q7,q9 @CalcV() + vmla.u16 q7,q4,q13 @112 * R[k] + vmls.u16 q7,q5,q14 @q0:U -(94 * G[k]) @128<<6+ 32 + v>>2 + vmls.u16 q7,q6,q15 @-(18 * B[k]) + vshr.u16 q7,q7, #8 @(128<<8+ 128 + v)>>8 + + + vtrn.8 q8,q7 + vst1.8 {q8}, [r1]! @write UV component to yuv420_buffer+linear_ylanesiez + + @-------------------------------------------Y ------------------------------------------ + + vmov.u16 q14, #66 @#66 + vmov.u16 q15, #129 @#129 + vmov.u16 q8, #25 @#25 + + @CalcY_Y() + + vmul.u16 q7,q4,q14 @q0 = 66 *R[k] + vmla.u16 q7,q5,q15 @q0 += 129 *G[k] + vmla.u16 q7,q6,q8 @q0 += 25 *B[k] + + vadd.u16 q7,q7,q10 + vshr.u16 q7,q7, #8 + + @vmov.u16 d8,d2 + @vmov.u16 d9,d6 + @vmov.u16 d10,d1 + @vmov.u16 d11,d5 + @vmov.u16 d12,d0 + @vmov.u16 d13,d4 + vmov.u16 d8,d0 + vmov.u16 d9,d4 + vmov.u16 d10,d1 + vmov.u16 d11,d5 + vmov.u16 d12,d2 + vmov.u16 d13,d6 + + vshr.u16 q4,q4,#8 @R + vshr.u16 q5,q5,#8 @G + vshr.u16 q6,q6,#8 @B + + vmul.u16 q0,q4,q14 @q0 = 66 *R[k] + vmla.u16 q0,q5,q15 @q0 += 129 *G[k] + vmla.u16 q0,q6,q8 @q0 += 25 *B[k] + vadd.u16 q0,q0,q10 + vshr.u16 q0,q0, #8 + + vtrn.8 q7,q0 + vst1.8 {q7}, [r0]!@write to Y to yuv420_buffer + + + + @-------------------------------------------Y ------------------------------------------ + + @---------------------------------------------Y1------------------------------------------- + + pld [r5, #(CACHE_LINE_SIZE*PRE_LOAD_OFFSET)] + vld4.8 {d0,d1,d2,d3}, [r5]! @loadRGB interleavely + vld4.8 {d4,d5,d6,d7}, [r5]! @loadRGB interleavely + + @vmov.u16 d8,d2 + @vmov.u16 d9,d6 + @vmov.u16 d10,d1 + @vmov.u16 d11,d5 + @vmov.u16 d12,d0 + @vmov.u16 d13,d4 + vmov.u16 d8,d0 + vmov.u16 d9,d4 + vmov.u16 d10,d1 + vmov.u16 d11,d5 + vmov.u16 d12,d2 + vmov.u16 d13,d6 + + vand.u16 q4,#0x00FF @R + vand.u16 q5,#0x00FF @G + vand.u16 q6,#0x00FF @B + + + + vmul.u16 q7,q4,q14 @q0 = 66 *R[k] + vmla.u16 q7,q5,q15 @q0 += 129 *G[k] + vmla.u16 q7,q6,q8 @q0 += 25 *B[k] + vadd.u16 q7,q7,q10 + vshr.u16 q7,q7, #8 + + @vmov.u16 d8,d2 + @vmov.u16 d9,d6 + @vmov.u16 d10,d1 + @vmov.u16 d11,d5 + @vmov.u16 d12,d0 + @vmov.u16 d13,d4 + vmov.u16 d8,d0 + vmov.u16 d9,d4 + vmov.u16 d10,d1 + vmov.u16 d11,d5 + vmov.u16 d12,d2 + vmov.u16 d13,d6 + + vshr.u16 q4,q4,#8 @R + vshr.u16 q5,q5,#8 @G + vshr.u16 q6,q6,#8 @B + + vmul.u16 q0,q4,q14 @q0 = 66 *R[k] + vmla.u16 q0,q5,q15 @q0 += 129 *G[k] + vmla.u16 q0,q6,q8 @q0 += 25 *B[k] + vadd.u16 q0,q0,q10 + vshr.u16 q0,q0, #8 + + vtrn.8 q7,q0 + vst1.8 {q7}, [r4]!@write to Y to yuv420_buffer + + subs r8,r8,#16 @nWidth16-- + BPL LOOP_NWIDTH16 @if nWidth16>0 + @-----------------------------------unaligned --------------------------------------- + + adds r8,r8,#16 @ + 16 - 2 + BEQ NO_UNALIGNED @in case that nWidht is multiple of 16 +LOOP_NWIDTH2: + @----------------------------------pDstRGB1--Y------------------------------------------ + @stmfd sp!, {r14} @backup r14 + + + ldr r9, [r2], #4 @loadRGB int + ldr r12, [r2], #4 @loadRGB int + + mov r10, r9,lsr #16 @copy to r10 + mov r14, r12 @copy to r10 + + ldr r6, =0x000000FF + and r10, r10, r6 @R: (rgbIn[k] & 0xF800) >> 10; + ldr r6, =0x00FF0000 + and r14, r14, r6 @R: (rgbIn[k] & 0xF800) >> 10; + add r10,r10,r14 + + mov r11, #66 @accumilator += R*66 + mul r7, r10, r11 + + mov r10, r9,lsr #8 @copy to r10 + mov r14, r12,lsl #8 @copy to r10 + + ldr r6, =0x000000FF + and r10, r10, r6 @G: + ldr r6, =0x00FF0000 + and r14, r14, r6 @G: + add r10,r10,r14 + + mov r11, #129 @accumilator += G *129 + mla r7, r10, r11, r7 + + mov r10, r9 @copy to r10 + mov r14, r12,lsl #16 @copy to r10 + + ldr r6, =0x000000FF + and r10, r10, r6 @B + ldr r6, =0x00FF0000 + and r14, r14, r6 @B + add r10,r10,r14 + + mov r11, #25 @accumilator 1 -= B *25 + mla r7, r10, r11, r7 + + ldr r6, =0x10801080 + add r7, r6 + + lsr r7, #8 + strb r7, [r0],#1 + lsr r7,#16 + strb r7, [r0],#1 + @ldmfd sp!, {r14} @load r14 + + + @----------------------------------pDstRGB2--UV------------------------------------------ + + mov r10, r9 @copy to r10 + ldr r7,=0x00008080 + mov r12,r7 + + ldr r6, =0x000000FF + and r10, r10, r6 @B: + + mov r11, #112 @accumilator += B*112 + mla r7, r10, r11, r7 + + + mov r11, #18 @accumilator -= B*18 + mul r11, r10, r11 + sub r12, r12, r11 + + + + + mov r10, r9, lsr #16 @copy to r10 + ldr r6, =0x000000FF + and r10, r10, r6 @R: (rgbIn[k] & 0xF800) >> 10; + + mov r11, #38 @accumilator -= R *38 + mul r11, r10, r11 + sub r7, r7, r11 + + mov r11, #112 @accumilator = R *112 + mla r12, r10, r11, r12 + + mov r10, r9,lsr #8 @copy to r10 + ldr r6, =0x000000FF + and r10, r10, r6 @G: (rgbIn[k] & 0x07E0) >> 5; + + mov r11, #74 @accumilator -= G*74 + mul r11, r10, r11 + sub r7, r7, r11 + + mov r11, #94 @accumilator -= G*94 + mul r11, r10, r11 + sub r12, r12, r11 + + lsr r7, #8 @ >>8 + strb r7, [r1],#1 + lsr r12, #8 @ >>8 + strb r12, [r1],#1 + + @----------------------------------pDstRGB2--Y------------------------------------------ + @stmfd sp!, {r14} @backup r14 + + + ldr r9, [r5], #4 @loadRGB int + ldr r12, [r5], #4 @loadRGB int + + mov r10, r9,lsr #16 @copy to r10 + mov r14, r12 @copy to r10 + + ldr r6, =0x000000FF + and r10, r10, r6 @R: (rgbIn[k] & 0xF800) >> 10; + ldr r6, =0x00FF0000 + and r14, r14, r6 @R: (rgbIn[k] & 0xF800) >> 10; + add r10,r10,r14 + + mov r11, #66 @accumilator += R*66 + mul r7, r10, r11 + + mov r10, r9,lsr #8 @copy to r10 + mov r14, r12,lsl #8 @copy to r10 + + ldr r6, =0x000000FF + and r10, r10, r6 @G: + ldr r6, =0x00FF0000 + and r14, r14, r6 @G: + add r10,r10,r14 + + mov r11, #129 @accumilator += G *129 + mla r7, r10, r11, r7 + + mov r10, r9 @copy to r10 + mov r14, r12,lsl #16 @copy to r10 + + ldr r6, =0x000000FF + and r10, r10, r6 @B + ldr r6, =0x00FF0000 + and r14, r14, r6 @B + add r10,r10,r14 + + + + + mov r11, #25 @accumilator 1 -= B *25 + mla r7, r10, r11, r7 + + ldr r6, =0x10801080 + add r7, r6 + lsr r7, #8 + + strb r7, [r4],#1 + lsr r7,#16 + strb r7, [r4],#1 + @ldmfd sp!, {r14} @load r14 + + + subs r8,r8,#2 @ nWidth2 -= 2 + BGT LOOP_NWIDTH2 @ if nWidth2>0 + + +NO_UNALIGNED: @in case that nWidht is multiple of 16 + + @----------------------------------------------------------------------------- + sub r8, r3, #16 @r8: nWidthTmp = nWidth -16 + add r0, r0, r3 @pDstY + nwidth + add r2, r2, r3, lsl #2 @pSrcRGB + nwidthx4 + add r4, r4, r3 @pDstY2 + nwidth + add r5, r5, r3, lsl #2 @pSrcRGB2 + nwidthx4 + + ldmfd sp!, {r12} + subs r12,r12,#2 @nHeight -=2 + BGT LOOP_NHEIGHT2 @if nHeight2>0 + + ldmfd sp!, {r4-r12,pc} @ backup registers + .fnend diff --git a/libswconverter/csc_interleave_memcpy_neon.s b/libswconverter/csc_interleave_memcpy_neon.s new file mode 100755 index 0000000..1ab25b6 --- /dev/null +++ b/libswconverter/csc_interleave_memcpy_neon.s @@ -0,0 +1,120 @@ +/* + * + * Copyright 2012 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_linear_to_tiled_crop_neon.s + * @brief SEC_OMX specific define + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2012.02.01 : Create + */ + +/* + * Interleave src1, src2 to dst + * + * @param dest + * dst address[out] + * + * @param src1 + * src1 address[in] + * + * @param src2 + * src2 address[in] + * + * @param src_size + * src_size or src1 + */ + + .arch armv7-a + .text + .global csc_interleave_memcpy_neon + .type csc_interleave_memcpy_neon, %function +csc_interleave_memcpy_neon: + .fnstart + + @r0 dest + @r1 src1 + @r2 src2 + @r3 src_size + @r4 + @r5 + @r6 + @r7 + @r8 temp1 + @r9 temp2 + @r10 dest_addr + @r11 src1_addr + @r12 src2_addr + @r14 i + + stmfd sp!, {r8-r12,r14} @ backup registers + + mov r10, r0 + mov r11, r1 + mov r12, r2 + mov r14, r3 + + cmp r14, #128 + blt LESS_THAN_128 + +LOOP_128: + vld1.8 {q0}, [r11]! + vld1.8 {q2}, [r11]! + vld1.8 {q4}, [r11]! + vld1.8 {q6}, [r11]! + vld1.8 {q8}, [r11]! + vld1.8 {q10}, [r11]! + vld1.8 {q12}, [r11]! + vld1.8 {q14}, [r11]! + vld1.8 {q1}, [r12]! + vld1.8 {q3}, [r12]! + vld1.8 {q5}, [r12]! + vld1.8 {q7}, [r12]! + vld1.8 {q9}, [r12]! + vld1.8 {q11}, [r12]! + vld1.8 {q13}, [r12]! + vld1.8 {q15}, [r12]! + + vst2.8 {q0, q1}, [r10]! + vst2.8 {q2, q3}, [r10]! + vst2.8 {q4, q5}, [r10]! + vst2.8 {q6, q7}, [r10]! + vst2.8 {q8, q9}, [r10]! + vst2.8 {q10, q11}, [r10]! + vst2.8 {q12, q13}, [r10]! + vst2.8 {q14, q15}, [r10]! + + sub r14, #128 + cmp r14, #128 + bgt LOOP_128 + +LESS_THAN_128: + cmp r14, #0 + beq RESTORE_REG + +LOOP_1: + ldrb r8, [r11], #1 + ldrb r9, [r12], #1 + strb r8, [r10], #1 + strb r9, [r10], #1 + subs r14, #1 + bne LOOP_1 + +RESTORE_REG: + ldmfd sp!, {r8-r12,r15} @ restore registers + .fnend diff --git a/libswconverter/csc_linear_to_tiled_crop_neon.s b/libswconverter/csc_linear_to_tiled_crop_neon.s new file mode 100755 index 0000000..8f59826 --- /dev/null +++ b/libswconverter/csc_linear_to_tiled_crop_neon.s @@ -0,0 +1,492 @@ +/* + * + * Copyright 2012 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_linear_to_tiled_crop_neon.s + * @brief SEC_OMX specific define + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2012.02.01 : Create + */ + +/* + * Converts linear data to tiled + * Crops left, top, right, buttom + * 1. Y of YUV420P to Y of NV12T + * 2. Y of YUV420S to Y of NV12T + * 3. UV of YUV420S to UV of NV12T + * + * @param nv12t_dest + * Y or UV plane address of NV12T[out] + * + * @param yuv420_src + * Y or UV plane address of YUV420P(S)[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left. It should be even. + * + * @param top + * Crop size of top. It should be even. + * + * @param right + * Crop size of right. It should be even. + * + * @param buttom + * Crop size of buttom. It should be even. + */ + + .arch armv7-a + .text + .global csc_linear_to_tiled_crop_neon + .type csc_linear_to_tiled_crop_neon, %function +csc_linear_to_tiled_crop_neon: + .fnstart + + @r0 tiled_dest + @r1 linear_src + @r2 yuv420_width + @r3 yuv420_height + @r4 j + @r5 i + @r6 nn(tiled_addr) + @r7 mm(linear_addr) + @r8 aligned_x_size + @r9 aligned_y_size + @r10 temp1 + @r11 temp2 + @r12 temp3 + @r14 temp4 + + stmfd sp!, {r4-r12,r14} @ backup registers + + ldr r11, [sp, #44] @ top + ldr r14, [sp, #52] @ buttom + ldr r10, [sp, #40] @ left + ldr r12, [sp, #48] @ right + + sub r9, r3, r11 @ aligned_y_size = ((yuv420_height-top-buttom)>>5)<<5 + sub r9, r9, r14 + bic r9, r9, #0x1F + + sub r8, r2, r10 @ aligned_x_size = ((yuv420_width-left-right)>>6)<<6 + sub r8, r8, r12 + bic r8, r8, #0x3F + + mov r5, #0 @ i = 0 +LOOP_ALIGNED_Y_SIZE: + + mov r4, #0 @ j = 0 +LOOP_ALIGNED_X_SIZE: + + bl GET_TILED_OFFSET + + ldr r10, [sp, #44] @ r10 = top + ldr r14, [sp, #40] @ r14 = left + add r10, r5, r10 @ temp1 = linear_x_size*(i+top) + mul r10, r2, r10 + add r7, r1, r4 @ linear_addr = linear_src+j + add r7, r7, r10 @ linear_addr = linear_addr+temp1 + add r7, r7, r14 @ linear_addr = linear_addr+left + sub r10, r2, #32 + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*1, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*2, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + pld [r7, r2] + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*3, 64} + pld [r7, r2] + vld1.8 {q14, q15}, [r7], r10 + add r6, r0, r6 @ tiled_addr = tiled_dest+tiled_addr + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*1} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*2} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*3} + vst1.8 {q14, q15}, [r6]! + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src+linear_x_size*4, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*5, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*6, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + pld [r7, r2] + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*7, 64} + pld [r7, r2] + vld1.8 {q14, q15}, [r7], r10 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr+64*4} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*5} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*6} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*7} + vst1.8 {q14, q15}, [r6]! + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src+linear_x_size*8, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*9, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*10, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + pld [r7, r2] + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*11, 64} + pld [r7, r2] + vld1.8 {q14, q15}, [r7], r10 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr+64*8} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*9} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*10} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*11} + vst1.8 {q14, q15}, [r6]! + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src+linear_x_size*12, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*13, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*14, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + pld [r7, r2] + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*15, 64} + pld [r7, r2] + vld1.8 {q14, q15}, [r7], r10 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr+64*12} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*13} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*14} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*15} + vst1.8 {q14, q15}, [r6]! + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src+linear_x_size*16, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*17, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*18, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + pld [r7, r2] + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*19, 64} + pld [r7, r2] + vld1.8 {q14, q15}, [r7], r10 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr+64*16} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*17} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*18} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*19} + vst1.8 {q14, q15}, [r6]! + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src+linear_x_size*20, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*21, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*22, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + pld [r7, r2] + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*23, 64} + pld [r7, r2] + vld1.8 {q14, q15}, [r7], r10 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr+64*20} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*21} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*22} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*23} + vst1.8 {q14, q15}, [r6]! + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src+linear_x_size*24, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*25, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*26, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + pld [r7, r2] + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*27, 64} + pld [r7, r2] + vld1.8 {q14, q15}, [r7], r10 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr+64*24} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*25} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*26} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*27} + vst1.8 {q14, q15}, [r6]! + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src+linear_x_size*28, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*29, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*30, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*31, 64} + vld1.8 {q14, q15}, [r7], r10 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr+64*28} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*29} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*30} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*31} + vst1.8 {q14, q15}, [r6]! + + add r4, r4, #64 @ j = j+64 + cmp r4, r8 @ j<aligned_x_size + blt LOOP_ALIGNED_X_SIZE + + add r5, r5, #32 @ i = i+32 + cmp r5, r9 @ i<aligned_y_size + blt LOOP_ALIGNED_Y_SIZE + + ldr r10, [sp, #44] @ r10 = top + ldr r11, [sp, #52] @ r11 = buttom + sub r10, r3, r10 + sub r10, r10, r11 + cmp r5, r10 @ i == (yuv420_height-top-buttom) + beq LOOP_LINEAR_Y_SIZE_2_START + +LOOP_LINEAR_Y_SIZE_1: + + mov r4, #0 @ j = 0 +LOOP_ALIGNED_X_SIZE_1: + + bl GET_TILED_OFFSET + + ldr r10, [sp, #44] @ r10 = top + ldr r14, [sp, #40] @ r14 = left + add r10, r5, r10 @ temp1 = yuv420_width*(i+top) + mul r10, r2, r10 + add r7, r1, r4 @ linear_addr = linear_src+j + add r7, r7, r10 @ linear_addr = linear_addr+temp1 + add r7, r7, r14 @ linear_addr = linear_addr+left + sub r10, r2, #32 @ temp1 = yuv420_width-32 + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*1, 64} + vld1.8 {q6, q7}, [r7] + add r6, r0, r6 @ tiled_addr = tiled_dest+tiled_addr + and r10, r5, #0x1F @ temp1 = i&0x1F + mov r10, r10, lsl #6 @ temp1 = 64*temp1 + add r6, r6, r10 @ tiled_addr = tiled_addr+temp1 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*1} + vst1.8 {q6, q7}, [r6]! + + add r4, r4, #64 @ j = j+64 + cmp r4, r8 @ j<aligned_x_size + blt LOOP_ALIGNED_X_SIZE_1 + + add r5, r5, #2 @ i = i+2 + ldr r10, [sp, #44] @ r10 = top + ldr r14, [sp, #52] @ r14 = buttom + sub r10, r3, r10 + sub r10, r10, r14 + cmp r5, r10 @ i<yuv420_height-top-buttom + blt LOOP_LINEAR_Y_SIZE_1 + +LOOP_LINEAR_Y_SIZE_2_START: + ldr r10, [sp, #40] @ r10 = left + ldr r11, [sp, #48] @ r11 = right + sub r10, r2, r10 + sub r10, r10, r11 + cmp r8, r10 @ aligned_x_size == (yuv420_width-left-right) + beq RESTORE_REG + + mov r5, #0 @ i = 0 +LOOP_LINEAR_Y_SIZE_2: + + mov r4, r8 @ j = aligned_x_size +LOOP_LINEAR_X_SIZE_2: + + bl GET_TILED_OFFSET + + ldr r10, [sp, #44] @ r14 = top + ldr r14, [sp, #40] @ r10 = left + add r10, r5, r10 + mul r10, r2, r10 @ temp1 = linear_x_size*(i+top) + add r7, r1, r4 @ linear_addr = linear_src+j + add r7, r7, r10 @ linear_addr = linear_addr+temp1 + add r7, r7, r14 @ linear_addr = linear_addr+left + + add r6, r0, r6 @ tiled_addr = tiled_dest+tiled_addr + and r11, r5, #0x1F @ temp2 = i&0x1F + mov r11, r11, lsl #6 @ temp2 = 64*temp2 + add r6, r6, r11 @ tiled_addr = tiled_addr+temp2 + and r11, r4, #0x3F @ temp2 = j&0x3F + add r6, r6, r11 @ tiled_addr = tiled_addr+temp2 + + ldrh r10, [r7], r2 + ldrh r11, [r7] + strh r10, [r6], #64 + strh r11, [r6] + + ldr r12, [sp, #40] @ r12 = left + ldr r14, [sp, #48] @ r14 = right + add r4, r4, #2 @ j = j+2 + sub r12, r2, r12 + sub r12, r12, r14 + cmp r4, r12 @ j<(yuv420_width-left-right) + blt LOOP_LINEAR_X_SIZE_2 + + ldr r12, [sp, #44] @ r12 = top + ldr r14, [sp, #52] @ r14 = buttom + add r5, r5, #2 @ i = i+2 + sub r12, r3, r12 + sub r12, r12, r14 + cmp r5, r12 @ i<(yuv420_height-top-buttom) + blt LOOP_LINEAR_Y_SIZE_2 + +RESTORE_REG: + ldmfd sp!, {r4-r12,r15} @ restore registers + +GET_TILED_OFFSET: + + mov r11, r5, asr #5 @ temp2 = i>>5 + mov r10, r4, asr #6 @ temp1 = j>>6 + + and r12, r11, #0x1 @ if (temp2 & 0x1) + cmp r12, #0x1 + bne GET_TILED_OFFSET_EVEN_FORMULA_1 + +GET_TILED_OFFSET_ODD_FORMULA: + sub r6, r11, #1 @ tiled_addr = temp2-1 + + ldr r7, [sp, #40] @ left + add r12, r2, #127 @ temp3 = linear_x_size+127 + sub r12, r12, r7 + ldr r7, [sp, #48] @ right + sub r12, r12, r7 + bic r12, r12, #0x7F @ temp3 = (temp3 >>7)<<7 + mov r12, r12, asr #6 @ temp3 = temp3>>6 + mul r6, r6, r12 @ tiled_addr = tiled_addr*temp3 + add r6, r6, r10 @ tiled_addr = tiled_addr+temp1 + add r6, r6, #2 @ tiled_addr = tiled_addr+2 + bic r12, r10, #0x3 @ temp3 = (temp1>>2)<<2 + add r6, r6, r12 @ tiled_addr = tiled_addr+temp3 + mov r6, r6, lsl #11 @ tiled_addr = tiled_addr<<11 + b GET_TILED_OFFSET_RETURN + +GET_TILED_OFFSET_EVEN_FORMULA_1: + ldr r7, [sp, #44] @ top + add r12, r3, #31 @ temp3 = linear_y_size+31 + sub r12, r12, r7 + ldr r7, [sp, #52] @ buttom + sub r12, r12, r7 + bic r12, r12, #0x1F @ temp3 = (temp3>>5)<<5 + sub r12, r12, #32 @ temp3 = temp3 - 32 + cmp r5, r12 @ if (i<(temp3-32)) { + bge GET_TILED_OFFSET_EVEN_FORMULA_2 + add r12, r10, #2 @ temp3 = temp1+2 + bic r12, r12, #3 @ temp3 = (temp3>>2)<<2 + add r6, r10, r12 @ tiled_addr = temp1+temp3 + ldr r7, [sp, #40] @ left + add r12, r2, #127 @ temp3 = linear_x_size+127 + sub r12, r12, r7 + ldr r7, [sp, #48] @ right + sub r12, r12, r7 + bic r12, r12, #0x7F @ temp3 = (temp3>>7)<<7 + mov r12, r12, asr #6 @ temp3 = temp3>>6 + mul r11, r11, r12 @ tiled_y_index = tiled_y_index*temp3 + add r6, r6, r11 @ tiled_addr = tiled_addr+tiled_y_index + mov r6, r6, lsl #11 @ + b GET_TILED_OFFSET_RETURN + +GET_TILED_OFFSET_EVEN_FORMULA_2: + ldr r7, [sp, #40] @ left + add r12, r2, #127 @ temp3 = linear_x_size+127 + sub r12, r12, r7 + ldr r7, [sp, #48] @ right + sub r12, r12, r7 + bic r12, r12, #0x7F @ temp3 = (temp3>>7)<<7 + mov r12, r12, asr #6 @ temp3 = temp3>>6 + mul r6, r11, r12 @ tiled_addr = temp2*temp3 + add r6, r6, r10 @ tiled_addr = tiled_addr+temp3 + mov r6, r6, lsl #11 @ tiled_addr = tiled_addr<<11@ + +GET_TILED_OFFSET_RETURN: + mov pc, lr + + .fnend diff --git a/libswconverter/csc_linear_to_tiled_interleave_crop_neon.s b/libswconverter/csc_linear_to_tiled_interleave_crop_neon.s new file mode 100755 index 0000000..33a31da --- /dev/null +++ b/libswconverter/csc_linear_to_tiled_interleave_crop_neon.s @@ -0,0 +1,563 @@ +/* + * + * Copyright 2012 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_linear_to_tiled_interleave_crop_neon.s + * @brief SEC_OMX specific define + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2012.02.01 : Create + */ + +/* + * Converts tiled data to linear + * Crops left, top, right, buttom + * 1. Y of NV12T to Y of YUV420P + * 2. Y of NV12T to Y of YUV420S + * 3. UV of NV12T to UV of YUV420S + * + * @param yuv420_dest + * Y or UV plane address of YUV420[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left. It should be even. + * + * @param top + * Crop size of top. It should be even. + * + * @param right + * Crop size of right. It should be even. + * + * @param buttom + * Crop size of buttom. It should be even. + */ + + .arch armv7-a + .text + .global csc_linear_to_tiled_interleave_crop_neon + .type csc_linear_to_tiled_interleave_crop_neon, %function +csc_linear_to_tiled_interleave_crop_neon: + .fnstart + + @r0 tiled_dest + @r1 linear_src_u + @r2 linear_src_v + @r3 yuv420_width + @r4 yuv420_height + @r5 j + @r6 i + @r7 tiled_addr + @r8 linear_addr + @r9 aligned_x_size + @r10 aligned_y_size + @r11 temp1 + @r12 temp2 + @r14 temp3 + + stmfd sp!, {r4-r12,r14} @ backup registers + + ldr r4, [sp, #40] @ load linear_y_size to r4 + + ldr r10, [sp, #48] @ r10 = top + ldr r14, [sp, #56] @ r14 = buttom + ldr r11, [sp, #44] @ r11 = left + ldr r12, [sp, #52] @ r12 = right + + sub r10, r4, r10 @ aligned_y_size = ((yuv420_height-top-buttom)>>5)<<5 + sub r10, r10, r14 + bic r10, r10, #0x1F + sub r11, r3, r11 @ aligned_x_size = ((yuv420_width-left-right)>>6)<<6 + sub r11, r11, r12 + bic r9, r11, #0x3F + + mov r6, #0 @ i = 0 +LOOP_ALIGNED_Y_SIZE: + + mov r5, #0 @ j = 0 +LOOP_ALIGNED_X_SIZE: + + bl GET_TILED_OFFSET + + ldr r12, [sp, #48] @ r12 = top + ldr r8, [sp, #44] @ r8 = left + + mov r11, r3, asr #1 @ temp1 = (yuv420_width/2)*(i+top) + add r12, r6, r12 + mul r11, r11, r12 + add r11, r11, r5, asr #1 @ temp1 = temp1+j/2 + add r11, r11, r8, asr #1 @ temp1 = temp1+left/2 + + mov r12, r3, asr #1 @ temp2 = yuv420_width/2 + sub r12, r12, #16 @ temp2 = yuv420_width-16 + + add r8, r1, r11 @ linear_addr = linear_src_u+temp1 + add r11, r2, r11 @ temp1 = linear_src_v+temp1 + add r7, r0, r7 @ tiled_addr = tiled_dest+tiled_addr + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*1, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*2, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*3, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*1, 32} + vld1.8 {q7}, [r11], r12 + pld [r8] + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*2, 32} + vld1.8 {q11}, [r11], r12 + pld [r8, r3, asr #1] + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*3, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*1} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*2} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*3} + vst2.8 {q14, q15}, [r7]! + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u+(linear_x_size/2)*4, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*5, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*6, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*7, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v+(linear_x_size/2)*4, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*5, 32} + vld1.8 {q7}, [r11], r12 + pld [r8] + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*6, 32} + vld1.8 {q11}, [r11], r12 + pld [r8, r3, asr #1] + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*7, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr+64*4} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*5} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*6} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*7} + vst2.8 {q14, q15}, [r7]! + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u+(linear_x_size/2)*8, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*9, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*10, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*11, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v+(linear_x_size/2)*8, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*9, 32} + vld1.8 {q7}, [r11], r12 + pld [r8] + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*10, 32} + vld1.8 {q11}, [r11], r12 + pld [r8, r3, asr #1] + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*11, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr+64*8} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*9} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*10} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*11} + vst2.8 {q14, q15}, [r7]! + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u+(linear_x_size/2)*12, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*13, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*14, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*15, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v+(linear_x_size/2)*12, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*13, 32} + vld1.8 {q7}, [r11], r12 + pld [r8] + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*14, 32} + vld1.8 {q11}, [r11], r12 + pld [r8, r3, asr #1] + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*15, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr+64*12} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*13} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*14} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*15} + vst2.8 {q14, q15}, [r7]! + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u+(linear_x_size/2)*16, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*17, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*18, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*19, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v+(linear_x_size/2)*16, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*17, 32} + vld1.8 {q7}, [r11], r12 + pld [r8] + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*18, 32} + vld1.8 {q11}, [r11], r12 + pld [r8, r3, asr #1] + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*19, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr+64*16} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*17} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*18} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*19} + vst2.8 {q14, q15}, [r7]! + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u+(linear_x_size/2)*20, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*21, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*22, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*23, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v+(linear_x_size/2)*20, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*21, 32} + vld1.8 {q7}, [r11], r12 + pld [r8] + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*22, 32} + vld1.8 {q11}, [r11], r12 + pld [r8, r3, asr #1] + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*23, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr+64*20} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*21} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*22} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*23} + vst2.8 {q14, q15}, [r7]! + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u+(linear_x_size/2)*24, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*25, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*26, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*27, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v+(linear_x_size/2)*24, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*25, 32} + vld1.8 {q7}, [r11], r12 + pld [r8] + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*26, 32} + vld1.8 {q11}, [r11], r12 + pld [r8, r3, asr #1] + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*27, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr+64*24} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*25} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*26} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*27} + vst2.8 {q14, q15}, [r7]! + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u+(linear_x_size/2)*28, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*29, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*30, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*31, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v+(linear_x_size/2)*28, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*29, 32} + vld1.8 {q7}, [r11], r12 + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*30, 32} + vld1.8 {q11}, [r11], r12 + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*31, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr+64*28} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*29} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*30} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*31} + vst2.8 {q14, q15}, [r7]! + + add r5, r5, #64 @ j = j+64 + cmp r5, r9 @ j<aligned_x_size + blt LOOP_ALIGNED_X_SIZE + + add r6, r6, #32 @ i = i+32 + cmp r6, r10 @ i<aligned_y_size + blt LOOP_ALIGNED_Y_SIZE + + cmp r6, r4 + beq LOOP_LINEAR_Y_SIZE_2_START + +LOOP_LINEAR_Y_SIZE_1: + + mov r5, #0 @ j = 0 +LOOP_ALIGNED_X_SIZE_1: + + bl GET_TILED_OFFSET + + ldr r12, [sp, #48] @ r12 = top + ldr r8, [sp, #44] @ r8 = left + + mov r11, r3, asr #1 @ temp1 = (yuv420_width/2)*(i+top) + add r12, r6, r12 + mul r11, r11, r12 + add r11, r11, r5, asr #1 @ temp1 = temp1+j/2 + add r11, r11, r8, asr #1 @ temp1 = temp1+left/2 + + add r8, r1, r11 @ linear_addr = linear_src_u+temp1 + add r11, r2, r11 @ temp1 = linear_src_v+temp1 + add r7, r0, r7 @ tiled_addr = tiled_dest+tiled_addr + and r14, r6, #0x1F @ temp3 = i&0x1F@ + mov r14, r14, lsl #6 @ temp3 = temp3*64 + add r7, r7, r14 @ tiled_addr = tiled_addr+temp3 + + vld1.8 {q0}, [r8]! @ load {linear_src_u, 32} + vld1.8 {q2}, [r8] + vld1.8 {q1}, [r11]! @ load {linear_src_v, 32} + vld1.8 {q3}, [r11] + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr} + vst2.8 {q2, q3}, [r7]! + + add r5, r5, #64 @ j = j+64 + cmp r5, r9 @ j<aligned_x_size + blt LOOP_ALIGNED_X_SIZE_1 + + ldr r12, [sp, #48] @ r12 = top + ldr r8, [sp, #56] @ r8 = buttom + add r6, r6, #1 @ i = i+1 + sub r12, r4, r12 + sub r12, r12, r8 + cmp r6, r12 @ i<(yuv420_height-top-buttom) + blt LOOP_LINEAR_Y_SIZE_1 + +LOOP_LINEAR_Y_SIZE_2_START: + cmp r5, r3 + beq RESTORE_REG + + mov r6, #0 @ i = 0 +LOOP_LINEAR_Y_SIZE_2: + + mov r5, r9 @ j = aligned_x_size +LOOP_LINEAR_X_SIZE_2: + + bl GET_TILED_OFFSET + + ldr r12, [sp, #48] @ r12 = top + ldr r8, [sp, #44] @ r8 = left + + mov r11, r3, asr #1 @ temp1 = (yuv420_width/2)*(i+top) + add r12, r6, r12 + mul r11, r11, r12 + add r11, r11, r5, asr #1 @ temp1 = temp1+j/2 + add r11, r11, r8, asr #1 @ temp1 = temp1+left/2 + + mov r12, r3, asr #1 @ temp2 = linear_x_size/2 + sub r12, r12, #1 @ temp2 = linear_x_size-1 + + add r8, r1, r11 @ linear_addr = linear_src_u+temp1 + add r11, r2, r11 @ temp1 = linear_src_v+temp1 + add r7, r0, r7 @ tiled_addr = tiled_dest+tiled_addr + and r14, r6, #0x1F @ temp3 = i&0x1F@ + mov r14, r14, lsl #6 @ temp3 = temp3*64 + add r7, r7, r14 @ tiled_addr = tiled_addr+temp3 + and r14, r5, #0x3F @ temp3 = j&0x3F + add r7, r7, r14 @ tiled_addr = tiled_addr+temp3 + + ldrb r10, [r8], #1 + ldrb r14, [r11], #1 + mov r14, r14, lsl #8 + orr r10, r10, r14 + strh r10, [r7], #2 + + ldr r12, [sp, #44] @ r12 = left + ldr r8, [sp, #52] @ r8 = right + add r5, r5, #2 @ j = j+2 + sub r12, r3, r12 + sub r12, r12, r8 + cmp r5, r12 @ j<(yuv420_width-left-right) + blt LOOP_LINEAR_X_SIZE_2 + + ldr r12, [sp, #48] @ r12 = top + ldr r8, [sp, #56] @ r8 = buttom + add r6, r6, #1 @ i = i+1 + sub r12, r4, r12 + sub r12, r12, r8 + cmp r6, r12 @ i<(yuv420_height-top-buttom) + blt LOOP_LINEAR_Y_SIZE_2 + +RESTORE_REG: + ldmfd sp!, {r4-r12,r15} @ restore registers + +GET_TILED_OFFSET: + stmfd sp!, {r14} + + mov r12, r6, asr #5 @ temp2 = i>>5 + mov r11, r5, asr #6 @ temp1 = j>>6 + + and r14, r12, #0x1 @ if (temp2 & 0x1) + cmp r14, #0x1 + bne GET_TILED_OFFSET_EVEN_FORMULA_1 + +GET_TILED_OFFSET_ODD_FORMULA: + + ldr r7, [sp, #48] @ r7 = left , (r14 was pushed to stack) + ldr r8, [sp, #56] @ r8 = right , (r14 was pushed to stack) + sub r14, r3, r7 + sub r14, r14, r8 + add r14, r14, #127 @ temp3 = (((yuv420_width-left-right)+127)>>7)<<7 + bic r14, r14, #0x7F @ temp3 = (temp3 >>7)<<7 + mov r14, r14, asr #6 @ temp3 = temp3>>6 + sub r7, r12, #1 @ tiled_addr = temp2-1 + mul r7, r7, r14 @ tiled_addr = tiled_addr*temp3 + add r7, r7, r11 @ tiled_addr = tiled_addr+temp1 + add r7, r7, #2 @ tiled_addr = tiled_addr+2 + bic r14, r11, #0x3 @ temp3 = (temp1>>2)<<2 + add r7, r7, r14 @ tiled_addr = tiled_addr+temp3 + mov r7, r7, lsl #11 @ tiled_addr = tiled_addr<<11 + b GET_TILED_OFFSET_RETURN + +GET_TILED_OFFSET_EVEN_FORMULA_1: + ldr r7, [sp, #52] @ r7 = top, (r14 was pushed to stack) + ldr r8, [sp, #60] @ r8 = buttom, (r14 was pushed to stack) + sub r14, r4, r7 + sub r14, r14, r8 + add r14, r14, #31 @ temp3 = (((yuv420_height-top-buttom)+31)>>5)<<5 + bic r14, r14, #0x1F @ temp3 = (temp3>>5)<<5 + sub r14, r14, #32 @ temp3 = temp3 - 32 + cmp r6, r14 @ if (i<(temp3-32)) { + bge GET_TILED_OFFSET_EVEN_FORMULA_2 + add r14, r11, #2 @ temp3 = temp1+2 + bic r14, r14, #3 @ temp3 = (temp3>>2)<<2 + add r7, r11, r14 @ tiled_addr = temp1+temp3 + ldr r8, [sp, #48] @ r8 = left, (r14 was pushed to stack) + sub r14, r3, r8 + ldr r8, [sp, #56] @ r8 = right, (r14 was pushed to stack) + sub r14, r14, r8 + add r14, r14, #127 @ temp3 = (((yuv420_width-left-right)+127)>>7)<<7 + bic r14, r14, #0x7F @ temp3 = (temp3>>7)<<7 + mov r14, r14, asr #6 @ temp3 = temp3>>6 + mul r12, r12, r14 @ tiled_y_index = tiled_y_index*temp3 + add r7, r7, r12 @ tiled_addr = tiled_addr+tiled_y_index + mov r7, r7, lsl #11 @ + b GET_TILED_OFFSET_RETURN + +GET_TILED_OFFSET_EVEN_FORMULA_2: + ldr r8, [sp, #48] @ r8 = left, (r14 was pushed to stack) + sub r14, r3, r8 + ldr r8, [sp, #56] @ r8 = right, (r14 was pushed to stack) + sub r14, r14, r8 + add r14, r14, #127 @ temp3 = (((yuv420_width-left-right)+127)>>7)<<7 + bic r14, r14, #0x7F @ temp3 = (temp3>>7)<<7 + mov r14, r14, asr #6 @ temp3 = temp3>>6 + mul r7, r12, r14 @ tiled_addr = temp2*temp3 + add r7, r7, r11 @ tiled_addr = tiled_addr+temp3 + mov r7, r7, lsl #11 @ tiled_addr = tiled_addr<<11@ + +GET_TILED_OFFSET_RETURN: + ldmfd sp!, {r15} @ restore registers + + .fnend + diff --git a/libswconverter/csc_tiled_to_linear_crop_neon.s b/libswconverter/csc_tiled_to_linear_crop_neon.s new file mode 100755 index 0000000..9cb81b5 --- /dev/null +++ b/libswconverter/csc_tiled_to_linear_crop_neon.s @@ -0,0 +1,701 @@ +/* + * + * Copyright 2012 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_tiled_to_linear_crop_neon.s + * @brief SEC_OMX specific define + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2012.02.01 : Create + */ + +/* + * Converts tiled data to linear + * Crops left, top, right, buttom + * 1. Y of NV12T to Y of YUV420P + * 2. Y of NV12T to Y of YUV420S + * 3. UV of NV12T to UV of YUV420S + * + * @param yuv420_dest + * Y or UV plane address of YUV420[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left. It should be even. + * + * @param top + * Crop size of top. It should be even. + * + * @param right + * Crop size of right. It should be even. + * + * @param buttom + * Crop size of buttom. It should be even. + */ + + .arch armv7-a + .text + .global csc_tiled_to_linear_crop_neon + .type csc_tiled_to_linear_crop_neon, %function +csc_tiled_to_linear_crop_neon: + .fnstart + + @r0 yuv420_dest + @r1 nv12t_src + @r2 yuv420_width + @r3 yuv420_height + @r4 + @r5 i + @r6 j + @r7 tiled_offset + @r8 tiled_offset1 + @r9 linear_offset + @r10 temp1 + @r11 temp2 + @r12 temp3 + @r14 temp4 + + stmfd sp!, {r4-r12,r14} @ backup registers + + ldr r12, [sp, #48] @ r12 = right + ldr r10, [sp, #40] @ r10 = left + sub r12, r2, r12 @ temp3 = yuv420_width-right@ + sub r10, r12, r10 @ temp1 = temp3-left@ + cmp r10, #256 @ if (temp1 >= 256) + blt LOOP_HEIGHT_64_START + + ldr r5, [sp, #44] @ i = top +LOOP_HEIGHT_256: + ldr r6, [sp, #40] @ j = left + mov r14, r5, asr #5 @ temp4 = i>>5 + bic r12, r6, #0xFF @ temp3 = (j>>8)<<8 + mov r12, r12, asr #6 @ temp3 = temp3>>6 + and r11, r14, #0x1 @ if (temp4 & 0x1) + cmp r11, #0x1 + bne LOOP_HEIGHT_256_GET_TILED_EVEN +LOOP_HEIGHT_256_GET_TILED_ODD: + sub r7, r14, #1 @ tiled_offset = temp4-1 + add r10, r2, #127 @ temp1 = ((yuv420_width+127)>>7)<<7 + bic r10, r10, #0x7F + mov r10, r10, asr #6 @ tiled_offset = tiled_offset*(temp1>>6) + mul r7, r7, r10 + add r7, r7, r12 @ tiled_offset = tiled_offset+temp3 + add r7, r7, #2 @ tiled_offset = tiled_offset+2 + bic r10, r12, #0x3 @ temp1 = (temp3>>2)<<2 + add r7, r7, r10 @ tiled_offset = tiled_offset+temp1 + mov r7, r7, lsl #11 @ tiled_offset = tiled_offset<<11 + add r8, r7, #4096 @ tiled_offset1 = tiled_offset+2048*2 + mov r14, #8 + b LOOP_HEIGHT_256_GET_TILED_END + +LOOP_HEIGHT_256_GET_TILED_EVEN: + add r11, r3, #31 @ temp2 = ((yuv420_height+31)>>5)<<5 + bic r11, r11, #0x1F + add r10, r5, #32 @ if ((i+32)<temp2) + cmp r10, r11 + bge LOOP_HEIGHT_256_GET_TILED_EVEN1 + add r10, r12, #2 @ temp1 = temp3+2 + bic r10, r10, #0x3 @ temp1 = (temp1>>2)<<2 + add r7, r12, r10 @ tiled_offset = temp3+temp1@ + add r10, r2, #127 @ temp1 = ((yuv420_width+127)>>7)<<7 + bic r10, r10, #0x7F + mov r10, r10, asr #6 @ tiled_offset = tiled_offset+temp4*(temp1>>6) + mla r7, r14, r10, r7 + mov r7, r7, lsl #11 @ tiled_offset = tiled_offset<<11 + add r8, r7, #12288 @ tiled_offset1 = tiled_offset+2048*6 + mov r14, #8 + b LOOP_HEIGHT_256_GET_TILED_END + +LOOP_HEIGHT_256_GET_TILED_EVEN1: + add r10, r2, #127 @ temp1 = ((yuv420_width+127)>>7)<<7 + bic r10, r10, #0x7F + mov r10, r10, asr #6 @ tiled_offset = temp4*(temp1>>6) + mul r7, r14, r10 + add r7, r7, r12 @ tiled_offset = tiled_offset+temp3 + mov r7, r7, lsl #11 @ tiled_offset = tiled_offset<<11 + add r8, r7, #4096 @ tiled_offset1 = tiled_offset+2048*2 + mov r14, #4 + +LOOP_HEIGHT_256_GET_TILED_END: + + ldr r12, [sp, #48] @ right + ldr r9, [sp, #44] @ top + and r10, r5, #0x1F @ temp1 = i&0x1F + add r7, r7, r10, lsl #6 @ tiled_offset = tiled_offset+64*(temp1) + add r8, r8, r10, lsl #6 @ tiled_offset1 = tiled_offset1+64*(temp1) + sub r11, r2, r6 @ temp2 = yuv420_width-left(==j)-right + sub r11, r11, r12 + sub r9, r5, r9 @ linear_offset = temp2*(i-top)@ + mul r9, r11, r9 + add r12, r6, #256 @ temp3 = ((j+256)>>8)<<8@ + bic r12, r12, #0xFF + sub r12, r12, r6 @ temp3 = temp3-j@ + and r10, r6, #0x3F @ temp1 = left(==j)&0x3F + + cmp r12, #192 @ if (temp3 > 192) + ble LOOP_HEIGHT_256_LEFT_192 + add r11, r1, r7 @ r11 = nv12t_src+tiled_offset+temp1 + add r11, r11, r10 + pld [r11] + add r12, r1, r7 @ r12 = nv12t_src+tiled_offset+2048 + pld [r11, #32] + add r12, r12, #2048 + pld [r12] + cmp r10, #0 + pld [r12, #32] + stmnefd sp!, {r9-r12, r14} @ backup registers + rsbne r10, r10, #64 + blne MEMCOPY_UNDER_64 + ldmnefd sp!, {r9-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_256_64 + vld1.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset+temp1, 64} + vld1.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r11]! @ store {yuv420_dest+linear_offset, 64} + vst1.8 {q2, q3}, [r11]! +LOOP_HEIGHT_256_LEFT_256_64: + add r11, r1, r8 @ r11 = nv12t_src+tiled_offset1 + pld [r11] + vld1.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r11, #32] + vld1.8 {q6, q7}, [r12] + add r12, r11, #2048 @ r12 = nv12t_src+tiled_offset1+2048 + pld [r12] + vld1.8 {q8, q9}, [r11]! @ load {nv12t_src+tiled_offset1, 64} + pld [r12, #32] + vld1.8 {q10, q11}, [r11] + vld1.8 {q12, q13}, [r12]! @ load {nv12t_src+tiled_offset1+2048, 64} + vld1.8 {q14, q15}, [r12] + + sub r11, r0, r10 @ r11 = yuv420_dest+linear_offset+64-temp1 + add r12, r9, #64 + add r11, r11, r12 + + vst1.8 {q4, q5}, [r11]! @ store {yuv420_dest+linear_offset+64-temp1, 64} + vst1.8 {q6, q7}, [r11]! + vst1.8 {q8, q9}, [r11]! @ store {yuv420_dest+linear_offset+128-temp1, 64} + vst1.8 {q10, q11}, [r11]! + vst1.8 {q12, q13}, [r11]! @ store {yuv420_dest+linear_offset+192-temp1, 64} + vst1.8 {q14, q15}, [r11]! + + add r9, r9, #256 + sub r9, r9, r10 + b LOOP_HEIGHT_256_LEFT_END + +LOOP_HEIGHT_256_LEFT_192: + cmp r12, #128 @ if (temp3 > 128) + ble LOOP_HEIGHT_256_LEFT_128 + add r11, r1, r7 @ r11 = nv12t_src+tiled_offset+2048+temp1 + add r11, r11, r10 + add r11, r11, #2048 + pld [r11] + add r12, r1, r8 @ r12 = nv12t_src+tiled_offset1 + pld [r11, #32] + cmp r10, #0 + pld [r12] + stmnefd sp!, {r9-r12, r14} @ backup registers + pld [r12, #32] + rsbne r10, r10, #64 + blne MEMCOPY_UNDER_64 + ldmnefd sp!, {r9-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_192_64 + vld1.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset+2048+temp1, 64} + vld1.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r11]! @ store {yuv420_dest+linear_offset, 64} + vst1.8 {q2, q3}, [r11]! +LOOP_HEIGHT_256_LEFT_192_64: + add r11, r1, r8 @ r11 = nv12t_src+tiled_offset1+2048 + add r11, r11, #2048 + pld [r11] + vld1.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset1, 64} + pld [r11, #32] + vld1.8 {q6, q7}, [r12] + vld1.8 {q8, q9}, [r11]! @ load {nv12t_src+tiled_offset1+2048, 64} + vld1.8 {q10, q11}, [r11] + + sub r11, r0, r10 @ r11 = yuv420_dest+linear_offset+64-temp1 + add r12, r9, #64 + add r11, r11, r12 + + vst1.8 {q4, q5}, [r11]! @ store {yuv420_dest+linear_offset+64-temp1, 64} + vst1.8 {q6, q7}, [r11]! + vst1.8 {q8, q9}, [r11]! @ store {yuv420_dest+linear_offset+128-temp1, 64} + vst1.8 {q10, q11}, [r11]! + + add r9, r9, #192 + sub r9, r9, r10 + b LOOP_HEIGHT_256_LEFT_END + +LOOP_HEIGHT_256_LEFT_128: + cmp r12, #64 @ if (temp3 > 64) + ble LOOP_HEIGHT_256_LEFT_64 + add r11, r1, r8 @ r11 = nv12t_src+tiled_offset1+temp1 + add r11, r11, r10 + pld [r11] + add r12, r1, r8 @ r12 = nv12t_src+tiled_offset1 + add r12, r12, #2048 + pld [r11, #32] + cmp r10, #0 + pld [r12] + stmnefd sp!, {r9-r12, r14} @ backup registers + pld [r12, #32] + rsbne r10, r10, #64 + blne MEMCOPY_UNDER_64 + ldmnefd sp!, {r9-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_128_64 + vld1.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset1+temp1, 64} + vld1.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r11]! @ store {yuv420_dest+linear_offset, 64} + vst1.8 {q2, q3}, [r11]! +LOOP_HEIGHT_256_LEFT_128_64: + vld1.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset1, 64} + vld1.8 {q6, q7}, [r12] + + sub r11, r0, r10 @ r11 = yuv420_dest+linear_offset+64-temp1 + add r12, r9, #64 + add r11, r11, r12 + + vst1.8 {q4, q5}, [r11]! @ store {yuv420_dest+linear_offset+64-temp1, 64} + vst1.8 {q6, q7}, [r11]! + + add r9, r9, #128 + sub r9, r9, r10 + b LOOP_HEIGHT_256_LEFT_END + +LOOP_HEIGHT_256_LEFT_64: + add r11, r1, r8 @ r11 = nv12t_src+tiled_offset1+2048+temp1 + add r11, r11, #2048 + add r11, r11, r10 + cmp r10, #0 + pld [r11] + stmnefd sp!, {r9-r12, r14} @ backup registers + pld [r11, #32] + rsbne r10, r10, #64 + blne MEMCOPY_UNDER_64 + ldmnefd sp!, {r9-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_64_64 + vld1.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset1+temp1, 64} + vld1.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r11]! @ store {yuv420_dest+linear_offset, 64} + vst1.8 {q2, q3}, [r11]! +LOOP_HEIGHT_256_LEFT_64_64: + add r9, r9, #64 + sub r9, r9, r10 + +LOOP_HEIGHT_256_LEFT_END: + + ldr r12, [sp, #48] @ right + add r7, r7, r14, lsl #11 @ tiled_offset = tiled_offset+temp4*2048 + add r10, r1, r7 @ r10 = nv12t_src+tiled_offset + pld [r10] + bic r6, r6, #0xFF @ j = (left>>8)<<8 + pld [r10, #32] + add r6, r6, #256 @ j = j + 256 + sub r11, r2, r12 @ temp2 = yuv420_width-right-256 + sub r11, r11, #256 + cmp r6, r11 + bgt LOOP_HEIGHT_256_WIDTH_END + +LOOP_HEIGHT_256_WIDTH: + add r12, r10, #2048 @ r12 = nv12t_src+tiled_offset+2048 + pld [r12] + vld1.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset, 64} + pld [r12, #32] + vld1.8 {q2, q3}, [r10] + + add r8, r8, r14, lsl #11 @ tiled_offset1 = tiled_offset1+temp4*2048 + add r10, r1, r8 @ r10 = nv12t_src+tiled_offset1 + pld [r10] + vld1.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r10, #32] + vld1.8 {q6, q7}, [r12] + + add r12, r10, #2048 @ r12 = nv12t_src+tiled_offset+2048 + pld [r12] + vld1.8 {q8, q9}, [r10]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r12, #32] + vld1.8 {q10, q11}, [r10] + + add r7, r7, r14, lsl #11 @ tiled_offset = tiled_offset+temp4*2048 + add r10, r1, r7 + pld [r10] + vld1.8 {q12, q13}, [r12]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r10, #32] + vld1.8 {q14, q15}, [r12] + + add r12, r0, r9 @ r12 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r12]! + vst1.8 {q2, q3}, [r12]! + vst1.8 {q4, q5}, [r12]! + vst1.8 {q6, q7}, [r12]! + vst1.8 {q8, q9}, [r12]! + vst1.8 {q10, q11}, [r12]! + vst1.8 {q12, q13}, [r12]! + vst1.8 {q14, q15}, [r12]! + add r9, r9, #256 @ linear_offset = linear_offset+256 + + add r12, r10, #2048 @ r12 = nv12t_src+tiled_offset+2048 + + add r6, r6, #256 @ j=j+256 + cmp r6, r11 @ j<=temp2 + ble LOOP_HEIGHT_256_WIDTH + +LOOP_HEIGHT_256_WIDTH_END: + + add r8, r8, r14, lsl #11 @ tiled_offset1 = tiled_offset1+temp4*2048 + ldr r14, [sp, #48] @ right + sub r11, r2, r6 @ temp2 = yuv420_width-right-j + sub r11, r11, r14 + cmp r11, #0 + beq LOOP_HEIGHT_256_RIGHT_END + cmp r11, #192 + ble LOOP_HEIGHT_256_RIGHT_192 + add r12, r10, #2048 + pld [r12] + vld1.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset} + pld [r12, #32] + vld1.8 {q2, q3}, [r10] + + add r10, r1, r8 @ r10 = nv12t_src+tiled_offset1 + pld [r10] + vld1.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048} + pld [r10, #32] + vld1.8 {q6, q7}, [r12] + + add r14, r10, #2048 @ r10 = nv12t_src+tiled_offset1+2048 + pld [r14] + vld1.8 {q8, q9}, [r10]! @ load {nv12t_src+tiled_offset1} + pld [r14, #32] + vld1.8 {q10, q11}, [r10] + + add r12, r0, r9 @ r12 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r12]! + vst1.8 {q2, q3}, [r12]! + vst1.8 {q4, q5}, [r12]! + vst1.8 {q6, q7}, [r12]! + vst1.8 {q8, q9}, [r12]! + vst1.8 {q10, q11}, [r12]! + add r9, r9, #192 @ linear_offset = linear_offset+192 + + stmfd sp!, {r9-r12, r14} @ backup registers + sub r10, r11, #192 + mov r11, r14 + bl MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12, r14} @ restore registers + b LOOP_HEIGHT_256_RIGHT_END + +LOOP_HEIGHT_256_RIGHT_192: + cmp r11, #128 + ble LOOP_HEIGHT_256_RIGHT_128 + add r12, r10, #2048 + pld [r12] + vld1.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset} + pld [r12, #32] + vld1.8 {q2, q3}, [r10] + + add r14, r1, r8 @ r10 = nv12t_src+tiled_offset1 + pld [r14] + vld1.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048} + pld [r14, #32] + vld1.8 {q6, q7}, [r12] + + add r12, r0, r9 @ r12 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r12]! + vst1.8 {q2, q3}, [r12]! + vst1.8 {q4, q5}, [r12]! + vst1.8 {q6, q7}, [r12]! + add r9, r9, #128 @ linear_offset = linear_offset+128 + + stmfd sp!, {r9-r12, r14} @ backup registers + sub r10, r11, #128 + mov r11, r14 + bl MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12, r14} @ restore registers + b LOOP_HEIGHT_256_RIGHT_END + +LOOP_HEIGHT_256_RIGHT_128: + cmp r11, #64 + ble LOOP_HEIGHT_256_RIGHT_64 + add r14, r10, #2048 + pld [r14] + vld1.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset} + pld [r14, #32] + vld1.8 {q2, q3}, [r10] + + add r12, r0, r9 @ r12 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r12]! + vst1.8 {q2, q3}, [r12]! + add r9, r9, #64 @ linear_offset = linear_offset+64 + + stmfd sp!, {r9-r12, r14} @ backup registers + sub r10, r11, #64 + mov r11, r14 + bl MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12, r14} @ restore registers + b LOOP_HEIGHT_256_RIGHT_END + +LOOP_HEIGHT_256_RIGHT_64: + stmfd sp!, {r9-r12, r14} @ backup registers + mov r14, r11 + mov r11, r10 + mov r10, r14 + bl MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12, r14} @ restore registers + +LOOP_HEIGHT_256_RIGHT_END: + + ldr r14, [sp, #52] @ buttom + add r5, r5, #1 @ i=i+1 + sub r14, r3, r14 @ i<yuv420_height-buttom + cmp r5, r14 + blt LOOP_HEIGHT_256 + b RESTORE_REG + +LOOP_HEIGHT_64_START: + cmp r10, #64 @ if (temp1 >= 64) + blt LOOP_HEIGHT_2_START + + ldr r5, [sp, #44] @ i = top +LOOP_HEIGHT_64: + ldr r6, [sp, #40] @ j = left + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r2 + mov r1, r3 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + ldr r9, [sp, #44] @ linear_offset = top + add r11, r6, #64 @ temp2 = ((j+64)>>6)<<6 + bic r11, r11, #0x3F + sub r11, r11, r6 @ temp2 = temp2-j + sub r9, r5, r9 @ linear_offset = temp1*(i-top) + mul r9, r9, r10 + and r14, r6, #0x3 @ temp4 = j&0x3 + add r7, r7, r14 @ tiled_offset = tiled_offset+temp4 + stmfd sp!, {r9-r12} @ backup parameters + mov r10, r11 + add r11, r1, r7 + bl MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12} @ restore parameters + add r9, r9, r11 @ linear_offset = linear_offset+temp2 + add r6, r6, r11 @ j = j+temp2@ + + add r14, r6, #64 + cmp r14, r12 + bgt LOOP_HEIGHT_64_1 + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r2 + mov r1, r3 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + add r7, r1, r7 + vld1.8 {q0, q1}, [r7]! + vld1.8 {q2, q3}, [r7] + add r7, r0, r9 + vst1.8 {q0, q1}, [r7]! + vst1.8 {q2, q3}, [r7] + add r9, r9, #64 + add r6, r6, #64 + +LOOP_HEIGHT_64_1: + add r14, r6, #64 + cmp r14, r12 + bgt LOOP_HEIGHT_64_2 + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r2 + mov r1, r3 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + add r7, r1, r7 + vld1.8 {q0, q1}, [r7]! + vld1.8 {q2, q3}, [r7] + add r7, r0, r9 + vst1.8 {q0, q1}, [r7]! + vst1.8 {q2, q3}, [r7] + add r9, r9, #64 + add r6, r6, #64 + +LOOP_HEIGHT_64_2: + cmp r6, r12 + bge LOOP_HEIGHT_64_3 + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r2 + mov r1, r3 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + sub r11, r12, r6 + stmfd sp!, {r9-r12} @ backup parameters + mov r10, r11 + add r11, r1, r7 + bl MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12} @ restore parameters + +LOOP_HEIGHT_64_3: + + ldr r14, [sp, #52] @ buttom + add r5, r5, #1 @ i=i+1 + sub r14, r3, r14 @ i<yuv420_height-buttom + cmp r5, r14 + blt LOOP_HEIGHT_64 + b RESTORE_REG + +LOOP_HEIGHT_2_START: + + ldr r5, [sp, #44] @ i = top +LOOP_HEIGHT_2: + + ldr r6, [sp, #40] @ j = left + ldr r9, [sp, #44] @ linear_offset = top + add r11, r6, #64 @ temp2 = ((j+64)>>6)<<6 + bic r11, r11, #0x3F + sub r11, r11, r6 @ temp2 = temp2-j + sub r9, r5, r9 @ linear_offset = temp1*(i-top) + mul r9, r10, r9 + add r9, r0, r9 @ linear_offset = linear_dst+linear_offset +LOOP_HEIGHT_2_WIDTH: + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r2 + mov r1, r3 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + + and r14, r6, #0x3 @ temp4 = j&0x3@ + add r7, r7, r14 @ tiled_offset = tiled_offset+temp4@ + add r7, r1, r7 + + ldrh r14, [r7] + strh r14, [r9], #2 + + ldr r14, [sp, #48] @ right + add r6, r6, #2 @ j=j+2 + sub r14, r2, r14 @ j<yuv420_width-right + cmp r6, r14 + blt LOOP_HEIGHT_2_WIDTH + + ldr r14, [sp, #52] @ buttom + add r5, r5, #1 @ i=i+1 + sub r14, r3, r14 @ i<yuv420_height-buttom + cmp r5, r14 + blt LOOP_HEIGHT_2 + +RESTORE_REG: + ldmfd sp!, {r4-r12,r15} @ restore registers + +MEMCOPY_UNDER_64: @ count=r10, src=r11 + cmp r10, #32 + add r9, r0, r9 @ r9 = yuv420_dest+linear_offset + blt MEMCOPY_UNDER_32 + vld1.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset+temp1, 64} + sub r10, r10, #32 + cmp r10, #0 + vst1.8 {q0, q1}, [r9]! @ load {nv12t_src+tiled_offset+temp1, 64} + beq MEMCOPY_UNDER_END +MEMCOPY_UNDER_32: + cmp r10, #16 + blt MEMCOPY_UNDER_16 + vld1.8 {q0}, [r11]! @ load {nv12t_src+tiled_offset+temp1, 64} + sub r10, r10, #16 + cmp r10, #0 + vst1.8 {q0}, [r9]! @ load {nv12t_src+tiled_offset+temp1, 64} + beq MEMCOPY_UNDER_END +MEMCOPY_UNDER_16: + ldrb r12, [r11], #1 + strb r12, [r9], #1 + subs r10, r10, #1 + bne MEMCOPY_UNDER_16 + +MEMCOPY_UNDER_END: + and r10, r6, #0x3F @ temp1 = left(==j)&0x3F + cmp r10, #0 + mov pc, lr + +tile_4x2_read_asm: +LFB0: + add ip, r3, #32 + sub r0, r0, #1 + cmp r1, ip + cmple r3, r1 + mov ip, r2, asr #2 + mov r0, r0, asr #7 + stmfd sp!, {r4, r5, lr} +LCFI0: + add r0, r0, #1 + bge L2 + sub r1, r1, #1 + tst r1, #32 + bne L2 + tst r3, #32 + bne L2 + mov r4, r2, asr #7 + and r1, r3, #31 + eor r4, r4, r3, asr #5 + ubfx r3, r3, #6, #8 + tst r4, #1 + ubfx r4, r2, #8, #6 + and ip, ip, #15 + mov r2, r2, asr #6 + mla r3, r0, r3, r4 + orr r1, ip, r1, asl #4 + b L9 +L2: + mov r2, ip, asr #5 + and r4, r3, #31 + eor r1, r2, r3, asr #5 + and r5, r2, #127 + ubfx r3, r3, #6, #8 + tst r1, #1 + and r1, ip, #15 + mov r2, ip, asr #4 + mla r3, r0, r3, r5 + orr r1, r1, r4, asl #4 +L9: + andne r2, r2, #1 + andeq r2, r2, #1 + orrne r2, r2, #2 + mov r1, r1, asl #2 + orr r3, r1, r3, asl #13 + orr r0, r3, r2, asl #11 + ldmfd sp!, {r4, r5, pc} +LFE0: + .fnend + diff --git a/libswconverter/csc_tiled_to_linear_deinterleave_crop_neon.s b/libswconverter/csc_tiled_to_linear_deinterleave_crop_neon.s new file mode 100755 index 0000000..cdd101e --- /dev/null +++ b/libswconverter/csc_tiled_to_linear_deinterleave_crop_neon.s @@ -0,0 +1,786 @@ +/* + * + * Copyright 2012 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_tiled_to_linear_deinterleave_crop_neon.s + * @brief SEC_OMX specific define + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2012.02.01 : Create + */ + +/* + * Converts and Deinterleaves tiled data to linear + * Crops left, top, right, buttom + * 1. UV of NV12T to UV of YUV420P + * + * @param yuv420_u_dest + * U plane address of YUV420P[out] + * + * @param yuv420_v_dest + * V plane address of YUV420P[out] + * + * @param nv12t_src + * UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_uv_height + * Height/2 of YUV420[in] + * + * @param left + * Crop size of left. It should be even. + * + * @param top + * Crop size of top. It should be even. + * + * @param right + * Crop size of right. It should be even. + * + * @param buttom + * Crop size of buttom. It should be even. + */ + + .arch armv7-a + .text + .global csc_tiled_to_linear_deinterleave_crop_neon + .type csc_tiled_to_linear_deinterleave_crop_neon, %function +csc_tiled_to_linear_deinterleave_crop_neon: + .fnstart + + @r0 yuv420_u_dest + @r1 yuv420_v_dest + @r2 nv12t_src + @r3 yuv420_width + @r4 yuv420_height + @r5 i + @r6 j + @r7 tiled_offset + @r8 tiled_offset1 + @r9 linear_offset + @r10 temp1 + @r11 temp2 + @r12 temp3 + @r14 temp4 + + stmfd sp!, {r4-r12,r14} @ backup registers + + ldr r4, [sp, #40] @ r4 = yuv420_height + + ldr r12, [sp, #52] @ r12 = right + ldr r10, [sp, #44] @ r10 = left + sub r12, r3, r12 @ temp3 = yuv420_width-right@ + sub r10, r12, r10 @ temp1 = temp3-left@ + cmp r10, #256 @ if (temp1 >= 256) + blt LOOP_HEIGHT_64_START + + ldr r5, [sp, #48] @ top +LOOP_HEIGHT_256: + ldr r6, [sp, #44] @ j = left + mov r14, r5, asr #5 @ temp4 = i>>5 + bic r12, r6, #0xFF @ temp3 = (j>>8)<<8 + mov r12, r12, asr #6 @ temp3 = temp3>>6 + and r11, r14, #0x1 @ if (temp4 & 0x1) + cmp r11, #0x1 + bne LOOP_HEIGHT_256_GET_TILED_EVEN +LOOP_HEIGHT_256_GET_TILED_ODD: + sub r7, r14, #1 @ tiled_offset = temp4-1 + add r10, r3, #127 @ temp1 = ((yuv420_width+127)>>7)<<7 + bic r10, r10, #0x7F + mov r10, r10, asr #6 @ tiled_offset = tiled_offset*(temp1>>6) + mul r7, r7, r10 + add r7, r7, r12 @ tiled_offset = tiled_offset+temp3 + add r7, r7, #2 @ tiled_offset = tiled_offset+2 + bic r10, r12, #0x3 @ temp1 = (temp3>>2)<<2 + add r7, r7, r10 @ tiled_offset = tiled_offset+temp1 + mov r7, r7, lsl #11 @ tiled_offset = tiled_offset<<11 + add r8, r7, #4096 @ tiled_offset1 = tiled_offset+2048*2 + mov r14, #8 + b LOOP_HEIGHT_256_GET_TILED_END + +LOOP_HEIGHT_256_GET_TILED_EVEN: + add r11, r4, #31 @ temp2 = ((yuv420_height+31)>>5)<<5 + bic r11, r11, #0x1F + add r10, r5, #32 @ if ((i+32)<temp2) + cmp r10, r11 + bge LOOP_HEIGHT_256_GET_TILED_EVEN1 + add r10, r12, #2 @ temp1 = temp3+2 + bic r10, r10, #0x3 @ temp1 = (temp1>>2)<<2 + add r7, r12, r10 @ tiled_offset = temp3+temp1@ + add r10, r3, #127 @ temp1 = ((yuv420_width+127)>>7)<<7 + bic r10, r10, #0x7F + mov r10, r10, asr #6 @ tiled_offset = tiled_offset+temp4*(temp1>>6) + mla r7, r14, r10, r7 + mov r7, r7, lsl #11 @ tiled_offset = tiled_offset<<11 + add r8, r7, #12288 @ tiled_offset1 = tiled_offset+2048*6 + mov r14, #8 + b LOOP_HEIGHT_256_GET_TILED_END + +LOOP_HEIGHT_256_GET_TILED_EVEN1: + add r10, r3, #127 @ temp1 = ((yuv420_width+127)>>7)<<7 + bic r10, r10, #0x7F + mov r10, r10, asr #6 @ tiled_offset = temp4*(temp1>>6) + mul r7, r14, r10 + add r7, r7, r12 @ tiled_offset = tiled_offset+temp3 + mov r7, r7, lsl #11 @ tiled_offset = tiled_offset<<11 + add r8, r7, #4096 @ tiled_offset1 = tiled_offset+2048*2 + mov r14, #4 + +LOOP_HEIGHT_256_GET_TILED_END: + + ldr r12, [sp, #52] @ right + ldr r9, [sp, #48] @ top + and r10, r5, #0x1F @ temp1 = i&0x1F + add r7, r7, r10, lsl #6 @ tiled_offset = tiled_offset+64*(temp1) + add r8, r8, r10, lsl #6 @ tiled_offset1 = tiled_offset1+64*(temp1) + sub r11, r3, r6 @ temp2 = yuv420_width-left(==j)-right + sub r11, r11, r12 + sub r9, r5, r9 @ linear_offset = temp2*(i-top)/2@ + mul r9, r11, r9 + mov r9, r9, asr #1 + add r12, r6, #256 @ temp3 = ((j+256)>>8)<<8@ + bic r12, r12, #0xFF + sub r12, r12, r6 @ temp3 = temp3-j@ + and r10, r6, #0x3F @ temp1 = left(==j)&0x3F + + cmp r12, #192 @ if (temp3 > 192) + ble LOOP_HEIGHT_256_LEFT_192 + add r11, r2, r7 @ r11 = nv12t_src+tiled_offset+temp1 + add r11, r11, r10 + pld [r11] + add r12, r2, r7 @ r12 = nv12t_src+tiled_offset+2048 + pld [r11, #32] + add r12, r12, #2048 + pld [r12] + cmp r10, #0 + pld [r12, #32] + stmnefd sp!, {r8-r12, r14} @ backup registers + rsbne r10, r10, #64 + blne INTERLEAVED_MEMCOPY_UNDER_64 + ldmnefd sp!, {r8-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_256_64 + vld2.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset+temp1, 64} + vld2.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r11]! + vst1.8 {q2}, [r11]! + add r11, r1, r9 @ r11 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r11]! + vst1.8 {q3}, [r11]! +LOOP_HEIGHT_256_LEFT_256_64: + add r11, r2, r8 @ r11 = nv12t_src+tiled_offset1 + pld [r11] + vld2.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r11, #32] + vld2.8 {q6, q7}, [r12] + add r12, r11, #2048 @ r12 = nv12t_src+tiled_offset1+2048 + pld [r12] + vld2.8 {q8, q9}, [r11]! @ load {nv12t_src+tiled_offset1, 64} + pld [r12, #32] + vld2.8 {q10, q11}, [r11] + vld2.8 {q12, q13}, [r12]! @ load {nv12t_src+tiled_offset1+2048, 64} + vld2.8 {q14, q15}, [r12] + + add r11, r0, r9 @ r11 = yuv420_u_dest+linear_offset+32-temp1/2 + add r11, r11, #32 + sub r11, r11, r10, asr #1 + vst1.8 {q4}, [r11]! + vst1.8 {q6}, [r11]! + vst1.8 {q8}, [r11]! + vst1.8 {q10}, [r11]! + vst1.8 {q12}, [r11]! + vst1.8 {q14}, [r11]! + + add r11, r1, r9 @ r11 = yuv420_v_dest+linear_offset+32-temp1/2 + add r11, r11, #32 + sub r11, r11, r10, asr #1 + vst1.8 {q5}, [r11]! + vst1.8 {q7}, [r11]! + vst1.8 {q9}, [r11]! + vst1.8 {q11}, [r11]! + vst1.8 {q13}, [r11]! + vst1.8 {q15}, [r11]! + + add r9, r9, #128 + sub r9, r9, r10, asr #1 + b LOOP_HEIGHT_256_LEFT_END + +LOOP_HEIGHT_256_LEFT_192: + cmp r12, #128 @ if (temp3 > 128) + ble LOOP_HEIGHT_256_LEFT_128 + add r11, r2, r7 @ r11 = nv12t_src+tiled_offset+2048+temp1 + add r11, r11, r10 + add r11, r11, #2048 + pld [r11] + add r12, r2, r8 @ r12 = nv12t_src+tiled_offset1 + pld [r11, #32] + cmp r10, #0 + pld [r12] + stmnefd sp!, {r8-r12, r14} @ backup registers + pld [r12, #32] + rsbne r10, r10, #64 + blne INTERLEAVED_MEMCOPY_UNDER_64 + ldmnefd sp!, {r8-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_192_64 + vld2.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset+2048+temp1, 64} + vld2.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r11]! + vst1.8 {q2}, [r11]! + add r11, r1, r9 @ r11 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r11]! + vst1.8 {q3}, [r11]! +LOOP_HEIGHT_256_LEFT_192_64: + add r11, r2, r8 @ r11 = nv12t_src+tiled_offset1+2048 + add r11, r11, #2048 + pld [r11] + vld2.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset1, 64} + pld [r11, #32] + vld2.8 {q6, q7}, [r12] + vld2.8 {q8, q9}, [r11]! @ load {nv12t_src+tiled_offset1+2048, 64} + vld2.8 {q10, q11}, [r11] + + add r11, r0, r9 @ r11 = yuv420_u_dest+linear_offset+32-temp1/2 + add r11, r11, #32 + sub r11, r11, r10, asr #1 + vst1.8 {q4}, [r11]! + vst1.8 {q6}, [r11]! + vst1.8 {q8}, [r11]! + vst1.8 {q10}, [r11]! + + add r11, r1, r9 @ r11 = yuv420_v_dest+linear_offset+32-temp1/2 + add r11, r11, #32 + sub r11, r11, r10, asr #1 + vst1.8 {q5}, [r11]! + vst1.8 {q7}, [r11]! + vst1.8 {q9}, [r11]! + vst1.8 {q11}, [r11]! + + add r9, r9, #96 + sub r9, r9, r10, asr #1 + b LOOP_HEIGHT_256_LEFT_END + +LOOP_HEIGHT_256_LEFT_128: + cmp r12, #64 @ if (temp3 > 64) + ble LOOP_HEIGHT_256_LEFT_64 + add r11, r2, r8 @ r11 = nv12t_src+tiled_offset1+temp1 + add r11, r11, r10 + pld [r11] + add r12, r2, r8 @ r12 = nv12t_src+tiled_offset1 + add r12, r12, #2048 + pld [r11, #32] + cmp r10, #0 + pld [r12] + stmnefd sp!, {r8-r12, r14} @ backup registers + pld [r12, #32] + rsbne r10, r10, #64 + blne INTERLEAVED_MEMCOPY_UNDER_64 + ldmnefd sp!, {r8-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_128_64 + vld2.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset1+temp1, 64} + vld2.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r11]! + vst1.8 {q2}, [r11]! + add r11, r1, r9 @ r11 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r11]! + vst1.8 {q3}, [r11]! +LOOP_HEIGHT_256_LEFT_128_64: + vld2.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset1, 64} + vld2.8 {q6, q7}, [r12] + + add r11, r0, r9 @ r11 = yuv420_u_dest+linear_offset+32-temp1/2 + add r11, r11, #32 + sub r11, r11, r10, asr #1 + vst1.8 {q4}, [r11]! + vst1.8 {q6}, [r11]! + + add r11, r1, r9 @ r11 = yuv420_v_dest+linear_offset+32-temp1/2 + add r11, r11, #32 + sub r11, r11, r10, asr #1 + vst1.8 {q5}, [r11]! + vst1.8 {q7}, [r11]! + + add r9, r9, #64 + sub r9, r9, r10, asr #1 + b LOOP_HEIGHT_256_LEFT_END + +LOOP_HEIGHT_256_LEFT_64: + add r11, r2, r8 @ r11 = nv12t_src+tiled_offset1+2048+temp1 + add r11, r11, #2048 + add r11, r11, r10 + cmp r10, #0 + pld [r11] + stmnefd sp!, {r8-r12, r14} @ backup registers + pld [r11, #32] + rsbne r10, r10, #64 + blne INTERLEAVED_MEMCOPY_UNDER_64 + ldmnefd sp!, {r8-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_64_64 + vld2.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset1+temp1, 64} + vld2.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r11]! @ store {yuv420_dest+linear_offset, 64} + vst1.8 {q2, q3}, [r11]! +LOOP_HEIGHT_256_LEFT_64_64: + add r9, r9, #32 + sub r9, r9, r10, asr #1 + +LOOP_HEIGHT_256_LEFT_END: + + ldr r12, [sp, #52] @ right + add r7, r7, r14, lsl #11 @ tiled_offset = tiled_offset+temp4*2048 + add r10, r2, r7 @ r10 = nv12t_src+tiled_offset + pld [r10] + bic r6, r6, #0xFF @ j = (left>>8)<<8 + pld [r10, #32] + add r6, r6, #256 @ j = j + 256 + sub r11, r3, r12 @ temp2 = yuv420_width-right-256 + sub r11, r11, #256 + cmp r6, r11 + bgt LOOP_HEIGHT_256_WIDTH_END + +LOOP_HEIGHT_256_WIDTH: + add r12, r10, #2048 @ r12 = nv12t_src+tiled_offset+2048 + pld [r12] + vld2.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset, 64} + pld [r12, #32] + vld2.8 {q2, q3}, [r10] + + add r8, r8, r14, lsl #11 @ tiled_offset1 = tiled_offset1+temp4*2048 + add r10, r2, r8 @ r10 = nv12t_src+tiled_offset1 + pld [r10] + vld2.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r10, #32] + vld2.8 {q6, q7}, [r12] + + add r12, r10, #2048 @ r12 = nv12t_src+tiled_offset+2048 + pld [r12] + vld2.8 {q8, q9}, [r10]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r12, #32] + vld2.8 {q10, q11}, [r10] + + add r7, r7, r14, lsl #11 @ tiled_offset = tiled_offset+temp4*2048 + add r10, r2, r7 + pld [r10] + vld2.8 {q12, q13}, [r12]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r10, #32] + vld2.8 {q14, q15}, [r12] + + add r12, r0, r9 @ r12 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r12]! + vst1.8 {q2}, [r12]! + vst1.8 {q4}, [r12]! + vst1.8 {q6}, [r12]! + vst1.8 {q8}, [r12]! + vst1.8 {q10}, [r12]! + vst1.8 {q12}, [r12]! + vst1.8 {q14}, [r12]! + add r12, r1, r9 @ r12 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r12]! + vst1.8 {q3}, [r12]! + vst1.8 {q5}, [r12]! + vst1.8 {q7}, [r12]! + vst1.8 {q9}, [r12]! + vst1.8 {q11}, [r12]! + vst1.8 {q13}, [r12]! + vst1.8 {q15}, [r12]! + add r9, r9, #128 @ linear_offset = linear_offset+128 + + add r12, r10, #2048 @ r12 = nv12t_src+tiled_offset+2048 + + add r6, r6, #256 @ j=j+256 + cmp r6, r11 @ j<=temp2 + ble LOOP_HEIGHT_256_WIDTH + +LOOP_HEIGHT_256_WIDTH_END: + + add r8, r8, r14, lsl #11 @ tiled_offset1 = tiled_offset1+temp4*2048 + ldr r14, [sp, #52] @ right + sub r11, r3, r6 @ temp2 = yuv420_width-right-j + sub r11, r11, r14 + cmp r11, #0 + beq LOOP_HEIGHT_256_RIGHT_END + cmp r11, #192 + ble LOOP_HEIGHT_256_RIGHT_192 + add r12, r10, #2048 + pld [r12] + vld2.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset} + pld [r12, #32] + vld2.8 {q2, q3}, [r10] + + add r10, r2, r8 @ r10 = nv12t_src+tiled_offset1 + pld [r10] + vld2.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048} + pld [r10, #32] + vld2.8 {q6, q7}, [r12] + + add r14, r10, #2048 @ r10 = nv12t_src+tiled_offset1+2048 + pld [r14] + vld2.8 {q8, q9}, [r10]! @ load {nv12t_src+tiled_offset1} + pld [r14, #32] + vld2.8 {q10, q11}, [r10] + + add r12, r0, r9 @ r12 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r12]! + vst1.8 {q2}, [r12]! + vst1.8 {q4}, [r12]! + vst1.8 {q6}, [r12]! + vst1.8 {q8}, [r12]! + vst1.8 {q10}, [r12]! + add r12, r1, r9 @ r12 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r12]! + vst1.8 {q3}, [r12]! + vst1.8 {q5}, [r12]! + vst1.8 {q7}, [r12]! + vst1.8 {q9}, [r12]! + vst1.8 {q11}, [r12]! + add r9, r9, #96 @ linear_offset = linear_offset+96 + + stmfd sp!, {r8-r12, r14} @ backup registers + sub r10, r11, #192 + mov r11, r14 + bl INTERLEAVED_MEMCOPY_UNDER_64 + ldmfd sp!, {r8-r12, r14} @ restore registers + b LOOP_HEIGHT_256_RIGHT_END + +LOOP_HEIGHT_256_RIGHT_192: + cmp r11, #128 + ble LOOP_HEIGHT_256_RIGHT_128 + add r12, r10, #2048 + pld [r12] + vld2.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset} + pld [r12, #32] + vld2.8 {q2, q3}, [r10] + + add r14, r2, r8 @ r10 = nv12t_src+tiled_offset1 + pld [r14] + vld2.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048} + pld [r14, #32] + vld2.8 {q6, q7}, [r12] + + add r12, r0, r9 @ r12 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r12]! + vst1.8 {q2}, [r12]! + vst1.8 {q4}, [r12]! + vst1.8 {q6}, [r12]! + add r12, r1, r9 @ r12 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r12]! + vst1.8 {q3}, [r12]! + vst1.8 {q5}, [r12]! + vst1.8 {q7}, [r12]! + add r9, r9, #64 @ linear_offset = linear_offset+64 + + stmfd sp!, {r8-r12, r14} @ backup registers + sub r10, r11, #128 + mov r11, r14 + bl INTERLEAVED_MEMCOPY_UNDER_64 + ldmfd sp!, {r8-r12, r14} @ restore registers + b LOOP_HEIGHT_256_RIGHT_END + +LOOP_HEIGHT_256_RIGHT_128: + cmp r11, #64 + ble LOOP_HEIGHT_256_RIGHT_64 + add r14, r10, #2048 + pld [r14] + vld2.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset} + pld [r14, #32] + vld2.8 {q2, q3}, [r10] + + add r12, r0, r9 @ r12 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r12]! + vst1.8 {q2}, [r12]! + add r12, r1, r9 @ r12 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r12]! + vst1.8 {q3}, [r12]! + add r9, r9, #32 @ linear_offset = linear_offset+32 + + stmfd sp!, {r8-r12, r14} @ backup registers + sub r10, r11, #64 + mov r11, r14 + bl INTERLEAVED_MEMCOPY_UNDER_64 + ldmfd sp!, {r8-r12, r14} @ restore registers + b LOOP_HEIGHT_256_RIGHT_END + +LOOP_HEIGHT_256_RIGHT_64: + stmfd sp!, {r8-r12, r14} @ backup registers + mov r14, r11 + mov r11, r10 + mov r10, r14 + bl INTERLEAVED_MEMCOPY_UNDER_64 + ldmfd sp!, {r8-r12, r14} @ restore registers + +LOOP_HEIGHT_256_RIGHT_END: + + ldr r14, [sp, #56] @ buttom + add r5, r5, #1 @ i=i+1 + sub r14, r4, r14 @ i<yuv420_height-buttom + cmp r5, r14 + blt LOOP_HEIGHT_256 + b RESTORE_REG + +LOOP_HEIGHT_64_START: + cmp r10, #64 @ if (temp1 >= 64) + blt LOOP_HEIGHT_2_START + + ldr r5, [sp, #48] @ i = top +LOOP_HEIGHT_64: + ldr r6, [sp, #44] @ j = left + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r3 + mov r1, r4 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + ldr r9, [sp, #48] @ linear_offset = top + ldr r12, [sp, #52] @ r12 = right + add r11, r6, #64 @ temp2 = ((j+64)>>6)<<6 + bic r11, r11, #0x3F + sub r11, r11, r6 @ temp2 = temp2-j + sub r12, r3, r12 @ temp3 = yuv420_width-right + sub r14, r12, r6 @ temp4 = temp3-left + sub r9, r5, r9 @ linear_offset = temp4*(i-top)/2 + mul r9, r9, r14 + mov r9, r9, asr #1 + and r14, r6, #0x3 @ temp4 = j&0x3 + add r7, r7, r14 @ tiled_offset = tiled_offset+temp4 + stmfd sp!, {r9-r12} @ backup parameters + mov r10, r11 + add r11, r2, r7 + bl INTERLEAVED_MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12} @ restore parameters + add r9, r9, r11, asr #1 @ linear_offset = linear_offset+temp2/2 + add r6, r6, r11 @ j = j+temp2@ + + add r14, r6, #64 + cmp r14, r12 + bgt LOOP_HEIGHT_64_1 + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r3 + mov r1, r4 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + add r7, r2, r7 + vld2.8 {q0, q1}, [r7]! + vld2.8 {q2, q3}, [r7] + add r7, r0, r9 + vst1.8 {q0}, [r7]! + vst1.8 {q2}, [r7] + add r7, r1, r9 + vst1.8 {q1}, [r7]! + vst1.8 {q3}, [r7] + add r9, r9, #32 + add r6, r6, #64 + +LOOP_HEIGHT_64_1: + add r14, r6, #64 + cmp r14, r12 + bgt LOOP_HEIGHT_64_2 + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r3 + mov r1, r4 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + add r7, r2, r7 + vld2.8 {q0, q1}, [r7]! + vld2.8 {q2, q3}, [r7] + add r7, r0, r9 + vst1.8 {q0}, [r7]! + vst1.8 {q2}, [r7] + add r7, r1, r9 + vst1.8 {q1}, [r7]! + vst1.8 {q3}, [r7] + add r9, r9, #32 + add r6, r6, #64 + +LOOP_HEIGHT_64_2: + cmp r6, r12 + bge LOOP_HEIGHT_64_3 + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r3 + mov r1, r4 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + sub r11, r12, r6 + stmfd sp!, {r9-r12} @ backup parameters + mov r10, r11 + add r11, r2, r7 + bl INTERLEAVED_MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12} @ restore parameters + +LOOP_HEIGHT_64_3: + + ldr r14, [sp, #56] @ buttom + add r5, r5, #1 @ i=i+1 + sub r14, r4, r14 @ i<yuv420_height-buttom + cmp r5, r14 + blt LOOP_HEIGHT_64 + b RESTORE_REG + +LOOP_HEIGHT_2_START: + + ldr r5, [sp, #48] @ i = top +LOOP_HEIGHT_2: + + ldr r12, [sp, #52] @ linear_offset = right + ldr r6, [sp, #44] @ j = left + ldr r9, [sp, #48] @ linear_offset = top + + sub r12, r3, r12 @ temp3 = yuv420_width-right + sub r14, r12, r6 @ temp4 = temp3-left@ + sub r9, r5, r9 @ r9 = i-top + mul r9, r14, r9 @ temp4*(i-top) + mov r9, r9, lsr #1 @ linear_offset = temp4*(i-top)/2 + add r11, r0, r9 + add r12, r1, r9 +LOOP_HEIGHT_2_WIDTH: + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r2 + mov r1, r3 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + + and r14, r6, #0x3 @ temp4 = j&0x3@ + add r7, r7, r14 @ tiled_offset = tiled_offset+temp4@ + add r7, r2, r7 + + ldrh r14, [r7] + strb r14, [r11], #1 + mov r14, r14, lsr #8 + strb r14, [r12], #1 + + ldr r14, [sp, #52] @ right + add r6, r6, #2 @ j=j+2 + sub r14, r3, r14 @ j<yuv420_width-right + cmp r6, r14 + blt LOOP_HEIGHT_2_WIDTH + + ldr r14, [sp, #56] @ buttom + add r5, r5, #1 @ i=i+1 + sub r14, r4, r14 @ i<yuv420_height-buttom + cmp r5, r14 + blt LOOP_HEIGHT_2 + +RESTORE_REG: + ldmfd sp!, {r4-r12,r15} @ restore registers + +INTERLEAVED_MEMCOPY_UNDER_64: @ count=r10, src=r11 + cmp r10, #32 + blt INTERLEAVED_MEMCOPY_UNDER_32 + vld2.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset+temp1, 64} + sub r10, r10, #32 + cmp r10, #0 + add r12, r0, r9 @ r12 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r12] @ load {nv12t_src+tiled_offset+temp1, 64} + add r12, r1, r9 @ r12 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r12] @ load {nv12t_src+tiled_offset+temp1, 64} + add r9, r9, #16 + beq INTERLEAVED_MEMCOPY_UNDER_END +INTERLEAVED_MEMCOPY_UNDER_32: + cmp r10, #16 + blt INTERLEAVED_MEMCOPY_UNDER_16 + vld2.8 {q0}, [r11]! @ load {nv12t_src+tiled_offset+temp1, 64} + sub r10, r10, #16 + cmp r10, #0 + add r12, r0, r9 @ r12 = yuv420_u_dest+linear_offset + vst1.8 {d0}, [r12]! @ load {nv12t_src+tiled_offset+temp1, 64} + add r12, r1, r9 @ r12 = yuv420_v_dest+linear_offset + vst1.8 {d1}, [r12]! @ load {nv12t_src+tiled_offset+temp1, 64} + add r9, r9, #8 + beq INTERLEAVED_MEMCOPY_UNDER_END +INTERLEAVED_MEMCOPY_UNDER_16: + ldrh r12, [r11], #2 + add r8, r0, r9 @ r8 = yuv420_u_dest+linear_offset + strb r12, [r8] + add r8, r1, r9 @ r8 = yuv420_v_dest+linear_offset + mov r12, r12, lsr #8 + strb r12, [r8] + subs r10, r10, #2 + add r9, r9, #1 + bne INTERLEAVED_MEMCOPY_UNDER_16 + +INTERLEAVED_MEMCOPY_UNDER_END: + and r10, r6, #0x3F @ temp1 = left(==j)&0x3F + cmp r10, #0 + mov pc, lr + +tile_4x2_read_asm: +LFB0: + add ip, r3, #32 + sub r0, r0, #1 + cmp r1, ip + cmple r3, r1 + mov ip, r2, asr #2 + mov r0, r0, asr #7 + stmfd sp!, {r4, r5, lr} +LCFI0: + add r0, r0, #1 + bge L2 + sub r1, r1, #1 + tst r1, #32 + bne L2 + tst r3, #32 + bne L2 + mov r4, r2, asr #7 + and r1, r3, #31 + eor r4, r4, r3, asr #5 + ubfx r3, r3, #6, #8 + tst r4, #1 + ubfx r4, r2, #8, #6 + and ip, ip, #15 + mov r2, r2, asr #6 + mla r3, r0, r3, r4 + orr r1, ip, r1, asl #4 + b L9 +L2: + mov r2, ip, asr #5 + and r4, r3, #31 + eor r1, r2, r3, asr #5 + and r5, r2, #127 + ubfx r3, r3, #6, #8 + tst r1, #1 + and r1, ip, #15 + mov r2, ip, asr #4 + mla r3, r0, r3, r5 + orr r1, r1, r4, asl #4 +L9: + andne r2, r2, #1 + andeq r2, r2, #1 + orrne r2, r2, #2 + mov r1, r1, asl #2 + orr r3, r1, r3, asl #13 + orr r0, r3, r2, asl #11 + ldmfd sp!, {r4, r5, pc} +LFE0: + .fnend + diff --git a/libswconverter/csc_tiled_to_linear_uv_deinterleave_neon.s b/libswconverter/csc_tiled_to_linear_uv_deinterleave_neon.s new file mode 100755 index 0000000..b4d5084 --- /dev/null +++ b/libswconverter/csc_tiled_to_linear_uv_deinterleave_neon.s @@ -0,0 +1,250 @@ +/* + * + * Copyright 2012 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_tiled_to_linear_uv_deinterleave_neon.s + * @brief SEC_OMX specific define. It support MFC 6.x tiled. + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2012.02.01 : Create + */ + +/* + * Converts and Deinterleave tiled data to linear for mfc 6.x + * 1. UV of NV12T to Y of YUV420P + * + * @param u_dst + * U address of YUV420[out] + * + * @param v_dst + * V address of YUV420[out] + * + * @param uv_src + * UV address of NV12T[in] + * + * @param yuv420_width + * real width of YUV420[in]. It should be even. + * + * @param yuv420_height + * real height of YUV420[in] It should be even. + */ + + .arch armv7-a + .text + .global csc_tiled_to_linear_uv_deinterleave_neon + .type csc_tiled_to_linear_uv_deinterleave_neon, %function +csc_tiled_to_linear_uv_deinterleave_neon: + .fnstart + + .equ CACHE_LINE_SIZE, 64 + .equ PRE_LOAD_OFFSET, 6 + + @r0 u_dst + @r1 v_dst + @r2 uv_src + @r3 width + @r4 height + @r5 i + @r6 j + @r7 dst_offset + @r8 src_offset + @r9 aligned_height + @r10 aligned_width + @r11 tiled_width + @r12 temp1 + @r14 temp2 + + stmfd sp!, {r4-r12,r14} @ backup registers + ldr r4, [sp, #40] @ r4 = height + + bic r9, r4, #0x7 @ aligned_height = height & (~0x7) + bic r10, r3, #0xF @ aligned_width = width & (~0xF) + add r11, r3, #15 @ tiled_width = ((width + 15) >> 4) << 4 + mov r11, r11, asr #4 + mov r11, r11, lsl #4 + + mov r5, #0 +LOOP_MAIN_ALIGNED_HEIGHT: + mul r8, r11, r5 @ src_offset = tiled_width * i + mov r6, #0 + add r8, r2, r8 @ src_offset = uv_src + src_offset +LOOP_MAIN_ALIGNED_WIDTH: + mov r12, r3, asr #1 @ temp1 = (width >> 1) * i + (j >> 1) + mul r12, r12, r5 + + pld [r8, #(CACHE_LINE_SIZE*PRE_LOAD_OFFSET)] + vld2.8 {q0, q1}, [r8]! + add r12, r12, r6, asr #1 + vld2.8 {q2, q3}, [r8]! + add r7, r0, r12 @ dst_offset = u_dst + temp1 + pld [r8, #(CACHE_LINE_SIZE*PRE_LOAD_OFFSET)] + vld2.8 {q4, q5}, [r8]! + mov r14, r3, asr #1 @ temp2 = width / 2 + vld2.8 {q6, q7}, [r8]! + + vst1.8 {d0}, [r7], r14 + vst1.8 {d1}, [r7], r14 + vst1.8 {d4}, [r7], r14 + vst1.8 {d5}, [r7], r14 + vst1.8 {d8}, [r7], r14 + vst1.8 {d9}, [r7], r14 + vst1.8 {d12}, [r7], r14 + vst1.8 {d13}, [r7], r14 + + add r7, r1, r12 @ dst_offset = v_dst + temp1 + + vst1.8 {d2}, [r7], r14 + vst1.8 {d3}, [r7], r14 + vst1.8 {d6}, [r7], r14 + vst1.8 {d7}, [r7], r14 + vst1.8 {d10}, [r7], r14 + vst1.8 {d11}, [r7], r14 + add r6, r6, #16 + vst1.8 {d14}, [r7], r14 + cmp r6, r10 + vst1.8 {d15}, [r7], r14 + blt LOOP_MAIN_ALIGNED_WIDTH + +MAIN_REMAIN_WIDTH_START: + cmp r10, r3 @ if (aligned_width != width) { + beq MAIN_REMAIN_WIDTH_END + stmfd sp!, {r0-r2,r4} @ backup registers + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 3) + add r8, r8, r6, lsl #3 + add r8, r2, r8 @ r8 = uv_src + src_offset + mov r12, r3, asr #1 @ temp1 = (width >> 1) * i + (j >> 1) + mul r12, r12, r5 + add r12, r12, r6, asr #1 + add r7, r0, r12 @ r7 = u_dst + temp1 + add r12, r1, r12 @ r12 = v_dst + temp1 + sub r14, r3, r6 @ r14 = (width - j) / 2 + mov r14, r14, asr #1 + + mov r4, #0 +LOOP_MAIN_REMAIN_HEIGHT: + mov r0, #0 @ r0 is index in de-interleave +LOOP_MAIN_REMAIN_WIDTH: + ldrb r1, [r8], #1 + ldrb r2, [r8], #1 + strb r1, [r7], #1 + strb r2, [r12], #1 + add r0, #1 + cmp r0, r14 + blt LOOP_MAIN_REMAIN_WIDTH + + sub r8, r8, r14, lsl #1 + sub r7, r7, r14 + sub r12, r12, r14 + add r8, r8, #16 + add r7, r7, r3, asr #1 + add r12, r12, r3, asr #1 + + add r4, #1 + cmp r4, #8 + blt LOOP_MAIN_REMAIN_HEIGHT + ldmfd sp!, {r0-r2,r4} @ restore registers +MAIN_REMAIN_WIDTH_END: + + add r5, r5, #8 + cmp r5, r9 + blt LOOP_MAIN_ALIGNED_HEIGHT + +REMAIN_HEIGHT_START: + cmp r9, r4 @ if (aligned_height != height) { + beq REMAIN_HEIGHT_END + + mov r6, #0 +LOOP_REMAIN_HEIGHT_WIDTH16: + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 3) + add r8, r8, r6, lsl #3 + add r8, r2, r8 @ src_offset = uv_src + src_offset + + mov r12, r3, asr #1 @ temp1 = (width >> 1) * i + (j >> 1) + mul r12, r12, r5 + add r12, r12, r6, asr #1 + add r7, r0, r12 @ r7 = u_dst + temp1 + add r12, r1, r12 @ r12 = v_dst + temp1 + mov r14, r3, asr #1 @ temp2 = width / 2 + + stmfd sp!, {r0-r1} @ backup registers + mov r0, #0 + sub r1, r4, r9 +LOOP_REMAIN_HEIGHT_WIDTH16_HEIGHT1: + vld2.8 {d0, d1}, [r8]! + vst1.8 {d0}, [r7], r14 + vst1.8 {d1}, [r12], r14 + + add r0, r0, #1 + cmp r0, r1 + blt LOOP_REMAIN_HEIGHT_WIDTH16_HEIGHT1 + ldmfd sp!, {r0-r1} @ restore registers + + add r6, r6, #16 + cmp r6, r10 + blt LOOP_REMAIN_HEIGHT_WIDTH16 + +REMAIN_HEIGHT_REMAIN_WIDTH_START: + cmp r10, r3 + beq REMAIN_HEIGHT_REMAIN_WIDTH_END + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 3) + add r8, r8, r6, lsl #3 + add r8, r2, r8 @ src_offset = uv_src + src_offset + + mov r12, r3, asr #1 @ temp1 = (width >> 1) * i + (j >> 1) + mul r12, r12, r5 + add r12, r12, r6, asr #1 + add r7, r0, r12 @ r7 = u_dst + temp1 + add r12, r1, r12 @ r12 = v_dst + temp1 + sub r14, r3, r6 @ r14 = (width - j) /2 + mov r14, r14, asr #1 + + stmfd sp!, {r0-r2,r4-r5} @ backup registers + mov r0, #0 + sub r1, r4, r9 +LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1: + + mov r4, #0 +LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1_WIDTHx: + ldrb r2, [r8], #1 + ldrb r5, [r8], #1 + strb r2, [r7], #1 + strb r5, [r12], #1 + add r4, #1 + cmp r4, r14 + blt LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1_WIDTHx + + sub r8, r8, r14, lsl #1 + sub r7, r7, r14 + sub r12, r12, r14 + add r8, r8, #16 + add r7, r7, r3, asr #1 + add r12, r12, r3, asr #1 + + add r0, r0, #1 + cmp r0, r1 + blt LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1 + ldmfd sp!, {r0-r2,r4-r5} @ restore registers + +REMAIN_HEIGHT_REMAIN_WIDTH_END: + +REMAIN_HEIGHT_END: + +RESTORE_REG: + ldmfd sp!, {r4-r12,r15} @ restore registers + + .fnend diff --git a/libswconverter/csc_tiled_to_linear_uv_neon.s b/libswconverter/csc_tiled_to_linear_uv_neon.s new file mode 100755 index 0000000..c90d1f3 --- /dev/null +++ b/libswconverter/csc_tiled_to_linear_uv_neon.s @@ -0,0 +1,217 @@ +/* + * + * Copyright 2012 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_tiled_to_linear_uv.s + * @brief SEC_OMX specific define. It support MFC 6.x tiled. + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2012.02.01 : Create + */ + +/* + * Converts tiled data to linear for mfc 6.x tiled + * 1. uv of nv12t to y of yuv420s + * + * @param dst + * uv address of yuv420s[out] + * + * @param src + * uv address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420s[in] + * + * @param yuv420_height + * real height of yuv420s[in] + * + */ + .arch armv7-a + .text + .global csc_tiled_to_linear_uv_neon + .type csc_tiled_to_linear_uv_neon, %function +csc_tiled_to_linear_uv_neon: + .fnstart + + .equ CACHE_LINE_SIZE, 64 + .equ PRE_LOAD_OFFSET, 6 + + @r0 y_dst + @r1 y_src + @r2 width + @r3 height + @r4 temp3 + @r5 i + @r6 j + @r7 dst_offset + @r8 src_offset + @r9 aligned_height + @r10 aligned_width + @r11 tiled_width + @r12 temp1 + @r14 temp2 + + stmfd sp!, {r4-r12,r14} @ backup registers + ldr r4, [sp, #40] @ r4 = height + + bic r9, r3, #0x7 @ aligned_height = height & (~0xF) + bic r10, r2, #0xF @ aligned_width = width & (~0xF) + add r11, r2, #15 @ tiled_width = ((width + 15) >> 4) << 4 + mov r11, r11, asr #4 + mov r11, r11, lsl #4 + + mov r5, #0 +LOOP_MAIN_ALIGNED_HEIGHT: + mul r8, r11, r5 @ src_offset = tiled_width * i + mov r6, #0 + add r8, r1, r8 @ src_offset = y_src + src_offset +LOOP_MAIN_ALIGNED_WIDTH: + pld [r8, #(CACHE_LINE_SIZE*PRE_LOAD_OFFSET)] + vld1.8 {q0, q1}, [r8]! + mul r12, r2, r5 @ temp1 = width * i + j; + vld1.8 {q2, q3}, [r8]! + add r12, r12, r6 + pld [r8, #(CACHE_LINE_SIZE*PRE_LOAD_OFFSET)] + vld1.8 {q4, q5}, [r8]! + add r7, r0, r12 @ dst_offset = y_dst + temp1 + vld1.8 {q6, q7}, [r8]! + + vst1.8 {q0}, [r7], r2 + vst1.8 {q1}, [r7], r2 + vst1.8 {q2}, [r7], r2 + vst1.8 {q3}, [r7], r2 + vst1.8 {q4}, [r7], r2 + vst1.8 {q5}, [r7], r2 + vst1.8 {q6}, [r7], r2 + vst1.8 {q7}, [r7], r2 + add r6, r6, #16 + cmp r6, r10 + blt LOOP_MAIN_ALIGNED_WIDTH + +MAIN_REMAIN_WIDTH_START: + cmp r10, r2 @ if (aligned_width != width) { + beq MAIN_REMAIN_WIDTH_END + + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 3); + add r8, r8, r6, lsl #3 + add r8, r1, r8 @ r8 = y_src + src_offset + + mul r12, r2, r5 @ temp1 = width * i + j; + add r12, r12, r6 + add r7, r0, r12 @ r7 = y_dst + temp1 + sub r14, r2, r6 @ r14 = width - j + + stmfd sp!, {r0-r1} @ backup registers + mov r1, #0 +LOOP_MAIN_REMAIN_HEIGHT: + mov r0, #0 @ r0 is index in memcpy +LOOP_MAIN_REMAIN_WIDTH: + ldrh r4, [r8], #2 + strh r4, [r7], #2 + add r0, #2 + cmp r0, r14 + blt LOOP_MAIN_REMAIN_WIDTH + + sub r8, r8, r14 + sub r7, r7, r14 + add r8, r8, #16 + add r7, r7, r2 + + add r1, #1 + cmp r1, #8 + blt LOOP_MAIN_REMAIN_HEIGHT + ldmfd sp!, {r0-r1} @ restore registers +MAIN_REMAIN_WIDTH_END: + + add r5, r5, #8 + cmp r5, r9 + blt LOOP_MAIN_ALIGNED_HEIGHT + +REMAIN_HEIGHT_START: + cmp r9, r3 @ if (aligned_height != height) { + beq REMAIN_HEIGHT_END + + mov r6, #0 +LOOP_REMAIN_HEIGHT_WIDTH16: + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 3) + add r8, r8, r6, lsl #3 + add r8, r1, r8 @ src_offset = y_src + src_offset + + mul r12, r2, r5 @ temp1 = width * i + j; + add r12, r12, r6 + add r7, r0, r12 @ r7 = y_dst + temp1 + + sub r12, r3, r9 + mov r14, #0 +LOOP_REMAIN_HEIGHT_WIDTH16_HEIGHT1: + vld1.8 {q0}, [r8]! + vld1.8 {q1}, [r8]! + vst1.8 {q0}, [r7], r2 + vst1.8 {q1}, [r7], r2 + + add r14, r14, #2 + cmp r14, r12 + blt LOOP_REMAIN_HEIGHT_WIDTH16_HEIGHT1 + + add r6, r6, #16 + cmp r6, r10 + blt LOOP_REMAIN_HEIGHT_WIDTH16 + +REMAIN_HEIGHT_REMAIN_WIDTH_START: + cmp r10, r2 + beq REMAIN_HEIGHT_REMAIN_WIDTH_END + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 3) + add r8, r8, r6, lsl #3 + add r8, r1, r8 @ src_offset = y_src + src_offset + + mul r12, r2, r5 @ temp1 = width * i + j; + add r12, r12, r6 + add r7, r0, r12 @ r7 = y_dst + temp1 + + stmfd sp!, {r0-r1,r3} @ backup registers + mov r0, #0 + sub r1, r3, r9 +LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1: + + sub r14, r2, r6 + mov r4, #0 +LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1_WIDTHx: + ldrh r3, [r8], #2 + strh r3, [r7], #2 + add r4, #2 + cmp r4, r14 + blt LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1_WIDTHx + + sub r8, r8, r14 + sub r7, r7, r14 + add r8, r8, #16 + add r7, r7, r2 + + add r0, r0, #1 + cmp r0, r1 + blt LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1 + ldmfd sp!, {r0-r1,r3} @ restore registers + +REMAIN_HEIGHT_REMAIN_WIDTH_END: + +REMAIN_HEIGHT_END: + +RESTORE_REG: + ldmfd sp!, {r4-r12,r15} @ restore registers + + .fnend diff --git a/libswconverter/csc_tiled_to_linear_y_neon.s b/libswconverter/csc_tiled_to_linear_y_neon.s new file mode 100755 index 0000000..3cdf092 --- /dev/null +++ b/libswconverter/csc_tiled_to_linear_y_neon.s @@ -0,0 +1,232 @@ +/* + * + * Copyright 2012 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_tiled_to_linear_y.s + * @brief SEC_OMX specific define. It support MFC 6.x tiled. + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2012.02.01 : Create + */ + +/* + * Converts tiled data to linear for mfc 6.x + * 1. Y of NV12T to Y of YUV420P + * 2. Y of NV12T to Y of YUV420S + * + * @param dst + * Y address of YUV420[out] + * + * @param src + * Y address of NV12T[in] + * + * @param yuv420_width + * real width of YUV420[in]. It should be even. + * + * @param yuv420_height + * real height of YUV420[in] It should be even. + * + */ + .arch armv7-a + .text + .global csc_tiled_to_linear_y_neon + .type csc_tiled_to_linear_y_neon, %function +csc_tiled_to_linear_y_neon: + .fnstart + + .equ CACHE_LINE_SIZE, 64 + .equ PRE_LOAD_OFFSET, 6 + + @r0 y_dst + @r1 y_src + @r2 width + @r3 height + @r4 temp3 + @r5 i + @r6 j + @r7 dst_offset + @r8 src_offset + @r9 aligned_height + @r10 aligned_width + @r11 tiled_width + @r12 temp1 + @r14 temp2 + + stmfd sp!, {r4-r12,r14} @ backup registers + ldr r4, [sp, #40] @ r4 = height + + bic r9, r3, #0xF @ aligned_height = height & (~0xF) + bic r10, r2, #0xF @ aligned_width = width & (~0xF) + add r11, r2, #15 @ tiled_width = ((width + 15) >> 4) << 4 + mov r11, r11, asr #4 + mov r11, r11, lsl #4 + + mov r5, #0 +LOOP_MAIN_ALIGNED_HEIGHT: + mul r8, r11, r5 @ src_offset = tiled_width * i + mov r6, #0 + add r8, r1, r8 @ src_offset = y_src + src_offset +LOOP_MAIN_ALIGNED_WIDTH: + pld [r8, #(CACHE_LINE_SIZE*PRE_LOAD_OFFSET)] + vld1.8 {q0, q1}, [r8]! + vld1.8 {q2, q3}, [r8]! + pld [r8, #(CACHE_LINE_SIZE*PRE_LOAD_OFFSET)] + vld1.8 {q4, q5}, [r8]! + vld1.8 {q6, q7}, [r8]! + mul r12, r2, r5 @ temp1 = width * i + j; + pld [r8, #(CACHE_LINE_SIZE*PRE_LOAD_OFFSET)] + vld1.8 {q8, q9}, [r8]! + add r12, r12, r6 + vld1.8 {q10, q11}, [r8]! + add r7, r0, r12 @ dst_offset = y_dst + temp1 + pld [r8, #(CACHE_LINE_SIZE*PRE_LOAD_OFFSET)] + vld1.8 {q12, q13}, [r8]! + vld1.8 {q14, q15}, [r8]! + + vst1.8 {q0}, [r7], r2 + vst1.8 {q1}, [r7], r2 + vst1.8 {q2}, [r7], r2 + vst1.8 {q3}, [r7], r2 + vst1.8 {q4}, [r7], r2 + vst1.8 {q5}, [r7], r2 + vst1.8 {q6}, [r7], r2 + vst1.8 {q7}, [r7], r2 + vst1.8 {q8}, [r7], r2 + vst1.8 {q9}, [r7], r2 + vst1.8 {q10}, [r7], r2 + vst1.8 {q11}, [r7], r2 + vst1.8 {q12}, [r7], r2 + vst1.8 {q13}, [r7], r2 + add r6, r6, #16 + vst1.8 {q14}, [r7], r2 + cmp r6, r10 + vst1.8 {q15}, [r7], r2 + blt LOOP_MAIN_ALIGNED_WIDTH + +MAIN_REMAIN_WIDTH_START: + cmp r10, r2 @ if (aligned_width != width) { + beq MAIN_REMAIN_WIDTH_END + + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 4); + add r8, r8, r6, lsl #4 + add r8, r1, r8 @ r8 = y_src + src_offset + + mul r12, r2, r5 @ temp1 = width * i + j; + add r12, r12, r6 + add r7, r0, r12 @ r7 = y_dst + temp1 + sub r14, r2, r6 @ r14 = width - j + + stmfd sp!, {r0-r1} @ backup registers + mov r1, #0 +LOOP_MAIN_REMAIN_HEIGHT: + mov r0, #0 @ r0 is index in memcpy +LOOP_MAIN_REMAIN_WIDTH: + ldrh r4, [r8], #2 + strh r4, [r7], #2 + add r0, #2 + cmp r0, r14 + blt LOOP_MAIN_REMAIN_WIDTH + + sub r8, r8, r14 + sub r7, r7, r14 + add r8, r8, #16 + add r7, r7, r2 + + add r1, #1 + cmp r1, #16 + blt LOOP_MAIN_REMAIN_HEIGHT + ldmfd sp!, {r0-r1} @ restore registers +MAIN_REMAIN_WIDTH_END: + + add r5, r5, #16 + cmp r5, r9 + blt LOOP_MAIN_ALIGNED_HEIGHT + +REMAIN_HEIGHT_START: + cmp r9, r3 @ if (aligned_height != height) { + beq REMAIN_HEIGHT_END + + mov r6, #0 +LOOP_REMAIN_HEIGHT_WIDTH16: + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 4) + add r8, r8, r6, lsl #4 + add r8, r1, r8 @ src_offset = y_src + src_offset + + mul r12, r2, r5 @ temp1 = width * i + j; + add r12, r12, r6 + add r7, r0, r12 @ r7 = y_dst + temp1 + + sub r12, r3, r9 + mov r14, #0 +LOOP_REMAIN_HEIGHT_WIDTH16_HEIGHT1: + vld1.8 {q0}, [r8]! + vld1.8 {q1}, [r8]! + vst1.8 {q0}, [r7], r2 + vst1.8 {q1}, [r7], r2 + + add r14, r14, #2 + cmp r14, r12 + blt LOOP_REMAIN_HEIGHT_WIDTH16_HEIGHT1 + + add r6, r6, #16 + cmp r6, r10 + blt LOOP_REMAIN_HEIGHT_WIDTH16 + +REMAIN_HEIGHT_REMAIN_WIDTH_START: + cmp r10, r2 + beq REMAIN_HEIGHT_REMAIN_WIDTH_END + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 4) + add r8, r8, r6, lsl #4 + add r8, r1, r8 @ src_offset = y_src + src_offset + + mul r12, r2, r5 @ temp1 = width * i + j; + add r12, r12, r6 + add r7, r0, r12 @ r7 = y_dst + temp1 + + stmfd sp!, {r0-r1,r3} @ backup registers + mov r0, #0 + sub r1, r3, r9 +LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1: + + sub r14, r2, r6 + mov r4, #0 +LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1_WIDTHx: + ldrh r3, [r8], #2 + strh r3, [r7], #2 + add r4, #2 + cmp r4, r14 + blt LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1_WIDTHx + + sub r8, r8, r14 + sub r7, r7, r14 + add r8, r8, #16 + add r7, r7, r2 + + add r0, r0, #1 + cmp r0, r1 + blt LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1 + ldmfd sp!, {r0-r1,r3} @ restore registers + +REMAIN_HEIGHT_REMAIN_WIDTH_END: + +REMAIN_HEIGHT_END: + +RESTORE_REG: + ldmfd sp!, {r4-r12,r15} @ restore registers + + .fnend diff --git a/libswconverter/swconvertor.c b/libswconverter/swconvertor.c new file mode 100755 index 0000000..b3330fe --- /dev/null +++ b/libswconverter/swconvertor.c @@ -0,0 +1,2214 @@ +/* + * + * Copyright 2012 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file swconvertor.c + * + * @brief Exynos_OMX specific define + * + * @author ShinWon Lee (shinwon.lee@samsung.com) + * + * @version 1.0 + * + * @history + * 2012.02.01 : Create + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "swconverter.h" + +#ifdef NEON_SUPPORT +#ifdef USE_NV12T_128X64 +/* MFC 5.X */ +/* + * Converts tiled data to linear + * Crops left, top, right, buttom + * 1. Y of NV12T to Y of YUV420P + * 2. Y of NV12T to Y of YUV420S + * 3. UV of NV12T to UV of YUV420S + * + * @param yuv420_dest + * Y or UV plane address of YUV420[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ + void csc_tiled_to_linear_crop_neon( + unsigned char *yuv420_dest, + unsigned char *nv12t_src, + unsigned int yuv420_width, + unsigned int yuv420_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom); + +/* + * Converts and Deinterleaves tiled data to linear + * Crops left, top, right, buttom + * 1. UV of NV12T to UV of YUV420P + * + * @param yuv420_u_dest + * U plane address of YUV420P[out] + * + * @param yuv420_v_dest + * V plane address of YUV420P[out] + * + * @param nv12t_src + * UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_uv_height + * Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +void csc_tiled_to_linear_deinterleave_crop_neon( + unsigned char *yuv420_u_dest, + unsigned char *yuv420_v_dest, + unsigned char *nv12t_uv_src, + unsigned int yuv420_width, + unsigned int yuv420_uv_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom); + +/* + * Converts linear data to tiled + * Crops left, top, right, buttom + * 1. Y of YUV420P to Y of NV12T + * 2. Y of YUV420S to Y of NV12T + * 3. UV of YUV420S to UV of NV12T + * + * @param nv12t_dest + * Y or UV plane address of NV12T[out] + * + * @param yuv420_src + * Y or UV plane address of YUV420P(S)[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +void csc_linear_to_tiled_crop_neon( + unsigned char *nv12t_dest, + unsigned char *yuv420_src, + unsigned int yuv420_width, + unsigned int yuv420_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom); + +/* + * Converts and Interleaves linear to tiled + * Crops left, top, right, buttom + * 1. UV of YUV420P to UV of NV12T + * + * @param nv12t_uv_dest + * UV plane address of NV12T[out] + * + * @param yuv420p_u_src + * U plane address of YUV420P[in] + * + * @param yuv420p_v_src + * V plane address of YUV420P[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_uv_height + * Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +void csc_linear_to_tiled_interleave_crop_neon( + unsigned char *nv12t_uv_dest, + unsigned char *yuv420_u_src, + unsigned char *yuv420_v_src, + unsigned int yuv420_width, + unsigned int yuv420_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom); +#else +/* others */ +void csc_tiled_to_linear_y_neon( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height); + +void csc_tiled_to_linear_uv_neon( + unsigned char *uv_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height); + +void csc_tiled_to_linear_uv_deinterleave_neon( + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height); +#endif /* USE_NV12T_128X64 */ +/* common */ +void csc_interleave_memcpy_neon( + unsigned char *dest, + unsigned char *src1, + unsigned char *src2, + unsigned int src_size); + +void csc_BGRA8888_to_YUV420SP_NEON( + unsigned char *y_dst, + unsigned char *uv_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height); + +void csc_RGBA8888_to_YUV420SP_NEON( + unsigned char *y_dst, + unsigned char *uv_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height); +#endif /* NEON_SUPPORT */ + + +#ifdef USE_NV12T_128X64 +/* + * It support MFC 5.x tiled. + * Get tiled address of position(x,y) + * + * @param x_size + * width of tiled[in] + * + * @param y_size + * height of tiled[in] + * + * @param x_pos + * x position of tield[in] + * + * @param src_size + * y position of tield[in] + * + * @return + * address of tiled data + */ +static int tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos) +{ + int pixel_x_m1, pixel_y_m1; + int roundup_x, roundup_y; + int linear_addr0, linear_addr1, bank_addr ; + int x_addr; + int trans_addr; + + pixel_x_m1 = x_size -1; + pixel_y_m1 = y_size -1; + + roundup_x = ((pixel_x_m1 >> 7) + 1); + roundup_y = ((pixel_x_m1 >> 6) + 1); + + x_addr = x_pos >> 2; + + if ((y_size <= y_pos+32) && ( y_pos < y_size) && + (((pixel_y_m1 >> 5) & 0x1) == 0) && (((y_pos >> 5) & 0x1) == 0)) { + linear_addr0 = (((y_pos & 0x1f) <<4) | (x_addr & 0xf)); + linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 6) & 0x3f)); + + if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1)) + bank_addr = ((x_addr >> 4) & 0x1); + else + bank_addr = 0x2 | ((x_addr >> 4) & 0x1); + } else { + linear_addr0 = (((y_pos & 0x1f) << 4) | (x_addr & 0xf)); + linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 5) & 0x7f)); + + if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1)) + bank_addr = ((x_addr >> 4) & 0x1); + else + bank_addr = 0x2 | ((x_addr >> 4) & 0x1); + } + + linear_addr0 = linear_addr0 << 2; + trans_addr = (linear_addr1 <<13) | (bank_addr << 11) | linear_addr0; + + return trans_addr; +} + +/* + * It support MFC 5.x tiled. + * Converts tiled data to linear + * Crops left, top, right, buttom + * 1. Y of NV12T to Y of YUV420P + * 2. Y of NV12T to Y of YUV420S + * 3. UV of NV12T to UV of YUV420S + * + * @param yuv420_dest + * Y or UV plane address of YUV420[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +static void csc_tiled_to_linear_crop( + unsigned char *yuv420_dest, + unsigned char *nv12t_src, + unsigned int yuv420_width, + unsigned int yuv420_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom) +{ + unsigned int i, j; + unsigned int tiled_offset = 0, tiled_offset1 = 0; + unsigned int linear_offset = 0; + unsigned int temp1 = 0, temp2 = 0, temp3 = 0, temp4 = 0; + + temp3 = yuv420_width-right; + temp1 = temp3-left; + /* real width is greater than or equal 256 */ + if (temp1 >= 256) { + for (i=top; i<yuv420_height-buttom; i=i+1) { + j = left; + temp3 = (j>>8)<<8; + temp3 = temp3>>6; + temp4 = i>>5; + if (temp4 & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = temp4-1; + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+temp3; + tiled_offset = tiled_offset+2; + temp1 = (temp3>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*2; + temp4 = 8; + } else { + temp2 = ((yuv420_height+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = temp3+2; + temp1 = (temp1>>2)<<2; + tiled_offset = temp3+temp1; + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = tiled_offset+temp4*(temp1>>6); + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*6; + temp4 = 8; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = temp4*(temp1>>6); + tiled_offset = tiled_offset+temp3; + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*2; + temp4 = 4; + } + } + + temp1 = i&0x1F; + tiled_offset = tiled_offset+64*(temp1); + tiled_offset1 = tiled_offset1+64*(temp1); + temp2 = yuv420_width-left-right; + linear_offset = temp2*(i-top); + temp3 = ((j+256)>>8)<<8; + temp3 = temp3-j; + temp1 = left&0x3F; + if (temp3 > 192) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset+temp1, 64-temp1); + temp2 = ((left+63)>>6)<<6; + temp3 = ((yuv420_width-right)>>6)<<6; + if (temp2 == temp3) { + temp2 = yuv420_width-right-(64-temp1); + } + memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset+2048, 64); + memcpy(yuv420_dest+linear_offset+128-temp1, nv12t_src+tiled_offset1, 64); + memcpy(yuv420_dest+linear_offset+192-temp1, nv12t_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+256-temp1; + } else if (temp3 > 128) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset+2048+temp1, 64-temp1); + memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset1, 64); + memcpy(yuv420_dest+linear_offset+128-temp1, nv12t_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+192-temp1; + } else if (temp3 > 64) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset1+temp1, 64-temp1); + memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+128-temp1; + } else if (temp3 > 0) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset1+2048+temp1, 64-temp1); + linear_offset = linear_offset+64-temp1; + } + + tiled_offset = tiled_offset+temp4*2048; + j = (left>>8)<<8; + j = j + 256; + temp2 = yuv420_width-right-256; + for (; j<=temp2; j=j+256) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + tiled_offset1 = tiled_offset1+temp4*2048; + memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64); + memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, 64); + tiled_offset = tiled_offset+temp4*2048; + memcpy(yuv420_dest+linear_offset+192, nv12t_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+256; + } + + tiled_offset1 = tiled_offset1+temp4*2048; + temp2 = yuv420_width-right-j; + if (temp2 > 192) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64); + memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, 64); + memcpy(yuv420_dest+linear_offset+192, nv12t_src+tiled_offset1+2048, temp2-192); + } else if (temp2 > 128) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64); + memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, temp2-128); + } else if (temp2 > 64) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, temp2-64); + } else { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2); + } + } + } else if (temp1 >= 64) { + for (i=top; i<(yuv420_height-buttom); i=i+1) { + j = left; + tiled_offset = tile_4x2_read(yuv420_width, yuv420_height, j, i); + temp2 = ((j+64)>>6)<<6; + temp2 = temp2-j; + linear_offset = temp1*(i-top); + temp4 = j&0x3; + tiled_offset = tiled_offset+temp4; + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2); + linear_offset = linear_offset+temp2; + j = j+temp2; + if ((j+64) <= temp3) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_height, j, i); + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + linear_offset = linear_offset+64; + j = j+64; + } + if ((j+64) <= temp3) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_height, j, i); + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + linear_offset = linear_offset+64; + j = j+64; + } + if (j < temp3) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_height, j, i); + temp2 = temp3-j; + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2); + } + } + } else { + for (i=top; i<(yuv420_height-buttom); i=i+1) { + linear_offset = temp1*(i-top); + for (j=left; j<(yuv420_width-right); j=j+2) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_height, j, i); + temp4 = j&0x3; + tiled_offset = tiled_offset+temp4; + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 2); + linear_offset = linear_offset+2; + } + } + } +} + +/* + * Converts and Deinterleaves tiled data to linear + * Crops left, top, right, buttom + * 1. UV of NV12T to UV of YUV420P + * + * @param yuv420_u_dest + * U plane address of YUV420P[out] + * + * @param yuv420_v_dest + * V plane address of YUV420P[out] + * + * @param nv12t_src + * UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_uv_height + * Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +static void csc_tiled_to_linear_deinterleave_crop( + unsigned char *yuv420_u_dest, + unsigned char *yuv420_v_dest, + unsigned char *nv12t_uv_src, + unsigned int yuv420_width, + unsigned int yuv420_uv_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom) +{ + unsigned int i, j; + unsigned int tiled_offset = 0, tiled_offset1 = 0; + unsigned int linear_offset = 0; + unsigned int temp1 = 0, temp2 = 0, temp3 = 0, temp4 = 0; + + temp3 = yuv420_width-right; + temp1 = temp3-left; + /* real width is greater than or equal 256 */ + if (temp1 >= 256) { + for (i=top; i<yuv420_uv_height-buttom; i=i+1) { + j = left; + temp3 = (j>>8)<<8; + temp3 = temp3>>6; + temp4 = i>>5; + if (temp4 & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = temp4-1; + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+temp3; + tiled_offset = tiled_offset+2; + temp1 = (temp3>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*2; + temp4 = 8; + } else { + temp2 = ((yuv420_uv_height+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = temp3+2; + temp1 = (temp1>>2)<<2; + tiled_offset = temp3+temp1; + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = tiled_offset+temp4*(temp1>>6); + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*6; + temp4 = 8; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = temp4*(temp1>>6); + tiled_offset = tiled_offset+temp3; + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*2; + temp4 = 4; + } + } + + temp1 = i&0x1F; + tiled_offset = tiled_offset+64*(temp1); + tiled_offset1 = tiled_offset1+64*(temp1); + temp2 = yuv420_width-left-right; + linear_offset = temp2*(i-top)/2; + temp3 = ((j+256)>>8)<<8; + temp3 = temp3-j; + temp1 = left&0x3F; + if (temp3 > 192) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, yuv420_v_dest+linear_offset, nv12t_uv_src+tiled_offset+temp1, 64-temp1); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+(32-temp1/2), + yuv420_v_dest+linear_offset+(32-temp1/2), + nv12t_uv_src+tiled_offset+2048, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+(64-temp1/2), + yuv420_v_dest+linear_offset+(64-temp1/2), + nv12t_uv_src+tiled_offset1, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+(96-temp1/2), + yuv420_v_dest+linear_offset+(96-temp1/2), + nv12t_uv_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+128-temp1/2; + } else if (temp3 > 128) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset+2048+temp1, 64-temp1); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+(32-temp1/2), + yuv420_v_dest+linear_offset+(32-temp1/2), + nv12t_uv_src+tiled_offset1, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+(64-temp1/2), + yuv420_v_dest+linear_offset+(64-temp1/2), + nv12t_uv_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+96-temp1/2; + } else if (temp3 > 64) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset1+temp1, 64-temp1); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+(32-temp1/2), + yuv420_v_dest+linear_offset+(32-temp1/2), + nv12t_uv_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+64-temp1/2; + } else if (temp3 > 0) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset1+2048+temp1, 64-temp1); + linear_offset = linear_offset+32-temp1/2; + } + + tiled_offset = tiled_offset+temp4*2048; + j = (left>>8)<<8; + j = j + 256; + temp2 = yuv420_width-right-256; + for (; j<=temp2; j=j+256) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, 64); + tiled_offset1 = tiled_offset1+temp4*2048; + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+32, + yuv420_v_dest+linear_offset+32, + nv12t_uv_src+tiled_offset+2048, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+64, + yuv420_v_dest+linear_offset+64, + nv12t_uv_src+tiled_offset1, 64); + tiled_offset = tiled_offset+temp4*2048; + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+96, + yuv420_v_dest+linear_offset+96, + nv12t_uv_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+128; + } + + tiled_offset1 = tiled_offset1+temp4*2048; + temp2 = yuv420_width-right-j; + if (temp2 > 192) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+32, + yuv420_v_dest+linear_offset+32, + nv12t_uv_src+tiled_offset+2048, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+64, + yuv420_v_dest+linear_offset+64, + nv12t_uv_src+tiled_offset1, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+96, + yuv420_v_dest+linear_offset+96, + nv12t_uv_src+tiled_offset1+2048, temp2-192); + } else if (temp2 > 128) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+32, + yuv420_v_dest+linear_offset+32, + nv12t_uv_src+tiled_offset+2048, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+64, + yuv420_v_dest+linear_offset+64, + nv12t_uv_src+tiled_offset1, temp2-128); + } else if (temp2 > 64) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+32, + yuv420_v_dest+linear_offset+32, + nv12t_uv_src+tiled_offset+2048, temp2-64); + } else { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, temp2); + } + } + } else if (temp1 >= 64) { + for (i=top; i<(yuv420_uv_height-buttom); i=i+1) { + j = left; + tiled_offset = tile_4x2_read(yuv420_width, yuv420_uv_height, j, i); + temp2 = ((j+64)>>6)<<6; + temp2 = temp2-j; + temp3 = yuv420_width-right; + temp4 = temp3-left; + linear_offset = temp4*(i-top)/2; + temp4 = j&0x3; + tiled_offset = tiled_offset+temp4; + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, temp2); + linear_offset = linear_offset+temp2/2; + j = j+temp2; + if ((j+64) <= temp3) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_uv_height, j, i); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, 64); + linear_offset = linear_offset+32; + j = j+64; + } + if ((j+64) <= temp3) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_uv_height, j, i); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, 64); + linear_offset = linear_offset+32; + j = j+64; + } + if (j < temp3) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_uv_height, j, i); + temp1 = temp3-j; + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, temp1); + } + } + } else { + for (i=top; i<(yuv420_uv_height-buttom); i=i+1) { + temp3 = yuv420_width-right; + temp4 = temp3-left; + linear_offset = temp4*(i-top)/2; + for (j=left; j<(yuv420_width-right); j=j+2) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_uv_height, j, i); + temp3 = j&0x3; + tiled_offset = tiled_offset+temp3; + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, 2); + linear_offset = linear_offset+1; + } + } + } +} + +/* + * Converts linear data to tiled + * Crops left, top, right, buttom + * 1. Y of YUV420P to Y of NV12T + * 2. Y of YUV420S to Y of NV12T + * 3. UV of YUV420S to UV of NV12T + * + * @param nv12t_dest + * Y or UV plane address of NV12T[out] + * + * @param yuv420_src + * Y or UV plane address of YUV420P(S)[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +static void csc_linear_to_tiled_crop( + unsigned char *nv12t_dest, + unsigned char *yuv420_src, + unsigned int yuv420_width, + unsigned int yuv420_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom) +{ + unsigned int i, j; + unsigned int tiled_x_index = 0, tiled_y_index = 0; + unsigned int aligned_x_size = 0, aligned_y_size = 0; + unsigned int tiled_offset = 0; + unsigned int temp1 = 0, temp2 = 0; + + aligned_y_size = ((yuv420_height-top-buttom)>>5)<<5; + aligned_x_size = ((yuv420_width-left-right)>>6)<<6; + + for (i=0; i<aligned_y_size; i=i+32) { + for (j=0; j<aligned_x_size; j=j+64) { + tiled_offset = 0; + tiled_x_index = j>>6; + tiled_y_index = i>>5; + if (tiled_y_index & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = tiled_y_index-1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset+2; + temp1 = (tiled_x_index>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + } else { + temp2 = (((yuv420_height-top-buttom)+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = tiled_x_index+2; + temp1 = (temp1>>2)<<2; + tiled_offset = tiled_x_index+temp1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset+tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset<<11; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset<<11; + } + } + + memcpy(nv12t_dest+tiled_offset, yuv420_src+left+j+yuv420_width*(i+top), 64); + memcpy(nv12t_dest+tiled_offset+64*1, yuv420_src+left+j+yuv420_width*(i+top+1), 64); + memcpy(nv12t_dest+tiled_offset+64*2, yuv420_src+left+j+yuv420_width*(i+top+2), 64); + memcpy(nv12t_dest+tiled_offset+64*3, yuv420_src+left+j+yuv420_width*(i+top+3), 64); + memcpy(nv12t_dest+tiled_offset+64*4, yuv420_src+left+j+yuv420_width*(i+top+4), 64); + memcpy(nv12t_dest+tiled_offset+64*5, yuv420_src+left+j+yuv420_width*(i+top+5), 64); + memcpy(nv12t_dest+tiled_offset+64*6, yuv420_src+left+j+yuv420_width*(i+top+6), 64); + memcpy(nv12t_dest+tiled_offset+64*7, yuv420_src+left+j+yuv420_width*(i+top+7), 64); + memcpy(nv12t_dest+tiled_offset+64*8, yuv420_src+left+j+yuv420_width*(i+top+8), 64); + memcpy(nv12t_dest+tiled_offset+64*9, yuv420_src+left+j+yuv420_width*(i+top+9), 64); + memcpy(nv12t_dest+tiled_offset+64*10, yuv420_src+left+j+yuv420_width*(i+top+10), 64); + memcpy(nv12t_dest+tiled_offset+64*11, yuv420_src+left+j+yuv420_width*(i+top+11), 64); + memcpy(nv12t_dest+tiled_offset+64*12, yuv420_src+left+j+yuv420_width*(i+top+12), 64); + memcpy(nv12t_dest+tiled_offset+64*13, yuv420_src+left+j+yuv420_width*(i+top+13), 64); + memcpy(nv12t_dest+tiled_offset+64*14, yuv420_src+left+j+yuv420_width*(i+top+14), 64); + memcpy(nv12t_dest+tiled_offset+64*15, yuv420_src+left+j+yuv420_width*(i+top+15), 64); + memcpy(nv12t_dest+tiled_offset+64*16, yuv420_src+left+j+yuv420_width*(i+top+16), 64); + memcpy(nv12t_dest+tiled_offset+64*17, yuv420_src+left+j+yuv420_width*(i+top+17), 64); + memcpy(nv12t_dest+tiled_offset+64*18, yuv420_src+left+j+yuv420_width*(i+top+18), 64); + memcpy(nv12t_dest+tiled_offset+64*19, yuv420_src+left+j+yuv420_width*(i+top+19), 64); + memcpy(nv12t_dest+tiled_offset+64*20, yuv420_src+left+j+yuv420_width*(i+top+20), 64); + memcpy(nv12t_dest+tiled_offset+64*21, yuv420_src+left+j+yuv420_width*(i+top+21), 64); + memcpy(nv12t_dest+tiled_offset+64*22, yuv420_src+left+j+yuv420_width*(i+top+22), 64); + memcpy(nv12t_dest+tiled_offset+64*23, yuv420_src+left+j+yuv420_width*(i+top+23), 64); + memcpy(nv12t_dest+tiled_offset+64*24, yuv420_src+left+j+yuv420_width*(i+top+24), 64); + memcpy(nv12t_dest+tiled_offset+64*25, yuv420_src+left+j+yuv420_width*(i+top+25), 64); + memcpy(nv12t_dest+tiled_offset+64*26, yuv420_src+left+j+yuv420_width*(i+top+26), 64); + memcpy(nv12t_dest+tiled_offset+64*27, yuv420_src+left+j+yuv420_width*(i+top+27), 64); + memcpy(nv12t_dest+tiled_offset+64*28, yuv420_src+left+j+yuv420_width*(i+top+28), 64); + memcpy(nv12t_dest+tiled_offset+64*29, yuv420_src+left+j+yuv420_width*(i+top+29), 64); + memcpy(nv12t_dest+tiled_offset+64*30, yuv420_src+left+j+yuv420_width*(i+top+30), 64); + memcpy(nv12t_dest+tiled_offset+64*31, yuv420_src+left+j+yuv420_width*(i+top+31), 64); + } + } + + for (i=aligned_y_size; i<(yuv420_height-top-buttom); i=i+2) { + for (j=0; j<aligned_x_size; j=j+64) { + tiled_offset = 0; + tiled_x_index = j>>6; + tiled_y_index = i>>5; + if (tiled_y_index & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = tiled_y_index-1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset+2; + temp1 = (tiled_x_index>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + } else { + temp2 = (((yuv420_height-top-buttom)+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = tiled_x_index+2; + temp1 = (temp1>>2)<<2; + tiled_offset = tiled_x_index+temp1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset+tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset<<11; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset<<11; + } + } + + temp1 = i&0x1F; + memcpy(nv12t_dest+tiled_offset+64*(temp1), yuv420_src+left+j+yuv420_width*(i+top), 64); + memcpy(nv12t_dest+tiled_offset+64*(temp1+1), yuv420_src+left+j+yuv420_width*(i+top+1), 64); + } + } + + for (i=0; i<(yuv420_height-top-buttom); i=i+2) { + for (j=aligned_x_size; j<(yuv420_width-left-right); j=j+2) { + tiled_offset = 0; + tiled_x_index = j>>6; + tiled_y_index = i>>5; + if (tiled_y_index & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = tiled_y_index-1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset+2; + temp1 = (tiled_x_index>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + } else { + temp2 = (((yuv420_height-top-buttom)+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = tiled_x_index+2; + temp1 = (temp1>>2)<<2; + tiled_offset = tiled_x_index+temp1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset+tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset<<11; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset<<11; + } + } + + temp1 = i&0x1F; + temp2 = j&0x3F; + memcpy(nv12t_dest+tiled_offset+temp2+64*(temp1), yuv420_src+left+j+yuv420_width*(i+top), 2); + memcpy(nv12t_dest+tiled_offset+temp2+64*(temp1+1), yuv420_src+left+j+yuv420_width*(i+top+1), 2); + } + } +} + +/* + * Converts and Interleaves linear to tiled + * Crops left, top, right, buttom + * 1. UV of YUV420P to UV of NV12T + * + * @param nv12t_uv_dest + * UV plane address of NV12T[out] + * + * @param yuv420p_u_src + * U plane address of YUV420P[in] + * + * @param yuv420p_v_src + * V plane address of YUV420P[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_uv_height + * Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +static void csc_linear_to_tiled_interleave_crop( + unsigned char *nv12t_uv_dest, + unsigned char *yuv420_u_src, + unsigned char *yuv420_v_src, + unsigned int yuv420_width, + unsigned int yuv420_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom) +{ + unsigned int i, j; + unsigned int tiled_x_index = 0, tiled_y_index = 0; + unsigned int aligned_x_size = 0, aligned_y_size = 0; + unsigned int tiled_offset = 0; + unsigned int temp1 = 0, temp2 = 0; + + aligned_y_size = ((yuv420_height-top-buttom)>>5)<<5; + aligned_x_size = ((yuv420_width-left-right)>>6)<<6; + + for (i=0; i<aligned_y_size; i=i+32) { + for (j=0; j<aligned_x_size; j=j+64) { + tiled_offset = 0; + tiled_x_index = j>>6; + tiled_y_index = i>>5; + if (tiled_y_index & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = tiled_y_index-1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset+2; + temp1 = (tiled_x_index>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + } else { + temp2 = (((yuv420_height-top-buttom)+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = tiled_x_index+2; + temp1 = (temp1>>2)<<2; + tiled_offset = tiled_x_index+temp1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset+tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset<<11; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset<<11; + } + } + + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*1, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+1), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+1), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*2, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+2), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+2), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*3, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+3), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+3), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*4, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+4), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+4), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*5, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+5), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+5), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*6, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+6), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+6), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*7, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+7), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+7), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*8, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+8), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+8), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*9, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+9), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+9), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*10, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+10), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+10), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*11, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+11), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+11), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*12, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+12), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+12), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*13, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+13), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+13), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*14, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+14), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+14), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*15, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+15), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+15), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*16, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+16), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+16), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*17, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+17), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+17), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*18, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+18), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+18), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*19, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+19), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+19), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*20, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+20), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+20), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*21, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+21), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+21), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*22, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+22), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+22), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*23, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+23), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+23), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*24, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+24), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+24), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*25, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+25), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+25), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*26, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+26), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+26), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*27, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+27), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+27), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*28, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+28), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+28), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*29, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+29), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+29), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*30, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+30), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+30), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*31, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+31), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+31), 32); + + } + } + + for (i=aligned_y_size; i<(yuv420_height-top-buttom); i=i+1) { + for (j=0; j<aligned_x_size; j=j+64) { + tiled_offset = 0; + tiled_x_index = j>>6; + tiled_y_index = i>>5; + if (tiled_y_index & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = tiled_y_index-1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset+2; + temp1 = (tiled_x_index>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + } else { + temp2 = (((yuv420_height-top-buttom)+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = tiled_x_index+2; + temp1 = (temp1>>2)<<2; + tiled_offset = tiled_x_index+temp1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset+tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset<<11; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset<<11; + } + } + temp1 = i&0x1F; + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*(temp1), + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top), 32); + } + } + + for (i=0; i<(yuv420_height-top-buttom); i=i+1) { + for (j=aligned_x_size; j<(yuv420_width-left-right); j=j+2) { + tiled_offset = 0; + tiled_x_index = j>>6; + tiled_y_index = i>>5; + if (tiled_y_index & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = tiled_y_index-1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset+2; + temp1 = (tiled_x_index>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + } else { + temp2 = (((yuv420_height-top-buttom)+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = tiled_x_index+2; + temp1 = (temp1>>2)<<2; + tiled_offset = tiled_x_index+temp1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset+tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset<<11; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset<<11; + } + } + temp1 = i&0x1F; + temp2 = j&0x3F; + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+temp2+64*(temp1), + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top), 1); + } + } +} +#else +/* 2D Configurable tiled memory access (TM) + * Return the linear address from tiled position (x, y) */ +static unsigned int Tile2D_To_Linear( + unsigned int width, + unsigned int height, + unsigned int xpos, + unsigned int ypos, + int crFlag) +{ + int tileNumX; + int tileX, tileY; + int tileAddr; + int offset; + int addr; + + width = ((width + 15) / 16) * 16; + height = ((height + 15) / 16) * 16; + tileNumX = width / 16; + + /* crFlag - 0: Y plane, 1: CbCr plane */ + if (crFlag == 0) { + tileX = xpos / 16; + tileY = ypos / 16; + tileAddr = tileY * tileNumX + tileX; + offset = (ypos & 15) * 16 + (xpos & 15); + addr = (tileAddr << 8) | offset; + } else { + tileX = xpos / 16; + tileY = ypos / 8; + tileAddr = tileY * tileNumX + tileX; + offset = (ypos & 7) * 16 + (xpos & 15); + addr = (tileAddr << 7) | offset; + } + + return addr; +} + +static void Tile2D_To_YUV420(unsigned char *Y_plane, unsigned char *Cb_plane, unsigned char *Cr_plane, + unsigned int y_addr, unsigned int c_addr, unsigned int width, unsigned int height) +{ + unsigned int x, y, j, k, l; + unsigned int out_of_width, actual_width, data; + unsigned long base_addr; + + // y: 0, 16, 32, ... + for (y = 0; y < height; y += 16) { + // x: 0, 16, 32, ... + for (x = 0; x < width; x += 16) { + out_of_width = (x + 16) > width ? 1 : 0; + base_addr = y_addr + Tile2D_To_Linear(width, height, x, y, 0); + + for (k = 0; (k < 16) && ((y + k) < height); k++) { + actual_width = out_of_width ? ((width%4)?((width%16) / 4 + 1) : ((width%16) / 4)) : 4; + for (l = 0; l < actual_width; l++) { + data = *((unsigned int *)(base_addr + 16*k + l*4)); + for (j = 0; (j < 4) && (x + l*4 + j) < width; j++) { + Y_plane[(y+k)*width + x + l*4 +j] = (data>>(8*j))&0xff; + } + } + } + } + } + + for (y = 0; y < height/2; y += 8) { + for (x = 0; x < width; x += 16) { + out_of_width = (x + 16) > width ? 1 : 0; + base_addr = c_addr + Tile2D_To_Linear(width, height/2, x, y, 1); + for (k = 0; (k < 8) && ((y+k) < height/2); k++) { + actual_width = out_of_width ? ((width%4) ? ((width%16) / 4 + 1) : ((width%16) / 4)) : 4; + for (l = 0; l < actual_width; l++) { + data = *((unsigned int *)(base_addr + 16*k + l*4)); + for (j = 0; (j < 2) && (x/2 + l*2 +j) < width/2; j++) { + Cb_plane[(y+k)*width/2 + x/2 + l*2 +j] = (data>> (8*2*j))&0xff; + Cr_plane[(y+k)*width/2 + x/2 + l*2 +j] = (data>>(8*2*j+8))&0xff; + } + } + } + } + } +} +#endif /* USE_NV12T_128X64 */ + +/* + * De-interleaves src to dest1, dest2 + * + * @param dest1 + * Address of de-interleaved data[out] + * + * @param dest2 + * Address of de-interleaved data[out] + * + * @param src + * Address of interleaved data[in] + * + * @param src_size + * Size of interleaved data[in] + */ +void csc_deinterleave_memcpy( + unsigned char *dest1, + unsigned char *dest2, + unsigned char *src, + unsigned int src_size) +{ + unsigned int i = 0; + for(i=0; i<src_size/2; i++) { + dest1[i] = src[i*2]; + dest2[i] = src[i*2+1]; + } +} + +/* + * Interleaves src1, src2 to dest + * + * @param dest + * Address of interleaved data[out] + * + * @param src1 + * Address of de-interleaved data[in] + * + * @param src2 + * Address of de-interleaved data[in] + * + * @param src_size + * Size of de-interleaved data[in] + */ +void csc_interleave_memcpy( + unsigned char *dest, + unsigned char *src1, + unsigned char *src2, + unsigned int src_size) +{ +#ifdef NEON_SUPPORT + csc_interleave_memcpy_neon(dest, src1, src2, src_size); +#else +/* not neon */ + unsigned int i = 0; + for(i=0; i<src_size; i++) { + dest[i*2] = src1[i]; + dest[i*2+1] = src2[i]; + } +#endif /* NEON_SUPPORT */ +} + +/* + * Converts tiled data to linear. + * 1. y of nv12t to y of yuv420p + * 2. y of nv12t to y of yuv420s + * + * @param dst + * y address of yuv420[out] + * + * @param src + * y address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_tiled_to_linear_y( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height) +{ +#ifdef NEON_SUPPORT +#ifdef USE_NV12T_128X64 + csc_tiled_to_linear_crop_neon(y_dst, y_src, width, height, 0, 0, 0, 0); +#else + csc_tiled_to_linear_y_neon(y_dst, y_src, width, height); +#endif /* USE_NV12T_128X64 */ + +#else +/* not neon */ +#ifdef USE_NV12T_128X64 + csc_tiled_to_linear_crop(y_dst, y_src, width, height, 0, 0, 0, 0); +#else + unsigned int i, j, k; + unsigned int aligned_width, aligned_height; + unsigned int tiled_width; + unsigned int src_offset, dst_offset; + + aligned_height = height & (~0xF); + aligned_width = width & (~0xF); + tiled_width = ((width + 15) >> 4) << 4; + + for (i = 0; i < aligned_height; i = i + 16) { + for (j = 0; j<aligned_width; j = j + 16) { + src_offset = (tiled_width * i) + (j << 4); + dst_offset = width * i + j; + for (k = 0; k < 8; k++) { + memcpy(y_dst + dst_offset, y_src + src_offset, 16); + src_offset += 16; + dst_offset += width; + memcpy(y_dst + dst_offset, y_src + src_offset, 16); + src_offset += 16; + dst_offset += width; + } + } + if (aligned_width != width) { + src_offset = (tiled_width * i) + (j << 4); + dst_offset = width * i + j; + for (k = 0; k < 8; k++) { + memcpy(y_dst + dst_offset, y_src + src_offset, width - j); + src_offset += 16; + dst_offset += width; + memcpy(y_dst + dst_offset, y_src + src_offset, width - j); + src_offset += 16; + dst_offset += width; + } + } + } + + if (aligned_height != height) { + for (j = 0; j<aligned_width; j = j + 16) { + src_offset = (tiled_width * i) + (j << 4); + dst_offset = width * i + j; + for (k = 0; k < height - aligned_height; k = k + 2) { + memcpy(y_dst + dst_offset, y_src + src_offset, 16); + src_offset += 16; + dst_offset += width; + memcpy(y_dst + dst_offset, y_src + src_offset, 16); + src_offset += 16; + dst_offset += width; + } + } + if (aligned_width != width) { + src_offset = (tiled_width * i) + (j << 4); + dst_offset = width * i + j; + for (k = 0; k < height - aligned_height; k = k + 2) { + memcpy(y_dst + dst_offset, y_src + src_offset, width - j); + src_offset += 16; + dst_offset += width; + memcpy(y_dst + dst_offset, y_src + src_offset, width - j); + src_offset += 16; + dst_offset += width; + } + } + } +#endif /* USE_NV12T_128X64 */ +#endif /* NEON_SUPPORT */ +} + +/* + * Converts tiled data to linear + * 1. uv of nv12t to y of yuv420s + * + * @param dst + * uv address of yuv420s[out] + * + * @param src + * uv address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420s[in] + * + * @param yuv420_height + * real height of yuv420s[in] + * + */ +void csc_tiled_to_linear_uv( + unsigned char *uv_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height) +{ +#ifdef NEON_SUPPORT +#ifdef USE_NV12T_128X64 + csc_tiled_to_linear_crop_neon(uv_dst, uv_src, width, height, 0, 0, 0, 0); +#else + csc_tiled_to_linear_uv_neon(uv_dst, uv_src, width, height); +#endif /* USE_NV12T_128X64 */ + +#else +/* not neon */ +#ifdef USE_NV12T_128X64 + csc_tiled_to_linear_crop(uv_dst, uv_src, width, height, 0, 0, 0, 0); +#else + unsigned int i, j, k; + unsigned int aligned_width, aligned_height; + unsigned int tiled_width; + unsigned int src_offset, dst_offset; + + aligned_height = height & (~0x7); + aligned_width = width & (~0xF); + tiled_width = ((width + 15) >> 4) << 4; + + for (i = 0; i < aligned_height; i = i + 8) { + for (j = 0; j<aligned_width; j = j + 16) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = width * i + j; + for (k = 0; k < 4; k++) { + memcpy(uv_dst + dst_offset, uv_src + src_offset, 16); + src_offset += 16; + dst_offset += width; + memcpy(uv_dst + dst_offset, uv_src + src_offset, 16); + src_offset += 16; + dst_offset += width; + } + } + if (aligned_width != width) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = width * i + j; + for (k = 0; k < 4; k++) { + memcpy(uv_dst + dst_offset, uv_src + src_offset, width - j); + src_offset += 16; + dst_offset += width; + memcpy(uv_dst + dst_offset, uv_src + src_offset, width - j); + src_offset += 16; + dst_offset += width; + } + } + } + + if (aligned_height != height) { + for (j = 0; j<aligned_width; j = j + 16) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = width * i + j; + for (k = 0; k < height - aligned_height; k = k + 1) { + memcpy(uv_dst + dst_offset, uv_src + src_offset, 16); + src_offset += 16; + dst_offset += width; + } + } + if (aligned_width != width) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = width * i + j; + for (k = 0; k < height - aligned_height; k = k + 1) { + memcpy(uv_dst + dst_offset, uv_src + src_offset, width - j); + src_offset += 16; + dst_offset += width; + } + } + } +#endif /* USE_NV12T_128X64 */ +#endif /* NEON_SUPPORT */ +} + +/* + * Converts tiled data to linear + * 1. uv of nt12t to uv of yuv420p + * + * @param u_dst + * u address of yuv420p[out] + * + * @param v_dst + * v address of yuv420p[out] + * + * @param uv_src + * uv address of nt12t[in] + * + * @param yuv420_width + * real width of yuv420p[in] + * + * @param yuv420_height + * real height of yuv420p[in] + */ +void csc_tiled_to_linear_uv_deinterleave( + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height) +{ +#ifdef NEON_SUPPORT +#ifdef USE_NV12T_128X64 + csc_tiled_to_linear_deinterleave_crop_neon(u_dst, v_dst, uv_src, width, height, 0, 0, 0, 0); +#else + csc_tiled_to_linear_uv_deinterleave_neon(u_dst, v_dst, uv_src, width, height); +#endif /* USE_NV12T_128X64 */ + +#else +/*not neon */ +#ifdef USE_NV12_128X64 + csc_tiled_to_linear_deinterleave_crop(u_dst, v_dst, uv_src, width, height, + 0, 0, 0, 0); +#else + unsigned int i, j, k; + unsigned int aligned_width, aligned_height; + unsigned int tiled_width; + unsigned int src_offset, dst_offset; + + aligned_height = height & (~0x7); + aligned_width = width & (~0xF); + tiled_width = ((width + 15) >> 4) << 4; + + for (i = 0; i < aligned_height; i = i + 8) { + for (j = 0; j<aligned_width; j = j + 16) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = (width >> 1) * i + (j >> 1); + for (k = 0; k < 4; k++) { + csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset, + uv_src + src_offset, 16); + src_offset += 16; + dst_offset += width >> 1; + csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset, + uv_src + src_offset, 16); + src_offset += 16; + dst_offset += width >> 1; + } + } + if (aligned_width != width) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = (width >> 1) * i + (j >> 1); + for (k = 0; k < 4; k++) { + csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset, + uv_src + src_offset, width - j); + src_offset += 16; + dst_offset += width >> 1; + csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset, + uv_src + src_offset, width - j); + src_offset += 16; + dst_offset += width >> 1; + } + } + } + if (aligned_height != height) { + for (j = 0; j<aligned_width; j = j + 16) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = (width >> 1) * i + (j >> 1); + for (k = 0; k < height - aligned_height; k = k + 1) { + csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset, + uv_src + src_offset, 16); + src_offset += 16; + dst_offset += width >> 1; + } + } + if (aligned_width != width) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = (width >> 1) * i + (j >> 1); + for (k = 0; k < height - aligned_height; k = k + 1) { + csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset, + uv_src + src_offset, width - j); + src_offset += 16; + dst_offset += width >> 1; + } + } + } +#endif /* USE_NV12T_128X64 */ +#endif /* NEON_SUPPORT */ +} + +/* + * Converts linear data to tiled + * 1. y of yuv420 to y of nv12t + * + * @param dst + * y address of nv12t[out] + * + * @param src + * y address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_linear_to_tiled_y( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height) +{ +#ifdef USE_NV12T_128X64 +#ifdef NEON_SUPPORT + csc_linear_to_tiled_crop_neon(y_dst, y_src, width, height, 0, 0, 0, 0); +#else + csc_linear_to_tiled_crop(y_dst, y_src, width, height, 0, 0, 0, 0); +#endif /* NEON_SUPPORT */ +#else + unsigned char *dst = y_dst; + unsigned char *src = y_src; + unsigned int w = width; + unsigned int h = height; +#endif /* USE_NV12T_128X64 */ +} + +/* + * Converts and interleaves linear data to tiled + * 1. uv of nv12t to uv of yuv420 + * + * @param dst + * uv address of nv12t[out] + * + * @param src + * u address of yuv420[in] + * + * @param src + * v address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * + * @param yuv420_height + * real height of yuv420[in] + * + */ +void csc_linear_to_tiled_uv( + unsigned char *uv_dst, + unsigned char *u_src, + unsigned char *v_src, + unsigned int width, + unsigned int height) +{ +#ifdef USE_NV12T_128X64 +#ifdef NEON_SUPPORT + csc_linear_to_tiled_interleave_crop_neon(uv_dst, u_src, v_src, width, height, 0, 0, 0, 0); +#else + csc_linear_to_tiled_interleave_crop(uv_dst, u_src, v_src, width, height, 0, 0, 0, 0); +#endif /* NEON_SUPPORT */ +#else + unsigned char *uv = uv_dst; + unsigned char *u = u_src; + unsigned char *v = v_src; + unsigned int w = width; + unsigned int h = height; +#endif /* USE_NV12T_128X64 */ +} + +/* + * Converts RGB565 to YUV420P + * + * @param y_dst + * Y plane address of YUV420P[out] + * + * @param u_dst + * U plane address of YUV420P[out] + * + * @param v_dst + * V plane address of YUV420P[out] + * + * @param rgb_src + * Address of RGB565[in] + * + * @param width + * Width of RGB565[in] + * + * @param height + * Height of RGB565[in] + */ +void csc_RGB565_to_YUV420P( + unsigned char *y_dst, + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *rgb_src, + int width, + int height) +{ + int i, j; + unsigned int tmp; + + unsigned int R, G, B; + unsigned int Y, U, V; + + unsigned int offset1 = width * height; + unsigned int offset2 = width/2 * height/2; + + unsigned short int *pSrc = (unsigned short int *)rgb_src; + + unsigned char *pDstY = (unsigned char *)y_dst; + unsigned char *pDstU = (unsigned char *)u_dst; + unsigned char *pDstV = (unsigned char *)v_dst; + + unsigned int yIndex = 0; + unsigned int uIndex = 0; + unsigned int vIndex = 0; + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + tmp = pSrc[j * width + i]; + + R = (tmp & 0x0000F800) >> 8; + G = (tmp & 0x000007E0) >> 3; + B = (tmp & 0x0000001F); + B = B << 3; + + Y = ((66 * R) + (129 * G) + (25 * B) + 128); + Y = Y >> 8; + Y += 16; + + pDstY[yIndex++] = (unsigned char)Y; + + if ((j % 2) == 0 && (i % 2) == 0) { + U = ((-38 * R) - (74 * G) + (112 * B) + 128); + U = U >> 8; + U += 128; + V = ((112 * R) - (94 * G) - (18 * B) + 128); + V = V >> 8; + V += 128; + + pDstU[uIndex++] = (unsigned char)U; + pDstV[vIndex++] = (unsigned char)V; + } + } + } +} + +/* + * Converts RGB565 to YUV420SP + * + * @param y_dst + * Y plane address of YUV420SP[out] + * + * @param uv_dst + * UV plane address of YUV420SP[out] + * + * @param rgb_src + * Address of RGB565[in] + * + * @param width + * Width of RGB565[in] + * + * @param height + * Height of RGB565[in] + */ +void csc_RGB565_to_YUV420SP( + unsigned char *y_dst, + unsigned char *uv_dst, + unsigned char *rgb_src, + int width, + int height) +{ + int i, j; + unsigned int tmp; + + unsigned int R, G, B; + unsigned int Y, U, V; + + unsigned int offset = width * height; + + unsigned short int *pSrc = (unsigned short int *)rgb_src; + + unsigned char *pDstY = (unsigned char *)y_dst; + unsigned char *pDstUV = (unsigned char *)uv_dst; + + unsigned int yIndex = 0; + unsigned int uvIndex = 0; + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + tmp = pSrc[j * width + i]; + + R = (tmp & 0x0000F800) >> 11; + R = R * 8; + G = (tmp & 0x000007E0) >> 5; + G = G * 4; + B = (tmp & 0x0000001F); + B = B * 8; + + Y = ((66 * R) + (129 * G) + (25 * B) + 128); + Y = Y >> 8; + Y += 16; + + pDstY[yIndex++] = (unsigned char)Y; + + if ((j % 2) == 0 && (i % 2) == 0) { + U = ((-38 * R) - (74 * G) + (112 * B) + 128); + U = U >> 8; + U += 128; + V = ((112 * R) - (94 * G) - (18 * B) + 128); + V = V >> 8; + V += 128; + + pDstUV[uvIndex++] = (unsigned char)U; + pDstUV[uvIndex++] = (unsigned char)V; + } + } + } +} + +/* + * Converts BGRA8888 to YUV420P + * + * @param y_dst + * Y plane address of YUV420P[out] + * + * @param u_dst + * U plane address of YUV420P[out] + * + * @param v_dst + * V plane address of YUV420P[out] + * + * @param rgb_src + * Address of BGRA8888[in] + * + * @param width + * Width of BGRA8888[in] + * + * @param height + * Height of BGRA8888[in] + */ +void csc_BGRA8888_to_YUV420P( + unsigned char *y_dst, + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height) +{ + unsigned int i, j; + unsigned int tmp; + + unsigned int R, G, B; + unsigned int Y, U, V; + + unsigned int offset1 = width * height; + unsigned int offset2 = width/2 * height/2; + + unsigned int *pSrc = (unsigned int *)rgb_src; + + unsigned char *pDstY = (unsigned char *)y_dst; + unsigned char *pDstU = (unsigned char *)u_dst; + unsigned char *pDstV = (unsigned char *)v_dst; + + unsigned int yIndex = 0; + unsigned int uIndex = 0; + unsigned int vIndex = 0; + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + tmp = pSrc[j * width + i]; + + R = (tmp & 0x00FF0000) >> 16; + G = (tmp & 0x0000FF00) >> 8; + B = (tmp & 0x000000FF); + + Y = ((66 * R) + (129 * G) + (25 * B) + 128); + Y = Y >> 8; + Y += 16; + + pDstY[yIndex++] = (unsigned char)Y; + + if ((j % 2) == 0 && (i % 2) == 0) { + U = ((-38 * R) - (74 * G) + (112 * B) + 128); + U = U >> 8; + U += 128; + V = ((112 * R) - (94 * G) - (18 * B) + 128); + V = V >> 8; + V += 128; + + pDstU[uIndex++] = (unsigned char)U; + pDstV[vIndex++] = (unsigned char)V; + } + } + } +} + +/* + * Converts RGBA8888 to YUV420P + * + * @param y_dst + * Y plane address of YUV420P[out] + * + * @param u_dst + * U plane address of YUV420P[out] + * + * @param v_dst + * V plane address of YUV420P[out] + * + * @param rgb_src + * Address of RGBA8888[in] + * + * @param width + * Width of RGBA8888[in] + * + * @param height + * Height of RGBA8888[in] + */ +void csc_RGBA8888_to_YUV420P( + unsigned char *y_dst, + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height) +{ + unsigned int i, j; + unsigned int tmp; + + unsigned int R, G, B; + unsigned int Y, U, V; + + unsigned int offset1 = width * height; + unsigned int offset2 = width/2 * height/2; + + unsigned int *pSrc = (unsigned int *)rgb_src; + + unsigned char *pDstY = (unsigned char *)y_dst; + unsigned char *pDstU = (unsigned char *)u_dst; + unsigned char *pDstV = (unsigned char *)v_dst; + + unsigned int yIndex = 0; + unsigned int uIndex = 0; + unsigned int vIndex = 0; + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + tmp = pSrc[j * width + i]; + + B = (tmp & 0x00FF0000) >> 16; + G = (tmp & 0x0000FF00) >> 8; + R = (tmp & 0x000000FF); + + Y = ((66 * R) + (129 * G) + (25 * B) + 128); + Y = Y >> 8; + Y += 16; + + pDstY[yIndex++] = (unsigned char)Y; + + if ((j % 2) == 0 && (i % 2) == 0) { + U = ((-38 * R) - (74 * G) + (112 * B) + 128); + U = U >> 8; + U += 128; + V = ((112 * R) - (94 * G) - (18 * B) + 128); + V = V >> 8; + V += 128; + + pDstU[uIndex++] = (unsigned char)U; + pDstV[vIndex++] = (unsigned char)V; + } + } + } +} + +/* + * Converts BGRA8888 to YUV420SP + * + * @param y_dst + * Y plane address of YUV420SP[out] + * + * @param uv_dst + * UV plane address of YUV420SP[out] + * + * @param rgb_src + * Address of BGRA8888[in] + * + * @param width + * Width of BGRA8888[in] + * + * @param height + * Height of BGRA8888[in] + */ +void csc_BGRA8888_to_YUV420SP( + unsigned char *y_dst, + unsigned char *uv_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height) +{ +#ifdef NEON_SUPPORT + csc_BGRA8888_to_YUV420SP_NEON(y_dst, uv_dst, rgb_src, width, height); +#else + unsigned int i, j; + unsigned int tmp; + + unsigned int R, G, B; + unsigned int Y, U, V; + + unsigned int offset = width * height; + + unsigned int *pSrc = (unsigned int *)rgb_src; + + unsigned char *pDstY = (unsigned char *)y_dst; + unsigned char *pDstUV = (unsigned char *)uv_dst; + + unsigned int yIndex = 0; + unsigned int uvIndex = 0; + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + tmp = pSrc[j * width + i]; + + R = (tmp & 0x00FF0000) >> 16; + G = (tmp & 0x0000FF00) >> 8; + B = (tmp & 0x000000FF); + + Y = ((66 * R) + (129 * G) + (25 * B) + 128); + Y = Y >> 8; + Y += 16; + + pDstY[yIndex++] = (unsigned char)Y; + + if ((j % 2) == 0 && (i % 2) == 0) { + U = ((-38 * R) - (74 * G) + (112 * B) + 128); + U = U >> 8; + U += 128; + V = ((112 * R) - (94 * G) - (18 * B) + 128); + V = V >> 8; + V += 128; + + pDstUV[uvIndex++] = (unsigned char)U; + pDstUV[uvIndex++] = (unsigned char)V; + } + } + } +#endif /* NEON_SUPPORT */ +} + +/* + * Converts RGBA8888 to YUV420SP + * + * @param y_dst + * Y plane address of YUV420SP[out] + * + * @param uv_dst + * UV plane address of YUV420SP[out] + * + * @param rgb_src + * Address of RGBA8888[in] + * + * @param width + * Width of RGBA8888[in] + * + * @param height + * Height of RGBA8888[in] + */ +void csc_RGBA8888_to_YUV420SP( + unsigned char *y_dst, + unsigned char *uv_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height) +{ +#ifdef NEON_SUPPORT + csc_RGBA8888_to_YUV420SP_NEON(y_dst, uv_dst, rgb_src, width, height); +#else + unsigned int i, j; + unsigned int tmp; + + unsigned int R, G, B; + unsigned int Y, U, V; + + unsigned int offset = width * height; + + unsigned int *pSrc = (unsigned int *)rgb_src; + + unsigned char *pDstY = (unsigned char *)y_dst; + unsigned char *pDstUV = (unsigned char *)uv_dst; + + unsigned int yIndex = 0; + unsigned int uvIndex = 0; + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + tmp = pSrc[j * width + i]; + + B = (tmp & 0x00FF0000) >> 16; + G = (tmp & 0x0000FF00) >> 8; + R = (tmp & 0x000000FF); + + Y = ((66 * R) + (129 * G) + (25 * B) + 128); + Y = Y >> 8; + Y += 16; + + pDstY[yIndex++] = (unsigned char)Y; + + if ((j % 2) == 0 && (i % 2) == 0) { + U = ((-38 * R) - (74 * G) + (112 * B) + 128); + U = U >> 8; + U += 128; + V = ((112 * R) - (94 * G) - (18 * B) + 128); + V = V >> 8; + V += 128; + + pDstUV[uvIndex++] = (unsigned char)U; + pDstUV[uvIndex++] = (unsigned char)V; + } + } + } +#endif /* NEON_SUPPORT */ +} diff --git a/libv4l2/Makefile.am b/libv4l2/Makefile.am new file mode 100755 index 0000000..0994321 --- /dev/null +++ b/libv4l2/Makefile.am @@ -0,0 +1,11 @@ +lib_LTLIBRARIES = libexynosv4l2.la + +libexynosv4l2_la_SOURCES = exynos_v4l2.c exynos_subdev.c exynos_mc.c +libexynosv4l2_la_CFLAGS = -I$(top_srcdir)/include -I/usr/include +libexynosv4l2_la_CFLAGS += -Wno-unused-variable -Wno-unused-value +libexynosv4l2_la_CFLAGS += -DLOG_TAG=\"LIBEXYNOSV4L2\" +if USE_DLOG +libexynosv4l2_la_CFLAGS += $(DLOG_CFLAGS) -DUSE_DLOG +endif + +libexynosv4l2_la_LIBADD = $(DLOG_LIBS) diff --git a/libv4l2/exynos_mc.c b/libv4l2/exynos_mc.c new file mode 100755 index 0000000..142c0aa --- /dev/null +++ b/libv4l2/exynos_mc.c @@ -0,0 +1,774 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*! + * \file exynos_mc.c + * \brief source file for libexynosv4l2 + * \author Jinsung Yang (jsgood.yang@samsung.com) + * \author Sangwoo Park (sw5771.park@samsung.com) + * \date 2012/01/17 + * + * <b>Revision History: </b> + * - 2012/01/17: Jinsung Yang (jsgood.yang@samsung.com) \n + * Initial version + * + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <fcntl.h> +#include <errno.h> +#include <ctype.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <linux/kdev_t.h> +#include <linux/types.h> + +#include <exynos_v4l2.h> + +#include <exynos_log.h> + +static inline unsigned int __media_entity_type(struct media_entity *entity) +{ + return entity->info.type & MEDIA_ENT_TYPE_MASK; +} + +static void __media_debug_default(void *ptr, ...) +{ + va_list argptr; + va_start(argptr, ptr); + vprintf((const char*)ptr, argptr); + va_end(argptr); +} + +static void __media_debug_set_handler( + struct media_device *media, + void (*debug_handler)(void *, ...), + void *debug_priv) +{ + if (debug_handler) { + media->debug_handler = debug_handler; + media->debug_priv = debug_priv; + } else { + media->debug_handler = __media_debug_default; + media->debug_priv = NULL; + } +} + +static struct media_link *__media_entity_add_link(struct media_entity *entity) +{ + if (entity->num_links >= entity->max_links) { + struct media_link *links = entity->links; + unsigned int max_links = entity->max_links * 2; + unsigned int i; + + links = (struct media_link*)realloc(links, max_links * sizeof *links); + if (links == NULL) + return NULL; + + for (i = 0; i < entity->num_links; ++i) + links[i].twin->twin = &links[i]; + + entity->max_links = max_links; + entity->links = links; + } + + return &entity->links[entity->num_links++]; +} + + +static int __media_enum_links(struct media_device *media) +{ + ALOGD("%s: start", __func__); + __u32 id; + int ret = 0; + + for (id = 1; id <= media->entities_count; id++) { + struct media_entity *entity = &media->entities[id - 1]; + struct media_links_enum links; + unsigned int i; + + links.entity = entity->info.id; + links.pads = (struct media_pad_desc*)malloc(entity->info.pads * sizeof(struct media_pad_desc)); + links.links = (struct media_link_desc*)malloc(entity->info.links * sizeof(struct media_link_desc)); + + if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) { + ALOGE("Unable to enumerate pads and links (%s)", strerror(errno)); + free(links.pads); + free(links.links); + return -errno; + } + + for (i = 0; i < entity->info.pads; ++i) { + entity->pads[i].entity = entity; + entity->pads[i].index = links.pads[i].index; + entity->pads[i].flags = links.pads[i].flags; + } + + for (i = 0; i < entity->info.links; ++i) { + struct media_link_desc *link = &links.links[i]; + struct media_link *fwdlink; + struct media_link *backlink; + struct media_entity *source; + struct media_entity *sink; + + source = exynos_media_get_entity_by_id(media, link->source.entity); + sink = exynos_media_get_entity_by_id(media, link->sink.entity); + if (source == NULL || sink == NULL) { + ALOGE("WARNING entity %u link %u from %u/%u to %u/%u is invalid!", + id, i, link->source.entity, + link->source.index, + link->sink.entity, + link->sink.index); + ret = -EINVAL; + } else { + fwdlink = __media_entity_add_link(source); + fwdlink->source = &source->pads[link->source.index]; + fwdlink->sink = &sink->pads[link->sink.index]; + fwdlink->flags = link->flags; + + backlink = __media_entity_add_link(sink); + backlink->source = &source->pads[link->source.index]; + backlink->sink = &sink->pads[link->sink.index]; + backlink->flags = link->flags; + + fwdlink->twin = backlink; + backlink->twin = fwdlink; + } + } + + free(links.pads); + free(links.links); + } + return ret; +} + +static int __media_get_devname_sysfs(struct media_entity *entity) +{ + //struct stat devstat; + char devname[32]; + char sysname[32]; + char target[1024]; + char *p; + int ret; + + snprintf(sysname, sizeof(sysname), "/sys/dev/char/%u:%u", entity->info.v4l.major, + entity->info.v4l.minor); + + ret = readlink(sysname, target, sizeof(target)); + if (ret < 0 || ret >= (int)sizeof(target)) + return -errno; + + target[ret] = '\0'; + p = strrchr(target, '/'); + if (p == NULL) + return -EINVAL; + + snprintf(devname, sizeof(devname), "/tmp/%s", p + 1); + + ret = mknod(devname, 0666 | S_IFCHR, MKDEV(81, entity->info.v4l.minor)); + strncpy(entity->devname, devname, sizeof(devname) - 1); + + return 0; +} + +static int __media_get_media_fd(const char *filename, struct media_device *media) +{ + ssize_t num; + int media_node; + char *ptr; + + ALOGD("%s: %s", __func__, filename); + + media->fd = open(filename, O_RDWR, 0); + if (media->fd < 0) { + ALOGE("Open sysfs media device failed, media->fd: %d", media->fd); + return -1; + } + + ALOGD("%s: media->fd: %d", __func__, media->fd); + + return media->fd; + +} + +static int __media_enum_entities(struct media_device *media) +{ + struct media_entity *entity, *temp_entity; + unsigned int size; + __u32 id; + int ret; + + temp_entity = entity = (struct media_entity*)calloc(1, sizeof(struct media_entity)); + for (id = 0, ret = 0; ; id = entity->info.id) { + size = (media->entities_count + 1) * sizeof(*media->entities); + media->entities = (struct media_entity*)realloc(media->entities, size); + + entity = &media->entities[media->entities_count]; + memset(entity, 0, sizeof(*entity)); + entity->fd = -1; + entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT; + entity->media = media; + + ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info); + + if (ret < 0) { + ret = errno != EINVAL ? -errno : 0; + break; + } + + /* Number of links (for outbound links) plus number of pads (for + * inbound links) is a good safe initial estimate of the total + * number of links. + */ + entity->max_links = entity->info.pads + entity->info.links; + + entity->pads = (struct media_pad*)malloc(entity->info.pads * sizeof(*entity->pads)); + entity->links = (struct media_link*)malloc(entity->max_links * sizeof(*entity->links)); + if (entity->pads == NULL || entity->links == NULL) { + ret = -ENOMEM; + break; + } + + media->entities_count++; + + /* Find the corresponding device name. */ + if (__media_entity_type(entity) != MEDIA_ENT_T_DEVNODE && + __media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV) + continue; + + /* Fall back to get the device name via sysfs */ + __media_get_devname_sysfs(entity); + if (ret < 0) + ALOGE("media_get_devname failed"); + } + free(temp_entity); + + return ret; +} + +static struct media_device *__media_open_debug( + const char *filename, + void (*debug_handler)(void *, ...), + void *debug_priv) +{ + struct media_device *media; + int ret; + + media = (struct media_device *)calloc(1, sizeof(struct media_device)); + if (media == NULL) { + ALOGE("media: %p", media); + return NULL; + } + + __media_debug_set_handler(media, debug_handler, debug_priv); + + ALOGD("%s: Opening media device %s", __func__, filename); + ALOGD("%s: media: %p", __func__, media); + + media->fd = __media_get_media_fd(filename, media); + if (media->fd < 0) { + exynos_media_close(media); + ALOGE("failed __media_get_media_fd %s", filename); + return NULL; + } + + ALOGD("%s: media->fd: %d", __func__, media->fd); + ret = __media_enum_entities(media); + + if (ret < 0) { + ALOGE("Unable to enumerate entities for device %s (%s)", filename, strerror(-ret)); + exynos_media_close(media); + return NULL; + } + + ALOGD("%s: Found %u entities", __func__, media->entities_count); + ALOGD("%s: Enumerating pads and links", __func__); + + ret = __media_enum_links(media); + if (ret < 0) { + ALOGE("Unable to enumerate pads and links for device %s", filename); + exynos_media_close(media); + return NULL; + } + + return media; +} + +/** + * @brief Open a media device. + * @param filename - name (including path) of the device node. + * + * Open the media device referenced by @a filename and enumerate entities, pads and + * links. + * + * @return A pointer to a newly allocated media_device structure instance on + * success and NULL on failure. The returned pointer must be freed with + * exynos_media_close when the device isn't needed anymore. + */ +struct media_device *exynos_media_open(const char *filename) +{ + return __media_open_debug(filename, (void (*)(void *, ...))fprintf, stdout); +} + +/** + * @brief Close a media device. + * @param media - device instance. + * + * Close the @a media device instance and free allocated resources. Access to the + * device instance is forbidden after this function returns. + */ +void exynos_media_close(struct media_device *media) +{ + unsigned int i; + + if (media->fd != -1) + close(media->fd); + + for (i = 0; i < media->entities_count; ++i) { + struct media_entity *entity = &media->entities[i]; + + free(entity->pads); + free(entity->links); + if (entity->fd != -1) + close(entity->fd); + } + + free(media->entities); + free(media); +} + +/** + * @brief Locate the pad at the other end of a link. + * @param pad - sink pad at one end of the link. + * + * Locate the source pad connected to @a pad through an enabled link. As only one + * link connected to a sink pad can be enabled at a time, the connected source + * pad is guaranteed to be unique. + * + * @return A pointer to the connected source pad, or NULL if all links connected + * to @a pad are disabled. Return NULL also if @a pad is not a sink pad. + */ +struct media_pad *exynos_media_entity_remote_source(struct media_pad *pad) +{ + unsigned int i; + + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + return NULL; + + for (i = 0; i < pad->entity->num_links; ++i) { + struct media_link *link = &pad->entity->links[i]; + + if (!(link->flags & MEDIA_LNK_FL_ENABLED)) + continue; + + if (link->sink == pad) + return link->source; + } + + return NULL; +} + +/** + * @brief Find an entity by its name. + * @param media - media device. + * @param name - entity name. + * @param length - size of @a name. + * + * Search for an entity with a name equal to @a name. + * + * @return A pointer to the entity if found, or NULL otherwise. + */ +struct media_entity *exynos_media_get_entity_by_name(struct media_device *media, + const char *name, size_t length) +{ + unsigned int i; + struct media_entity *entity; + + for (i = 0; i < media->entities_count; ++i) { + entity = &media->entities[i]; + + if (strncmp(entity->info.name, name, length) == 0) + return entity; + } + + return NULL; +} + +/** + * @brief Find an entity by its ID. + * @param media - media device. + * @param id - entity ID. + * + * Search for an entity with an ID equal to @a id. + * + * @return A pointer to the entity if found, or NULL otherwise. + */ +struct media_entity *exynos_media_get_entity_by_id(struct media_device *media, + __u32 id) +{ + unsigned int i; + + for (i = 0; i < media->entities_count; ++i) { + struct media_entity *entity = &media->entities[i]; + + if (entity->info.id == id) + return entity; + } + + return NULL; +} + +/** + * @brief Configure a link. + * @param media - media device. + * @param source - source pad at the link origin. + * @param sink - sink pad at the link target. + * @param flags - configuration flags. + * + * Locate the link between @a source and @a sink, and configure it by applying + * the new @a flags. + * + * Only the MEDIA_LINK_FLAG_ENABLED flag is writable. + * + * @return 0 on success, -1 on failure: + * -ENOENT: link not found + * - other error codes returned by MEDIA_IOC_SETUP_LINK + */ +int exynos_media_setup_link(struct media_device *media, + struct media_pad *source, + struct media_pad *sink, + __u32 flags) +{ + struct media_link *link; + struct media_link_desc ulink; + unsigned int i; + int ret; + + for (i = 0; i < source->entity->num_links; i++) { + link = &source->entity->links[i]; + + if (link->source->entity == source->entity && + link->source->index == source->index && + link->sink->entity == sink->entity && + link->sink->index == sink->index) + break; + } + + if (i == source->entity->num_links) { + ALOGE("Link not found"); + return -ENOENT; + } + + /* source pad */ + ulink.source.entity = source->entity->info.id; + ulink.source.index = source->index; + ulink.source.flags = MEDIA_PAD_FL_SOURCE; + + /* sink pad */ + ulink.sink.entity = sink->entity->info.id; + ulink.sink.index = sink->index; + ulink.sink.flags = MEDIA_PAD_FL_SINK; + + ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE); + + ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink); + if (ret == -1) { + ALOGE("Unable to setup link (%s)", strerror(errno)); + return -errno; + } + + link->flags = ulink.flags; + link->twin->flags = ulink.flags; + return 0; +} + +/** + * @brief Reset all links to the disabled state. + * @param media - media device. + * + * Disable all links in the media device. This function is usually used after + * opening a media device to reset all links to a known state. + * + * @return 0 on success, or a negative error code on failure. + */ +int exynos_media_reset_links(struct media_device *media) +{ + unsigned int i, j; + int ret; + + for (i = 0; i < media->entities_count; ++i) { + struct media_entity *entity = &media->entities[i]; + + for (j = 0; j < entity->num_links; j++) { + struct media_link *link = &entity->links[j]; + + if (link->flags & MEDIA_LNK_FL_IMMUTABLE || + link->source->entity != entity) + continue; + + ret = exynos_media_setup_link(media, link->source, link->sink, + link->flags & ~MEDIA_LNK_FL_ENABLED); + if (ret < 0) + return ret; + } + } + + return 0; +} + +#ifdef HAVE_LIBUDEV + +#include <libudev.h> + +static inline int __media_udev_open(struct udev **udev) +{ + *udev = udev_new(); + if (*udev == NULL) + return -ENOMEM; + return 0; +} + +static inline void __media_udev_close(struct udev *udev) +{ + if (udev != NULL) + udev_unref(udev); +} + +static int __media_get_devname_udev(struct udev *udev, + struct media_entity *entity) +{ + struct udev_device *device; + dev_t devnum; + const char *p; + int ret = -ENODEV; + + if (udev == NULL) + return -EINVAL; + + devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor); + ALOGE("looking up device: %u:%u", + major(devnum), minor(devnum)); + device = udev_device_new_from_devnum(udev, 'c', devnum); + if (device) { + p = udev_device_get_devnode(device); + if (p) { + strncpy(entity->devname, p, sizeof(entity->devname)); + entity->devname[sizeof(entity->devname) - 1] = '\0'; + } + ret = 0; + } + + udev_device_unref(device); + + return ret; +} + +#else /* HAVE_LIBUDEV */ + +struct udev; + +static inline int __media_udev_open(struct udev **udev) { return 0; } + +static inline void __media_udev_close(struct udev *udev) { } + +static inline int __media_get_devname_udev(struct udev *udev, + struct media_entity *entity) +{ + return -ENOTSUP; +} + +#endif /* HAVE_LIBUDEV */ + +/** + * @brief Parse string to a pad on the media device. + * @param media - media device. + * @param p - input string + * @param endp - pointer to string where parsing ended + * + * Parse NULL terminated string describing a pad and return its struct + * media_pad instance. + * + * @return Pointer to struct media_pad on success, NULL on failure. + */ +struct media_pad *exynos_media_parse_pad(struct media_device *media, + const char *p, char **endp) +{ + unsigned int entity_id, pad; + struct media_entity *entity; + char *end; + + for (; isspace(*p); ++p); + + if (*p == '"') { + for (end = (char *)p + 1; *end && *end != '"'; ++end); + if (*end != '"') + return NULL; + + entity = exynos_media_get_entity_by_name(media, p + 1, end - p - 1); + if (entity == NULL) + return NULL; + + ++end; + } else { + entity_id = strtoul(p, &end, 10); + entity = exynos_media_get_entity_by_id(media, entity_id); + if (entity == NULL) + return NULL; + } + for (; isspace(*end); ++end); + + if (*end != ':') + return NULL; + for (p = end + 1; isspace(*p); ++p); + + pad = strtoul(p, &end, 10); + for (p = end; isspace(*p); ++p); + + if (pad >= entity->info.pads) + return NULL; + + for (p = end; isspace(*p); ++p); + if (endp) + *endp = (char *)p; + + return &entity->pads[pad]; +} + +/** + * @brief Parse string to a link on the media device. + * @param media - media device. + * @param p - input string + * @param endp - pointer to p where parsing ended + * + * Parse NULL terminated string p describing a link and return its struct + * media_link instance. + * + * @return Pointer to struct media_link on success, NULL on failure. + */ +struct media_link *exynos_media_parse_link( + struct media_device *media, + const char *p, + char **endp) +{ + struct media_link *link; + struct media_pad *source; + struct media_pad *sink; + unsigned int i; + char *end; + + source = exynos_media_parse_pad(media, p, &end); + if (source == NULL) + return NULL; + + if (end[0] != '-' || end[1] != '>') + return NULL; + p = end + 2; + + sink = exynos_media_parse_pad(media, p, &end); + if (sink == NULL) + return NULL; + + *endp = end; + + for (i = 0; i < source->entity->num_links; i++) { + link = &source->entity->links[i]; + + if (link->source == source && link->sink == sink) + return link; + } + + return NULL; +} + +/** + * @brief Parse string to a link on the media device and set it up. + * @param media - media device. + * @param p - input string + * + * Parse NULL terminated string p describing a link and its configuration + * and configure the link. + * + * @return 0 on success, or a negative error code on failure. + */ +int exynos_media_parse_setup_link( + struct media_device *media, + const char *p, + char **endp) +{ + struct media_link *link; + __u32 flags; + char *end; + + link = exynos_media_parse_link(media, p, &end); + if (link == NULL) { + ALOGE("Unable to parse link"); + return -EINVAL; + } + + p = end; + if (*p++ != '[') { + ALOGE("Unable to parse link flags"); + return -EINVAL; + } + + flags = strtoul(p, &end, 10); + for (p = end; isspace(*p); p++); + if (*p++ != ']') { + ALOGE("Unable to parse link flags"); + return -EINVAL; + } + + for (; isspace(*p); p++); + *endp = (char *)p; + + ALOGD("%s: Setting up link %u:%u -> %u:%u [%u]", __func__, + link->source->entity->info.id, link->source->index, + link->sink->entity->info.id, link->sink->index, + flags); + + return exynos_media_setup_link(media, link->source, link->sink, flags); +} + +/** + * @brief Parse string to link(s) on the media device and set it up. + * @param media - media device. + * @param p - input string + * + * Parse NULL terminated string p describing link(s) separated by + * commas (,) and configure the link(s). + * + * @return 0 on success, or a negative error code on failure. + */ +int exynos_media_parse_setup_links(struct media_device *media, const char *p) +{ + char *end; + int ret; + + do { + ret = exynos_media_parse_setup_link(media, p, &end); + if (ret < 0) + return ret; + + p = end + 1; + } while (*end == ','); + + return *end ? -EINVAL : 0; +} diff --git a/libv4l2/exynos_subdev.c b/libv4l2/exynos_subdev.c new file mode 100755 index 0000000..cca0357 --- /dev/null +++ b/libv4l2/exynos_subdev.c @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*! + * \file exynos_subdev.c + * \brief source file for libv4l2 + * \author Jinsung Yang (jsgood.yang@samsung.com) + * \author Sangwoo Park (sw5771.park@samsung.com) + * \date 2012/01/17 + * + * <b>Revision History: </b> + * - 2012/01/17: Jinsung Yang (jsgood.yang@samsung.com) \n + * Initial version + * + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdarg.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> + +#include <exynos_v4l2.h> + +#include <exynos_log.h> +#include <string.h> + +#define SUBDEV_MAX 191 + +static int __subdev_open(const char *filename, int oflag, va_list ap) +{ + mode_t mode = 0; + int fd; + + if (oflag & O_CREAT) + mode = va_arg(ap, int); + + fd = open(filename, oflag, mode); + + return fd; +} + +int exynos_subdev_open(const char *filename, int oflag, ...) +{ + va_list ap; + int fd; + + va_start(ap, oflag); + fd = __subdev_open(filename, oflag, ap); + va_end(ap); + + return fd; +} + +int exynos_subdev_get_node_num(const char *devname, int oflag, ...) +{ + bool found = false; + int ret = -1; + struct stat s; + va_list ap; + FILE *stream_fd; + char filename[64], name[64]; + int i = 0; + + do { + if (i > (SUBDEV_MAX - 128)) + break; + + /* video device node */ + snprintf(filename, sizeof(filename), "/dev/v4l-subdev%d", i); + + /* if the node is video device */ + if ((lstat(filename, &s) == 0) && S_ISCHR(s.st_mode) && + ((int)((unsigned short)(s.st_rdev) >> 8) == 81)) { + ALOGD("try node: %s", filename); + /* open sysfs entry */ + snprintf(filename, sizeof(filename), "/sys/class/video4linux/v4l-subdev%d/name", i); + if (S_ISLNK(s.st_mode)) { + ALOGE("symbolic link detected"); + return -1; + } + stream_fd = fopen(filename, "r"); + if (stream_fd == NULL) { + ALOGE("failed to open sysfs entry for subdev"); + continue; /* try next */ + } + + /* read sysfs entry for device name */ + char *p = fgets(name, sizeof(name), stream_fd); + fclose(stream_fd); + + /* check read size */ + if (p == NULL) { + ALOGE("failed to read sysfs entry for subdev"); + } else { + /* matched */ + if (strncmp(name, devname, strlen(devname)) == 0) { + ALOGI("node found for device %s: /dev/v4l-subdev%d", devname, i); + found = true; + break; + } + } + } + i++; + } while (found == false); + + if (found) + ret = i; + else + ALOGE("no subdev device found"); + + return ret; +} + +int exynos_subdev_open_devname(const char *devname, int oflag, ...) +{ + bool found = false; + int fd = -1; + struct stat s; + va_list ap; + FILE *stream_fd; + char filename[64], name[64]; + long size; + int i = 0; + + do { + if (i > (SUBDEV_MAX - 128)) + break; + + /* video device node */ + snprintf(filename, sizeof(filename), "/dev/v4l-subdev%d", i); + + /* if the node is video device */ + if ((lstat(filename, &s) == 0) && S_ISCHR(s.st_mode) && + ((int)((unsigned short)(s.st_rdev) >> 8) == 81)) { + ALOGD("try node: %s", filename); + /* open sysfs entry */ + snprintf(filename, sizeof(filename), "/sys/class/video4linux/v4l-subdev%d/name", i); + if (S_ISLNK(s.st_mode)) { + ALOGE("symbolic link detected"); + return -1; + } + stream_fd = fopen(filename, "r"); + if (stream_fd == NULL) { + ALOGE("failed to open sysfs entry for subdev"); + continue; /* try next */ + } + + /* read sysfs entry for device name */ + char *p = fgets(name, sizeof(name), stream_fd); + fclose(stream_fd); + + /* check read size */ + if (p == NULL) { + ALOGE("failed to read sysfs entry for subdev"); + } else { + /* matched */ + if (strncmp(name, devname, strlen(devname)) == 0) { + ALOGI("node found for device %s: /dev/v4l-subdev%d", devname, i); + found = true; + break; + } + } + } + i++; + } while (found == false); + + if (found) { + snprintf(filename, sizeof(filename), "/dev/v4l-subdev%d", i); + va_start(ap, oflag); + fd = __subdev_open(filename, oflag, ap); + va_end(ap); + + if (fd > 0) + ALOGI("open subdev device %s", filename); + else + ALOGE("failed to open subdev device %s", filename); + } else { + ALOGE("no subdev device found"); + } + + return fd; +} + +int exynos_subdev_close(int fd) +{ + int ret = -1; + + if (fd < 0) + ALOGE("%s: invalid fd: %d", __func__, fd); + else + ret = close(fd); + + return ret; +} + +/** + * @brief enum frame size on a pad. + * @return 0 on success, or a negative error code on failure. + */ +int exynos_subdev_enum_frame_size(int fd, struct v4l2_subdev_frame_size_enum *frame_size_enum) +{ + int ret = -1; + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!frame_size_enum) { + ALOGE("%s: frame_size_enum is NULL", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, frame_size_enum); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_FRAME_SIZE"); + return ret; + } + + return ret; +} + +/** + * @brief Retrieve the format on a pad. + * @return 0 on success, or a negative error code on failure. + */ +int exynos_subdev_g_fmt(int fd, struct v4l2_subdev_format *fmt) +{ + int ret = -1; + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!fmt) { + ALOGE("%s: fmt is NULL", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_SUBDEV_G_FMT, fmt); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_FMT"); + return ret; + } + + return ret; +} + +/** + * @brief Set the format on a pad. + * @return 0 on success, or a negative error code on failure. + */ +int exynos_subdev_s_fmt(int fd, struct v4l2_subdev_format *fmt) +{ + int ret = -1; + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!fmt) { + ALOGE("%s: fmt is NULL", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_SUBDEV_S_FMT, fmt); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_FMT"); + return ret; + } + + return ret; +} + +/** + * @brief Retrieve the crop rectangle on a pad. + * @return 0 on success, or a negative error code on failure. + */ +int exynos_subdev_g_crop(int fd, struct v4l2_subdev_crop *crop) +{ + int ret = -1; + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!crop) { + ALOGE("%s: crop is NULL", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_SUBDEV_G_CROP, crop); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_CROP"); + return ret; + } + + return ret; +} + +/** + * @brief Set the crop rectangle on a pad. + * @return 0 on success, or a negative error code on failure. + */ +int exynos_subdev_s_crop(int fd, struct v4l2_subdev_crop *crop) +{ + int ret = -1; + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!crop) { + ALOGE("%s: crop is NULL", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_SUBDEV_S_CROP, crop); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_CROP"); + return ret; + } + + return ret; +} + +/** + * @brief Retrieve the frame interval on a sub-device. + * @return 0 on success, or a negative error code on failure. + */ +int exynos_subdev_enum_frame_interval(int fd, struct v4l2_subdev_frame_interval_enum *frame_internval_enum) +{ + int ret = -1; + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!frame_internval_enum) { + ALOGE("%s: frame_internval_enum is NULL", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, frame_internval_enum); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL"); + return ret; + } + + return ret; +} + +/** + * @brief Retrieve the frame interval on a sub-device. + * @return 0 on success, or a negative error code on failure. + */ +int exynos_subdev_g_frame_interval(int fd, struct v4l2_subdev_frame_interval *frame_internval) +{ + int ret = -1; + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!frame_internval) { + ALOGE("%s: frame_internval is NULL", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, frame_internval); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_FRAME_INTERVAL"); + return ret; + } + + return ret; +} + +/** + * @brief Set the frame interval on a sub-device. + * @return 0 on success, or a negative error code on failure. + */ +int exynos_subdev_s_frame_interval(int fd, struct v4l2_subdev_frame_interval *frame_internval) +{ + int ret = -1; + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!frame_internval) { + ALOGE("%s: frame_internval is NULL", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, frame_internval); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_FRAME_INTERVAL"); + return ret; + } + + return ret; +} + +/** + * @brief enum mbus code + * @return 0 on success, or a negative error code on failure. + */ +int exynos_subdev_enum_mbus_code(int fd, struct v4l2_subdev_mbus_code_enum *mbus_code_enum) +{ + int ret = -1; + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!mbus_code_enum) { + ALOGE("%s: mbus_code_enum is NULL", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_MBUS_CODE, mbus_code_enum); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_MBUS_CODE"); + return ret; + } + + return ret; +} diff --git a/libv4l2/exynos_v4l2.c b/libv4l2/exynos_v4l2.c new file mode 100755 index 0000000..3286e8d --- /dev/null +++ b/libv4l2/exynos_v4l2.c @@ -0,0 +1,889 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*! + * \file exynos_v4l2.c + * \brief source file for libv4l2 + * \author Jinsung Yang (jsgood.yang@samsung.com) + * \author Sangwoo Park (sw5771.park@samsung.com) + * \date 2012/01/17 + * + * <b>Revision History: </b> + * - 2012/01/17: Jinsung Yang (jsgood.yang@samsung.com) \n + * Initial version + * + */ + +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <stdarg.h> +#include <fcntl.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> + +#include <exynos_v4l2.h> + +#include <exynos_log.h> + +#include <linux/videodev2.h> + +#define VIDEODEV_MAX 255 + +//#define EXYNOS_V4L2_TRACE 0 +#ifdef EXYNOS_V4L2_TRACE +#define Exynos_v4l2_In() ALOGV("%s In , Line: %d", __FUNCTION__, __LINE__) +#define Exynos_v4l2_Out() ALOGV("%s Out , Line: %d", __FUNCTION__, __LINE__) +#else +#define Exynos_v4l2_In() ((void *)0) +#define Exynos_v4l2_Out() ((void *)0) +#endif + +static bool __v4l2_check_buf_type(enum v4l2_buf_type type) +{ + bool supported; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + supported = true; + break; + + default: + supported = (type >= V4L2_BUF_TYPE_PRIVATE) ? true : false; + break; + } + + return supported; +} + +static int __v4l2_open(const char *filename, int oflag, va_list ap) +{ + mode_t mode = 0; + int fd; + + if (oflag & O_CREAT) + mode = va_arg(ap, int); + + fd = open(filename, oflag, mode); + + return fd; +} + +int exynos_v4l2_open(const char *filename, int oflag, ...) +{ + va_list ap; + int fd; + + Exynos_v4l2_In(); + + va_start(ap, oflag); + fd = __v4l2_open(filename, oflag, ap); + va_end(ap); + + Exynos_v4l2_Out(); + + return fd; +} + +int exynos_v4l2_open_devname(const char *devname, int oflag, ...) +{ + bool found = false; + int fd = -1; + struct stat s; + va_list ap; + FILE *stream_fd; + char filename[64], name[64]; + int i = 0; + + Exynos_v4l2_In(); + + do { + if (i > VIDEODEV_MAX) + break; + + /* video device node */ + snprintf(filename, sizeof(filename), "/dev/video%d", i); + + /* if the node is video device */ + if ((lstat(filename, &s) == 0) && S_ISCHR(s.st_mode) && + ((int)((unsigned short)(s.st_rdev) >> 8) == 81)) { + ALOGD("try node: %s", filename); + /* open sysfs entry */ + snprintf(filename, sizeof(filename), "/sys/class/video4linux/video%d/name", i); + if (S_ISLNK(s.st_mode)) { + ALOGE("symbolic link detected"); + return -1; + } + stream_fd = fopen(filename, "r"); + if (stream_fd == NULL) { + ALOGE("failed to open sysfs entry for videodev"); + continue; /* try next */ + } + + /* read sysfs entry for device name */ + char *p = fgets(name, sizeof(name), stream_fd); + fclose(stream_fd); + + /* check read size */ + if (p == NULL) { + ALOGE("failed to read sysfs entry for videodev"); + } else { + /* matched */ + if (strncmp(name, devname, strlen(devname)) == 0) { + ALOGI("node found for device %s: /dev/video%d", devname, i); + found = true; + break; + } + } + } + i++; + } while (found == false); + + if (found) { + snprintf(filename, sizeof(filename), "/dev/video%d", i); + va_start(ap, oflag); + fd = __v4l2_open(filename, oflag, ap); + va_end(ap); + + if (fd > 0) + ALOGI("open video device %s", filename); + else + ALOGE("failed to open video device %s", filename); + } else { + ALOGE("no video device found"); + } + + Exynos_v4l2_Out(); + + return fd; +} + +int exynos_v4l2_close(int fd) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) + ALOGE("%s: invalid fd: %d", __func__, fd); + else + ret = close(fd); + + Exynos_v4l2_Out(); + + return ret; +} + +bool exynos_v4l2_enuminput(int fd, int index, char *input_name_buf) +{ + int ret = -1; + struct v4l2_input input; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return NULL; + } + + input.index = index; + ret = ioctl(fd, VIDIOC_ENUMINPUT, &input, 32); + if (ret) { + ALOGE("%s: no matching index founds", __func__); + return false; + } + + ALOGI("Name of input channel[%d] is %s", input.index, input.name); + + strncpy(input_name_buf, (const char *)input.name, 32); + + Exynos_v4l2_Out(); + + return true; +} + +int exynos_v4l2_s_input(int fd, int index) +{ + int ret = -1; + struct v4l2_input input; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + input.index = index; + + ret = ioctl(fd, VIDIOC_S_INPUT, &input); + if (ret){ + ALOGE("failed to ioctl: VIDIOC_S_INPUT (%d - %s)", errno, strerror(errno)); + return ret; + } + + Exynos_v4l2_Out(); + + return ret; +} + +bool exynos_v4l2_querycap(int fd, unsigned int need_caps) +{ + struct v4l2_capability cap; + int ret; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return false; + } + + if (!(need_caps & V4L2_CAP_VIDEO_CAPTURE) && + !(need_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE) && + !(need_caps & V4L2_CAP_VIDEO_OUTPUT) && + !(need_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE) && + !(need_caps & V4L2_CAP_VIDEO_OVERLAY)) { + ALOGE("%s: unsupported capabilities", __func__); + return false; + } + + memset(&cap, 0, sizeof(cap)); + + ret = ioctl(fd, VIDIOC_QUERYCAP, &cap); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_QUERYCAP (%d - %s)", errno, strerror(errno)); + return false; + } + + if ((need_caps & cap.capabilities) != need_caps) { + ALOGE("%s: unsupported capabilities", __func__); + return false; + } + + Exynos_v4l2_Out(); + + return true; +} + +bool exynos_v4l2_enum_fmt(int fd, enum v4l2_buf_type type, unsigned int fmt) +{ + struct v4l2_fmtdesc fmtdesc; + int found = 0; + + Exynos_v4l2_In(); + + fmtdesc.type = type; + fmtdesc.index = 0; + + while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) { + if (fmtdesc.pixelformat == fmt) { + ALOGE("Passed fmt = %#x found pixel format[%d]: %s", fmt, fmtdesc.index, fmtdesc.description); + found = 1; + break; + } + + fmtdesc.index++; + } + + if (!found) { + ALOGE("%s: unsupported pixel format", __func__); + return false; + } + + Exynos_v4l2_Out(); + + return true; +} + +int exynos_v4l2_g_fmt(int fd, struct v4l2_format *fmt) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!fmt) { + ALOGE("%s: fmt is NULL", __func__); + return ret; + } + + if (__v4l2_check_buf_type(fmt->type) == false) { + ALOGE("%s: unsupported buffer type", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_G_FMT, fmt); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_G_FMT (%d - %s)", errno, strerror(errno)); + return ret; + } + + Exynos_v4l2_Out(); + + return ret; +} + +static int __v4l2_s_fmt(int fd, unsigned int request, struct v4l2_format *fmt) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!fmt) { + ALOGE("%s: fmt is NULL", __func__); + return ret; + } + + if (__v4l2_check_buf_type(fmt->type) == false) { + ALOGE("%s: unsupported buffer type", __func__); + return ret; + } else { + ret = ioctl(fd, request, fmt); + if (ret) { + if (request == VIDIOC_TRY_FMT) + ALOGE("failed to ioctl: VIDIOC_TRY_FMT (%d - %s)", errno, strerror(errno)); + else + ALOGE("failed to ioctl: VIDIOC_S_FMT (%d - %s)", errno, strerror(errno)); + + return ret; + } + } + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_try_fmt(int fd, struct v4l2_format *fmt) +{ + return __v4l2_s_fmt(fd, VIDIOC_TRY_FMT, fmt); +} + +int exynos_v4l2_s_fmt(int fd, struct v4l2_format *fmt) +{ + return __v4l2_s_fmt(fd, VIDIOC_S_FMT, fmt); +} + +int exynos_v4l2_reqbufs(int fd, struct v4l2_requestbuffers *req) +{ + int ret = -1; + unsigned int count; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!req) { + ALOGE("%s: req is NULL", __func__); + return ret; + } + + if ((req->memory != V4L2_MEMORY_MMAP) && + (req->memory != V4L2_MEMORY_USERPTR) && + (req->memory != V4L2_MEMORY_DMABUF)) { + ALOGE("%s: unsupported memory type", __func__); + return ret; + } + + if (__v4l2_check_buf_type(req->type) == false) { + ALOGE("%s: unsupported buffer type", __func__); + return ret; + } + + count = req->count; + + ret = ioctl(fd, VIDIOC_REQBUFS, req); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_REQBUFS (%d - %s)", ret, strerror(errno)); + return ret; + } + + if (count != req->count) { + ALOGW("number of buffers had been changed: %d => %d", count, req->count); + } + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_querybuf(int fd, struct v4l2_buffer *buf) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!buf) { + ALOGE("%s: buf is NULL", __func__); + return ret; + } + + if ((buf->memory != V4L2_MEMORY_MMAP) && + (buf->memory != V4L2_MEMORY_DMABUF)) { + ALOGE("%s: unsupported memory type", __func__); + return ret; + } + + if (__v4l2_check_buf_type(buf->type) == false) { + ALOGE("%s: unsupported buffer type", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_QUERYBUF, buf); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_QUERYBUF (%d - %s)", errno, strerror(errno)); + return ret; + } + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_qbuf(int fd, struct v4l2_buffer *buf) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!buf) { + ALOGE("%s: buf is NULL", __func__); + return ret; + } + + if ((buf->memory != V4L2_MEMORY_MMAP) && + (buf->memory != V4L2_MEMORY_USERPTR) && + (buf->memory != V4L2_MEMORY_DMABUF)) { + ALOGE("%s: unsupported memory type", __func__); + return ret; + } + + if (__v4l2_check_buf_type(buf->type) == false) { + ALOGE("%s: unsupported buffer type", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_QBUF, buf); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_QBUF (%d - %s)", errno, strerror(errno)); + return ret; + } + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_dqbuf(int fd, struct v4l2_buffer *buf) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!buf) { + ALOGE("%s: buf is NULL", __func__); + return ret; + } + + if ((buf->memory != V4L2_MEMORY_MMAP) && + (buf->memory != V4L2_MEMORY_USERPTR) && + (buf->memory != V4L2_MEMORY_DMABUF)) { + ALOGE("%s: unsupported memory type", __func__); + return ret; + } + + if (__v4l2_check_buf_type(buf->type) == false) { + ALOGE("%s: unsupported buffer type", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_DQBUF, buf); + if (ret) { + if (errno == EAGAIN) + return -errno; + + ALOGW("failed to ioctl: VIDIOC_DQBUF (%d - %s)", errno, strerror(errno)); + return ret; + } + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_streamon(int fd, enum v4l2_buf_type type) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (__v4l2_check_buf_type(type) == false) { + ALOGE("%s: unsupported buffer type", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_STREAMON, &type); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_STREAMON (%d - %s)", errno, strerror(errno)); + return ret; + } + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_streamoff(int fd, enum v4l2_buf_type type) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (__v4l2_check_buf_type(type) == false) { + ALOGE("%s: unsupported buffer type", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_STREAMOFF, &type); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_STREAMOFF (%d - %s)", errno, strerror(errno)); + return ret; + } + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_cropcap(int fd, struct v4l2_cropcap *crop) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!crop) { + ALOGE("%s: crop is NULL", __func__); + return ret; + } + + if (__v4l2_check_buf_type(crop->type) == false) { + ALOGE("%s: unsupported buffer type", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_CROPCAP, crop); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_CROPCAP (%d - %s)", errno, strerror(errno)); + return ret; + } + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_g_crop(int fd, struct v4l2_crop *crop) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!crop) { + ALOGE("%s: crop is NULL", __func__); + return ret; + } + + if (__v4l2_check_buf_type(crop->type) == false) { + ALOGE("%s: unsupported buffer type", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_G_CROP, crop); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_G_CROP (%d - %s)", errno, strerror(errno)); + return ret; + } + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_s_crop(int fd, struct v4l2_crop *crop) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (!crop) { + ALOGE("%s: crop is NULL", __func__); + return ret; + } + + if (__v4l2_check_buf_type(crop->type) == false) { + ALOGE("%s: unsupported buffer type", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_S_CROP, crop); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_S_CROP (%d - %s)", errno, strerror(errno)); + return ret; + } + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_g_ctrl(int fd, unsigned int id, int *value) +{ + int ret = -1; + struct v4l2_control ctrl; + + Exynos_v4l2_In(); + + ctrl.id = id; + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + ret = ioctl(fd, VIDIOC_G_CTRL, &ctrl); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_G_CTRL (%d - %s)", errno, strerror(errno)); + return ret; + } + + *value = ctrl.value; + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_s_ctrl(int fd, unsigned int id, int value) +{ + int ret = -1; + struct v4l2_control ctrl; + + Exynos_v4l2_In(); + + ctrl.id = id; + ctrl.value = value; + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + ret = ioctl(fd, VIDIOC_S_CTRL, &ctrl); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_S_CTRL (%d)", errno); + return ret; + } + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_prepare(int fd, struct v4l2_buffer *arg) +{ + int ret = -1; + struct v4l2_control ctrl; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + ret = ioctl(fd, VIDIOC_PREPARE_BUF, arg); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_PREPARE_BUF (%d)", errno); + return ret; + } + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_g_parm(int fd, struct v4l2_streamparm *streamparm) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (__v4l2_check_buf_type(streamparm->type) == false) { + ALOGE("%s: unsupported buffer type", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_G_PARM, streamparm); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_G_PARM (%d - %s)", errno, strerror(errno)); + return ret; + } + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_s_parm(int fd, struct v4l2_streamparm *streamparm) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (__v4l2_check_buf_type(streamparm->type) == false) { + ALOGE("%s: unsupported buffer type", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_S_PARM, streamparm); + if (ret) { + ALOGE("failed to ioctl: VIDIOC_S_PARM (%d - %s)", errno, strerror(errno)); + return ret; + } + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_g_ext_ctrl(int fd, struct v4l2_ext_controls *ctrl) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (ctrl == NULL) { + ALOGE("%s: ctrl is NULL", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_G_EXT_CTRLS, ctrl); + if (ret) + ALOGE("failed to ioctl: VIDIOC_G_EXT_CTRLS (%d - %s)", errno, strerror(errno)); + + Exynos_v4l2_Out(); + + return ret; +} + +int exynos_v4l2_s_ext_ctrl(int fd, struct v4l2_ext_controls *ctrl) +{ + int ret = -1; + + Exynos_v4l2_In(); + + if (fd < 0) { + ALOGE("%s: invalid fd: %d", __func__, fd); + return ret; + } + + if (ctrl == NULL) { + ALOGE("%s: ctrl is NULL", __func__); + return ret; + } + + ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, ctrl); + if (ret) + ALOGE("failed to ioctl: VIDIOC_S_EXT_CTRLS (%d - %s)", errno, strerror(errno)); + + Exynos_v4l2_Out(); + + return ret; +} diff --git a/packaging/libexynos-common.spec b/packaging/libexynos-common.spec new file mode 100755 index 0000000..493f7b4 --- /dev/null +++ b/packaging/libexynos-common.spec @@ -0,0 +1,96 @@ +Name: libexynos-common +Summary: HAL support library +Version: 0.0.1 +License: TO BE FILLED IN +Group: Development/Libraries +Release: 0 +ExclusiveArch: %arm +Source: %{name}-%{version}.tar.gz +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig +#!BuildIgnore: kernel-headers +BuildRequires: kernel-headers-exynos7270-tw2 +BuildRequires: pkgconfig(dlog) +BuildConflicts: linux-glibc-devel + +%description +implementation of libexynos common + + +%package devel +Summary: HAL support library (Developement) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +development package for libexynos-common + +%prep +%setup -q + +%build +./autogen.sh + +export CFLAGS+=" -mfpu=neon\ + -DUSE_DLOG\ + -DGST_EXT_TIME_ANALYSIS" + +LDFLAGS+="-Wl,--rpath=%{_prefix}/lib -Wl,--hash-style=both -Wl,--as-needed"; export LDFLAGS +%configure --prefix=%{_prefix} --disable-static --enable-dlog + + +#make %{?jobs:-j%jobs} +make + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}/usr/share/license +cp COPYING %{buildroot}/usr/share/license/%{name} +mkdir -p %{buildroot}%{_includedir} +mkdir -p %{buildroot}%{_includedir}/linux +mkdir -p %{buildroot}%{_includedir}/system +mkdir -p %{buildroot}%{_libdir}/pkgconfig +mkdir -p %{buildroot}/usr/libion/include/ion/ +mkdir -p %{buildroot}/usr/libion/kernel-headers/linux +install -m0644 include/content_protect.h %{buildroot}%{_includedir} +install -m0644 include/csc.h %{buildroot}%{_includedir} +install -m0644 include/exynos_format.h %{buildroot}%{_includedir} +install -m0644 include/exynos_gscaler.h %{buildroot}%{_includedir} +install -m0644 include/exynos_ion.h %{buildroot}%{_includedir} +install -m0644 include/exynos_log.h %{buildroot}%{_includedir} +install -m0644 include/exynos_scaler.h %{buildroot}%{_includedir} +install -m0644 include/exynos_v4l2.h %{buildroot}%{_includedir} +install -m0644 include/ion.h %{buildroot}%{_includedir} +install -m0644 include/media.h %{buildroot}%{_includedir} +install -m0644 include/swconverter.h %{buildroot}%{_includedir} +install -m0644 include/linux/compiler.h %{buildroot}%{_includedir}/linux +install -m0644 include/system/graphics.h %{buildroot}%{_includedir}/system +install -m0644 libion/include/ion/ion.h %{buildroot}/usr/libion/include/ion/ +install -m0644 libion/kernel-headers/linux/ion.h %{buildroot}/usr/libion/kernel-headers/linux +install exynos-common.pc %{buildroot}%{_libdir}/pkgconfig/ +%make_install + + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + + +%files +%manifest libexynos-common.manifest +%defattr(-,root,root,-) +%{_libdir}/libcsc.so* +%{_libdir}/libexynosgscaler.so* +%{_libdir}/libion.so* +%{_libdir}/libswconverter.so* +%{_libdir}/libexynosv4l2.so* +/usr/share/license/%{name} + +%files devel +%defattr(-,root,root,-) +%{_includedir}/* +/usr/libion/include/ion/* +/usr/libion/kernel-headers/linux/* +%{_libdir}/pkgconfig/* + + |