diff options
author | HyunKyung Kim <hk310.kim@samsung.com> | 2019-08-12 15:27:36 +0900 |
---|---|---|
committer | HyunKyung Kim <hk310.kim@samsung.com> | 2019-09-18 19:34:02 +0900 |
commit | 6935a9b0ac01b978519d8d704dee3994440ff023 (patch) | |
tree | b221bd0957f7ca7d936d598394dfc7dbf44ecdf7 /libscaler | |
parent | ac1c0535583ce3eeb8f2b59431ebe510619c0416 (diff) |
Add initial source code
Change-Id: I285a55c44c9fd5d3a8abaa781ef9dc8d9d39f53a
Signed-off-by: HyunKyung Kim <hk310.kim@samsung.com>
Diffstat (limited to 'libscaler')
-rw-r--r-- | libscaler/Android.mk | 46 | ||||
-rw-r--r-- | libscaler/NOTICE | 190 | ||||
-rw-r--r-- | libscaler/include/exynos_scaler.h | 540 | ||||
-rw-r--r-- | libscaler/libscaler-common.h | 127 | ||||
-rw-r--r-- | libscaler/libscaler-m2m1shot.cpp | 346 | ||||
-rw-r--r-- | libscaler/libscaler-m2m1shot.h | 119 | ||||
-rw-r--r-- | libscaler/libscaler-swscaler.cpp | 106 | ||||
-rw-r--r-- | libscaler/libscaler-swscaler.h | 61 | ||||
-rw-r--r-- | libscaler/libscaler-v4l2.cpp | 652 | ||||
-rw-r--r-- | libscaler/libscaler-v4l2.h | 325 | ||||
-rw-r--r-- | libscaler/libscaler.cpp | 765 | ||||
-rw-r--r-- | libscaler/libscalerblend-v4l2.cpp | 167 | ||||
-rw-r--r-- | libscaler/libscalerblend-v4l2.h | 64 | ||||
-rw-r--r-- | libscaler/m2m1shot.h | 96 |
14 files changed, 3604 insertions, 0 deletions
diff --git a/libscaler/Android.mk b/libscaler/Android.mk new file mode 100644 index 0000000..66824fb --- /dev/null +++ b/libscaler/Android.mk @@ -0,0 +1,46 @@ +# Copyright (C) 2013 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. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := liblog libutils libcutils +LOCAL_HEADER_LIBRARIES := libcutils_headers libsystem_headers libhardware_headers google_hal_headers + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include + +LOCAL_SRC_FILES := libscaler.cpp libscaler-v4l2.cpp libscalerblend-v4l2.cpp libscaler-m2m1shot.cpp libscaler-swscaler.cpp +ifeq ($(BOARD_USES_SCALER_M2M1SHOT), true) +LOCAL_CFLAGS += -DSCALER_USE_M2M1SHOT +endif + +ifeq ($(BOARD_USES_ALIGN_RESTRICTION), true) +LOCAL_CFLAGS += -DSCALER_ALIGN_RESTRICTION +endif + +ifneq ($(filter 3.18 4.4, $(TARGET_LINUX_KERNEL_VERSION)),) +LOCAL_CFLAGS += -DSCALER_USE_PREMUL_FMT +endif + +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := libexynosscaler + +ifeq ($(BOARD_USES_VENDORIMAGE), true) + LOCAL_PROPRIETARY_MODULE := true +endif + +include $(BUILD_SHARED_LIBRARY) diff --git a/libscaler/NOTICE b/libscaler/NOTICE new file mode 100644 index 0000000..316b4eb --- /dev/null +++ b/libscaler/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2014, 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. + + 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. + + + 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 + diff --git a/libscaler/include/exynos_scaler.h b/libscaler/include/exynos_scaler.h new file mode 100644 index 0000000..af5bb05 --- /dev/null +++ b/libscaler/include/exynos_scaler.h @@ -0,0 +1,540 @@ +/* + * 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 <stdbool.h> + +#include "exynos_format.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_PIX_FMT_NV21M_RGB32 v4l2_fourcc('V', 'N', 'R', 'G') +#define V4L2_PIX_FMT_NV21M_BGR32 v4l2_fourcc('V', 'N', 'B', 'G') +#define V4L2_PIX_FMT_NV21_RGB32 v4l2_fourcc('V', 'N', '1', 'R') +#define V4L2_PIX_FMT_YVU420_RGB32 v4l2_fourcc('Y', 'V', 'R', 'G') +#define V4L2_PIX_FMT_NV12M_P010 v4l2_fourcc('P', 'M', '1', '2') + +// 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 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_sc_img; + +enum colorspace { + COLORSPACE_SMPTE170M, + COLORSPACE_SMPTE240M, + COLORSPACE_REC709, + COLORSPACE_BT878, + COLORSPACE_470_SYSTEM_M, + COLORSPACE_470_SYSTEM_BG, + COLORSPACE_JPEG, + COLORSPACE_SRGB, +}; + +struct CSC_Spec{ + uint32_t enable; // set 'true' for user-defined + enum colorspace space; + uint32_t wide; +}; + +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 +}; + +struct SrcGlobalAlpha { + uint32_t enable; + unsigned int val; +}; + +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; +}; + +#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); + +/*! + * Set framerate (optional). + * + * \ingroup exynos_scaler + * + * \param handle + * libscaler handle[in] + * + * \param framerate + * frame rate[in] + */ +void exynos_sc_set_framerate( + void *handle, + int framerate); +////// 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); + +int hal_pixfmt_to_v4l2(int hal_pixel_format); + +#ifdef __cplusplus +} +#endif + +#endif /* _EXYNOS_SCALER_H_ */ diff --git a/libscaler/libscaler-common.h b/libscaler/libscaler-common.h new file mode 100644 index 0000000..2262e6e --- /dev/null +++ b/libscaler/libscaler-common.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2014 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 libscaler-common.h + * \brief source file for Scaler HAL + * \author Cho KyongHo <pullip.cho@samsung.com> + * \date 2014/05/08 + * + * <b>Revision History: </b> + * - 2014.05.08 : Cho KyongHo (pullip.cho@samsung.com) \n + * Create + */ +#ifndef _LIBSCALER_COMMON_H_ +#define _LIBSCALER_COMMON_H_ + +#define LOG_TAG "libexynosscaler" +#include <log/log.h> +#include <cerrno> +#include <cstring> + +//#define LOG_NDEBUG 0 + +#ifdef __GNUC__ +# define __UNUSED__ __attribute__((__unused__)) +#else +# define __UNUSED__ +#endif + +#define SC_LOGERR(fmt, args...) ((void)ALOG(LOG_ERROR, LOG_TAG, "%s: " fmt " [%s]", __func__, ##args, strerror(errno))) +#define SC_LOGE(fmt, args...) ((void)ALOG(LOG_ERROR, LOG_TAG, "%s: " fmt, __func__, ##args)) +#define SC_LOGI(fmt, args...) ((void)ALOG(LOG_INFO, LOG_TAG, "%s: " fmt, __func__, ##args)) +#define SC_LOGI_IF(cond, fmt, args...) do { \ + if (cond) \ + SC_LOGI(fmt, ##args); \ + } while (0) +#define SC_LOGE_IF(cond, fmt, args...) do { \ + if (cond) \ + SC_LOGE(fmt, ##args); \ + } while (0) +#define SC_LOG_ASSERT(cont, fmt, args...) ((void)ALOG_ASSERT(cond, "%s: " fmt, __func__, ##args)) + +#ifdef SC_DEBUG +#define SC_LOGD(args...) ((void)ALOG(LOG_INFO, LOG_TAG, ##args)) +#define SC_LOGD_IF(cond, fmt, args...) do { \ + if (cond) \ + SC_LOGD(fmt, ##args); \ + } while (0) +#else +#define SC_LOGD(args...) do { } while (0) +#define SC_LOGD_IF(cond, fmt, args...) do { } while (0) +#endif + +#define ARRSIZE(arr) (sizeof(arr)/sizeof(arr[0])) + + + +namespace LibScaler { +template <typename T> +static inline T min (T a, T b) { + return (a > b) ? b : a; +} + +template <typename T> +static inline void swap(T &a, T &b) { + T t = a; + a = b; + b = t; +} + +static inline bool UnderOne16thScaling(unsigned int srcw, unsigned int srch, + unsigned int dstw, unsigned int dsth, unsigned int rot) { + if ((rot == 90) || (rot == 270)) + swap(srcw, srch); + + return ((srcw > (dstw * 16)) || (srch > (dsth * 16))); +} + +}; +// marker for output parameters +#define __out + +#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) + +#ifndef V4L2_CID_GLOBAL_ALPHA +#define V4L2_CID_GLOBAL_ALPHA (V4L2_CID_EXYNOS_BASE + 1) +#endif +#ifndef V4L2_CID_2D_BLEND_OP +#define V4L2_CID_2D_BLEND_OP (V4L2_CID_EXYNOS_BASE + 103) +#endif +#ifndef V4L2_CID_2D_COLOR_FILL +#define V4L2_CID_2D_COLOR_FILL (V4L2_CID_EXYNOS_BASE + 104) +#endif +#ifndef V4L2_CID_2D_DITH +#define V4L2_CID_2D_DITH (V4L2_CID_EXYNOS_BASE + 105) +#endif +#ifndef V4L2_CID_2D_FMT_PREMULTI +#define V4L2_CID_2D_FMT_PREMULTI (V4L2_CID_EXYNOS_BASE + 106) +#endif + +#define SC_CID_FRAMERATE (V4L2_CID_EXYNOS_BASE + 110) + +#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) + +#endif //_LIBSCALER_COMMON_H_ diff --git a/libscaler/libscaler-m2m1shot.cpp b/libscaler/libscaler-m2m1shot.cpp new file mode 100644 index 0000000..485ee9c --- /dev/null +++ b/libscaler/libscaler-m2m1shot.cpp @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2014 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 libscaler-m2m1shot.cpp + * \brief source file for Scaler HAL + * \author Cho KyongHo <pullip.cho@samsung.com> + * \date 2014/05/08 + * + * <b>Revision History: </b> + * - 2014.05.08 : Cho KyongHo (pullip.cho@samsung.com) \n + * Create + */ +#include <cstring> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/mman.h> + +#include <exynos_scaler.h> + +#include "libscaler-common.h" +#include "libscaler-m2m1shot.h" +#include "libscaler-swscaler.h" + +using namespace std; + +const char *dev_base_name[] = { + "/dev/m2m1shot_scaler0", + "/dev/m2m1shot_scaler1", + "/dev/m2m1shot_scaler2", + "/dev/m2m1shot_scaler3", +}; + +struct PixFormat { + unsigned int pixfmt; + char planes; + char bit_pp[3]; +}; + +const static PixFormat g_pixfmt_table[] = { + {V4L2_PIX_FMT_RGB32, 1, {32, 0, 0}, }, + {V4L2_PIX_FMT_BGR32, 1, {32, 0, 0}, }, + {V4L2_PIX_FMT_RGB565, 1, {16, 0, 0}, }, + {V4L2_PIX_FMT_RGB555X, 1, {16, 0, 0}, }, + {V4L2_PIX_FMT_RGB444, 1, {16, 0, 0}, }, + {V4L2_PIX_FMT_YUYV, 1, {16, 0, 0}, }, + {V4L2_PIX_FMT_YVYU, 1, {16, 0, 0}, }, + {V4L2_PIX_FMT_UYVY, 1, {16, 0, 0}, }, + {V4L2_PIX_FMT_NV16, 1, {16, 0, 0}, }, + {V4L2_PIX_FMT_NV61, 1, {16, 0, 0}, }, + {V4L2_PIX_FMT_YUV420, 1, {12, 0, 0}, }, + {V4L2_PIX_FMT_YVU420, 1, {12, 0, 0}, }, + {V4L2_PIX_FMT_NV12M, 2, {8, 4, 0}, }, + {V4L2_PIX_FMT_NV21M, 2, {8, 4, 0}, }, + {v4l2_fourcc('V', 'M', '1', '2'), 2, {8, 4, 0}, }, + {V4L2_PIX_FMT_NV12, 1, {12, 0, 0}, }, + {V4L2_PIX_FMT_NV21, 1, {12, 0, 0}, }, + {v4l2_fourcc('N', 'M', '2', '1'), 2, {8, 4, 0}, }, + {V4L2_PIX_FMT_YUV420M, 3, {8, 2, 2}, }, + {V4L2_PIX_FMT_YVU420M, 3, {8, 2, 2}, }, + {V4L2_PIX_FMT_NV12M_P010, 2, {16, 8, 0}, }, + {V4L2_PIX_FMT_NV24, 1, {24, 0, 0}, }, + {V4L2_PIX_FMT_NV42, 1, {24, 0, 0}, }, +}; + + +CScalerM2M1SHOT::CScalerM2M1SHOT(int devid, int __UNUSED__ drm) : m_iFD(-1) +{ + memset(&m_task, 0, sizeof(m_task)); + + if ((devid < 0) || (devid > 3)) { // instance number must be between 0 ~ 3 + SC_LOGE("Invalid device instance ID %d", devid); + return; + } + + m_iFD = open(dev_base_name[devid], O_RDWR); + if (m_iFD < 0) { + SC_LOGERR("Failed to open '%s'", dev_base_name[devid]); + } else { + // default 3 planes not to miss any buffer address + m_task.buf_out.num_planes = 3; + m_task.buf_cap.num_planes = 3; + } +} + +CScalerM2M1SHOT::~CScalerM2M1SHOT() +{ + if (m_iFD >= 0) + close(m_iFD); +} + +bool CScalerM2M1SHOT::Run() +{ + int ret; + + if (LibScaler::UnderOne16thScaling( + m_task.fmt_out.crop.width, m_task.fmt_out.crop.height, + m_task.fmt_cap.crop.width, m_task.fmt_cap.crop.height, + m_task.op.rotate)) + return RunSWScaling(); + + ret = ioctl(m_iFD, M2M1SHOT_IOC_PROCESS, &m_task); + if (ret < 0) { + SC_LOGERR("Failed to process the given M2M1SHOT task"); + return false; + } + + return true; +} + +#define SCALER_EXT_SIZE 512 +bool CScalerM2M1SHOT::SetFormat(m2m1shot_pix_format &fmt, m2m1shot_buffer &buf, + unsigned int width, unsigned int height, unsigned int v4l2_fmt) { + const PixFormat *pixfmt = NULL; + + fmt.width = width; + fmt.height = height; + fmt.fmt = v4l2_fmt; + + for (size_t i = 0; i < ARRSIZE(g_pixfmt_table); i++) { + if (g_pixfmt_table[i].pixfmt == v4l2_fmt) { + pixfmt = &g_pixfmt_table[i]; + break; + } + } + + if (!pixfmt) { + SC_LOGE("Format %#x is not supported", v4l2_fmt); + return false; + } + + for (int i = 0; i < pixfmt->planes; i++) { + if (((pixfmt->bit_pp[i] * width) % 8) != 0) { + SC_LOGE("Plane %d of format %#x must have even width", i, v4l2_fmt); + return false; + } + buf.plane[i].len = (pixfmt->bit_pp[i] * width * height) / 8; + } + + if (pixfmt->pixfmt == V4L2_PIX_FMT_YVU420) { + unsigned int y_size = width * height; + unsigned int c_span = ALIGN(width / 2, 16); + buf.plane[0].len = y_size + (c_span * height / 2) * 2; + } + +#ifdef SCALER_ALIGN_RESTRICTION + for (int i = 0; i < pixfmt->planes; i++) + buf.plane[i].len += (i == 0) ? SCALER_EXT_SIZE : SCALER_EXT_SIZE / 2; +#endif + + buf.num_planes = pixfmt->planes; + + return true; +} + +bool CScalerM2M1SHOT::SetCrop(m2m1shot_pix_format &fmt, + unsigned int l, unsigned int t, unsigned int w, unsigned int h) { + if (fmt.width <= l) { + SC_LOGE("crop left %d is larger than image width %d", l, fmt.width); + return false; + } + if (fmt.height <= t) { + SC_LOGE("crop top %d is larger than image height %d", t, fmt.height); + return false; + } + if (fmt.width < (l + w)) { + SC_LOGE("crop width %d@%d exceeds image width %d", w, l, fmt.width); + return false; + } + if (fmt.height < (t + h)) { + SC_LOGE("crop height %d@%d exceeds image height %d", h, t, fmt.height); + return false; + } + + fmt.crop.left = l; + fmt.crop.top = t; + fmt.crop.width = w; + fmt.crop.height = h; + + return true; +} + +bool CScalerM2M1SHOT::SetAddr( + m2m1shot_buffer &buf, void *addr[SC_NUM_OF_PLANES], int mem_type) { + if (mem_type == V4L2_MEMORY_DMABUF) { + buf.type = M2M1SHOT_BUFFER_DMABUF; + for (int i = 0; i < buf.num_planes; i++) + buf.plane[i].fd = static_cast<__s32>(reinterpret_cast<long>(addr[i])); + } else if (mem_type == V4L2_MEMORY_USERPTR) { + buf.type = M2M1SHOT_BUFFER_USERPTR; + for (int i = 0; i < buf.num_planes; i++) + buf.plane[i].userptr = reinterpret_cast<unsigned long>(addr[i]); + } else { + SC_LOGE("Unknown buffer type %d", mem_type); + return false; + } + + return true; +} + +bool CScalerM2M1SHOT::SetRotate(int rot, int hflip, int vflip) { + if ((rot % 90) != 0) { + SC_LOGE("Rotation degree %d must be multiple of 90", rot); + return false; + } + + rot = rot % 360; + if (rot < 0) + rot = 360 + rot; + + m_task.op.rotate = rot; + m_task.op.op &= ~(M2M1SHOT_OP_FLIP_HORI | M2M1SHOT_OP_FLIP_VIRT); + if (hflip) + m_task.op.op |= M2M1SHOT_OP_FLIP_HORI; + if (vflip) + m_task.op.op |= M2M1SHOT_OP_FLIP_VIRT; + + return true; +} + +static bool GetBuffer(m2m1shot_buffer &buf, char *addr[]) +{ + for (int i = 0; i < buf.num_planes; i++) { + if (buf.type == M2M1SHOT_BUFFER_DMABUF) { + addr[i] = reinterpret_cast<char *>(mmap(NULL, buf.plane[i].len, + PROT_READ | PROT_WRITE, MAP_SHARED, + buf.plane[i].fd, 0)); + if (addr[i] == MAP_FAILED) { + SC_LOGE("Failed to map FD %d", buf.plane[i].fd); + while (i-- > 0) + munmap(addr[i], buf.plane[i].len); + return false; + } + } else { + addr[i] = reinterpret_cast<char *>(buf.plane[i].userptr); + } + } + + return true; +} + +static void PutBuffer(m2m1shot_buffer &buf, char *addr[]) +{ + for (int i = 0; i < buf.num_planes; i++) { + if (buf.type == M2M1SHOT_BUFFER_DMABUF) + munmap(addr[i], buf.plane[i].len); + } +} + +bool CScalerM2M1SHOT::RunSWScaling() +{ + if (m_task.fmt_cap.fmt != m_task.fmt_out.fmt) { + SC_LOGE("Source and target image format must be the same"); + return false; + } + + if (m_task.op.rotate != 0) { + SC_LOGE("Rotation is not allowed for S/W Scaling"); + return false; + } + + SC_LOGI("Running S/W Scaler: %dx%d -> %dx%d", + m_task.fmt_out.crop.width, m_task.fmt_out.crop.height, + m_task.fmt_cap.crop.width, m_task.fmt_cap.crop.height); + + CScalerSW *swsc; + char *src[3], *dst[3]; + + switch (m_task.fmt_cap.fmt) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + if (!GetBuffer(m_task.buf_out, src)) + return false; + + if (!GetBuffer(m_task.buf_cap, dst)) { + PutBuffer(m_task.buf_out, src); + return false; + } + + swsc = new CScalerSW_YUYV(src[0], dst[0]); + break; + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV21M: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + if (!GetBuffer(m_task.buf_out, src)) + return false; + + if (!GetBuffer(m_task.buf_cap, dst)) { + PutBuffer(m_task.buf_out, src); + return false; + } + + if (m_task.buf_out.num_planes == 1) + src[1] = src[0] + m_task.fmt_out.width * m_task.fmt_out.height; + + if (m_task.buf_cap.num_planes == 1) + dst[1] = dst[0] + m_task.fmt_cap.width * m_task.fmt_cap.height; + + swsc = new CScalerSW_NV12(src[0], src[1], dst[0], dst[1]); + break; + case V4L2_PIX_FMT_UYVY: // TODO: UYVY is not implemented yet. + default: + SC_LOGE("Format %x is not supported", m_task.fmt_out.fmt); + return false; + } + + if (swsc == NULL) { + SC_LOGE("Failed to allocate SW Scaler"); + PutBuffer(m_task.buf_out, src); + PutBuffer(m_task.buf_cap, dst); + return false; + } + + swsc->SetSrcRect(m_task.fmt_out.crop.left, m_task.fmt_out.crop.top, + m_task.fmt_out.crop.width, m_task.fmt_out.crop.height, + m_task.fmt_out.width); + + swsc->SetDstRect(m_task.fmt_cap.crop.left, m_task.fmt_cap.crop.top, + m_task.fmt_cap.crop.width, m_task.fmt_cap.crop.height, + m_task.fmt_cap.width); + + bool ret = swsc->Scale(); + + delete swsc; + + PutBuffer(m_task.buf_out, src); + PutBuffer(m_task.buf_cap, dst); + + return ret; +} diff --git a/libscaler/libscaler-m2m1shot.h b/libscaler/libscaler-m2m1shot.h new file mode 100644 index 0000000..5143598 --- /dev/null +++ b/libscaler/libscaler-m2m1shot.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2014 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 libscaler-m2m1shot.h + * \brief source file for Scaler HAL + * \author Cho KyongHo <pullip.cho@samsung.com> + * \date 2014/05/08 + * + * <b>Revision History: </b> + * - 2014.05.08 : Cho KyongHo (pullip.cho@samsung.com) \n + * Create + */ +#ifndef _LIBSCALER_M2M1SHOT_H_ +#define _LIBSCALER_M2M1SHOT_H_ + +#include "m2m1shot.h" + +class CScalerM2M1SHOT { + int m_iFD; + m2m1shot m_task; + + bool SetFormat(m2m1shot_pix_format &fmt, m2m1shot_buffer &buf, + unsigned int width, unsigned int height, unsigned int v4l2_fmt); + bool SetCrop(m2m1shot_pix_format &fmt, + unsigned int l, unsigned int t, unsigned int w, unsigned int h); + bool SetAddr(m2m1shot_buffer &buf, void *addr[SC_NUM_OF_PLANES], int mem_type); + + bool RunSWScaling(); +public: + CScalerM2M1SHOT(int devid, int allow_drm = 0); + ~CScalerM2M1SHOT(); + + bool Run(); + + inline bool Valid() { return m_iFD >= 0; } + + inline bool SetSrcFormat(unsigned int width, unsigned int height, unsigned int v4l2_fmt) { + return SetFormat(m_task.fmt_out, m_task.buf_out, width, height, v4l2_fmt); + } + + inline bool SetDstFormat(unsigned int width, unsigned int height, unsigned int v4l2_fmt) { + return SetFormat(m_task.fmt_cap, m_task.buf_cap, width, height, v4l2_fmt); + } + + inline bool SetSrcCrop(unsigned int l, unsigned int t, unsigned int w, unsigned int h) { + return SetCrop(m_task.fmt_out, l, t, w, h); + } + + inline bool SetDstCrop(unsigned int l, unsigned int t, unsigned int w, unsigned int h) { + return SetCrop(m_task.fmt_cap, l, t, w, h); + } + + inline bool SetSrcAddr(void *addr[SC_NUM_OF_PLANES], int mem_type) { + return SetAddr(m_task.buf_out, addr, mem_type); + } + + inline bool SetDstAddr(void *addr[SC_NUM_OF_PLANES], int mem_type) { + return SetAddr(m_task.buf_cap, addr, mem_type); + } + + bool SetRotate(int rot, int hflip, int vflip); + + inline void SetCSCWide(bool wide) { + m_task.op.op &= ~(M2M1SHOT_OP_CSC_WIDE | M2M1SHOT_OP_CSC_NARROW); + m_task.op.op |= wide ? M2M1SHOT_OP_CSC_WIDE : M2M1SHOT_OP_CSC_NARROW; + } + + inline void SetCSCEq(unsigned int colorspace) { + /* TODO: need to add M2M1SHOT_OP_CSC_2020 */ + m_task.op.op &= ~(M2M1SHOT_OP_CSC_601 | M2M1SHOT_OP_CSC_709); + if (colorspace == V4L2_COLORSPACE_REC709) + m_task.op.op |= M2M1SHOT_OP_CSC_709; + else + m_task.op.op |= M2M1SHOT_OP_CSC_601; + } + + inline void SetFilter(unsigned int filter) { + m_task.op.op &= ~LIBSC_M2M1SHOT_OP_FILTER_MASK; + m_task.op.op |= filter << LIBSC_M2M1SHOT_OP_FILTER_SHIFT; + } + + inline void SetFrameRate(int framerate) { + m_task.reserved[0] = (unsigned long)framerate; + } + + /* No effect in M2M1SHOT */ + inline void SetDRM(bool __UNUSED__ drm) { } + inline void SetSrcPremultiplied(bool __UNUSED__ premultiplied) { } + inline void SetDstPremultiplied(bool __UNUSED__ premultiplied) { } + inline void SetSrcCacheable(bool __UNUSED__ cacheable) { } + inline void SetDstCacheable(bool __UNUSED__ cacheable) { } + inline bool Stop() { return true; } + inline bool DevSetCtrl() { return false; } + inline bool DevSetFormat() { return false; } + inline bool ReqBufs() { return false; } + inline bool StreamOn() { return false; } + inline bool DQBuf() { return false; } + inline bool QBuf(int __UNUSED__ *pfdSrcReleaseFence = NULL, int __UNUSED__ *pfdDstReleaseFence = NULL) { + return false; + } + +}; + +#endif //_LIBSCALER_M2M1SHOT_H_ diff --git a/libscaler/libscaler-swscaler.cpp b/libscaler/libscaler-swscaler.cpp new file mode 100644 index 0000000..515b11e --- /dev/null +++ b/libscaler/libscaler-swscaler.cpp @@ -0,0 +1,106 @@ +#include "libscaler-swscaler.h" + +void CScalerSW::Clear() { + m_pSrc[0] = NULL; + m_pSrc[1] = NULL; + m_pSrc[2] = NULL; + m_pDst[0] = NULL; + m_pDst[1] = NULL; + m_pDst[2] = NULL; + + m_nSrcLeft = 0; + m_nSrcTop = 0; + m_nSrcWidth = 0; + m_nSrcHeight = 0; + m_nSrcStride = 0; + m_nDstLeft = 0; + m_nDstTop = 0; + m_nDstWidth = 0; + m_nDstHeight = 0; + m_nDstStride = 0; +} + +bool CScalerSW_YUYV::Scale() { + if (((m_nSrcLeft | m_nSrcWidth | m_nDstWidth | m_nSrcStride) % 2) != 0) { + SC_LOGE("Width of YUV422 should be even"); + return false; + } + + unsigned int h_ratio = (m_nSrcWidth << 16) / m_nDstWidth; + unsigned int v_ratio = (m_nSrcHeight << 16) / m_nDstHeight; + + unsigned int src_x; + unsigned int src_y = m_nSrcTop << 16; + + // Luminance + Chrominance at once + for (unsigned int y = m_nDstTop; y < (m_nDstTop + m_nDstHeight); y++) { + src_x = m_nSrcLeft << 16; + for (unsigned int x = m_nDstLeft; x < (m_nDstLeft + m_nDstWidth); x++) { + m_pDst[0][y * (m_nDstStride * 2) + x * 2] = + m_pSrc[0][(src_y >> 16) * (m_nSrcStride * 2) + (src_x >> 16) * 2]; + + if (!(x & 1)) { + unsigned int cx = (src_x >> 16) & ~1; + + m_pDst[0][y * (m_nDstStride * 2) + x * 2 + 1] = + m_pSrc[0][(src_y >> 16) * (m_nSrcStride * 2) + cx * 2 + 1]; + m_pDst[0][y * (m_nDstStride * 2) + x * 2 + 3] = + m_pSrc[0][(src_y >> 16) * (m_nSrcStride * 2) + cx * 2 + 3]; + + } + + src_x = LibScaler::min(src_x + h_ratio, (m_nSrcLeft + m_nSrcWidth) << 16); + } + + src_y = LibScaler::min(src_y + v_ratio, (m_nSrcTop + m_nSrcHeight) << 16); + } + + return true; +} + +bool CScalerSW_NV12::Scale() { + if (((m_nSrcLeft | m_nSrcTop | m_nSrcWidth | m_nSrcHeight | m_nSrcStride | + m_nDstLeft | m_nDstTop | m_nDstWidth | m_nDstHeight | m_nDstStride) % 2) != 0) { + SC_LOGE("Both of width and height of YUV420 should be even"); + return false; + } + + unsigned int h_ratio = (m_nSrcWidth << 16) / m_nDstWidth; + unsigned int v_ratio = (m_nSrcHeight << 16) / m_nDstHeight; + + unsigned int src_x; + unsigned int src_y = m_nSrcTop << 16; + + // Luminance + for (unsigned int y = m_nDstTop; y < (m_nDstTop + m_nDstHeight); y++) { + src_x = m_nSrcLeft << 16; + for (unsigned int x = m_nDstLeft; x < (m_nDstLeft + m_nDstWidth); x++) { + m_pDst[0][y * m_nDstStride + x] = m_pSrc[0][(src_y >> 16) * m_nSrcStride + (src_x >> 16)]; + + src_x = LibScaler::min(src_x + h_ratio, (m_nSrcLeft + m_nSrcWidth) << 16); + } + + src_y = LibScaler::min(src_y + v_ratio, (m_nSrcTop + m_nSrcHeight) << 16); + } + + // Chrominance + + // change pointers to 1-byte to pointers to 2-byte storage. + unsigned short *src = reinterpret_cast<unsigned short *>(m_pSrc[1]); + unsigned short *dst = reinterpret_cast<unsigned short *>(m_pDst[1]); + + src_y = (m_nSrcTop / 2) << 16; + for (unsigned int y = m_nDstTop / 2; y < ((m_nDstTop + m_nDstHeight) / 2); y++) { + // Move 2 pixels at once (CbCr) + src_x = (m_nSrcLeft / 2) << 16; + for (unsigned int x = m_nDstLeft / 2; x < ((m_nDstLeft + m_nDstWidth) / 2); x++) { + dst[y * (m_nDstStride / 2) + x] = src[(src_y >> 16) * (m_nSrcStride / 2) + (src_x >> 16)]; + + src_x = LibScaler::min(src_x + h_ratio, ((m_nSrcLeft + m_nSrcWidth) / 2) << 16); + } + + src_y = LibScaler::min(src_y + v_ratio, ((m_nSrcTop + m_nSrcHeight) / 2) << 16); + } + + return true; +} diff --git a/libscaler/libscaler-swscaler.h b/libscaler/libscaler-swscaler.h new file mode 100644 index 0000000..085d744 --- /dev/null +++ b/libscaler/libscaler-swscaler.h @@ -0,0 +1,61 @@ +#ifndef __LIBSCALER_SWSCALER_H__ +#define __LIBSCALER_SWSCALER_H__ + +#include "libscaler-common.h" + +class CScalerSW { + protected: + char *m_pSrc[3]; + char *m_pDst[3]; + unsigned int m_nSrcLeft, m_nSrcTop; + unsigned int m_nSrcWidth, m_nSrcHeight; + unsigned int m_nSrcStride; + unsigned int m_nDstLeft, m_nDstTop; + unsigned int m_nDstWidth, m_nDstHeight; + unsigned int m_nDstStride; + public: + CScalerSW() { Clear(); } + virtual ~CScalerSW() { }; + void Clear(); + virtual bool Scale() = 0; + + void SetSrcRect(unsigned int left, unsigned int top, unsigned int width, unsigned int height, unsigned int stride) { + m_nSrcLeft = left; + m_nSrcTop = top; + m_nSrcWidth = width; + m_nSrcHeight = height; + m_nSrcStride = stride; + } + + void SetDstRect(unsigned int left, unsigned int top, unsigned int width, unsigned int height, unsigned int stride) { + m_nDstLeft = left; + m_nDstTop = top; + m_nDstWidth = width; + m_nDstHeight = height; + m_nDstStride = stride; + } +}; + +class CScalerSW_YUYV: public CScalerSW { + public: + CScalerSW_YUYV(char *src, char *dst) { + m_pSrc[0] = src; + m_pDst[0] = dst; + } + + virtual bool Scale(); +}; + +class CScalerSW_NV12: public CScalerSW { + public: + CScalerSW_NV12(char *src0, char *src1, char *dst0, char *dst1) { + m_pSrc[0] = src0; + m_pDst[0] = dst0; + m_pSrc[1] = src1; + m_pDst[1] = dst1; + } + + virtual bool Scale(); +}; + +#endif //__LIBSCALER_SWSCALER_H__ diff --git a/libscaler/libscaler-v4l2.cpp b/libscaler/libscaler-v4l2.cpp new file mode 100644 index 0000000..8b9dd98 --- /dev/null +++ b/libscaler/libscaler-v4l2.cpp @@ -0,0 +1,652 @@ +/* + * Copyright (C) 2014 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 libscaler-v4l2.cpp + * \brief source file for Scaler HAL + * \author Cho KyongHo <pullip.cho@samsung.com> + * \date 2014/05/12 + * + * <b>Revision History: </b> + * - 2014.05.12 : Cho KyongHo (pullip.cho@samsung.com) \n + * Create + */ + +#include <cstring> +#include <cstdlib> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/mman.h> + +#include "libscaler-v4l2.h" +#include "libscaler-swscaler.h" + + +#define V4L2_CID_EXYNOS_BASE (V4L2_CTRL_CLASS_USER | 0x2000) +#define V4L2_CID_CSC_EQ_MODE (V4L2_CID_EXYNOS_BASE + 100) +#define V4L2_CID_CSC_EQ (V4L2_CID_EXYNOS_BASE + 101) +#define V4L2_CID_CSC_RANGE (V4L2_CID_EXYNOS_BASE + 102) +#define V4L2_CID_CONTENT_PROTECTION (V4L2_CID_EXYNOS_BASE + 201) + +void CScalerV4L2::Initialize(int instance) +{ + snprintf(m_cszNode, SC_MAX_NODENAME, SC_DEV_NODE "%d", SC_NODE(instance)); + + m_fdScaler = open(m_cszNode, O_RDWR); + if (m_fdScaler < 0) { + SC_LOGERR("Failed to open '%s'", m_cszNode); + return; + } + + m_fdValidate = -m_fdScaler; +} + +CScalerV4L2::CScalerV4L2(int instance, int allow_drm) +{ + m_fdScaler = -1; + m_iInstance = instance; + m_nRotDegree = 0; + m_fStatus = 0; + m_filter = 0; + + memset(&m_frmSrc, 0, sizeof(m_frmSrc)); + memset(&m_frmDst, 0, sizeof(m_frmDst)); + + m_frmSrc.fdAcquireFence = -1; + m_frmDst.fdAcquireFence = -1; + + m_frmSrc.name = "output"; + m_frmDst.name = "capture"; + + m_frmSrc.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + m_frmDst.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + m_frameRate = 0; + + Initialize(instance); + + if(Valid()) { + if (allow_drm) + SetFlag(m_fStatus, SCF_ALLOW_DRM); + SC_LOGD("Successfully opened '%s'; returned fd %d; drmmode %s", + m_cszNode, m_fdScaler, allow_drm ? "enabled" : "disabled"); + } +} + +CScalerV4L2::~CScalerV4L2() +{ + if (m_fdScaler >= 0) + close(m_fdScaler); + + m_fdScaler = -1; +} + +bool CScalerV4L2::Stop() +{ + if (!ResetDevice(m_frmSrc)) { + SC_LOGE("Failed to stop Scaler for the output frame"); + return false; + } + + if (!ResetDevice(m_frmDst)) { + SC_LOGE("Failed to stop Scaler for the cature frame"); + return false; + } + + return true; +} + +bool CScalerV4L2::Run() +{ + if (LibScaler::UnderOne16thScaling( + m_frmSrc.crop.width, m_frmSrc.crop.height, + m_frmDst.crop.width, m_frmDst.crop.height, + m_nRotDegree)) + return RunSWScaling(); + + if (!DevSetCtrl()) + return false; + + if (!DevSetFormat()) + return false; + + if (!ReqBufs()) + return false; + + if (!StreamOn()) + return false; + + if (!QBuf()) { + Stop(); + return false; + } + + return DQBuf(); +} + +bool CScalerV4L2::SetCtrl() +{ + struct v4l2_control ctrl; + + if (TestFlag(m_fStatus, SCF_DRM_FRESH)) { + if (!Stop()) + return false; + + ctrl.id = V4L2_CID_CONTENT_PROTECTION; + ctrl.value = TestFlag(m_fStatus, SCF_DRM); + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed configure V4L2_CID_CONTENT_PROTECTION to %d", TestFlag(m_fStatus, SCF_DRM)); + return false; + } + + ClearFlag(m_fStatus, SCF_DRM_FRESH); + } else { + SC_LOGD("Skipping DRM configuration"); + } + + if (TestFlag(m_fStatus, SCF_ROTATION_FRESH)) { + if (!Stop()) + return false; + + ctrl.id = V4L2_CID_ROTATE; + ctrl.value = m_nRotDegree; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed V4L2_CID_ROTATE with degree %d", m_nRotDegree); + return false; + } + + ctrl.id = V4L2_CID_VFLIP; + ctrl.value = TestFlag(m_fStatus, SCF_HFLIP); + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed V4L2_CID_VFLIP - %d", TestFlag(m_fStatus, SCF_VFLIP)); + return false; + } + + ctrl.id = V4L2_CID_HFLIP; + ctrl.value = TestFlag(m_fStatus, SCF_VFLIP); + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed V4L2_CID_HFLIP - %d", TestFlag(m_fStatus, SCF_HFLIP)); + return false; + } + + SC_LOGD("Successfully set CID_ROTATE(%d), CID_VFLIP(%d) and CID_HFLIP(%d)", + m_nRotDegree, TestFlag(m_fStatus, SCF_VFLIP), TestFlag(m_fStatus, SCF_HFLIP)); + ClearFlag(m_fStatus, SCF_ROTATION_FRESH); + } else { + SC_LOGD("Skipping rotation and flip setting due to no change"); + } + + if (m_filter > 0) { + if (!Stop()) + return false; + + ctrl.id = LIBSC_V4L2_CID_DNOISE_FT; + ctrl.value = m_filter; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed LIBSC_V4L2_CID_DNOISE_FT to %d", m_filter); + return false; + } + } + + if (TestFlag(m_fStatus, SCF_CSC_FRESH)) { + if (!Stop()) + return false; + + ctrl.id = V4L2_CID_CSC_RANGE; + ctrl.value = TestFlag(m_fStatus, SCF_CSC_WIDE) ? 1 : 0; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed V4L2_CID_CSC_RANGE to %d", TestFlag(m_fStatus, SCF_CSC_WIDE)); + return false; + } + + ctrl.id = V4L2_CID_CSC_EQ; + ctrl.value = m_colorspace; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed V4L2_CID_CSC_EQ to %d", m_colorspace); + } + ClearFlag(m_fStatus, SCF_CSC_FRESH); + } + + /* This is optional, so we don't return failure. */ + if (TestFlag(m_fStatus, SCF_FRAMERATE)) { + if (!Stop()) + return false; + + ctrl.id = SC_CID_FRAMERATE; + ctrl.value = m_frameRate; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGD("Failed SC_CID_FRAMERATE to %d", m_frameRate); + } + ClearFlag(m_fStatus, SCF_FRAMERATE); + } + + return true; +} + +bool CScalerV4L2::DevSetCtrl() +{ + return SetCtrl(); +} + +bool CScalerV4L2::ResetDevice(FrameInfo &frm) +{ + DQBuf(frm); + + if (TestFlag(frm.flags, SCFF_STREAMING)) { + if (ioctl(m_fdScaler, VIDIOC_STREAMOFF, &frm.type) < 0) { + SC_LOGERR("Failed STREAMOFF for the %s", frm.name); + } + ClearFlag(frm.flags, SCFF_STREAMING); + } + + SC_LOGD("VIDIC_STREAMOFF is successful for the %s", frm.name); + + if (TestFlag(frm.flags, SCFF_REQBUFS)) { + v4l2_requestbuffers reqbufs; + memset(&reqbufs, 0, sizeof(reqbufs)); + reqbufs.type = frm.type; + reqbufs.memory = frm.memory; + if (ioctl(m_fdScaler, VIDIOC_REQBUFS, &reqbufs) < 0 ) { + SC_LOGERR("Failed to REQBUFS(0) for the %s", frm.name); + } + + ClearFlag(frm.flags, SCFF_REQBUFS); + } + + SC_LOGD("VIDIC_REQBUFS(0) is successful for the %s", frm.name); + + return true; +} + +bool CScalerV4L2::DevSetFormat(FrameInfo &frm) +{ + + if (!TestFlag(frm.flags, SCFF_BUF_FRESH)) { + SC_LOGD("Skipping S_FMT for the %s since it is already done", frm.name); + return true; + } + + if (!ResetDevice(frm)) { + SC_LOGE("Failed to VIDIOC_S_FMT for the %s", frm.name); + return false; + } + + v4l2_format fmt; + memset(&fmt, 0, sizeof(fmt)); + fmt.type = frm.type; + fmt.fmt.pix_mp.pixelformat = frm.color_format; + fmt.fmt.pix_mp.width = frm.width; + fmt.fmt.pix_mp.height = frm.height; + + if (TestFlag(frm.flags, SCFF_PREMULTIPLIED)) { +#ifdef SCALER_USE_PREMUL_FMT + fmt.fmt.pix_mp.flags = V4L2_PIX_FMT_FLAG_PREMUL_ALPHA; +#else + fmt.fmt.pix_mp.reserved[1] = SC_V4L2_FMT_PREMULTI_FLAG; +#endif + } + + if (ioctl(m_fdScaler, VIDIOC_S_FMT, &fmt) < 0) { + SC_LOGERR("Failed S_FMT(fmt: %d, w:%d, h:%d) for the %s", + fmt.fmt.pix_mp.pixelformat, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height, + frm.name); + return false; + } + + // returned fmt.fmt.pix_mp.num_planes and fmt.fmt.pix_mp.plane_fmt[i].sizeimage + frm.out_num_planes = fmt.fmt.pix_mp.num_planes; + + for (int i = 0; i < frm.out_num_planes; i++) + frm.out_plane_size[i] = fmt.fmt.pix_mp.plane_fmt[i].sizeimage; + + v4l2_crop crop; + crop.type = frm.type; + crop.c = frm.crop; + + if (ioctl(m_fdScaler, VIDIOC_S_CROP, &crop) < 0) { + SC_LOGERR("Failed S_CROP(fmt: %d, l:%d, t:%d, w:%d, h:%d) for the %s", + crop.type, crop.c.left, crop.c.top, crop.c.width, crop.c.height, + frm.name); + return false; + } + + if (frm.out_num_planes > SC_MAX_PLANES) { + SC_LOGE("Number of planes exceeds %d of %s", frm.out_num_planes, frm.name); + return false; + } + + ClearFlag(frm.flags, SCFF_BUF_FRESH); + + SC_LOGD("Successfully S_FMT and S_CROP for the %s", frm.name); + + return true; +} + +bool CScalerV4L2::DevSetFormat() +{ + if (!DevSetFormat(m_frmSrc)) + return false; + + return DevSetFormat(m_frmDst); +} + +bool CScalerV4L2::QBuf(FrameInfo &frm, int *pfdReleaseFence) +{ + v4l2_buffer buffer; + v4l2_plane planes[SC_MAX_PLANES]; + + if (!TestFlag(frm.flags, SCFF_REQBUFS)) { + SC_LOGE("Trying to QBUF without REQBUFS for %s is not allowed", + frm.name); + return false; + } + + if (!DQBuf(frm)) + return false; + + memset(&buffer, 0, sizeof(buffer)); + memset(&planes, 0, sizeof(planes)); + + buffer.type = frm.type; + buffer.memory = frm.memory; + buffer.index = 0; + buffer.length = frm.out_num_planes; + + if (pfdReleaseFence) { + buffer.flags = V4L2_BUF_FLAG_USE_SYNC; + buffer.reserved = frm.fdAcquireFence; + } + + buffer.m.planes = planes; + for (unsigned long i = 0; i < buffer.length; i++) { + planes[i].length = frm.out_plane_size[i]; + if (V4L2_TYPE_IS_OUTPUT(buffer.type)) + planes[i].bytesused = planes[i].length; + if (buffer.memory == V4L2_MEMORY_DMABUF) + planes[i].m.fd = static_cast<__s32>(reinterpret_cast<long>(frm.addr[i])); + else + planes[i].m.userptr = reinterpret_cast<unsigned long>(frm.addr[i]); + } + + + if (ioctl(m_fdScaler, VIDIOC_QBUF, &buffer) < 0) { + SC_LOGERR("Failed to QBUF for the %s", frm.name); + return false; + } + + SetFlag(frm.flags, SCFF_QBUF); + + if (pfdReleaseFence) { + if (frm.fdAcquireFence >= 0) + close(frm.fdAcquireFence); + frm.fdAcquireFence = -1; + + *pfdReleaseFence = static_cast<int>(buffer.reserved); + } + + SC_LOGD("Successfully QBUF for the %s", frm.name); + + return true; +} + +bool CScalerV4L2::ReqBufs(FrameInfo &frm) +{ + v4l2_requestbuffers reqbufs; + + if (TestFlag(frm.flags, SCFF_REQBUFS)) { + SC_LOGD("Skipping REQBUFS for the %s since it is already done", frm.name); + return true; + } + + memset(&reqbufs, 0, sizeof(reqbufs)); + + reqbufs.type = frm.type; + reqbufs.memory = frm.memory; + reqbufs.count = 1; + + if (ioctl(m_fdScaler, VIDIOC_REQBUFS, &reqbufs) < 0) { + SC_LOGERR("Failed to REQBUFS for the %s", frm.name); + return false; + } + + SetFlag(frm.flags, SCFF_REQBUFS); + + SC_LOGD("Successfully REQBUFS for the %s", frm.name); + + return true; +} + +bool CScalerV4L2::SetRotate(int rot, int flip_h, int flip_v) +{ + if ((rot % 90) != 0) { + SC_LOGE("Rotation of %d degree is not supported", rot); + return false; + } + + SetRotDegree(rot); + + if (flip_h) + SetFlag(m_fStatus, SCF_VFLIP); + else + ClearFlag(m_fStatus, SCF_VFLIP); + + if (flip_v) + SetFlag(m_fStatus, SCF_HFLIP); + else + ClearFlag(m_fStatus, SCF_HFLIP); + + SetFlag(m_fStatus, SCF_ROTATION_FRESH); + + return true; +} + +bool CScalerV4L2::StreamOn(FrameInfo &frm) +{ + if (!TestFlag(frm.flags, SCFF_REQBUFS)) { + SC_LOGE("Trying to STREAMON without REQBUFS for %s is not allowed", + frm.name); + return false; + } + + if (!TestFlag(frm.flags, SCFF_STREAMING)) { + if (ioctl(m_fdScaler, VIDIOC_STREAMON, &frm.type) < 0 ) { + SC_LOGERR("Failed StreamOn for the %s", frm.name); + return false; + } + + SetFlag(frm.flags, SCFF_STREAMING); + + SC_LOGD("Successfully VIDIOC_STREAMON for the %s", frm.name); + } + + return true; +} + +bool CScalerV4L2::DQBuf(FrameInfo &frm) +{ + if (!TestFlag(frm.flags, SCFF_QBUF)) + return true; + + v4l2_buffer buffer; + v4l2_plane plane[SC_NUM_OF_PLANES]; + + memset(&buffer, 0, sizeof(buffer)); + + buffer.type = frm.type; + buffer.memory = frm.memory; + + if (V4L2_TYPE_IS_MULTIPLANAR(buffer.type)) { + memset(plane, 0, sizeof(plane)); + + buffer.length = frm.out_num_planes; + buffer.m.planes = plane; + } + + ClearFlag(frm.flags, SCFF_QBUF); + + if (ioctl(m_fdScaler, VIDIOC_DQBUF, &buffer) < 0 ) { + SC_LOGERR("Failed to DQBuf the %s", frm.name); + return false; + } + + if (buffer.flags & V4L2_BUF_FLAG_ERROR) { + SC_LOGE("Error occurred while processing streaming data"); + return false; + } + + SC_LOGD("Successfully VIDIOC_DQBUF for the %s", frm.name); + + return true; +} + +static bool GetBuffer(CScalerV4L2::FrameInfo &frm, char *addr[]) +{ + for (int i = 0; i < frm.out_num_planes; i++) { + if (frm.memory == V4L2_MEMORY_DMABUF) { + addr[i] = reinterpret_cast<char *>(mmap(NULL, frm.out_plane_size[i], + PROT_READ | PROT_WRITE, MAP_SHARED, + static_cast<int>(reinterpret_cast<long>(frm.addr[i])), 0)); + if (addr[i] == MAP_FAILED) { + SC_LOGE("Failed to map FD %ld", reinterpret_cast<long>(frm.addr[i])); + while (i-- > 0) + munmap(addr[i], frm.out_plane_size[i]); + return false; + } + } else { + addr[i] = reinterpret_cast<char *>(frm.addr[i]); + } + } + + return true; +} + +static void PutBuffer(CScalerV4L2::FrameInfo &frm, char *addr[]) +{ + for (int i = 0; i < frm.out_num_planes; i++) { + if (frm.memory == V4L2_MEMORY_DMABUF) { + munmap(addr[i], frm.out_plane_size[i]); + } + } +} + +bool CScalerV4L2::RunSWScaling() +{ + if (m_frmSrc.color_format != m_frmDst.color_format) { + SC_LOGE("Source and target image format must be the same"); + return false; + } + + if (m_nRotDegree != 0) { + SC_LOGE("Rotation is not allowed for S/W Scaling"); + return false; + } + + SC_LOGI("Running S/W Scaler: %dx%d -> %dx%d", + m_frmSrc.crop.width, m_frmSrc.crop.height, + m_frmDst.crop.width, m_frmDst.crop.height); + + CScalerSW *swsc; + char *src[3], *dst[3]; + + switch (m_frmSrc.color_format) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + m_frmSrc.out_num_planes = 1; + m_frmSrc.out_plane_size[0] = m_frmSrc.width * m_frmSrc.height * 2; + m_frmDst.out_num_planes = 1; + m_frmDst.out_plane_size[0] = m_frmDst.width * m_frmDst.height * 2; + + if (!GetBuffer(m_frmSrc, src)) + return false; + + if (!GetBuffer(m_frmDst, dst)) { + PutBuffer(m_frmSrc, src); + return false; + } + + swsc = new CScalerSW_YUYV(src[0], dst[0]); + break; + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV21M: + m_frmSrc.out_num_planes = 2; + m_frmDst.out_num_planes = 2; + m_frmSrc.out_plane_size[0] = m_frmSrc.width * m_frmSrc.height; + m_frmDst.out_plane_size[0] = m_frmDst.width * m_frmDst.height; + m_frmSrc.out_plane_size[1] = m_frmSrc.out_plane_size[0] / 2; + m_frmDst.out_plane_size[1] = m_frmDst.out_plane_size[0] / 2; + + if (!GetBuffer(m_frmSrc, src)) + return false; + + if (!GetBuffer(m_frmDst, dst)) { + PutBuffer(m_frmSrc, src); + return false; + } + + swsc = new CScalerSW_NV12(src[0], src[1], dst[0], dst[1]); + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + m_frmSrc.out_num_planes = 1; + m_frmDst.out_num_planes = 1; + m_frmSrc.out_plane_size[0] = m_frmSrc.width * m_frmSrc.height; + m_frmDst.out_plane_size[0] = m_frmDst.width * m_frmDst.height; + m_frmSrc.out_plane_size[0] += m_frmSrc.out_plane_size[0] / 2; + m_frmDst.out_plane_size[0] += m_frmDst.out_plane_size[0] / 2; + + if (!GetBuffer(m_frmSrc, src)) + return false; + + if (!GetBuffer(m_frmDst, dst)) { + PutBuffer(m_frmSrc, src); + return false; + } + + src[1] = src[0] + m_frmSrc.width * m_frmSrc.height; + dst[1] = dst[0] + m_frmDst.width * m_frmDst.height; + + swsc = new CScalerSW_NV12(src[0], src[1], dst[0], dst[1]); + break; + case V4L2_PIX_FMT_UYVY: // TODO: UYVY is not implemented yet. + default: + SC_LOGE("Format %x is not supported", m_frmSrc.color_format); + return false; + } + + if (swsc == NULL) { + SC_LOGE("Failed to allocate SW Scaler"); + PutBuffer(m_frmSrc, src); + PutBuffer(m_frmDst, dst); + return false; + } + + swsc->SetSrcRect(m_frmSrc.crop.left, m_frmSrc.crop.top, + m_frmSrc.crop.width, m_frmSrc.crop.height, m_frmSrc.width); + + swsc->SetDstRect(m_frmDst.crop.left, m_frmDst.crop.top, + m_frmDst.crop.width, m_frmDst.crop.height, m_frmDst.width); + + bool ret = swsc->Scale(); + + delete swsc; + + PutBuffer(m_frmSrc, src); + PutBuffer(m_frmDst, dst); + + return ret; +} diff --git a/libscaler/libscaler-v4l2.h b/libscaler/libscaler-v4l2.h new file mode 100644 index 0000000..98d45e2 --- /dev/null +++ b/libscaler/libscaler-v4l2.h @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2014 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 libscaler-v4l2.h + * \brief source file for Scaler HAL + * \author Cho KyongHo <pullip.cho@samsung.com> + * \date 2014/05/12 + * + * <b>Revision History: </b> + * - 2014.05.12 : Cho KyongHo (pullip.cho@samsung.com) \n + * Create + */ +#ifndef _LIBSCALER_V4L2_H_ +#define _LIBSCALER_V4L2_H_ + +#include <fcntl.h> + +#include <exynos_scaler.h> + +#include "libscaler-common.h" + +#define V4L2_CID_EXYNOS_BASE (V4L2_CTRL_CLASS_USER | 0x2000) +#define V4L2_CID_CSC_EQ_MODE (V4L2_CID_EXYNOS_BASE + 100) +#define V4L2_CID_CSC_EQ (V4L2_CID_EXYNOS_BASE + 101) +#define V4L2_CID_CSC_RANGE (V4L2_CID_EXYNOS_BASE + 102) +#define V4L2_CID_CONTENT_PROTECTION (V4L2_CID_EXYNOS_BASE + 201) + +#define V4L2_PIX_FMT_NV12N v4l2_fourcc('N', 'N', '1', '2') +#define V4L2_PIX_FMT_NV12NT v4l2_fourcc('T', 'N', '1', '2') +#define V4L2_PIX_FMT_YUV420N v4l2_fourcc('Y', 'N', '1', '2') +#define V4L2_PIX_FMT_NV12N_10B v4l2_fourcc('B', 'N', '1', '2') + +#define V4L2_BUF_FLAG_USE_SYNC 0x00008000 + +class CScalerV4L2 { +public: + enum { SC_MAX_PLANES = SC_NUM_OF_PLANES }; + enum { SC_MAX_NODENAME = 14 }; + enum { SC_V4L2_FMT_PREMULTI_FLAG = 10 }; + + enum SC_FRAME_FLAG { + // frame status + SCFF_BUF_FRESH = 0, + // h/w setting + SCFF_CACHEABLE, + SCFF_PREMULTIPLIED, + // v4l2 status + SCFF_REQBUFS, + SCFF_QBUF, + SCFF_STREAMING, + }; + + enum SC_FLAG { + SCF_RESERVED = 0, + // session status + SCF_ROTATION_FRESH, + SCF_CSC_FRESH, + SCF_DRM_FRESH, + // h/w setting setting + SCF_HFLIP, + SCF_VFLIP, + SCF_DRM, + SCF_ALLOW_DRM, + SCF_CSC_WIDE, + SCF_SRC_BLEND, + SCF_FRAMERATE, + }; + + struct FrameInfo { + const char *name; + v4l2_buf_type type; + unsigned int width, height; + v4l2_rect crop; + unsigned int color_format; + void *addr[SC_MAX_PLANES]; + int fdAcquireFence; + enum v4l2_memory memory; + int out_num_planes; + unsigned long out_plane_size[SC_MAX_PLANES]; + unsigned long flags; // enum SC_FRAME_FLAG + }; + +private: + FrameInfo m_frmSrc; + FrameInfo m_frmDst; + + unsigned int m_nRotDegree; + unsigned int m_frameRate; + char m_cszNode[SC_MAX_NODENAME]; // /dev/videoXX + int m_iInstance; + + int m_fdValidate; + + unsigned int m_filter; + unsigned int m_colorspace; + + void Initialize(int instance); + bool ResetDevice(FrameInfo &frm); + + inline void SetRotDegree(int rot) { + rot = rot % 360; + if (rot < 0) + rot = 360 + rot; + + m_nRotDegree = rot; + SetFlag(m_fStatus, SCF_ROTATION_FRESH); + } + + bool DevSetFormat(FrameInfo &frm); + bool ReqBufs(FrameInfo &frm); + bool QBuf(FrameInfo &frm, int *pfdReleaseFence); + bool StreamOn(FrameInfo &frm); + bool DQBuf(FrameInfo &frm); + + inline bool SetFormat(FrameInfo &frm, unsigned int width, unsigned int height, + unsigned int v4l2_colorformat) { + frm.color_format = v4l2_colorformat; + frm.width = width; + frm.height = height; + SetFlag(frm.flags, SCFF_BUF_FRESH); + return true; + } + + inline bool SetCrop(FrameInfo &frm, unsigned int left, unsigned int top, + unsigned int width, unsigned int height) { + frm.crop.left = left; + frm.crop.top = top; + frm.crop.width = width; + frm.crop.height = height; + SetFlag(frm.flags, SCFF_BUF_FRESH); + return true; + } + + inline void SetPremultiplied(FrameInfo &frm, unsigned int premultiplied) { + if (premultiplied) + SetFlag(frm.flags, SCFF_PREMULTIPLIED); + else + ClearFlag(frm.flags, SCFF_PREMULTIPLIED); + } + + inline void SetCacheable(FrameInfo &frm, bool __UNUSED__ cacheable) { + SetFlag(frm.flags, SCFF_CACHEABLE); + } + + inline void SetAddr(FrameInfo &frm, void *addr[SC_NUM_OF_PLANES], int mem_type, int fence) + { + for (int i = 0; i < SC_MAX_PLANES; i++) + frm.addr[i] = addr[i]; + + frm.memory = static_cast<v4l2_memory>(mem_type); + frm.fdAcquireFence = fence; + } + + bool RunSWScaling(); + +protected: + unsigned long m_fStatus; // enum SC_FLAG + + int m_fdScaler; + + inline void SetFlag(unsigned long &flags, unsigned long flag) { + flags |= (1 << flag); + } + + inline void ClearFlag(unsigned long &flags, unsigned long flag) { + flags &= ~(1 << flag); + } + + inline bool TestFlag(unsigned long &flags, unsigned long flag) { + return (flags & (1 << flag)) != 0; + } + + +public: + inline bool Valid() { return (m_fdScaler >= 0) && (m_fdScaler == -m_fdValidate); } + + CScalerV4L2(int instance, int allow_drm = 0); + virtual ~CScalerV4L2(); + + bool SetCtrl(); + + inline bool IsDRMAllowed() { return TestFlag(m_fStatus, SCF_ALLOW_DRM); } + inline int GetScalerID() { return m_iInstance; } + + bool Stop(); + bool Run(); // Blocking mode + + // H/W Control + virtual bool DevSetCtrl(); + bool DevSetFormat(); + + inline bool ReqBufs() { + if (!ReqBufs(m_frmSrc)) + return false; + + return ReqBufs(m_frmDst); + } + + inline bool QBuf(int *pfdSrcReleaseFence = NULL, int *pfdDstReleaseFence = NULL) { + if (!QBuf(m_frmSrc, pfdSrcReleaseFence)) + return false; + + if (!QBuf(m_frmDst, pfdDstReleaseFence)) { + ClearFlag(m_frmSrc.flags, SCFF_QBUF); + return false; + } + return true; + } + + inline bool StreamOn() { + if (!StreamOn(m_frmSrc)) + return false; + + return StreamOn(m_frmDst); + } + + inline bool DQBuf() { + if (!DQBuf(m_frmSrc)) + return false; + + return DQBuf(m_frmDst); + } + + inline bool SetSrcFormat(unsigned int width, unsigned int height, + unsigned int v4l2_colorformat) { + return SetFormat(m_frmSrc, width, height, v4l2_colorformat); + } + + inline bool SetDstFormat(unsigned int width, unsigned int height, + unsigned int v4l2_colorformat) { + return SetFormat(m_frmDst, width, height, v4l2_colorformat); + } + + inline bool SetSrcCrop(unsigned int left, unsigned int top, + unsigned int width, unsigned int height) { + return SetCrop(m_frmSrc, left, top, width, height); + } + + inline bool SetDstCrop(unsigned int left, unsigned int top, + unsigned int width, unsigned int height) { + return SetCrop(m_frmDst, left, top, width, height); + } + + inline void SetDRM(bool drm) { + if (drm != TestFlag(m_fStatus, SCF_DRM)) { + if (drm) + SetFlag(m_fStatus, SCF_DRM); + else + ClearFlag(m_fStatus, SCF_DRM); + SetFlag(m_fStatus, SCF_DRM_FRESH); + } + } + + inline void SetCSCWide(bool wide) { + if (wide) + SetFlag(m_fStatus, SCF_CSC_WIDE); + else + ClearFlag(m_fStatus, SCF_CSC_WIDE); + + SetFlag(m_fStatus, SCF_CSC_FRESH); + } + + inline void SetCSCEq(unsigned int v4l2_colorspace) { + if (v4l2_colorspace == V4L2_COLORSPACE_SMPTE170M) + m_colorspace = V4L2_COLORSPACE_DEFAULT; + else + m_colorspace = v4l2_colorspace; + SetFlag(m_fStatus, SCF_CSC_FRESH); + } + + inline void SetFilter(unsigned int filter) { + m_filter = filter; + } + + inline void SetSrcCacheable(bool cacheable) { + return SetCacheable(m_frmSrc, cacheable); + } + + inline void SetDstCacheable(bool cacheable) { + return SetCacheable(m_frmDst, cacheable); + } + + inline void SetSrcPremultiplied(bool premultiplied) { + return SetPremultiplied(m_frmSrc, premultiplied); + } + + inline void SetDstPremultiplied(bool premultiplied) { + return SetPremultiplied(m_frmDst, premultiplied); + } + + // Parameter Extraction + bool SetRotate(int rot, int flip_h, int flip_v); + + inline bool SetSrcAddr(void *addr[SC_NUM_OF_PLANES], int mem_type, int fence = -1) { + SetAddr(m_frmSrc, addr, mem_type, fence); + return true; + } + + inline bool SetDstAddr(void *addr[SC_NUM_OF_PLANES], int mem_type, int fence = -1) { + SetAddr(m_frmDst, addr, mem_type, fence); + return true; + } + + inline void SetFrameRate(int framerate) { + m_frameRate = framerate; + SetFlag(m_fStatus, SCF_FRAMERATE); + } +}; + +#endif //_LIBSCALER_V4L2_H_ diff --git a/libscaler/libscaler.cpp b/libscaler/libscaler.cpp new file mode 100644 index 0000000..28cceb3 --- /dev/null +++ b/libscaler/libscaler.cpp @@ -0,0 +1,765 @@ + /* + * 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 libscaler.cpp + * \brief source 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.10 : Cho KyongHo (pullip.cho@samsung.com) \n + * Refactoring + * + */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <system/graphics.h> + +#include "exynos_scaler.h" + +#include "libscaler-common.h" +#include "libscalerblend-v4l2.h" +#include "libscaler-v4l2.h" +#include "libscaler-m2m1shot.h" + +int hal_pixfmt_to_v4l2(int hal_pixel_format) +{ + int v4l2_pixel_format = -1; + + switch (hal_pixel_format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + v4l2_pixel_format = V4L2_PIX_FMT_RGB32; + break; + + case HAL_PIXEL_FORMAT_RGB_888: + v4l2_pixel_format = V4L2_PIX_FMT_RGB24; + break; + + case HAL_PIXEL_FORMAT_RGB_565: + v4l2_pixel_format = V4L2_PIX_FMT_RGB565; + break; + + case HAL_PIXEL_FORMAT_BGRA_8888: + v4l2_pixel_format = V4L2_PIX_FMT_BGR32; + break; + + case HAL_PIXEL_FORMAT_EXYNOS_YV12_M: + v4l2_pixel_format = V4L2_PIX_FMT_YVU420M; + break; + + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M: + v4l2_pixel_format = V4L2_PIX_FMT_YUV420M; + break; + + case HAL_PIXEL_FORMAT_YV12: + v4l2_pixel_format = V4L2_PIX_FMT_YVU420; + break; + + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P: + v4l2_pixel_format = V4L2_PIX_FMT_YUV420; + break; + + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_PN: + v4l2_pixel_format = V4L2_PIX_FMT_YUV420N; + break; + + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + v4l2_pixel_format = V4L2_PIX_FMT_NV16; + break; + + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP: + v4l2_pixel_format = V4L2_PIX_FMT_NV12; + break; + + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN: + v4l2_pixel_format = V4L2_PIX_FMT_NV12N; + 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: + v4l2_pixel_format = V4L2_PIX_FMT_NV12M; + break; + + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_S10B: + v4l2_pixel_format = V4L2_PIX_FMT_NV12N_10B; + break; + + case HAL_PIXEL_FORMAT_YCbCr_422_I: + v4l2_pixel_format = V4L2_PIX_FMT_YUYV; + break; + + case HAL_PIXEL_FORMAT_EXYNOS_CbYCrY_422_I: + v4l2_pixel_format = V4L2_PIX_FMT_UYVY; + break; + + case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_422_SP: + v4l2_pixel_format = V4L2_PIX_FMT_NV61; + break; + + case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M: + case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_FULL: + v4l2_pixel_format = V4L2_PIX_FMT_NV21M; + break; + + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + v4l2_pixel_format = V4L2_PIX_FMT_NV21; + break; + + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_TILED: +#ifdef USES_FIMC + v4l2_pixel_format = V4L2_PIX_FMT_NV12MT; +#else + v4l2_pixel_format = V4L2_PIX_FMT_NV12MT_16X16; +#endif + break; + + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_TILED: + v4l2_pixel_format = V4L2_PIX_FMT_NV12NT; + break; + + case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_422_I: + v4l2_pixel_format = V4L2_PIX_FMT_YVYU; + break; + + case HAL_PIXEL_FORMAT_EXYNOS_CrYCbY_422_I: + v4l2_pixel_format = V4L2_PIX_FMT_VYUY; + break; + + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M: + v4l2_pixel_format = V4L2_PIX_FMT_NV12M_P010; + break; + + default: + ALOGE("%s::unmatched HAL_PIXEL_FORMAT color_space(0x%x)\n", + __func__, hal_pixel_format); + break; + } + + return v4l2_pixel_format; +} + +static bool find_pixel(unsigned int sc_pxfmt, unsigned int __out *v4l2_pxfmt) +{ + const static unsigned int sc_fmt_tbl[][2] = { + {EXYNOS_SC_FMT_RGB32, V4L2_PIX_FMT_RGB32}, + {EXYNOS_SC_FMT_BGR32, V4L2_PIX_FMT_BGR32}, + {EXYNOS_SC_FMT_RGB565, V4L2_PIX_FMT_RGB565}, + {EXYNOS_SC_FMT_RGB555X, V4L2_PIX_FMT_RGB555X}, + {EXYNOS_SC_FMT_RGB444, V4L2_PIX_FMT_RGB444}, + }; + + for (size_t i = 0; i < ARRSIZE(sc_fmt_tbl); i++) { + if (sc_pxfmt == sc_fmt_tbl[i][0]) { + *v4l2_pxfmt = sc_fmt_tbl[i][1]; + return true; + } + } + + SC_LOGE("Unknown format value %d", sc_pxfmt); + + return false; +} + +bool exynos_sc_copy_pixels(exynos_sc_pxinfo *pxinfo, int dev_num) +{ + unsigned int srcfmt; + unsigned int dstfmt; + + CScalerM2M1SHOT sc(dev_num); + + if (!sc.Valid()) + return false; + + if (!find_pixel(pxinfo->src.pxfmt, &srcfmt)) + return false; + + if (!find_pixel(pxinfo->dst.pxfmt, &dstfmt)) + return false; + + if (!sc.SetSrcFormat(pxinfo->src.width, pxinfo->src.height, srcfmt)) + return false; + + if (!sc.SetDstFormat(pxinfo->dst.width, pxinfo->dst.height, dstfmt)) + return false; + + if (!sc.SetSrcCrop(pxinfo->src.crop_left, pxinfo->src.crop_top, + pxinfo->src.crop_width, pxinfo->src.crop_height)) + return false; + + if (!sc.SetDstCrop(pxinfo->dst.crop_left, pxinfo->dst.crop_top, + pxinfo->dst.crop_width, pxinfo->dst.crop_height)) + return false; + + if (!sc.SetRotate(pxinfo->rotate, pxinfo->hflip, pxinfo->vflip)) + return false; + + // the first argument ot CScalerM2M1SHOT.SetXXXAddr() must be void *[3] + // it is safe to pass void *[1] which is not an array actually + // because CScalerM2M1SHOT.SetAddr() just accesses the array elements + // that are used for the specified format and this function just specifies + // RGB formats with one planar. + void *addr[SC_NUM_OF_PLANES]; + for (size_t i = 1; i < SC_NUM_OF_PLANES; i++) + addr[i] = NULL; + + addr[0] = pxinfo->src.addr; + if (!sc.SetSrcAddr(addr, V4L2_MEMORY_USERPTR)) + return false; + + addr[0] = pxinfo->dst.addr; + if (!sc.SetDstAddr(addr, V4L2_MEMORY_USERPTR)) + return false; + + return sc.Run(); +} + +#ifdef SCALER_USE_M2M1SHOT +typedef CScalerM2M1SHOT CScalerNonStream; +#else +typedef CScalerV4L2 CScalerNonStream; +#endif + +static CScalerNonStream *GetNonStreamScaler(void *handle) +{ + if (handle == NULL) { + SC_LOGE("NULL Scaler handle"); + return NULL; + } + + CScalerNonStream *sc = reinterpret_cast<CScalerNonStream *>(handle); + if (!sc->Valid()) { + SC_LOGE("Invalid Scaler handle %p", handle); + return NULL; + } + + return sc; +} + +void *exynos_sc_create(int dev_num) +{ + CScalerNonStream *sc = new CScalerNonStream(dev_num); + + if (!sc) { + SC_LOGE("Failed to allocate a Scaler handle for instance %d", dev_num); + return NULL; + } + + if (!sc->Valid()) { + SC_LOGE("Failed to create a Scaler handle for instance %d", dev_num); + delete sc; + return NULL; + } + + return reinterpret_cast<void *>(sc); +} + +int exynos_sc_destroy(void *handle) +{ + int ret = 0; + + CScalerNonStream *sc = GetNonStreamScaler(handle); + if (!sc) + return -1; + + if (!sc->Stop()) { + SC_LOGE("Failed to stop Scaler (handle %p)", handle); + ret = -1; + } + + delete sc; + + return ret; +} + +int exynos_sc_set_csc_property( + void *handle, + unsigned int csc_range, + unsigned int v4l2_colorspace, + unsigned int filter) + +{ + CScalerNonStream *sc = GetNonStreamScaler(handle); + if (!sc) + return -1; + + sc->SetCSCWide(csc_range); + sc->SetCSCEq(v4l2_colorspace); + sc->SetFilter(filter); + + return 0; +} + +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) +{ + CScalerNonStream *sc = GetNonStreamScaler(handle); + if (!sc) + return -1; + + sc->SetSrcPremultiplied(premultiplied != 0); + sc->SetSrcCacheable(cacheable != 0); + sc->SetDRM(mode_drm != 0); + + if (!sc->SetSrcFormat(width, height, v4l2_colorformat)) + return -1; + + return sc->SetSrcCrop(crop_left, crop_top, crop_width, crop_height) ? 0 : -1; +} + +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) +{ + CScalerNonStream *sc = GetNonStreamScaler(handle); + if (!sc) + return -1; + + sc->SetDstPremultiplied(premultiplied != 0); + sc->SetDstCacheable(cacheable != 0); + sc->SetDRM(mode_drm != 0); + + if (!sc->SetDstFormat(width, height, v4l2_colorformat)) + return -1; + + if (!sc->SetDstCrop(crop_left, crop_top, crop_width, crop_height)) + return -1; + + return 0; +} + +int exynos_sc_set_rotation( + void *handle, + int rot, + int flip_h, + int flip_v) +{ + CScalerNonStream *sc = GetNonStreamScaler(handle); + if (!sc) + return -1; + + return sc->SetRotate(rot, flip_h, flip_v) ? 0 : -1; +} + +void exynos_sc_set_framerate( + void *handle, + int framerate) +{ + CScalerNonStream *sc = GetNonStreamScaler(handle); + if (!sc) + return; + + sc->SetFrameRate(framerate); +} + +int exynos_sc_set_src_addr( + void *handle, + void *addr[SC_NUM_OF_PLANES], + int mem_type, + int __UNUSED__ acquireFenceFd) +{ + CScalerNonStream *sc = GetNonStreamScaler(handle); + if (!sc) + return -1; + + // acquireFenceFd is ignored by blocking mode + return sc->SetSrcAddr(addr, mem_type) ? 0 : -1; +} + +int exynos_sc_set_dst_addr( + void *handle, + void *addr[SC_NUM_OF_PLANES], + int mem_type, + int __UNUSED__ acquireFenceFd) +{ + CScalerNonStream *sc = GetNonStreamScaler(handle); + if (!sc) + return -1; + + // acquireFenceFd is ignored by blocking mode + return sc->SetDstAddr(addr, mem_type) ? 0 : -1; +} + +int exynos_sc_convert(void *handle) +{ + CScalerNonStream *sc = GetNonStreamScaler(handle); + if (!sc) + return -1; + + return sc->Run() ? 0 : -1; +} + +static CScalerBlendV4L2 *GetScalerBlend(void *handle) +{ + if (handle == NULL) { + SC_LOGE("NULL Scaler handle"); + return NULL; + } + + CScalerBlendV4L2 *sc = reinterpret_cast<CScalerBlendV4L2 *>(handle); + if (!sc->Valid()) { + SC_LOGE("Invalid Scaler handle %p", handle); + return NULL; + } + + return sc; +} + +static CScalerV4L2 *GetScaler(void *handle) +{ + if (handle == NULL) { + SC_LOGE("NULL Scaler handle"); + return NULL; + } + + CScalerV4L2 *sc = reinterpret_cast<CScalerV4L2 *>(handle); + if (!sc->Valid()) { + SC_LOGE("Invalid Scaler handle %p", handle); + return NULL; + } + + return sc; +} + +void *exynos_sc_create_exclusive( + int dev_num, + int allow_drm + ) +{ + CScalerV4L2 *sc; + + sc = new CScalerV4L2(dev_num, allow_drm); + if (!sc) { + SC_LOGE("Failed to allocate a Scaler handle for instance %d", dev_num); + return NULL; + } + + if (!sc->Valid()) { + SC_LOGE("Failed to create a Scaler handle for instance %d", dev_num); + delete sc; + return NULL; + } + + SC_LOGD("Scaler %d is successfully created", dev_num); + return reinterpret_cast<void *>(sc); +} + +int exynos_sc_free_and_close(void *handle) +{ + CScalerV4L2 *sc = GetScaler(handle); + if (!sc) + return -1; + + int ret = 0; + if (!sc->Stop()) { + SC_LOGE("Failed to stop Scaler (handle %p)", handle); + ret = -1; + } + + delete sc; + + return ret; +} + +int exynos_sc_stop_exclusive(void *handle) +{ + CScalerV4L2 *sc = GetScaler(handle); + if (!sc) + return -1; + + if (!sc->Stop()) { + SC_LOGE("Failed to stop Scaler (handle %p)", handle); + return -1; + } + + return 0; +} + +int exynos_sc_csc_exclusive(void *handle, + unsigned int range_full, + unsigned int v4l2_colorspace) +{ + CScalerV4L2 *sc = GetScaler(handle); + if (!sc) + return -1; + + sc->SetCSCWide(range_full); + sc->SetCSCEq(v4l2_colorspace); + + return 0; +} + +int exynos_sc_config_exclusive( + void *handle, + exynos_sc_img *src_img, + exynos_sc_img *dst_img) +{ + CScalerV4L2 *sc = GetScaler(handle); + if (!sc) + return -1; + + if (src_img->drmMode && !sc->IsDRMAllowed()) { + SC_LOGE("Invalid DRM state request for Scaler%d (s=%d d=%d)", + sc->GetScalerID(), src_img->drmMode, dst_img->drmMode); + return -1; + } + + unsigned int rot = 0; + unsigned int flip_h = 0; + unsigned int flip_v = 0; + + if (dst_img->rot == HAL_TRANSFORM_ROT_270) { + rot = 270; + } else { + if (dst_img->rot & HAL_TRANSFORM_FLIP_H) + flip_h = 1; + if (dst_img->rot & HAL_TRANSFORM_FLIP_V) + flip_v = 1; + if (dst_img->rot & HAL_TRANSFORM_ROT_90) + rot = 90; + } + + if (!sc->SetRotate(rot, flip_h, flip_v)) { + SC_LOGE("Failed to set rotation degree %d, hflip %d, vflip %d", + rot, flip_h, flip_v); + return -1; + } + + int32_t src_color_space = hal_pixfmt_to_v4l2(src_img->format); + int32_t dst_color_space = hal_pixfmt_to_v4l2(dst_img->format); + + if (!sc->SetSrcFormat(src_img->fw, src_img->fh, src_color_space)) + return -1; + + if (!sc->SetSrcCrop(src_img->x, src_img->y, src_img->w, src_img->h)) + return -1; + + if (!sc->SetDstFormat(dst_img->fw, dst_img->fh, dst_color_space)) + return -1; + + if (!sc->SetDstCrop(dst_img->x, dst_img->y, dst_img->w, dst_img->h)) + return -1; + + sc->SetCSCWide(!dst_img->narrowRgb); + + sc->SetSrcCacheable(src_img->cacheable != 0); + sc->SetDstCacheable(dst_img->cacheable != 0); + + sc->SetSrcPremultiplied(src_img->pre_multi); + sc->SetDstPremultiplied(dst_img->pre_multi); + + sc->SetDRM(src_img->drmMode != 0 || dst_img->drmMode != 0); + + return 0; +} + +int exynos_sc_run_exclusive( + void *handle, + exynos_sc_img *src_img, + exynos_sc_img *dst_img) +{ + CScalerV4L2 *sc = GetScaler(handle); + if (!sc) + return -1; + + void *addr[SC_NUM_OF_PLANES]; + + addr[0] = (void *)src_img->yaddr; + addr[1] = (void *)src_img->uaddr; + addr[2] = (void *)src_img->vaddr; + sc->SetSrcAddr(addr, src_img->mem_type, src_img->acquireFenceFd); + + addr[0] = (void *)dst_img->yaddr; + addr[1] = (void *)dst_img->uaddr; + addr[2] = (void *)dst_img->vaddr; + sc->SetDstAddr(addr, dst_img->mem_type, dst_img->acquireFenceFd); + + if (!sc->DevSetCtrl()) + return -1; + + if (!sc->DevSetFormat()) + return -1; + + if (!sc->ReqBufs()) + return -1; + + int fdSrcReleaseFence, fdDstReleaseFence; + + if (!sc->QBuf(&fdSrcReleaseFence, &fdDstReleaseFence)) + return -1; + + if (!sc->StreamOn()) { + close(fdSrcReleaseFence); + close(fdDstReleaseFence); + return -1; + } + + src_img->releaseFenceFd = fdSrcReleaseFence; + dst_img->releaseFenceFd = fdDstReleaseFence; + + return 0; +} + +void *exynos_sc_create_blend_exclusive( + int dev_num, + int allow_drm + ) +{ + CScalerBlendV4L2 *sc; + + sc = new CScalerBlendV4L2(dev_num, allow_drm); + if (!sc) { + SC_LOGE("Failed to allocate a Scaler blend handle for instance %d", dev_num); + return NULL; + } + + if (!sc->Valid()) { + SC_LOGE("Failed to create a Scaler blend handle for instance %d", dev_num); + delete sc; + return NULL; + } + + SC_LOGD("Scaler blend %d is successfully created", dev_num); + return reinterpret_cast<void *>(sc); +} + +int exynos_sc_config_blend_exclusive( + void *handle, + exynos_sc_img *src_img, + exynos_sc_img *dst_img, + struct SrcBlendInfo *srcblendinfo) +{ + + CScalerBlendV4L2 *sc = GetScalerBlend(handle); + if (!sc) + return -1; + + if (src_img->drmMode && !sc->IsDRMAllowed()) { + SC_LOGE("Invalid DRM state request for Scaler%d (s=%d d=%d)", + sc->GetScalerID(), src_img->drmMode, dst_img->drmMode); + return -1; + } + unsigned int rot = 0; + unsigned int flip_h = 0; + unsigned int flip_v = 0; + + if (dst_img->rot == HAL_TRANSFORM_ROT_270) { + rot = 270; + } else { + if (dst_img->rot & HAL_TRANSFORM_FLIP_H) + flip_h = 1; + if (dst_img->rot & HAL_TRANSFORM_FLIP_V) + flip_v = 1; + if (dst_img->rot & HAL_TRANSFORM_ROT_90) + rot = 90; + } + + if (!sc->SetRotate(rot, flip_h, flip_v)) { + SC_LOGE("Failed to set rotation degree %d, hflip %d, vflip %d", + rot, flip_h, flip_v); + return -1; + } + + int32_t src_color_space = hal_pixfmt_to_v4l2(src_img->format); + int32_t dst_color_space = hal_pixfmt_to_v4l2(dst_img->format); + int32_t src_blend_color_space = hal_pixfmt_to_v4l2(srcblendinfo->srcblendfmt); + + sc->GetCustomAlphaBlendFmt(src_color_space, src_blend_color_space); + if (src_color_space < 0) { + SC_LOGE("src blending format not supported"); + return -1; + } + + sc->SetSrcBlendOp(srcblendinfo->blop); + + sc->SetSrcGlobalAlpha(srcblendinfo->globalalpha.val, + srcblendinfo->globalalpha.enable); + + sc->SetSrcBlendVPos(srcblendinfo->srcblendvpos); + + sc->SetSrcBlendHPos(srcblendinfo->srcblendhpos); + + sc->SetSrcBlendPremulti(srcblendinfo->srcblendpremulti); + + sc->SetSrcBlendFmt(src_blend_color_space); + + sc->SetSrcBlendStride(srcblendinfo->srcblendstride); + + sc->SetSrcBlendWidth(srcblendinfo->srcblendwidth); + + sc->SetSrcBlendHeight(srcblendinfo->srcblendheight); + + sc->SetSrcBlendCSCSpace(srcblendinfo->cscspec.enable, + srcblendinfo->cscspec.space, + srcblendinfo->cscspec.wide); + + if (!sc->SetSrcFormat(src_img->fw, src_img->fh, src_color_space)) + return -1; + + if (!sc->SetSrcCrop(src_img->x, src_img->y, src_img->w, src_img->h)) + return -1; + + if (!sc->SetDstFormat(dst_img->fw, dst_img->fh, dst_color_space)) + return -1; + + if (!sc->SetDstCrop(dst_img->x, dst_img->y, dst_img->w, dst_img->h)) + return -1; + + sc->SetSrcCacheable(src_img->cacheable != 0); + sc->SetDstCacheable(dst_img->cacheable != 0); + + sc->SetDRM(src_img->drmMode != 0 || dst_img->drmMode != 0); + + return 0; +} + +int exynos_sc_wait_frame_done_exclusive( + void *handle) +{ + CScalerV4L2 *sc = GetScaler(handle); + if (!sc) + return -1; + + return sc->DQBuf() ? 0 : -1; +} diff --git a/libscaler/libscalerblend-v4l2.cpp b/libscaler/libscalerblend-v4l2.cpp new file mode 100644 index 0000000..77ec956 --- /dev/null +++ b/libscaler/libscalerblend-v4l2.cpp @@ -0,0 +1,167 @@ +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <linux/videodev2.h> + +#include "libscaler-v4l2.h" +#include "libscalerblend-v4l2.h" + +bool CScalerBlendV4L2::DevSetCtrl() +{ + struct v4l2_control ctrl; + + if (!SetCtrl()) + return false; + + /* Blending related ctls */ + if (!TestFlag(m_fStatus, SCF_SRC_BLEND)) + return false; + + ctrl.id = V4L2_CID_2D_BLEND_OP; + ctrl.value = m_SrcBlndCfg.blop; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed S_CTRL V4L2_CID_2D_BLEND_OP"); + return false; + } + + if (m_SrcBlndCfg.globalalpha.enable) { + ctrl.id = V4L2_CID_GLOBAL_ALPHA; + ctrl.value = m_SrcBlndCfg.globalalpha.val; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed S_CTRL V4L2_CID_GLOBAL_ALPHA"); + return false; + } + } else { + ctrl.id = V4L2_CID_GLOBAL_ALPHA; + ctrl.value = 0xff; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed S_CTRL V4L2_CID_GLOBAL_ALPHA 0xff"); + return false; + } + } + + if (m_SrcBlndCfg.cscspec.enable) { + bool is_bt709 = (m_SrcBlndCfg.cscspec.space == COLORSPACE_REC709)? true : false; + + ctrl.id = V4L2_CID_CSC_EQ; + ctrl.value = is_bt709; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed S_CTRL V4L2_CID_CSC_EQ - %d", + m_SrcBlndCfg.cscspec.space); + return false; + } + + ctrl.id = V4L2_CID_CSC_RANGE; + ctrl.value = m_SrcBlndCfg.cscspec.wide; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed S_CTRL V4L2_CID_CSC_RANGE - %d", + m_SrcBlndCfg.cscspec.wide); + return false; + } + } + + ctrl.id = V4L2_CID_2D_SRC_BLEND_SET_FMT; + ctrl.value = m_SrcBlndCfg.srcblendfmt; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed V4L2_CID_2D_SRC_BLEND_SET_FMT - %d", + m_SrcBlndCfg.srcblendfmt); + return false; + } + + ctrl.id = V4L2_CID_2D_SRC_BLEND_FMT_PREMULTI; + ctrl.value = m_SrcBlndCfg.srcblendpremulti; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed V4L2_CID_2D_BLEND_FMT_PREMULTI - %d", + m_SrcBlndCfg.srcblendpremulti); + return false; + } + + ctrl.id = V4L2_CID_2D_SRC_BLEND_SET_STRIDE; + ctrl.value = m_SrcBlndCfg.srcblendstride; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed V4L2_CID_2D_SRC_BLEND_SET_STRIDE - %d", + m_SrcBlndCfg.srcblendstride); + return false; + } + + ctrl.id = V4L2_CID_2D_SRC_BLEND_SET_H_POS; + ctrl.value = m_SrcBlndCfg.srcblendhpos; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed V4L2_CID_2D_SRC_BLEND_SET_H_POS with degree %d", + m_SrcBlndCfg.srcblendhpos); + return false; + } + + ctrl.id = V4L2_CID_2D_SRC_BLEND_SET_V_POS; + ctrl.value = m_SrcBlndCfg.srcblendvpos; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed V4L2_CID_2D_SRC_BLEND_SET_V_POS - %d", + m_SrcBlndCfg.srcblendvpos); + return false; + } + + ctrl.id = V4L2_CID_2D_SRC_BLEND_SET_WIDTH; + ctrl.value = m_SrcBlndCfg.srcblendwidth; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed V4L2_CID_2D_SRC_BLEND_SET_WIDTH with degree %d", + m_SrcBlndCfg.srcblendwidth); + return false; + } + + ctrl.id = V4L2_CID_2D_SRC_BLEND_SET_HEIGHT; + ctrl.value = m_SrcBlndCfg.srcblendheight; + if (ioctl(m_fdScaler, VIDIOC_S_CTRL, &ctrl) < 0) { + SC_LOGERR("Failed V4L2_CID_2D_SRC_BLEND_SET_HEIGHT - %d", + m_SrcBlndCfg.srcblendheight); + return false; + } + + ClearFlag(m_fStatus, SCF_SRC_BLEND); + return true; +} + +void CScalerBlendV4L2::GetCustomAlphaBlendFmt(int32_t &src_color_space, + unsigned int srcblendfmt) { + + if (src_color_space == V4L2_PIX_FMT_NV12M) { + if (srcblendfmt == V4L2_PIX_FMT_RGB32) + src_color_space = V4L2_PIX_FMT_NV12M_RGB32; + else if (srcblendfmt == V4L2_PIX_FMT_BGR32) + src_color_space = V4L2_PIX_FMT_NV12M_BGR32; + else if (srcblendfmt == V4L2_PIX_FMT_RGB565) + src_color_space = V4L2_PIX_FMT_NV12M_RGB565; + else if (srcblendfmt == V4L2_PIX_FMT_RGB444) + src_color_space = V4L2_PIX_FMT_NV12M_RGB444; + else if (srcblendfmt == V4L2_PIX_FMT_RGB555X) + src_color_space = V4L2_PIX_FMT_NV12M_RGB555X; + } else if (src_color_space == V4L2_PIX_FMT_NV12) { + if (srcblendfmt == V4L2_PIX_FMT_RGB32) + src_color_space = V4L2_PIX_FMT_NV12_RGB32; + } else if (src_color_space == V4L2_PIX_FMT_NV12N) { + if (srcblendfmt == V4L2_PIX_FMT_RGB32) + src_color_space = V4L2_PIX_FMT_NV12N_RGB32; + } else if (src_color_space == V4L2_PIX_FMT_NV12MT_16X16) { + if (srcblendfmt == V4L2_PIX_FMT_RGB32) + src_color_space = V4L2_PIX_FMT_NV12MT_16X16_RGB32; + } else if (src_color_space == V4L2_PIX_FMT_NV21M) { + if (srcblendfmt == V4L2_PIX_FMT_RGB32) + src_color_space = V4L2_PIX_FMT_NV21M_RGB32; + else if (srcblendfmt == V4L2_PIX_FMT_BGR32) + src_color_space = V4L2_PIX_FMT_NV21M_BGR32; + } else if (src_color_space == V4L2_PIX_FMT_NV21) { + if (srcblendfmt == V4L2_PIX_FMT_RGB32) + src_color_space = V4L2_PIX_FMT_NV21_RGB32; + } else if (src_color_space == V4L2_PIX_FMT_YVU420) { + if (srcblendfmt == V4L2_PIX_FMT_RGB32) + src_color_space = V4L2_PIX_FMT_YVU420_RGB32; + } else { + src_color_space = -1; + } +} + +CScalerBlendV4L2::CScalerBlendV4L2(int dev_num, int allow_drm) : CScalerV4L2(dev_num, allow_drm){ + +} + +CScalerBlendV4L2::~CScalerBlendV4L2(){ + +} diff --git a/libscaler/libscalerblend-v4l2.h b/libscaler/libscalerblend-v4l2.h new file mode 100644 index 0000000..a7d7741 --- /dev/null +++ b/libscaler/libscalerblend-v4l2.h @@ -0,0 +1,64 @@ +#ifndef _EXYNOS_SCALERBLEND_H_ +#define _EXYNOS_SCALERBLEND_H_ + +#include "libscaler-v4l2.h" + +class CScalerBlendV4L2 : public CScalerV4L2 { + +public: + CScalerBlendV4L2(int instance, int allow_drm); + ~CScalerBlendV4L2(); + struct SrcBlendInfo m_SrcBlndCfg; + + // H/W Control + virtual bool DevSetCtrl(); + + void GetCustomAlphaBlendFmt(int32_t &src_color_space, + unsigned int srcblendfmt); + + inline void SetSrcBlendOp(SRC_BL_OP op) { + m_SrcBlndCfg.blop = op; + SetFlag(m_fStatus, SCF_SRC_BLEND); + } + + inline void SetSrcBlendHPos(int srcblendhpos) { + m_SrcBlndCfg.srcblendhpos = srcblendhpos; + } + + inline void SetSrcBlendVPos(int srcblendvpos) { + m_SrcBlndCfg.srcblendvpos = srcblendvpos; + } + + inline void SetSrcBlendPremulti(int srcblendpremulti) { + m_SrcBlndCfg.srcblendpremulti = srcblendpremulti; + } + + inline void SetSrcBlendFmt(int srcblendfmt) { + m_SrcBlndCfg.srcblendfmt = srcblendfmt; + } + + inline void SetSrcBlendStride(int srcblendstride) { + m_SrcBlndCfg.srcblendstride = srcblendstride; + } + + inline void SetSrcBlendWidth(int srcblendwidth) { + m_SrcBlndCfg.srcblendwidth= srcblendwidth; + } + + inline void SetSrcBlendHeight(int srcblendheight) { + m_SrcBlndCfg.srcblendheight = srcblendheight; + } + + inline void SetSrcGlobalAlpha(int globalalpha, bool enable) { + m_SrcBlndCfg.globalalpha.enable = enable; + m_SrcBlndCfg.globalalpha.val = globalalpha; + } + + inline void SetSrcBlendCSCSpace(bool enable, + enum colorspace space, bool wide) { + m_SrcBlndCfg.cscspec.enable = enable; + m_SrcBlndCfg.cscspec.space = space; + m_SrcBlndCfg.cscspec.wide = wide; + } +}; +#endif diff --git a/libscaler/m2m1shot.h b/libscaler/m2m1shot.h new file mode 100644 index 0000000..ec9c6f6 --- /dev/null +++ b/libscaler/m2m1shot.h @@ -0,0 +1,96 @@ +/**************************************************************************** + **************************************************************************** + *** + *** 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__M2M1SHOT_H_ +#define _UAPI__M2M1SHOT_H_ +#include <linux/ioctl.h> +#include <linux/types.h> +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#include <linux/videodev2.h> +#define M2M1SHOT_MAX_PLANES 3 +struct m2m1shot_rect { + __s16 left; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + __s16 top; + __u16 width; + __u16 height; +}; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +struct m2m1shot_pix_format { + __u32 fmt; + __u32 width; + __u32 height; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + struct v4l2_rect crop; +}; +enum m2m1shot_buffer_type { + M2M1SHOT_BUFFER_NONE, +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + M2M1SHOT_BUFFER_DMABUF, + M2M1SHOT_BUFFER_USERPTR, +}; +struct m2m1shot_buffer_plane { +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + union { + __s32 fd; + unsigned long userptr; + }; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + size_t len; +}; +struct m2m1shot_buffer { + struct m2m1shot_buffer_plane plane[M2M1SHOT_MAX_PLANES]; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + __u8 type; + __u8 num_planes; +}; +#define M2M1SHOT_OP_FLIP_VIRT (1 << 0) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define M2M1SHOT_OP_FLIP_HORI (1 << 1) +#define M2M1SHOT_OP_CSC_WIDE (1 << 8) +#define M2M1SHOT_OP_CSC_NARROW (1 << 9) +#define M2M1SHOT_OP_CSC_601 (1 << 10) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define M2M1SHOT_OP_CSC_709 (1 << 11) +#define M2M1SHOT_OP_PREMULTIPLIED_ALPHA (1 << 16) +#define M2M1SHOT_OP_DITHERING (1 << 17) +struct m2m1shot_operation { +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + __s16 quality_level; + __s16 rotate; + __u32 op; +}; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +struct m2m1shot { + struct m2m1shot_pix_format fmt_out; + struct m2m1shot_pix_format fmt_cap; + struct m2m1shot_buffer buf_out; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ + struct m2m1shot_buffer buf_cap; + struct m2m1shot_operation op; + unsigned long reserved[2]; +}; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +struct m2m1shot_custom_data { + unsigned int cmd; + unsigned long arg; +}; +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define M2M1SHOT_IOC_PROCESS _IOWR('M', 0, struct m2m1shot) +#define M2M1SHOT_IOC_CUSTOM _IOWR('M', 16, struct m2m1shot_custom_data) +#endif |