diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2018-01-14 08:26:46 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2018-01-14 08:26:46 +0000 |
commit | 97f8476916e67917026de4c6e43c12d2fa1d68c7 (patch) | |
tree | 1f0dec9c0c265727b557747742d98fc4625a5467 | |
parent | e8717c7735a46d6fca4b1f3d961ed2b410c944fe (diff) | |
parent | 6bd266236b4d1fb459cd90faeb32810e50b1a9d5 (diff) | |
download | libxcam-97f8476916e67917026de4c6e43c12d2fa1d68c7.tar.gz |
Snap for 4545621 from 6bd266236b4d1fb459cd90faeb32810e50b1a9d5 to pi-releaseandroid-wear-9.0.0_r9android-wear-9.0.0_r8android-wear-9.0.0_r7android-wear-9.0.0_r6android-wear-9.0.0_r5android-wear-9.0.0_r4android-wear-9.0.0_r34android-wear-9.0.0_r33android-wear-9.0.0_r32android-wear-9.0.0_r31android-wear-9.0.0_r30android-wear-9.0.0_r3android-wear-9.0.0_r29android-wear-9.0.0_r28android-wear-9.0.0_r27android-wear-9.0.0_r26android-wear-9.0.0_r25android-wear-9.0.0_r24android-wear-9.0.0_r23android-wear-9.0.0_r22android-wear-9.0.0_r21android-wear-9.0.0_r20android-wear-9.0.0_r2android-wear-9.0.0_r19android-wear-9.0.0_r18android-wear-9.0.0_r17android-wear-9.0.0_r16android-wear-9.0.0_r15android-wear-9.0.0_r14android-wear-9.0.0_r13android-wear-9.0.0_r12android-wear-9.0.0_r11android-wear-9.0.0_r10android-wear-9.0.0_r1android-vts-9.0_r9android-vts-9.0_r8android-vts-9.0_r7android-vts-9.0_r6android-vts-9.0_r5android-vts-9.0_r4android-vts-9.0_r19android-vts-9.0_r18android-vts-9.0_r17android-vts-9.0_r16android-vts-9.0_r15android-vts-9.0_r14android-vts-9.0_r13android-vts-9.0_r12android-vts-9.0_r11android-vts-9.0_r10android-security-9.0.0_r76android-security-9.0.0_r75android-security-9.0.0_r74android-security-9.0.0_r73android-security-9.0.0_r72android-security-9.0.0_r71android-security-9.0.0_r70android-security-9.0.0_r69android-security-9.0.0_r68android-security-9.0.0_r67android-security-9.0.0_r66android-security-9.0.0_r65android-security-9.0.0_r64android-security-9.0.0_r63android-security-9.0.0_r62android-cts-9.0_r9android-cts-9.0_r8android-cts-9.0_r7android-cts-9.0_r6android-cts-9.0_r5android-cts-9.0_r4android-cts-9.0_r3android-cts-9.0_r20android-cts-9.0_r2android-cts-9.0_r19android-cts-9.0_r18android-cts-9.0_r17android-cts-9.0_r16android-cts-9.0_r15android-cts-9.0_r14android-cts-9.0_r13android-cts-9.0_r12android-cts-9.0_r11android-cts-9.0_r10android-cts-9.0_r1android-9.0.0_r9android-9.0.0_r8android-9.0.0_r7android-9.0.0_r61android-9.0.0_r60android-9.0.0_r6android-9.0.0_r59android-9.0.0_r58android-9.0.0_r57android-9.0.0_r56android-9.0.0_r55android-9.0.0_r54android-9.0.0_r53android-9.0.0_r52android-9.0.0_r51android-9.0.0_r50android-9.0.0_r5android-9.0.0_r49android-9.0.0_r48android-9.0.0_r3android-9.0.0_r2android-9.0.0_r18android-9.0.0_r17android-9.0.0_r10android-9.0.0_r1security-pi-releasepie-vts-releasepie-security-releasepie-s2-releasepie-release-2pie-releasepie-r2-s2-releasepie-r2-s1-releasepie-r2-releasepie-platform-releasepie-gsipie-cuttlefish-testingpie-cts-release
Change-Id: If4b034303371be3212369843236041d628ee6619
393 files changed, 75604 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1620cc7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# http://www.gnu.org/software/automake + +Makefile.in +Makefile + +# http://www.gnu.org/software/autoconf + +config.* +/libtool +/ltmain.sh +/autom4te.cache +/aclocal.m4 +/compile +/configure +/depcomp +/install-sh +/missing +/stamp-h1 +/pkgconfig/*.pc +.deps +.libs + +# Object files +*.o +*.lo + +# Static libraries +*.la diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0a830b8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ext/atomisp"] + path = ext/atomisp + url = https://github.com/windyuan/atomisp_headers.git @@ -0,0 +1,17 @@ +This project is maintained by Intel corporation + +Maintainers: +Wind Yuan <feng.yuan@intel.com> + +Contributors: (orders by first name) +Fei Wang <feix.w.wang@intel.com> +Jia Meng <jia.meng@intel.com> +John Ye <john.ye@intel.com> +Juan Zhao <juan.j.zhao@intel.com> +Junkai Wu <wujunkai166@gmail.com> +Sameer Kibey <sameer.kibey@intel.com> +Shincy Tu <shincy.tu@intel.com> +Wei Zong <wei.zong@intel.com> +Yan Zhang <yan.y.zhang@intel.com> +Yao Wang <yao.y.wang@intel.com> +Yinhang Liu <yinhangx.liu@intel.com> diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..87c00c1 --- /dev/null +++ b/Android.mk @@ -0,0 +1,116 @@ +LOCAL_PATH := $(call my-dir) + +# XCam Version Num 1.1.0 +XCAM_VERSION_CFLAGS := -DXCAM_VERSION=0x110 + +XCAM_CFLAGS := -fPIC -W -Wall -D_REENTRANT -Wformat -Wno-unused-parameter -Wformat-security -fstack-protector +XCAM_CFLAGS += $(XCAM_VERSION_CFLAGS) -DANDROID + +ifeq ($(ENABLE_DEBUG), 1) +XCAM_CFLAGS += -DDEBUG +endif + +ENABLE_OPENCV := 0 +ifneq ($(filter $(TARGET_ARCH),x86 x86_64),) + +ifneq ($(wildcard external/opencv),) +ENABLE_OPENCV := 1 +XCAM_CFLAGS += -DHAVE_OPENCV=1 +endif + +endif + + +# For libxcam +# ================================================= + +include $(CLEAR_VARS) + +LOCAL_MODULE := libxcam +LOCAL_MODULE_TAGS := optional + +ifeq ($(ENABLE_OPENCV), 1) +LOCAL_STATIC_LIBRARIES := libcv libcxcore +endif + +XCAM_XCORE_SRC_FILES := \ + xcore/buffer_pool.cpp \ + xcore/calibration_parser.cpp \ + xcore/file_handle.cpp \ + xcore/image_file_handle.cpp \ + xcore/image_handler.cpp \ + xcore/surview_fisheye_dewarp.cpp \ + xcore/thread_pool.cpp \ + xcore/video_buffer.cpp \ + xcore/worker.cpp \ + xcore/xcam_buffer.cpp \ + xcore/xcam_common.cpp \ + xcore/xcam_thread.cpp \ + xcore/xcam_utils.cpp \ + xcore/interface/blender.cpp \ + xcore/interface/feature_match.cpp \ + xcore/interface/geo_mapper.cpp \ + xcore/interface/stitcher.cpp \ + $(NULL) + +XCAM_SOFT_SRC_FILES := \ + modules/soft/soft_blender.cpp \ + modules/soft/soft_blender_tasks_priv.cpp \ + modules/soft/soft_copy_task.cpp \ + modules/soft/soft_geo_mapper.cpp \ + modules/soft/soft_geo_tasks_priv.cpp \ + modules/soft/soft_handler.cpp \ + modules/soft/soft_stitcher.cpp \ + modules/soft/soft_video_buf_allocator.cpp \ + modules/soft/soft_worker.cpp \ + $(NULL) + +ifeq ($(ENABLE_OPENCV), 1) +XCAM_SOFT_SRC_FILES += modules/soft/cv_capi_feature_match.cpp +endif + +LOCAL_SRC_FILES := $(XCAM_XCORE_SRC_FILES) $(XCAM_SOFT_SRC_FILES) + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/xcore \ + $(LOCAL_PATH)/modules \ + $(NULL) + +ifeq ($(ENABLE_OPENCV), 1) +LOCAL_C_INCLUDES += \ + external/opencv/cv/include/ \ + external/opencv/cxcore/include \ + $(NULL) +endif + +LOCAL_CFLAGS := $(XCAM_CFLAGS) +LOCAL_CPPFLAGS := $(LOCAL_CFLAGS) -frtti + +include $(BUILD_SHARED_LIBRARY) + + +# For test-soft-image +# ================================================= + +include $(CLEAR_VARS) + +LOCAL_MODULE := test-soft-image +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libxcam + +LOCAL_SRC_FILES := \ + tests/test-soft-image.cpp + $(NULL) + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/xcore \ + $(LOCAL_PATH)/modules \ + $(LOCAL_PATH)/tests \ + $(NULL) + +LOCAL_CFLAGS := $(XCAM_CFLAGS) +LOCAL_CPPFLAGS := $(LOCAL_CFLAGS) + +include $(BUILD_EXECUTABLE) + @@ -0,0 +1,193 @@ + + Copyright (c) 2014-2015 Intel Corporation + + 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. + + + 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/ChangeLog b/ChangeLog new file mode 100644 index 0000000..7182275 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,206 @@ +2017/07/10: release libxcam version 1.0.0 + * 360 video stitching performance and quality improvement. + - enable geometry map to improve performance. + - quality tuned on different resolutions (1080P and 4K). + - support CPU and OpenCL path in feature match. + - enable lens shading correction based on fisheye image. + + * gyroscope-based video stabilization enabling. + - enable gyroscope 3-DoF (orientation) assist video stabilization. + - orientation (gyro) data should be measured by quaternion as the pose + of target frame reference to base frame + + * CL framework refine. + - enable CL argument template instead of member variables in kernel. + - CL kernel support async mode. + - image handler take over input/output buffer management from image kernel. + + * prepare libxcam debian package and fix most warnings. + +2017/04/01: release libxcam version 0.9.0 + * 360 video stitching improvement. + - remove sharp boundary in sphere mode by local/global area resize. + - tune algorithm parameters to preserve blinking. + - integrate 360 stitching pipeline into libxcam module. + - gst-xcam-filter supports 360 stitching case. + + * export C APIs for each OpenCL feature. + - support stich/3d-nr/wavelet-nr/defog features by xcam handle. + - be designed for FFmpeg xcam video filter usage. + +2016/12/30: release libxcam version 0.8.0 + * Digital Video Stabilization (DVS) + - enable DVS smart analysis plugin. + - algorithms used in DVS (feature detect, optical flow, motion model estimation) are based on OpenCV. + - implement image warp perspective algorithm in CL kernel. + + * Image stitching to create panorama photography + - implement fisheye calculation which map location to equirectangular. + - enable feature detection and match based on OpenCV optical flow algorithm. + - enable seam mask to improve the quality of blender. + + * gstreamer plugin xcamfilter can co-work with xcamsrc + +2016/09/30: release libxcam version 0.7.0 + * 3D-NR quality and performance improvement. + - use image exposure parameters to adjust global denoise strength. + - calculate image local variation to adjust local denoise strength. + - optimize OCL kernel by shared local memory and sub-group to + improve performance. + + * defog/dehaze quality improvement based on DCP(dark channel prior). + - enable dark channel prior to improve hazy image quality. + - fix image corruption in recover step. + - add lateral-range filter to smooth dark channel and remove + halo effect. + + * enable multi-band blender for image stitching. + - based on gaussian and laplacian pyramid and blend images in each + band, then reconstruct stitching image from pyramid level. + - blender can smooth seams and prevent ghosting. + + * enable geometry correction. + - map 2D image from src to dst image based on coordinate table which + is center aligned. + - prevent sawtooth edge by OCL sampler. + * gst-xcamfilter feature supports. + - xcamfilter can co-work with different camera source. + +2016/07/29: release libxcam version 0.6.1 +* enable 3D noise reduction, performance stay tuned. + - suppress image noise in both temporal and spatial domain. + - the algorithm applies denoise filter based on pixel-block differences + in neighbor blocks and previous frames. + - the processed image is much more clean and preserves motion objects + edge in low-light conditions. + + * support gst xcamfilter plugin which is independent from camera source. + - xcamfilter plugin can work with gstreamer source plugins, + e.g. videotestsrc/filesrc/v4l2src. + - xcamfilter features support defog/wireframe/waveletNR/3d-denoise. + - sink pad supports format NV12, src pad supports DMA buffer-sharing + for performace if links to HW plugin(encoder). + - wireframe/scaler/waveletNR moved to post image processor which can + co-work with isp processor(as pre-image processor) + +2016/06/30: release libxcam version 0.6.0 + * enable block-split version of histogram based WDR tone-mapping algorithm. + - divide image into several blocks and apply bidirectional log based + function on luminance to improve the contrast inside each block. + - apply weight function based on distance between target pixel and center + pixel of each neighbor block to smooth and eliminate block boundaries. + - apply weight function based on pixel intensity deviation between neighbor + blocks keep differentiation and weaken boundaries. + - image quality is improved and more details in both over-exposured and + under-exposured area can be shown clearly on screen. + + * Bayesian wavelet shrinkage for adaptive noise filtering. + - enable adaptive noise filtering based on Bayesian shrinkage estimation + - estimate the image’s background noise level by analyzing. + wavelet coefficient. + - optimize the threshold T which minimizes the Bayesian risk, + i.e, the expected value of the mean square error. + + * Haar wavelet tuning improvement. + - fine tuning the threshold statistic data for ultra-low light condition. + to prevent edge from over smoothing. + + * face detection supports. + - enable face detection framework and support FD plugins. + - enable wire-frame to track faces. + + * fog removal improvement based on Retinex algorithm. + - support multi-scale algorithm to reduce halo effects. + - tune parameters to keep brightness and clear edge. + - improve saturation based on chroma enhancement. + + * image processing service framework. + - add pipe-manager to support smart-analysis and post image processor. + - separate major code into different modules, e.g. xcore/isp/ocl/3a. + - support NV12 stream as fake input instead of camera sensor. + +2016/03/28: release libxcam version 0.5.0 + * enable new WDR tone mapping based on histogram adjustment. + - apply bidirectional log based function on luminance to improve + image contrast. + - transmit wide dynamic range image data to 8-bit color data by + novel histogram adjustment algorithm. + - details in both over-exposured and under-exposured area clearly + show up on screen. + * enable wavelet-based algorithm for noise reduction. + - decompose image into multiple-scales by wavelet transform with + low pass and high pass filters. + - perform soft threshold on smaller coefficients(high-pass) + to reduce noise. + - threshold should be suitably decided by tuned parameters. + - reconstruct image from scaled low-pass and high-pass images. + - enable Haar-wavelet and Hat-wavelet NR filters. + * enable fog removal feature based on retinex algorithm. + - base on retinex single-scale algorithm. + - scale down image for gaussian blur to improve performance. + - scale up blured image and amplify log differences with original + image. + * improve sharpness in normal light with extreme profile. + * support cl post processing with isp mode. + * support swap-buffer on nv12 format if only single plane need to + process. + +2015/12/30: release libxcam version 0.4.0 + * improve performance on OCL pipeline. + - design new formats and pipeline to save memory IO. + - improve bayer noise reduction with bilateral filter. + - support edge enhancement into bayer pipe. + - make gpu/cpu working together for 3a-statistics calculation. + - move tonemapping kernel from RBG to bayer format. + * improve WDR-tonemapping algorithm for quality. + - utilize an new adaptive local tone mapping algorithm. + - provide the mapping between 16-bit wide dynamic range images to + 8-bit images to have “nice looking”. + - preserve more information on luminance values of the scene + especially for high contrast images. + * tonemapping parameters calculated to increase the contrast between + high light and low light. + - tone mapping regularization parameters are calculated according + to the distribution of brightness histogram. + - the local adaptive parameter are calculated by weighting the + neighbor pixels with a Gaussian blur filter. + * add bayer raw video input to simulate camera sensor. + +2015/10/19: release libxcam version 0.3.0 + * improved OCL pipeline on basic and advanced/extreme pipeline + - add new bayer noise-reduction into demosaic + - merged yuv-tnr into yuv-pipe kernel + - merged TNR-yuv and TNR-rgb together + * support WDR(wide dynamic range) feature + * add 3a analysis tuner framework for more features tunning, e.g TNR + * add hybrid 3a analysis framework + - support partial customized 3a algorith, e.g AWB/AE + * add smart analysis framework + - generate small scaled picture + - support customized to analyze small picture and feedback results + - support loading user-defined method on smart analysis + +2015/07/31: release libxcam version 0.2.1 + * improved OCL pipeline on basic 3a image processing + - merged bayer kernels with blc, wb, gamma, demosaic and 3a stats. + - merged yuv kernerls with rgb2yuv color conversion and macc. + - support async framework as option on cl features + - support OCL buffer allocation which can choose tiling mode. + * support different AIQ versions. + * fix capture of dead-loop and sensor format setting. + +2015/07/02: release libxcam version 0.2.0 + * add gstreamer plugin 'xcamsrc' for Linux media framework support + * support loading user-defined 3a algorithm lib dynamically + * support more manual 3a features on ISP, e.g multiple-ae-window, ae/awb speed... + * add OpenCL pipeline for 3a image processing + - bayer format features, black level correction, defect pixel + correction, whitebalance, 3a statistics calculation, + demosaic, gamma correction, HDR(high dynamic range) + - RGBA format features, bilateral NR(noise reduction), simple NR, + temporal NR, macc, color correction + - YUV format features, temporal NR, edge enhancement, color conversion + - support any user-defined 3a algorithms(e.g AIQ) + * rich test cases, e.g. test-device-manager, test-cl-image + +2015/01/15: Initial xcam version 0.1 @@ -0,0 +1,193 @@ + + Copyright (c) 2014-2015 Intel Corporation + + 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. + + + 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/METADATA b/METADATA new file mode 100644 index 0000000..8d3766c --- /dev/null +++ b/METADATA @@ -0,0 +1,18 @@ +name: "LibXCam" +description: + "libXCam is a project for extended camera and computer " + "vision features. This library can work on GPU, CPU and " + "other HW platforms to improve image/video quality. " + "OpenCL as one of the common parallel computing languages " + "is used to improve performance in different platforms. " + "Other shading language supports are in roadmap." + +third_party { + url { + type: GIT + value: "https://github.com/01org/libxcam.git" + } + version: "1.0.0" + last_upgrade_date { year: 2017 month: 9 day: 11 } + license_type: "Apache-2.0" +} diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..3f59882 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,23 @@ +if HAVE_LIBCL +CLX_KERNEL_DIR = clx_kernel +else +CLX_KERNEL_DIR = +endif + +if HAVE_LIBCL +TESTS_DIR = tests +else +if ENABLE_IA_AIQ +TESTS_DIR = tests +else +TESTS_DIR = +endif +endif + +if ENABLE_CAPI +CAPI_DIR = capi +else +CAPI_DIR = +endif +SUBDIRS = xcore $(CLX_KERNEL_DIR) modules plugins \ + wrapper $(CAPI_DIR) $(TESTS_DIR) pkgconfig @@ -0,0 +1,5 @@ +All files in xcore, tests directory are Apache 2.0 License. +All header files in ext/atomisp are from Linux kernel user api headers +All header files in ext/ia_imaging are Apache 2.0 License +All dynamic libraries in ext/ia_imaging are provided by Intel Corporation + diff --git a/README.md b/README.md new file mode 100644 index 0000000..5958597 --- /dev/null +++ b/README.md @@ -0,0 +1,99 @@ +## libXCam + +Copyright (C) 2014-2017 Intel Corporation + +libxcam core source code under the terms of Apache License, Version 2.0 + +#### Description: +libXCam is a project for extended camera features and focus on image +quality improvement and video analysis. There are lots features supported +in image pre-processing, image post-processing and smart analysis. This +library makes GPU/CPU/ISP working together to improve image quality. +OpenCL is used to improve performance in different platforms. + +#### Features: + * Image processing features. + - Advanced features + - 360 Image stiching: generate 360 degree panorama photography by + stitching multiple neighbor fisheye images. + - Digital Video Stabilization: + - OpenCV feature-matched based video stabilization. + - gyroscope 3-DoF (orientation) based video stabilization. + - Blender: multi-band blender. + - Noise reduction. + - adaptive NR based on wavelet-haar and Bayersian shrinkage. + - 3D-NR with inter-block and intra-block reference. + - wavelet-hat NR (obsolete). + - Wide dynamic range (WDR). + - histogram adjustment tone-mapping. + - gaussian-based tone-mapping (obsolete). + - Fog removal: retinex and dark channel prior algorithm. + - dark channel prior algorithm based defog. + - multi-scale retinex based defog (obsolete). + - Basic pipeline from bayer to YUV/RGB format. + - Gamma correction, MACC, color space, demosaicing, simple bilateral + noise reduction, edge enhancement and temporal noise reduction. + - 3A features. + - Auto whitebalance, auto exposure, auto focus, black level correction, + color correction, 3a-statistics calculation. + * Support 3rd party 3A lib which can be loaded dynamically. + - hybrid 3a plugin. + * Support 3a analysis tuning framework for different features. + * Support smart analysis framework. + - Face detection interface/plugin. + * Enable gstreamer plugin. + - xcamsrc, capture from usb/isp camera, process 3a/basic/advanced features. + - xcamfilter, improve image quality by advanced features and smart analysis. + +#### Prerequisite: + * install gcc/g++, automake, autoconf, libtool, gawk, pkg-config + * Linux kernel > 3.10 + * install libdrm-dev + * install ocl-icd-dev, ocl-icd-opencl-dev + * If --enable-libcl, need compile ocl driver <https://www.freedesktop.org/wiki/Software/Beignet/> + * If --enable-opencv, need compile opencv <http://opencv.org> (or: <https://github.com/opencv/opencv/wiki>) + * If --enable-gst, need install libgstreamer1.0-dev, libgstreamer-plugins-base1.0-dev + * If --enable-aiq, need get ia_imaging lib which we don't support. + +#### Building and installing: + * Environment variable settings<BR> + For different --prefix options, the environment variables may be different. Please set the environment variable according to the actual situation.<BR> + --prefix=/usr/local: + + export LD_LIBRARY_PATH=/usr/local/lib/:$LD_LIBRARY_PATH + export GST_PLUGIN_PATH=/usr/local/lib/gstreamer-1.0:$GST_PLUGIN_PATH + + --prefix=/usr: + + export LD_LIBRARY_PATH=/usr/lib/:$LD_LIBRARY_PATH + export GST_PLUGIN_PATH=/usr/lib/gstreamer-1.0:$GST_PLUGIN_PATH + + * $ ./autogen.sh [options] + + --prefix=PREFIX install architecture-independent files in PREFIX [default=/usr/local] + --enable-debug enable debug, [default=no] + --enable-profiling enable profiling, [default=no] + --enable-drm enable drm buffer, [default=yes] + --enable-aiq enable Aiq 3A algorithm build, [default=no] + --enable-gst enable gstreamer plugin build, [default=no] + --enable-libcl enable libcl image processor, [default=yes] + --enable-opencv enable opencv library, [default=no] + --enable-docs build Doxygen documentation [default=no] + --enable-3alib enable 3A lib build, [default=no] + --enable-smartlib enable smart analysis lib build, [default=no] + + For example: + + $ ./autogen.sh --prefix=/usr --enable-3alib --enable-aiq --enable-gst --enable-drm \ + --enable-libcl --enable-opencv --enable-profiling --enable-smartlib + + * $ make + * $ sudo make install + +#### Testing: + * For detailed test cases, please refer to:<BR> + <https://github.com/01org/libxcam/wiki/Tests> + +#### Reporting Bugs: + * Bugs or suggestions can be reported on the github issues page:<BR> + <https://github.com/01org/libxcam/issues> diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..8121655 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +pre_commit_hook=".git/hooks/pre-commit" +if test ! -L $pre_commit_hook; +then + rm -rf $pre_commit_hook + ln -s ../../tools/pre-commit-code-style.sh $pre_commit_hook + echo "link $pre_commit_hook to code style check" +fi + +echo "git submodule update" +git submodule sync +git submodule init +git submodule update + +echo "Generating configure files" +autoreconf -i +# Run twice to get around a "ltmain.sh" bug +autoreconf --install --force + +srcdir=`dirname "$0"` +test -z "$srcdir" && srcdir=. + +if test -z "$NOCONFIGURE"; then + $srcdir/configure "$@" +fi diff --git a/capi/Makefile.am b/capi/Makefile.am new file mode 100644 index 0000000..029fd7a --- /dev/null +++ b/capi/Makefile.am @@ -0,0 +1,53 @@ +lib_LTLIBRARIES = libxcam_capi.la + +XCAMCAPI_LIBS = \ + $(LIBCL_LIBS) \ + -ldl \ + $(NULL) + +XCAMCAPI_CXXFLAGS = \ + $(XCAM_CXXFLAGS) \ + $(LIBCL_CFLAGS) \ + -I$(top_srcdir)/xcore \ + -I$(top_srcdir)/modules \ + $(NULL) + +if HAVE_LIBDRM +XCAMCAPI_CXXFLAGS += $(LIBDRM_CFLAGS) +XCAMCAPI_LIBS += \ + -ldrm_intel \ + $(LIBDRM_LIBS) \ + $(NULL) +endif + +xcam_ocl_sources = \ + xcam_handle.cpp \ + context_priv.cpp \ + $(NULL) + +libxcam_capi_la_SOURCES = \ + $(xcam_ocl_sources) \ + $(NULL) + +libxcam_capi_la_CXXFLAGS = \ + $(XCAMCAPI_CXXFLAGS) \ + $(NULL) + +libxcam_capi_la_LIBADD = \ + $(top_builddir)/modules/ocl/libxcam_ocl.la \ + $(top_builddir)/xcore/libxcam_core.la \ + $(XCAMCAPI_LIBS) \ + $(NULL) + +libxcam_capi_la_LDFLAGS = \ + $(XCAM_LT_LDFLAGS) \ + $(PTHREAD_LDFLAGS) \ + $(NULL) + +libxcam_capiincludedir = $(includedir)/xcam/capi + +nobase_libxcam_capiinclude_HEADERS = \ + xcam_handle.h \ + $(NULL) + +libxcam_capi_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/capi/context_priv.cpp b/capi/context_priv.cpp new file mode 100644 index 0000000..ecbffa6 --- /dev/null +++ b/capi/context_priv.cpp @@ -0,0 +1,231 @@ +/* + * context_priv.cpp - capi private context + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "context_priv.h" +#include <ocl/cl_device.h> +#include <ocl/cl_image_handler.h> +#include <ocl/cl_tonemapping_handler.h> +#include <ocl/cl_gauss_handler.h> +#include <ocl/cl_wavelet_denoise_handler.h> +#include <ocl/cl_newwavelet_denoise_handler.h> +#include <ocl/cl_defog_dcp_handler.h> +#include <ocl/cl_3d_denoise_handler.h> +#include <ocl/cl_image_warp_handler.h> +#include <ocl/cl_fisheye_handler.h> +#include <ocl/cl_image_360_stitch.h> +#include <ocl/cl_utils.h> + +using namespace XCam; + +#define DEFAULT_INPUT_BUFFER_POOL_COUNT 20 +static const char *HandleNames[] = { + "None", + "3DNR", + "WaveletNR", + "Fisheye", + "Defog", + "DVS", + "Stitch", +}; + +bool +handle_name_equal (const char *name, HandleType type) +{ + return !strncmp (name, HandleNames[type], strlen(HandleNames[type])); +} + +ContextBase::ContextBase (HandleType type) + : _type (type) + , _usage (NULL) + , _image_width (0) + , _image_height (0) + , _alloc_out_buf (false) +{ + if (!_inbuf_pool.ptr()) { + _inbuf_pool = new CLVideoBufferPool (); + XCAM_ASSERT (_inbuf_pool.ptr ()); + } +} + +ContextBase::~ContextBase () +{ + xcam_free (_usage); +} + +const char* +ContextBase::get_type_name () const +{ + XCAM_ASSERT ((int)_type < sizeof(HandleNames) / sizeof (HandleNames[0])); + return HandleNames [_type]; +} + +static const char* +find_value (const ContextParams ¶m_list, const char *name) +{ + ContextParams::const_iterator i = param_list.find (name); + if (i != param_list.end ()) + return (i->second); + return NULL; +} + +XCamReturn +ContextBase::set_parameters (ContextParams ¶m_list) +{ + VideoBufferInfo buf_info; + uint32_t image_format = V4L2_PIX_FMT_NV12; + _image_width = 1920; + _image_height = 1080; + + const char *width = find_value (param_list, "width"); + if (width) { + _image_width = atoi(width); + } + const char *height = find_value (param_list, "height"); + if (height) { + _image_height = atoi(height); + } + if (_image_width == 0 || _image_height == 0) { + XCAM_LOG_ERROR ("illegal image size width:%d height:%d", _image_width, _image_height); + return XCAM_RETURN_ERROR_PARAM; + } + + buf_info.init (image_format, _image_width, _image_height); + _inbuf_pool->set_video_info (buf_info); + if (!_inbuf_pool->reserve (DEFAULT_INPUT_BUFFER_POOL_COUNT)) { + XCAM_LOG_ERROR ("init buffer pool failed"); + return XCAM_RETURN_ERROR_MEM; + } + + const char *flag = find_value (param_list, "alloc-out-buf"); + if (flag && !strncasecmp (flag, "true", strlen("true"))) { + _alloc_out_buf = true; + } else { + _alloc_out_buf = false; + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +ContextBase::init_handler () +{ + SmartPtr<CLContext> cl_context = CLDevice::instance()->get_context (); + XCAM_FAIL_RETURN ( + ERROR, cl_context.ptr (), XCAM_RETURN_ERROR_UNKNOWN, + "ContextBase::init_handler(%s) failed since cl-context is NULL", + get_type_name ()); + + SmartPtr<CLImageHandler> handler = create_handler (cl_context); + XCAM_FAIL_RETURN ( + ERROR, handler.ptr (), XCAM_RETURN_ERROR_UNKNOWN, + "ContextBase::init_handler(%s) create handler failed", get_type_name ()); + + handler->disable_buf_pool (!_alloc_out_buf); + set_handler (handler); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +ContextBase::uinit_handler () +{ + if (!_handler.ptr ()) + return XCAM_RETURN_NO_ERROR; + + _handler->emit_stop (); + _handler.release (); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +ContextBase::execute (SmartPtr<VideoBuffer> &buf_in, SmartPtr<VideoBuffer> &buf_out) +{ + if (!_alloc_out_buf) { + XCAM_FAIL_RETURN ( + ERROR, buf_out.ptr (), XCAM_RETURN_ERROR_MEM, + "context (%s) execute failed, buf_out need set.", get_type_name ()); + } else { + XCAM_FAIL_RETURN ( + ERROR, !buf_out.ptr (), XCAM_RETURN_ERROR_MEM, + "context (%s) execute failed, buf_out need NULL.", get_type_name ()); + } + + return _handler->execute (buf_in, buf_out); +} + +SmartPtr<CLImageHandler> +NR3DContext::create_handler (SmartPtr<CLContext> &context) +{ + return create_cl_3d_denoise_image_handler ( + context, CL_IMAGE_CHANNEL_Y | CL_IMAGE_CHANNEL_UV, 3); +} + +SmartPtr<CLImageHandler> +NRWaveletContext::create_handler (SmartPtr<CLContext> &context) +{ + return create_cl_newwavelet_denoise_image_handler ( + context, CL_IMAGE_CHANNEL_UV | CL_IMAGE_CHANNEL_Y, false); +} + +SmartPtr<CLImageHandler> +FisheyeContext::create_handler (SmartPtr<CLContext> &context) +{ + return create_fisheye_handler (context); +} + +SmartPtr<CLImageHandler> +DefogContext::create_handler (SmartPtr<CLContext> &context) +{ + return create_cl_defog_dcp_image_handler (context);; +} + +SmartPtr<CLImageHandler> +DVSContext::create_handler (SmartPtr<CLContext> &context) +{ + return create_cl_image_warp_handler (context); +} + +SmartPtr<CLImageHandler> +StitchContext::create_handler (SmartPtr<CLContext> &context) +{ + uint32_t sttch_width = _image_width; + uint32_t sttch_height = XCAM_ALIGN_UP (sttch_width / 2, 16); + if (sttch_width != sttch_height * 2) { + XCAM_LOG_ERROR ("incorrect stitch size width:%d height:%d", sttch_width, sttch_height); + return NULL; + } + + SurroundMode surround_mode = SphereView; + StitchResMode res_mode = StitchRes1080P; + if (_res_mode == StitchRes4K) + res_mode = StitchRes4K; + + SmartPtr<CLImage360Stitch> image_360 = + create_image_360_stitch (context, _need_seam, _scale_mode, + _fisheye_map, _need_lsc, surround_mode, res_mode).dynamic_cast_ptr<CLImage360Stitch> (); + XCAM_FAIL_RETURN (ERROR, image_360.ptr (), NULL, "create image stitch handler failed"); + image_360->set_output_size (sttch_width, sttch_height); + XCAM_LOG_INFO ("stitch output size width:%d height:%d", sttch_width, sttch_height); + +#if HAVE_OPENCV + image_360->set_feature_match_ocl (_fm_ocl); +#endif + + return image_360; +} + diff --git a/capi/context_priv.h b/capi/context_priv.h new file mode 100644 index 0000000..fe5c0a9 --- /dev/null +++ b/capi/context_priv.h @@ -0,0 +1,184 @@ +/* + * context_priv.h - capi private context + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CONTEXT_PRIV_H +#define XCAM_CONTEXT_PRIV_H + +#include <xcam_utils.h> +#include <string.h> +#include <ocl/cl_image_handler.h> +#include <ocl/cl_context.h> +#include <ocl/cl_blender.h> +#include <interface/stitcher.h> + +using namespace XCam; + +enum HandleType { + HandleTypeNone = 0, + HandleType3DNR, + HandleTypeWaveletNR, + HandleTypeFisheye, + HandleTypeDefog, + HandleTypeDVS, + HandleTypeStitch, +}; + +#define CONTEXT_CAST(Type, handle) (Type*)(handle) +#define CONTEXT_BASE_CAST(handle) (ContextBase*)(handle) +#define HANDLE_CAST(context) (XCamHandle*)(context) + +bool handle_name_equal (const char *name, HandleType type); + +typedef struct _CompareStr { + bool operator() (const char* str1, const char* str2) const { + return strncmp(str1, str2, 1024) < 0; + } +} CompareStr; + +typedef std::map<const char*, const char*, CompareStr> ContextParams; + +class ContextBase { +public: + virtual ~ContextBase (); + + virtual XCamReturn set_parameters (ContextParams ¶m_list); + virtual const char* get_usage () const { + return _usage; + } + XCamReturn init_handler (); + XCamReturn uinit_handler (); + + XCamReturn execute (SmartPtr<VideoBuffer> &buf_in, SmartPtr<VideoBuffer> &buf_out); + + SmartPtr<CLImageHandler> get_handler() const { + return _handler; + } + SmartPtr<BufferPool> get_input_buffer_pool() const { + return _inbuf_pool; + } + HandleType get_type () const { + return _type; + } + const char* get_type_name () const; + +protected: + ContextBase (HandleType type); + void set_handler (const SmartPtr<CLImageHandler> &ptr) { + _handler = ptr; + } + + virtual SmartPtr<CLImageHandler> create_handler (SmartPtr<CLContext> &context) = 0; + +private: + XCAM_DEAD_COPY (ContextBase); + +protected: + HandleType _type; + char *_usage; + SmartPtr<CLImageHandler> _handler; + SmartPtr<BufferPool> _inbuf_pool; + + //parameters + uint32_t _image_width; + uint32_t _image_height; + bool _alloc_out_buf; +}; + +class NR3DContext + : public ContextBase +{ +public: + NR3DContext () + : ContextBase (HandleType3DNR) + {} + + virtual SmartPtr<CLImageHandler> create_handler (SmartPtr<CLContext> &context); +}; + +class NRWaveletContext + : public ContextBase +{ +public: + NRWaveletContext () + : ContextBase (HandleTypeWaveletNR) + {} + + virtual SmartPtr<CLImageHandler> create_handler (SmartPtr<CLContext> &context); +}; + +class FisheyeContext + : public ContextBase +{ +public: + FisheyeContext () + : ContextBase (HandleTypeFisheye) + {} + + virtual SmartPtr<CLImageHandler> create_handler (SmartPtr<CLContext> &context); +}; + +class DefogContext + : public ContextBase +{ +public: + DefogContext () + : ContextBase (HandleTypeDefog) + {} + + virtual SmartPtr<CLImageHandler> create_handler (SmartPtr<CLContext> &context); +}; + +class DVSContext + : public ContextBase +{ +public: + DVSContext () + : ContextBase (HandleTypeDVS) + {} + + virtual SmartPtr<CLImageHandler> create_handler (SmartPtr<CLContext> &context); +}; + +class StitchContext + : public ContextBase +{ +public: + StitchContext () + : ContextBase (HandleTypeStitch) + , _need_seam (false) + , _fisheye_map (false) + , _need_lsc (false) + , _fm_ocl (false) + , _scale_mode (CLBlenderScaleLocal) + , _res_mode (StitchRes1080P) + {} + + virtual SmartPtr<CLImageHandler> create_handler (SmartPtr<CLContext> &context); + +private: + bool _need_seam; + bool _fisheye_map; + bool _need_lsc; + bool _fm_ocl; + CLBlenderScaleMode _scale_mode; + StitchResMode _res_mode; +}; + +#endif //XCAM_CONTEXT_PRIV_H diff --git a/capi/xcam_handle.cpp b/capi/xcam_handle.cpp new file mode 100644 index 0000000..37a99b1 --- /dev/null +++ b/capi/xcam_handle.cpp @@ -0,0 +1,271 @@ +/* + * xcam_handle.cpp - xcam handle implementation + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include <xcam_utils.h> +#include <xcam_handle.h> +#include <dma_video_buffer.h> +#include "context_priv.h" +#include <stdarg.h> +#if HAVE_LIBDRM +#include <drm_bo_buffer.h> +#endif + +using namespace XCam; + +XCamHandle * +xcam_create_handle (const char *name) +{ + ContextBase *context = NULL; + + if (handle_name_equal (name, HandleType3DNR)) { + context = new NR3DContext; + } else if (handle_name_equal (name, HandleTypeWaveletNR)) { + context = new NRWaveletContext; + } else if (handle_name_equal (name, HandleTypeFisheye)) { + context = new FisheyeContext; + } else if (handle_name_equal (name, HandleTypeDefog)) { + context = new DefogContext; + } else if (handle_name_equal (name, HandleTypeDVS)) { + context = new DVSContext; + } else if (handle_name_equal (name, HandleTypeStitch)) { + context = new StitchContext; + } else { + XCAM_LOG_ERROR ("create handle failed with unsupported type:%s", name); + return NULL; + } + + return HANDLE_CAST (context); +} + +void +xcam_destroy_handle (XCamHandle *handle) +{ + if (handle) + delete CONTEXT_BASE_CAST (handle); +} + +XCamReturn +xcam_handle_init (XCamHandle *handle) +{ + ContextBase *context = CONTEXT_BASE_CAST (handle); + SmartPtr<CLImageHandler> handler_ptr; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_FAIL_RETURN ( + ERROR, context, XCAM_RETURN_ERROR_PARAM, + "xcam_handler_init failed, handle can NOT be NULL, did you have xcam_create_handler first?"); + + ret = context->init_handler (); + XCAM_FAIL_RETURN ( + ERROR, ret == XCAM_RETURN_NO_ERROR, ret, + "xcam_handler_init, create handle ptr(%s) failed", context->get_type_name ()); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +xcam_handle_uinit (XCamHandle *handle) +{ + ContextBase *context = CONTEXT_BASE_CAST (handle); + + XCAM_FAIL_RETURN ( + ERROR, context, XCAM_RETURN_ERROR_PARAM, + "xcam_handler_uinit failed, handle can NOT be NULL"); + + return context->uinit_handler (); +} + +XCamReturn +xcam_handle_get_usage (XCamHandle *handle, char *usage_buf, int *usage_len) +{ + ContextBase *context = CONTEXT_BASE_CAST (handle); + XCAM_FAIL_RETURN ( + ERROR, context, XCAM_RETURN_ERROR_PARAM, + "xcam_handle_get_usage failed, handle can NOT be NULL"); + + const char *usage = context->get_usage (); + int len = strlen (usage) + 1; + if (len < *usage_len) + len = *usage_len; + strncpy (usage_buf, usage, len - 1); + *usage_len = len; + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +xcam_handle_set_parameters ( + XCamHandle *handle, const char *field, ...) +{ + ContextBase *context = CONTEXT_BASE_CAST (handle); + ContextParams params; + + XCAM_FAIL_RETURN ( + ERROR, context, XCAM_RETURN_ERROR_PARAM, + "xcam_handle_set_parameters failed, handle can NOT be NULL"); + + const char *vfield, *vvalue; + vfield = field; + va_list args; + va_start (args, field); + while (vfield) { + vvalue = va_arg (args, const char *); + XCAM_FAIL_RETURN ( + ERROR, vvalue, XCAM_RETURN_ERROR_PARAM, + "xcam_handle(%s) set_parameters failed, param(field:%s) value should never be NULL", + context->get_type_name (), vfield); + + params[vfield] = vvalue; + vfield = va_arg (args, const char *); + } + va_end (args); + + return context->set_parameters (params); +} + +SmartPtr<VideoBuffer> +external_buf_to_drm_buf (XCamVideoBuffer *buf) +{ +#if HAVE_LIBDRM + SmartPtr<DrmDisplay> display = DrmDisplay::instance (); + SmartPtr<DmaVideoBuffer> dma_buf; + SmartPtr<VideoBuffer> drm_buf; + SmartPtr<VideoBuffer> video_buf; + + dma_buf = external_buf_to_dma_buf (buf); + + XCAM_FAIL_RETURN ( + ERROR, dma_buf.ptr (), NULL, + "external_buf_to_drm_buf failed"); + + video_buf = dma_buf; + XCAM_ASSERT (display.ptr ()); + drm_buf = display->convert_to_drm_bo_buf (display, video_buf); + return drm_buf; +#else + XCAM_LOG_ERROR ("VideoBuffer doesn't support drm buf"); + + XCAM_UNUSED (buf); + return NULL; +#endif +} + +SmartPtr<VideoBuffer> +copy_external_buf_to_drm_buf (XCamHandle *handle, XCamVideoBuffer *buf) +{ + if (!handle || !buf) { + XCAM_LOG_WARNING ("xcam handle can NOT be NULL"); + return NULL; + } + + ContextBase *context = CONTEXT_BASE_CAST (handle); + if (!context) { + XCAM_LOG_WARNING ("xcam handle context can NOT be NULL"); + return NULL; + } + + const XCamVideoBufferInfo src_info = buf->info; + uint8_t* src = buf->map (buf); + uint8_t* p_src = src; + if (!src) { + XCAM_LOG_WARNING ("xcam handle map buffer failed"); + return NULL; + } + uint32_t height = src_info.height; + + SmartPtr<BufferPool> buf_pool = context->get_input_buffer_pool(); + XCAM_ASSERT (buf_pool.ptr ()); + SmartPtr<VideoBuffer> video_buf = buf_pool->get_buffer (buf_pool); + XCAM_ASSERT (video_buf.ptr ()); + const XCamVideoBufferInfo dest_info = video_buf->get_video_info (); + + uint8_t* dest = video_buf->map (); + uint8_t* p_dest = dest; + + for (uint32_t index = 0; index < src_info.components; index++) { + src += (int32_t)src_info.offsets[index]; + p_src = src; + + dest += dest_info.offsets[index]; + p_dest = dest; + if (src_info.format == V4L2_PIX_FMT_NV12) { + height = height >> index; + } + for (uint32_t i = 0; i < height; i++) { + memcpy (p_dest, p_src, src_info.strides[index]); + p_src += src_info.strides[index]; + p_dest += dest_info.strides[index]; + } + } + + buf->unmap (buf); + video_buf->unmap (); + + return video_buf; +} + +XCamReturn +xcam_handle_execute (XCamHandle *handle, XCamVideoBuffer *buf_in, XCamVideoBuffer **buf_out) +{ + ContextBase *context = CONTEXT_BASE_CAST (handle); + SmartPtr<VideoBuffer> input, output; + + XCAM_FAIL_RETURN ( + ERROR, context && buf_in && buf_out, XCAM_RETURN_ERROR_PARAM, + "xcam_handle_execute failed, either of handle/buf_in/buf_out can NOT be NULL"); + + XCAM_FAIL_RETURN ( + ERROR, context->get_handler().ptr (), XCAM_RETURN_ERROR_PARAM, + "context (%s) failed, handler was not initialized", context->get_type_name ()); + + if (buf_in->mem_type == XCAM_MEM_TYPE_GPU) { + input = external_buf_to_drm_buf (buf_in); + } else { + input = copy_external_buf_to_drm_buf (handle, buf_in); + } + XCAM_FAIL_RETURN ( + ERROR, input.ptr (), XCAM_RETURN_ERROR_MEM, + "xcam_handle(%s) execute failed, buf_in convert to DRM buffer failed.", + context->get_type_name ()); + + if (*buf_out) { + output = external_buf_to_drm_buf (*buf_out); + XCAM_FAIL_RETURN ( + ERROR, output.ptr (), XCAM_RETURN_ERROR_MEM, + "xcam_handle(%s) execute failed, buf_out set but convert to DRM buffer failed.", + context->get_type_name ()); + } + + XCamReturn ret = context->execute (input, output); + + XCAM_FAIL_RETURN ( + ERROR, ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS, + ret, + "context (%s) failed, handler execute failed", context->get_type_name ()); + + if (*buf_out == NULL && output.ptr ()) { + XCamVideoBuffer *new_buf = convert_to_external_buffer (output); + XCAM_FAIL_RETURN ( + ERROR, new_buf, XCAM_RETURN_ERROR_MEM, + "xcam_handle(%s) execute failed, out buffer can't convert to external buffer.", + context->get_type_name ()); + *buf_out = new_buf; + } + return ret; +} diff --git a/capi/xcam_handle.h b/capi/xcam_handle.h new file mode 100644 index 0000000..cd721fa --- /dev/null +++ b/capi/xcam_handle.h @@ -0,0 +1,90 @@ +/* + * xcam_handle.h - image processing handles + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef C_XCAM_HANDLE_H +#define C_XCAM_HANDLE_H + +#include <base/xcam_defs.h> +#include <base/xcam_common.h> +#include <base/xcam_buffer.h> + +XCAM_BEGIN_DECLARE + +typedef struct _XCamHandle XCamHandle; + +/*! \brief create xcam handle to process buffer + * + * \params[in] name, filter name + * \return XCamHandle create correct hanle, else return NULL. + */ +XCamHandle *xcam_create_handle (const char *name); + +/*! \brief destroy xcam handle + * + * \params[in] handle handle need to destory + */ +void xcam_destroy_handle (XCamHandle *handle); + +/*! \brief xcam handle get usage how to set parameters + * + * \params[in] handle xcam handle + * \params[out] usage_buf buffer to store usage + * \params[in,out] usage_len buffer length + * \return XCamReturn XCAM_RETURN_NO_ERROR on sucess; others on errors. + */ +XCamReturn xcam_handle_get_usage (XCamHandle *handle, char *usage_buf, int *usage_len); + +/*! \brief set handle parameters before init + * + * \params[in] handle xcam handle + * \params[in] field0, value0, field1, value1, ..., fieldN, valueN field and value in pairs + * \return XCamReturn XCAM_RETURN_NO_ERROR on sucess; others on errors. + */ +XCamReturn xcam_handle_set_parameters ( + XCamHandle *handle, const char *field, ...); + +/*! \brief xcam handle initialize + * + * \params[in] handle xcam handle + * \return XCamReturn XCAM_RETURN_NO_ERROR on sucess; others on errors. + */ +XCamReturn xcam_handle_init (XCamHandle *handle); + +/*! \brief xcam handle uninitialize + * + * \params[in] handle xcam handle + * \return XCamReturn XCAM_RETURN_NO_ERROR on sucess; others on errors. + */ +XCamReturn xcam_handle_uinit (XCamHandle *handle); + +// buf_out was allocated outside or inside ?? +/*! \brief xcam handle process buffer + * + * \params[in] handle xcam handle + * \params[in] buf_in input buffer + * \params[in,out] buf_out output buffer, can be allocated outside or inside, + * if set param "alloc-out-buf" "true", allocate outside; else inside. + * \return XCamReturn XCAM_RETURN_NO_ERROR on sucess; others on errors. + */ +XCamReturn xcam_handle_execute (XCamHandle *handle, XCamVideoBuffer *buf_in, XCamVideoBuffer **buf_out); + +XCAM_END_DECLARE + +#endif //C_XCAM_HANDLE_H diff --git a/cl_kernel/kernel_3d_denoise.cl b/cl_kernel/kernel_3d_denoise.cl new file mode 100644 index 0000000..c94c1d7 --- /dev/null +++ b/cl_kernel/kernel_3d_denoise.cl @@ -0,0 +1,269 @@ +/* + * function: kernel_3d_denoise + * 3D Noise Reduction + * gain: The parameter determines the filtering strength for the reference block + * threshold: Noise variances of observed image + * restoredPrev: The previous restored image, image2d_t as read only + * output: restored image, image2d_t as write only + * input: observed image, image2d_t as read only + * inputPrev1: reference image, image2d_t as read only + * inputPrev2: reference image, image2d_t as read only + */ + +#ifndef REFERENCE_FRAME_COUNT +#define REFERENCE_FRAME_COUNT 2 +#endif + +#ifndef ENABLE_IIR_FILERING +#define ENABLE_IIR_FILERING 1 +#endif + +#define ENABLE_GRADIENT 1 + +#ifndef WORKGROUP_WIDTH +#define WORKGROUP_WIDTH 2 +#endif + +#ifndef WORKGROUP_HEIGHT +#define WORKGROUP_HEIGHT 32 +#endif + +#define REF_BLOCK_X_OFFSET 1 +#define REF_BLOCK_Y_OFFSET 4 + +#define REF_BLOCK_WIDTH (WORKGROUP_WIDTH + 2 * REF_BLOCK_X_OFFSET) +#define REF_BLOCK_HEIGHT (WORKGROUP_HEIGHT + 2 * REF_BLOCK_Y_OFFSET) + +inline int2 subgroup_pos(const int sg_id, const int sg_lid) +{ + int2 pos; + pos.x = mad24(2, sg_id % 2, sg_lid % 2); + pos.y = mad24(4, sg_id / 2, sg_lid / 2); + + return pos; +} + +inline void average_slice(float8 ref, + float8 observe, + float8* restore, + float2* sum_weight, + float gain, + float threshold, + uint sg_id, + uint sg_lid) +{ + float8 grad = 0.0f; + float8 gradient = 0.0f; + float8 dist = 0.0f; + float8 distance = 0.0f; + float weight = 0.0f; + +#if ENABLE_GRADIENT + // calculate & cumulate gradient + if (sg_lid % 2 == 0) { + grad = intel_sub_group_shuffle(ref, 4); + } else { + grad = intel_sub_group_shuffle(ref, 5); + } + gradient = (float8)(grad.s1, grad.s1, grad.s1, grad.s1, grad.s5, grad.s5, grad.s5, grad.s5); + + // normalize gradient "1/(4*255.0f) = 0.00098039f" + grad = fabs(gradient - ref) * 0.00098039f; + //grad = mad(-2, gradient, (ref + grad)) * 0.0004902f; + + grad.s0 = (grad.s0 + grad.s1 + grad.s2 + grad.s3); + grad.s4 = (grad.s4 + grad.s5 + grad.s6 + grad.s7); +#endif + // calculate & normalize distance "1/255.0f = 0.00392157f" + dist = (observe - ref) * 0.00392157f; + dist = dist * dist; + + float8 dist_shuffle[8]; + dist_shuffle[0] = (intel_sub_group_shuffle(dist, 0)); + dist_shuffle[1] = (intel_sub_group_shuffle(dist, 1)); + dist_shuffle[2] = (intel_sub_group_shuffle(dist, 2)); + dist_shuffle[3] = (intel_sub_group_shuffle(dist, 3)); + dist_shuffle[4] = (intel_sub_group_shuffle(dist, 4)); + dist_shuffle[5] = (intel_sub_group_shuffle(dist, 5)); + dist_shuffle[6] = (intel_sub_group_shuffle(dist, 6)); + dist_shuffle[7] = (intel_sub_group_shuffle(dist, 7)); + + if (sg_lid % 2 == 0) { + distance = dist_shuffle[0]; + distance += dist_shuffle[2]; + distance += dist_shuffle[4]; + distance += dist_shuffle[6]; + } + else { + distance = dist_shuffle[1]; + distance += dist_shuffle[3]; + distance += dist_shuffle[5]; + distance += dist_shuffle[7]; + } + + // cumulate distance + dist.s0 = (distance.s0 + distance.s1 + distance.s2 + distance.s3); + dist.s4 = (distance.s4 + distance.s5 + distance.s6 + distance.s7); + gain = (grad.s0 < threshold) ? gain : 2.0f * gain; + weight = native_exp(-gain * dist.s0); + (*restore).lo = mad(weight, ref.lo, (*restore).lo); + (*sum_weight).lo = (*sum_weight).lo + weight; + + gain = (grad.s4 < threshold) ? gain : 2.0f * gain; + weight = native_exp(-gain * dist.s4); + (*restore).hi = mad(weight, ref.hi, (*restore).hi); + (*sum_weight).hi = (*sum_weight).hi + weight; +} + +inline void weighted_average (__read_only image2d_t input, + __local uchar8* ref_cache, + bool load_observe, + float8* observe, + float8* restore, + float2* sum_weight, + float gain, + float threshold, + uint sg_id, + uint sg_lid) +{ + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + int local_id_x = get_local_id(0); + int local_id_y = get_local_id(1); + const int group_id_x = get_group_id(0); + const int group_id_y = get_group_id(1); + + int start_x = mad24(group_id_x, WORKGROUP_WIDTH, -REF_BLOCK_X_OFFSET); + int start_y = mad24(group_id_y, WORKGROUP_HEIGHT, -REF_BLOCK_Y_OFFSET); + + int i = local_id_x + local_id_y * WORKGROUP_WIDTH; + for ( int j = i; j < (REF_BLOCK_HEIGHT * REF_BLOCK_WIDTH); + j += (WORKGROUP_HEIGHT * WORKGROUP_WIDTH) ) { + int corrd_x = start_x + (j % REF_BLOCK_WIDTH); + int corrd_y = start_y + (j / REF_BLOCK_WIDTH); + + ref_cache[j] = as_uchar8( convert_ushort4(read_imageui(input, + sampler, + (int2)(corrd_x, corrd_y)))); + } + barrier(CLK_LOCAL_MEM_FENCE); + +#if WORKGROUP_WIDTH == 4 + int2 pos = subgroup_pos(sg_id, sg_lid); + local_id_x = pos.x; + local_id_y = pos.y; +#endif + + if (load_observe) { + (*observe) = convert_float8( + ref_cache[mad24(local_id_y + REF_BLOCK_Y_OFFSET, + REF_BLOCK_WIDTH, + local_id_x + REF_BLOCK_X_OFFSET)]); + (*restore) = (*observe); + (*sum_weight) = 1.0f; + } + + float8 ref[2] = {0.0f, 0.0f}; + __local uchar4* p_ref = (__local uchar4*)(ref_cache); + + // top-left + ref[0] = convert_float8(*(__local uchar8*)(p_ref + mad24(local_id_y, + 2 * REF_BLOCK_WIDTH, + mad24(2, local_id_x, 1)))); + average_slice(ref[0], *observe, restore, sum_weight, gain, threshold, sg_id, sg_lid); + + // top-right + ref[1] = convert_float8(*(__local uchar8*)(p_ref + mad24(local_id_y, + 2 * REF_BLOCK_WIDTH, + mad24(2, local_id_x, 3)))); + average_slice(ref[1], *observe, restore, sum_weight, gain, threshold, sg_id, sg_lid); + + // top-mid + average_slice((float8)(ref[0].hi, ref[1].lo), *observe, restore, sum_weight, gain, threshold, sg_id, sg_lid); + + // mid-left + ref[0] = convert_float8(*(__local uchar8*)(p_ref + mad24((local_id_y + 4), + 2 * REF_BLOCK_WIDTH, + mad24(2, local_id_x, 1)))); + average_slice(ref[0], *observe, restore, sum_weight, gain, threshold, sg_id, sg_lid); + + // mid-right + ref[1] = convert_float8(*(__local uchar8*)(p_ref + mad24((local_id_y + 4), + 2 * REF_BLOCK_WIDTH, + mad24(2, local_id_x, 3)))); + average_slice(ref[1], *observe, restore, sum_weight, gain, threshold, sg_id, sg_lid); + + // mid-mid + if (!load_observe) { + average_slice((float8)(ref[0].hi, ref[1].lo), *observe, restore, sum_weight, gain, threshold, sg_id, sg_lid); + } + + // bottom-left + ref[0] = convert_float8(*(__local uchar8*)(p_ref + mad24((local_id_y + 8), + 2 * REF_BLOCK_WIDTH, + mad24(2, local_id_x, 1)))); + average_slice(ref[0], *observe, restore, sum_weight, gain, threshold, sg_id, sg_lid); + + // bottom-right + ref[1] = convert_float8(*(__local uchar8*)(p_ref + mad24((local_id_y + 8), + 2 * REF_BLOCK_WIDTH, + mad24(2, local_id_x, 3)))); + average_slice(ref[1], *observe, restore, sum_weight, gain, threshold, sg_id, sg_lid); + + // bottom-mid + average_slice((float8)(ref[0].hi, ref[1].lo), *observe, restore, sum_weight, gain, threshold, sg_id, sg_lid); +} + +__kernel void kernel_3d_denoise ( float gain, + float threshold, + __read_only image2d_t restoredPrev, + __write_only image2d_t output, + __read_only image2d_t input, + __read_only image2d_t inputPrev1, + __read_only image2d_t inputPrev2) +{ + float8 restore = 0.0f; + float8 observe = 0.0f; + float2 sum_weight = 0.0f; + + const int sg_id = get_sub_group_id(); + const int sg_lid = (get_local_id(1) * WORKGROUP_WIDTH + get_local_id(0)) % 8; + + __local uchar8 ref_cache[REF_BLOCK_HEIGHT * REF_BLOCK_WIDTH]; + + weighted_average (input, ref_cache, true, &observe, &restore, &sum_weight, gain, threshold, sg_id, sg_lid); + +#if ENABLE_IIR_FILERING + weighted_average (restoredPrev, ref_cache, false, &observe, &restore, &sum_weight, gain, threshold, sg_id, sg_lid); +#else +#if REFERENCE_FRAME_COUNT > 1 + weighted_average (inputPrev1, ref_cache, false, &observe, &restore, &sum_weight, gain, threshold, sg_id, sg_lid); +#endif + +#if REFERENCE_FRAME_COUNT > 2 + weighted_average (inputPrev2, ref_cache, false, &observe, &restore, &sum_weight, gain, threshold, sg_id, sg_lid); +#endif +#endif + + restore.lo = restore.lo / sum_weight.lo; + restore.hi = restore.hi / sum_weight.hi; + + int local_id_x = get_local_id(0); + int local_id_y = get_local_id(1); + const int group_id_x = get_group_id(0); + const int group_id_y = get_group_id(1); + +#if WORKGROUP_WIDTH == 4 + int2 pos = subgroup_pos(sg_id, sg_lid); + local_id_x = pos.x; + local_id_y = pos.y; +#endif + + int coor_x = mad24(group_id_x, WORKGROUP_WIDTH, local_id_x); + int coor_y = mad24(group_id_y, WORKGROUP_HEIGHT, local_id_y); + + write_imageui(output, + (int2)(coor_x, coor_y), + convert_uint4(as_ushort4(convert_uchar8(restore)))); +} + diff --git a/cl_kernel/kernel_3d_denoise_slm.cl b/cl_kernel/kernel_3d_denoise_slm.cl new file mode 100644 index 0000000..55eef62 --- /dev/null +++ b/cl_kernel/kernel_3d_denoise_slm.cl @@ -0,0 +1,219 @@ +/* + * function: kernel_3d_denoise_slm + * 3D Noise Reduction + * gain: The parameter determines the filtering strength for the reference block + * threshold: Noise variances of observed image + * restoredPrev: The previous restored image, image2d_t as read only + * output: restored image, image2d_t as write only + * input: observed image, image2d_t as read only + * inputPrev1: reference image, image2d_t as read only + * inputPrev2: reference image, image2d_t as read only + */ + +#ifndef REFERENCE_FRAME_COUNT +#define REFERENCE_FRAME_COUNT 2 +#endif + +#ifndef ENABLE_IIR_FILERING +#define ENABLE_IIR_FILERING 1 +#endif + +#define WORK_GROUP_WIDTH 8 +#define WORK_GROUP_HEIGHT 1 + +#define WORK_BLOCK_WIDTH 8 +#define WORK_BLOCK_HEIGHT 8 + +#define REF_BLOCK_X_OFFSET 1 +#define REF_BLOCK_Y_OFFSET 4 + +#define REF_BLOCK_WIDTH (WORK_BLOCK_WIDTH + 2 * REF_BLOCK_X_OFFSET) +#define REF_BLOCK_HEIGHT (WORK_BLOCK_HEIGHT + 2 * REF_BLOCK_Y_OFFSET) + + +inline void weighted_average (__read_only image2d_t input, + __local float4* ref_cache, + bool load_observe, + __local float4* observe_cache, + float4* restore, + float2* sum_weight, + float gain, + float threshold) +{ + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + const int local_id_x = get_local_id(0); + const int local_id_y = get_local_id(1); + const int group_id_x = get_group_id(0); + const int group_id_y = get_group_id(1); + + int i = local_id_x + local_id_y * WORK_BLOCK_WIDTH; + int start_x = mad24(group_id_x, WORK_BLOCK_WIDTH, -REF_BLOCK_X_OFFSET); + int start_y = mad24(group_id_y, WORK_BLOCK_HEIGHT, -REF_BLOCK_Y_OFFSET); + for (int j = i; j < REF_BLOCK_WIDTH * REF_BLOCK_HEIGHT; j += (WORK_GROUP_WIDTH * WORK_GROUP_HEIGHT)) { + int corrd_x = start_x + (j % REF_BLOCK_WIDTH); + int corrd_y = start_y + (j / REF_BLOCK_WIDTH); + ref_cache[j] = read_imagef(input, sampler, (int2)(corrd_x, corrd_y)); + } + barrier(CLK_LOCAL_MEM_FENCE); + + if (load_observe) { + for (int i = 0; i < WORK_BLOCK_HEIGHT; i++) { + observe_cache[i * WORK_BLOCK_WIDTH + local_id_x] = + ref_cache[(i + REF_BLOCK_Y_OFFSET) * REF_BLOCK_WIDTH + + local_id_x + REF_BLOCK_X_OFFSET]; + } + } + + float4 dist = (float4)(0.0f, 0.0f, 0.0f, 0.0f); + float4 gradient = (float4)(0.0f, 0.0f, 0.0f, 0.0f); + float weight = 0.0f; + +#pragma unroll + for (int i = 0; i < 3; i++) { +#pragma unroll + for (int j = 0; j < 3; j++) { + dist = (ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, local_id_x + j)] - + observe_cache[local_id_x]) * + (ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, local_id_x + j)] - + observe_cache[local_id_x]); + dist = mad((ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)] - + observe_cache[WORK_BLOCK_WIDTH + local_id_x]), + (ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)] - + observe_cache[WORK_BLOCK_WIDTH + local_id_x]), + dist); + dist = mad((ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 2 * REF_BLOCK_WIDTH + local_id_x + j)] - + observe_cache[2 * WORK_BLOCK_WIDTH + local_id_x]), + (ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 2 * REF_BLOCK_WIDTH + local_id_x + j)] - + observe_cache[2 * WORK_BLOCK_WIDTH + local_id_x]), + dist); + dist = mad((ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 3 * REF_BLOCK_WIDTH + local_id_x + j)] - + observe_cache[3 * WORK_BLOCK_WIDTH + local_id_x]), + (ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 3 * REF_BLOCK_WIDTH + local_id_x + j)] - + observe_cache[3 * WORK_BLOCK_WIDTH + local_id_x]), + dist); + + gradient = (float4)(ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)].s2, + ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)].s2, + ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)].s2, + ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)].s2); + gradient = (gradient - ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, local_id_x + j)]) + + (gradient - ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)]) + + (gradient - ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 2 * REF_BLOCK_WIDTH + local_id_x + j)]) + + (gradient - ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 3 * REF_BLOCK_WIDTH + local_id_x + j)]); + gradient.s0 = (gradient.s0 + gradient.s1 + gradient.s2 + gradient.s3) / 15.0f; + gain = (gradient.s0 < threshold) ? gain : 2.0f * gain; + + weight = native_exp(-gain * (dist.s0 + dist.s1 + dist.s2 + dist.s3)); + weight = (weight < 0) ? 0 : weight; + (*sum_weight).s0 = (*sum_weight).s0 + weight; + + restore[0] = mad(weight, ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, local_id_x + j)], restore[0]); + restore[1] = mad(weight, ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)], restore[1]); + restore[2] = mad(weight, ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 2 * REF_BLOCK_WIDTH + local_id_x + j)], restore[2]); + restore[3] = mad(weight, ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 3 * REF_BLOCK_WIDTH + local_id_x + j)], restore[3]); + } + } + +#pragma unroll + for (int i = 1; i < 4; i++) { +#pragma unroll + for (int j = 0; j < 3; j++) { + dist = (ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, local_id_x + j)] - + observe_cache[4 * WORK_BLOCK_WIDTH + local_id_x]) * + (ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, local_id_x + j)] - + observe_cache[4 * WORK_BLOCK_WIDTH + local_id_x]); + dist = mad((ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)] - + observe_cache[5 * WORK_BLOCK_WIDTH + local_id_x]), + (ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)] - + observe_cache[5 * WORK_BLOCK_WIDTH + local_id_x]), + dist); + dist = mad((ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 2 * REF_BLOCK_WIDTH + local_id_x + j)] - + observe_cache[6 * WORK_BLOCK_WIDTH + local_id_x]), + (ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 2 * REF_BLOCK_WIDTH + local_id_x + j)] - + observe_cache[6 * WORK_BLOCK_WIDTH + local_id_x]), + dist); + dist = mad((ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 3 * REF_BLOCK_WIDTH + local_id_x + j)] - + observe_cache[7 * WORK_BLOCK_WIDTH + local_id_x]), + (ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 3 * REF_BLOCK_WIDTH + local_id_x + j)] - + observe_cache[7 * WORK_BLOCK_WIDTH + local_id_x]), + dist); + + gradient = (float4)(ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)].s2, + ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)].s2, + ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)].s2, + ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)].s2); + gradient = (gradient - ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, local_id_x + j)]) + + (gradient - ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)]) + + (gradient - ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 2 * REF_BLOCK_WIDTH + local_id_x + j)]) + + (gradient - ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 3 * REF_BLOCK_WIDTH + local_id_x + j)]); + gradient.s0 = (gradient.s0 + gradient.s1 + gradient.s2 + gradient.s3) / 15.0f; + gain = (gradient.s0 < threshold) ? gain : 2.0f * gain; + + weight = native_exp(-gain * (dist.s0 + dist.s1 + dist.s2 + dist.s3)); + weight = (weight < 0) ? 0 : weight; + (*sum_weight).s1 = (*sum_weight).s1 + weight; + + restore[4] = mad(weight, ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, local_id_x + j)], restore[4]); + restore[5] = mad(weight, ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, REF_BLOCK_WIDTH + local_id_x + j)], restore[5]); + restore[6] = mad(weight, ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 2 * REF_BLOCK_WIDTH + local_id_x + j)], restore[6]); + restore[7] = mad(weight, ref_cache[mad24(i, 4 * REF_BLOCK_WIDTH, 3 * REF_BLOCK_WIDTH + local_id_x + j)], restore[7]); + } + } +} + +__kernel void kernel_3d_denoise_slm( float gain, + float threshold, + __read_only image2d_t restoredPrev, + __write_only image2d_t output, + __read_only image2d_t input, + __read_only image2d_t inputPrev1, + __read_only image2d_t inputPrev2) +{ + float4 restore[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; + float2 sum_weight = {0.0f, 0.0f}; + + __local float4 ref_cache[REF_BLOCK_HEIGHT * REF_BLOCK_WIDTH]; + __local float4 observe_cache[WORK_BLOCK_HEIGHT * WORK_BLOCK_WIDTH]; + + weighted_average (input, ref_cache, true, observe_cache, restore, &sum_weight, gain, threshold); + +#if 1 + +#if ENABLE_IIR_FILERING + weighted_average (restoredPrev, ref_cache, false, observe_cache, restore, &sum_weight, gain, threshold); +#else +#if REFERENCE_FRAME_COUNT > 1 + weighted_average (inputPrev1, ref_cache, false, observe_cache, restore, &sum_weight, gain, threshold); +#endif + +#if REFERENCE_FRAME_COUNT > 2 + weighted_average (inputPrev2, ref_cache, false, observe_cache, restore, &sum_weight, gain, threshold); +#endif +#endif + +#endif + + restore[0] = restore[0] / sum_weight.s0; + restore[1] = restore[1] / sum_weight.s0; + restore[2] = restore[2] / sum_weight.s0; + restore[3] = restore[3] / sum_weight.s0; + + restore[4] = restore[4] / sum_weight.s1; + restore[5] = restore[5] / sum_weight.s1; + restore[6] = restore[6] / sum_weight.s1; + restore[7] = restore[7] / sum_weight.s1; + + const int global_id_x = get_global_id (0); + const int global_id_y = get_global_id (1); + + write_imagef(output, (int2)(global_id_x, 8 * global_id_y), restore[0]); + write_imagef(output, (int2)(global_id_x, mad24(8, global_id_y, 1)), restore[1]); + write_imagef(output, (int2)(global_id_x, mad24(8, global_id_y, 2)), restore[2]); + write_imagef(output, (int2)(global_id_x, mad24(8, global_id_y, 3)), restore[3]); + write_imagef(output, (int2)(global_id_x, mad24(8, global_id_y, 4)), restore[4]); + write_imagef(output, (int2)(global_id_x, mad24(8, global_id_y, 5)), restore[5]); + write_imagef(output, (int2)(global_id_x, mad24(8, global_id_y, 6)), restore[6]); + write_imagef(output, (int2)(global_id_x, mad24(8, global_id_y, 7)), restore[7]); +} + diff --git a/cl_kernel/kernel_bayer_basic.cl b/cl_kernel/kernel_bayer_basic.cl new file mode 100644 index 0000000..e6c19dd --- /dev/null +++ b/cl_kernel/kernel_bayer_basic.cl @@ -0,0 +1,260 @@ +/* + * function: kernel_bayer_copy + * sample code of default kernel arguments + * input: image2d_t as read only + * output: image2d_t as write only + */ + +//#define ENABLE_IMAGE_2D_INPUT 0 + +#ifndef STATS_BITS +#define STATS_BITS 8 +#endif + +/* + * GROUP_PIXEL_X_SIZE = 2 * GROUP_CELL_X_SIZE + * GROUP_PIXEL_Y_SIZE = 2 * GROUP_CELL_Y_SIZE +*/ + +#define GROUP_CELL_X_SIZE 64 +#define GROUP_CELL_Y_SIZE 4 + +//float4; 16 +#define SLM_X_SIZE (GROUP_CELL_X_SIZE / 4) +#define SLM_Y_SIZE GROUP_CELL_Y_SIZE + +#define STATS_3A_CELL_X_SIZE 8 +#define STATS_3A_CELL_Y_SIZE GROUP_CELL_Y_SIZE + +typedef struct { + float level_gr; /* Black level for GR pixels */ + float level_r; /* Black level for R pixels */ + float level_b; /* Black level for B pixels */ + float level_gb; /* Black level for GB pixels */ + uint color_bits; +} CLBLCConfig; + + +typedef struct +{ + float r_gain; + float gr_gain; + float gb_gain; + float b_gain; +} CLWBConfig; + +inline int slm_pos (const int x, const int y) +{ + return mad24 (y, SLM_X_SIZE, x); +} + +inline void gamma_correct(float8 *in_out, __global float *table) +{ + in_out->s0 = table[clamp(convert_int(in_out->s0 * 255.0f), 0, 255)]; + in_out->s1 = table[clamp(convert_int(in_out->s1 * 255.0f), 0, 255)]; + in_out->s2 = table[clamp(convert_int(in_out->s2 * 255.0f), 0, 255)]; + in_out->s3 = table[clamp(convert_int(in_out->s3 * 255.0f), 0, 255)]; + in_out->s4 = table[clamp(convert_int(in_out->s4 * 255.0f), 0, 255)]; + in_out->s5 = table[clamp(convert_int(in_out->s5 * 255.0f), 0, 255)]; + in_out->s6 = table[clamp(convert_int(in_out->s6 * 255.0f), 0, 255)]; + in_out->s7 = table[clamp(convert_int(in_out->s7 * 255.0f), 0, 255)]; +} + +inline float avg_float8 (float8 data) +{ + return (data.s0 + data.s1 + data.s2 + data.s3 + data.s4 + data.s5 + data.s6 + data.s7) * 0.125f; +} + +inline void stats_3a_calculate ( + __local float4 * slm_gr, + __local float4 * slm_r, + __local float4 * slm_b, + __local float4 * slm_gb, + __global ushort8 * stats_output, + CLWBConfig *wb_config) +{ + const int group_x_size = get_num_groups (0); + const int group_id_x = get_group_id (0); + const int group_id_y = get_group_id (1); + + const int l_id_x = get_local_id (0); + const int l_id_y = get_local_id (1); + const int l_size_x = get_local_size (0); + const int stats_float4_x_count = STATS_3A_CELL_X_SIZE / 4; + int count = stats_float4_x_count * STATS_3A_CELL_Y_SIZE / 4; + + int index = mad24 (l_id_y, l_size_x, l_id_x); + int index_x = index % SLM_X_SIZE; + int index_y = index / SLM_X_SIZE; + + if (mad24 (index_y, stats_float4_x_count, index_x % stats_float4_x_count) < count) { + int pitch_count = count / stats_float4_x_count * SLM_X_SIZE; + int index1 = index + pitch_count; + int index2 = index1 + pitch_count; + int index3 = index2 + pitch_count; + slm_gr[index] = (slm_gr[index] + slm_gr[index1] + slm_gr[index2] + slm_gr[index3]) * 0.25f; + slm_r[index] = (slm_r[index] + slm_r[index1] + slm_r[index2] + slm_r[index3]) * 0.25f; + slm_b[index] = (slm_b[index] + slm_b[index1] + slm_b[index2] + slm_b[index3]) * 0.25f; + slm_gb[index] = (slm_gb[index] + slm_gb[index1] + slm_gb[index2] + slm_gb[index3]) * 0.25f; + } + barrier (CLK_LOCAL_MEM_FENCE); + + if (index < SLM_X_SIZE / 2) { + float result_gr, result_r, result_b, result_gb, avg_y; + float8 tmp; + tmp = ((__local float8*)slm_gr)[index]; + result_gr = avg_float8 (tmp); + + tmp = ((__local float8*)slm_r)[index]; + result_r = avg_float8 (tmp); + + tmp = ((__local float8*)slm_b)[index]; + result_b = avg_float8 (tmp); + + tmp = ((__local float8*)slm_gb)[index]; + result_gb = avg_float8 (tmp); + + int out_index = mad24 (mad24 (group_id_y, group_x_size, group_id_x), + (GROUP_CELL_X_SIZE / STATS_3A_CELL_X_SIZE) * (GROUP_CELL_Y_SIZE / STATS_3A_CELL_Y_SIZE), + index); + +#if STATS_BITS==8 + avg_y = mad ((result_gr * wb_config->gr_gain + result_gb * wb_config->gb_gain), 74.843f, + mad (result_r * wb_config->r_gain, 76.245f, result_b * 29.070f)); + + //ushort avg_y; avg_r; avg_gr; avg_gb; avg_b; valid_wb_count; f_value1; f_value2; + stats_output[out_index] = (ushort8) ( + convert_ushort (convert_uchar_sat (avg_y)), + convert_ushort (convert_uchar_sat (result_r * 255.0f)), + convert_ushort (convert_uchar_sat (result_gr * 255.0f)), + convert_ushort (convert_uchar_sat (result_gb * 255.0f)), + convert_ushort (convert_uchar_sat (result_b * 255.0f)), + STATS_3A_CELL_X_SIZE * STATS_3A_CELL_Y_SIZE, + 0, + 0); +#elif STATS_BITS==12 + avg_y = mad ((result_gr * wb_config->gr_gain + result_gb * wb_config->gb_gain), 1201.883f, + mad (result_r * wb_config->r_gain, 1224.405f, result_b * 466.830f)); + + stats_output[out_index] = (ushort8) ( + convert_ushort (clamp (avg_y, 0.0f, 4095.0f)), + convert_ushort (clamp (result_r * 4096.0f, 0.0f, 4095.0f)), + convert_ushort (clamp (result_gr * 4096.0f, 0.0f, 4095.0f)), + convert_ushort (clamp (result_gb * 4096.0f, 0.0f, 4095.0f)), + convert_ushort (clamp (result_b * 4096.0f, 0.0f, 4095.0f)), + STATS_3A_CELL_X_SIZE * STATS_3A_CELL_Y_SIZE, + 0, + 0); +#else + printf ("kernel 3a-stats error, wrong bit depth:%d\n", STATS_BITS); +#endif + } +} + + +__kernel void kernel_bayer_basic ( +#if ENABLE_IMAGE_2D_INPUT + __read_only image2d_t input, +#else + __global const ushort8 *input, +#endif + uint input_aligned_width, + __write_only image2d_t output, + uint out_height, + CLBLCConfig blc_config, + CLWBConfig wb_config, + __global float *gamma_table, + __global ushort8 *stats_output +) +{ + int g_x = get_global_id (0); + int g_y = get_global_id (1); + + const int l_x = get_local_id (0); + const int l_y = get_local_id (1); + const int l_x_size = get_local_size (0); + const int l_y_size = get_local_size (1); + const int group_id_x = get_group_id (0); + const int group_id_y = get_group_id (1); + + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; + + int index = mad24 (l_y, l_x_size, l_x); + int x_cell_start = (GROUP_CELL_X_SIZE / 4) * group_id_x; + int y_cell_start = GROUP_CELL_Y_SIZE * group_id_y; + int x, y; + + float blc_multiplier = (float)(1 << (16 - blc_config.color_bits)); + + __local float4 slm_gr[SLM_X_SIZE * SLM_Y_SIZE], slm_r[SLM_X_SIZE * SLM_Y_SIZE], slm_b[SLM_X_SIZE * SLM_Y_SIZE], slm_gb[SLM_X_SIZE * SLM_Y_SIZE]; + + for (; index < SLM_X_SIZE * SLM_Y_SIZE; index += l_x_size * l_y_size) { + float8 line1; + float8 line2; + + x = index % SLM_X_SIZE + x_cell_start; + y = index / SLM_X_SIZE + y_cell_start; + +#if ENABLE_IMAGE_2D_INPUT + line1 = convert_float8 (as_ushort8 (read_imageui(input, sampler, (int2)(x, y * 2)))) / 65536.0f; + line2 = convert_float8 (as_ushort8 (read_imageui(input, sampler, (int2)(x, y * 2 + 1)))) / 65536.0f; +#else + line1 = convert_float8 (input [y * 2 * input_aligned_width + x]) / 65536.0f; + line2 = convert_float8 (input [(y * 2 + 1) * input_aligned_width + x]) / 65536.0f; +#endif + + float4 gr = mad (line1.even, blc_multiplier, - blc_config.level_gr); + float4 r = mad (line1.odd, blc_multiplier, - blc_config.level_r); + float4 b = mad (line2.even, blc_multiplier, - blc_config.level_b); + float4 gb = mad (line2.odd, blc_multiplier, - blc_config.level_gb); + + slm_gr[index] = gr; + slm_r[index] = r; + slm_b[index] = b; + slm_gb[index] = gb; + } + barrier(CLK_LOCAL_MEM_FENCE); + + float8 data_gr, data_r, data_b, data_gb; + index = mad24 (l_y, l_x_size, l_x); + x = mad24 (GROUP_CELL_X_SIZE / 8, group_id_x, index % (SLM_X_SIZE / 2)); + y = mad24 (GROUP_CELL_Y_SIZE, group_id_y, index / (SLM_X_SIZE / 2)); + + data_gr = ((__local float8*)slm_gr)[index]; + data_gr = data_gr * wb_config.gr_gain; + + data_r = ((__local float8*)slm_r)[index]; + data_r = data_r * wb_config.r_gain; + + data_b = ((__local float8*)slm_b)[index]; + data_b = data_b * wb_config.b_gain; + + data_gb = ((__local float8*)slm_gb)[index]; + data_gb = data_gb * wb_config.gb_gain; + +#if ENABLE_GAMMA + gamma_correct (&data_gr, gamma_table); + gamma_correct (&data_r, gamma_table); + gamma_correct (&data_b, gamma_table); + gamma_correct (&data_gb, gamma_table); +#endif + +#if 0 + if (x % 16 == 0 && y % 16 == 0) { + uint8 value = convert_uint8(convert_uchar8_sat(data_gr * 255.0f)); + printf ("(x:%d, y:%d) (blc.bit:%d, level:%d) (wb.gr:%f)=> (%d, %d, %d, %d, %d, %d, %d, %d)\n", + x * 8, y, + blc_config.color_bits, convert_uint(blc_config.level_gr * 255.0f), + wb_config.gr_gain, + value.s0, value.s1, value.s2, value.s3, value.s4, value.s5, value.s6, value.s7); + } +#endif + + write_imageui (output, (int2)(x, y), as_uint4 (convert_ushort8 (data_gr * 65536.0f))); + write_imageui (output, (int2)(x, y + out_height), as_uint4 (convert_ushort8 (data_r * 65536.0f))); + write_imageui (output, (int2)(x, y + out_height * 2), as_uint4 (convert_ushort8 (data_b * 65536.0f))); + write_imageui (output, (int2)(x, y + out_height * 3), as_uint4 (convert_ushort8 (data_gb * 65536.0f))); + + stats_3a_calculate (slm_gr, slm_r, slm_b, slm_gb, stats_output, &wb_config); +} + diff --git a/cl_kernel/kernel_bayer_pipe.cl b/cl_kernel/kernel_bayer_pipe.cl new file mode 100644 index 0000000..91dd362 --- /dev/null +++ b/cl_kernel/kernel_bayer_pipe.cl @@ -0,0 +1,384 @@ +/* + * function: kernel_bayer_pipe + * params: + * input: image2d_t as read only + * output: image2d_t as write only + * blc_config: black level correction configuration + * wb_config: whitebalance configuration + * gamma_table: RGGB table + * stats_output: 3a stats output + */ + + +#define WORKGROUP_CELL_WIDTH 64 +#define WORKGROUP_CELL_HEIGHT 4 + +#define DEMOSAIC_X_CELL_PER_WORKITEM 2 + +#define PIXEL_PER_CELL 2 + +#define SLM_CELL_X_OFFSET 4 +#define SLM_CELL_Y_OFFSET 1 + +// 8x8 +#define SLM_CELL_X_VALID_SIZE WORKGROUP_CELL_WIDTH +#define SLM_CELL_Y_VALID_SIZE WORKGROUP_CELL_HEIGHT + +// 10x10 +#define SLM_CELL_X_SIZE (SLM_CELL_X_VALID_SIZE + SLM_CELL_X_OFFSET * 2) +#define SLM_CELL_Y_SIZE (SLM_CELL_Y_VALID_SIZE + SLM_CELL_Y_OFFSET * 2) + +#define GUASS_DELTA_S_1 1.031739f +#define GUASS_DELTA_S_1_5 1.072799f +#define GUASS_DELTA_S_2 1.133173f +#define GUASS_DELTA_S_2_5 1.215717f + +typedef struct +{ + float ee_gain; + float ee_threshold; + float nr_gain; +} CLEeConfig; + +inline int get_shared_pos_x (int i) +{ + return i % SLM_CELL_X_SIZE; +} + +inline int get_shared_pos_y (int i) +{ + return i / SLM_CELL_X_SIZE; +} + +inline int shared_pos (int x, int y) +{ + return mad24(y, SLM_CELL_X_SIZE, x); +} + +/* BA10=> GRBG */ +inline void grbg_slm_load ( + __local float *px, __local float *py, __local float *pz, __local float *pw, + int index, __read_only image2d_t input, uint input_height, int x_start, int y_start +) +{ + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + float4 data1, data2, line1, line2; + int x0 = (get_shared_pos_x (index) + x_start) / 4; + int y0 = get_shared_pos_y (index) + y_start; + int2 pos = (int2)(x0, y0); + float4 gr, r, b, gb; + + y0 = y0 > 0 ? y0 : 0; + + gr = read_imagef (input, sampler, (int2)(x0, y0)); + r = read_imagef (input, sampler, (int2)(x0, y0 + input_height)); + b = read_imagef (input, sampler, (int2)(x0, y0 + input_height * 2)); + gb = read_imagef (input, sampler, (int2)(x0, y0 + input_height * 3)); + + (*(__local float4 *)(px + index)) = gr; + (*(__local float4 *)(py + index)) = r; + (*(__local float4 *)(pz + index)) = b; + (*(__local float4 *)(pw + index)) = gb; +} + +#define MAX_DELTA_COFF 5.0f +#define MIN_DELTA_COFF 1.0f +#define DEFAULT_DELTA_COFF 4.0f + +inline float2 delta_coff (float2 in, __local float *table) +{ + float2 out; + out.x = table[(int)(fabs(in.x * 64.0f))]; + out.y = table[(int)(fabs(in.y * 64.0f))]; + + return out; +} + +inline float2 dot_denoise (float2 value, float2 in1, float2 in2, float2 in3, float2 in4, __local float *table, float coff0) +{ + float2 coff1, coff2, coff3, coff4, coff5; + coff1 = delta_coff (in1 - value, table); + coff2 = delta_coff (in2 - value, table); + coff3 = delta_coff (in3 - value, table); + coff4 = delta_coff (in4 - value, table); + //(in1 * coff1 + in2 * coff2 + in3 * coff3 + in4 * coff4 + value * coff0) + float2 sum1 = (mad (in1, coff1, + mad (in2, coff2, + mad (in3, coff3, + mad (in4, coff4, value * coff0))))); + return sum1 / (coff0 + coff1 + coff2 + coff3 + coff4); +} + +inline float2 dot_ee (float2 value, float2 in1, float2 in2, float2 in3, float2 in4, float2 out, CLEeConfig ee_config, float2 *egain) +{ + + float2 ee = mad(in1 + in2 + in3 + in4, -0.25f, value); + ee = fabs(ee) > ee_config.ee_threshold ? ee : 0.0f; + + egain[0] = mad(ee, ee_config.ee_gain, out + 0.03f) / (out + 0.03f); + + return out * egain[0]; +} + +inline float2 dot_denoise_ee (float2 value, float2 in1, float2 in2, float2 in3, float2 in4, __local float *table, float coff0, float2 *egain, CLEeConfig ee_config) +{ + float2 out = dot_denoise(value, in1, in2, in3, in4, table, coff0); + return dot_ee(value, in1, in2, in3, in4, out, ee_config, egain); +} + +void demosaic_2_cell ( + __local float *x_data_in, __local float *y_data_in, __local float *z_data_in, __local float *w_data_in, + int in_x, int in_y, + __write_only image2d_t out, uint out_height, int out_x, int out_y) +{ + float4 out_data; + float2 value; + int index; + { + float3 R_y[2]; + index = shared_pos (in_x - 1, in_y); + R_y[0] = *(__local float3*)(y_data_in + index); + index = shared_pos (in_x - 1, in_y + 1); + R_y[1] = *(__local float3*)(y_data_in + index); + + out_data.s02 = (R_y[0].s01 + R_y[0].s12) * 0.5f; + out_data.s13 = R_y[0].s12; + write_imagef (out, (int2)(out_x, out_y), out_data); + + out_data.s02 = (R_y[0].s01 + R_y[0].s12 + R_y[1].s01 + R_y[1].s12) * 0.25f; + out_data.s13 = (R_y[0].s12 + R_y[1].s12) * 0.5f; + write_imagef (out, (int2)(out_x, out_y + 1), out_data); + } + + { + float3 B_z[2]; + index = shared_pos (in_x, in_y - 1); + B_z[0] = *(__local float3*)(z_data_in + index); + index = shared_pos (in_x, in_y); + B_z[1] = *(__local float3*)(z_data_in + index); + + out_data.s02 = (B_z[0].s01 + B_z[1].s01) * 0.5f; + out_data.s13 = (B_z[0].s01 + B_z[0].s12 + B_z[1].s01 + B_z[1].s12) * 0.25f; + write_imagef (out, (int2)(out_x, out_y + out_height * 2), out_data); + + out_data.s02 = B_z[1].s01; + out_data.s13 = (B_z[1].s01 + B_z[1].s12) * 0.5f; + write_imagef (out, (int2)(out_x, out_y + 1 + out_height * 2), out_data); + } + + { + float3 Gr_x[2], Gb_w[2]; + index = shared_pos (in_x, in_y); + Gr_x[0] = *(__local float3*)(x_data_in + index); + index = shared_pos (in_x, in_y + 1); + Gr_x[1] = *(__local float3*)(x_data_in + index); + + index = shared_pos (in_x - 1, in_y - 1); + Gb_w[0] = *(__local float3*)(w_data_in + index); + index = shared_pos (in_x - 1, in_y); + Gb_w[1] = *(__local float3*)(w_data_in + index); + + out_data.s02 = (Gr_x[0].s01 * 4.0f + Gb_w[0].s01 + + Gb_w[0].s12 + Gb_w[1].s01 + Gb_w[1].s12) * 0.125f; + out_data.s13 = (Gr_x[0].s01 + Gr_x[0].s12 + Gb_w[0].s12 + Gb_w[1].s12) * 0.25f; + write_imagef (out, (int2)(out_x, out_y + out_height), out_data); + + out_data.s02 = (Gr_x[0].s01 + Gr_x[1].s01 + Gb_w[1].s01 + Gb_w[1].s12) * 0.25f; + + out_data.s13 = (Gb_w[1].s12 * 4.0f + Gr_x[0].s01 + + Gr_x[0].s12 + Gr_x[1].s01 + Gr_x[1].s12) * 0.125f; + write_imagef (out, (int2)(out_x, out_y + 1 + out_height), out_data); + } +} + +void demosaic_denoise_2_cell ( + __local float *x_data_in, __local float *y_data_in, __local float *z_data_in, __local float *w_data_in, + int in_x, int in_y, + __write_only image2d_t out, uint out_height, int out_x, int out_y, __local float *table, CLEeConfig ee_config) +{ + float4 out_data_r[2]; + float4 out_data_g[2]; + float4 out_data_b[2]; + float2 value; + int index; + float2 egain[4]; + float2 de; + float gain_coff0 = table[0]; + + float4 R_y[3], B_z[3];; + float2 Gr_x0, Gb_w2; + float4 Gr_x1, Gb_w1; + float3 Gr_x2, Gb_w0; + + // R egain + { + index = shared_pos (in_x - 1, in_y - 1); + R_y[0] = *(__local float4*)(y_data_in + index); + index = shared_pos (in_x - 1, in_y); + R_y[1] = *(__local float4*)(y_data_in + index); + index = shared_pos (in_x - 1, in_y + 1); + R_y[2] = *(__local float4*)(y_data_in + index); + + out_data_r[0].s13 = dot_denoise_ee (R_y[1].s12, R_y[0].s12, R_y[1].s01, R_y[1].s23, R_y[2].s12, + table, gain_coff0 * GUASS_DELTA_S_2, &egain[1], ee_config); + } + + // Gr, Gb egain + { + index = shared_pos (in_x, in_y - 1); + Gr_x0 = *(__local float2*)(x_data_in + index); + index = shared_pos (in_x - 1, in_y); + Gr_x1 = *(__local float4*)(x_data_in + index); + index = shared_pos (in_x, in_y + 1); + Gr_x2 = *(__local float3*)(x_data_in + index); + + index = shared_pos (in_x - 1, in_y - 1); + Gb_w0 = *(__local float3*)(w_data_in + index); + index = shared_pos (in_x - 1, in_y); + Gb_w1 = *(__local float4*)(w_data_in + index); + index = shared_pos (in_x, in_y + 1); + Gb_w2 = *(__local float2*)(w_data_in + index); + + value = mad (Gr_x1.s12, 4.0f, (Gb_w0.s01 + Gb_w0.s12 + Gb_w1.s01 + Gb_w1.s12)) * 0.125f; + de = dot_denoise (value, Gb_w0.s01, Gb_w0.s12, Gb_w1.s01, Gb_w1.s12, table, gain_coff0 * GUASS_DELTA_S_1_5); + out_data_g[0].s02 = dot_ee(Gr_x1.s12, Gr_x0, Gr_x1.s01, Gr_x1.s23, Gr_x2.s01, de, ee_config, &egain[0]); + + value = mad (Gb_w1.s12, 4.0f, (Gr_x1.s12 + Gr_x1.s23 + Gr_x2.s01 + Gr_x2.s12)) * 0.125f; + de = dot_denoise (value, Gr_x1.s12, Gr_x1.s23, Gr_x2.s01, Gr_x2.s12, table, gain_coff0 * GUASS_DELTA_S_1_5); + out_data_g[1].s13 = dot_ee(Gb_w1.s12, Gb_w0.s12, Gb_w1.s01, Gb_w1.s23, Gb_w2, de, ee_config, &egain[3]); + } + + // B egain + { + index = shared_pos (in_x - 1, in_y - 1); + B_z[0] = *(__local float4*)(z_data_in + index); + index = shared_pos (in_x - 1, in_y); + B_z[1] = *(__local float4*)(z_data_in + index); + index = shared_pos (in_x - 1, in_y + 1); + B_z[2] = *(__local float4*)(z_data_in + index); + + out_data_b[1].s02 = dot_denoise_ee (B_z[1].s12, B_z[0].s12, B_z[1].s01, B_z[1].s23, B_z[2].s12, + table, gain_coff0 * GUASS_DELTA_S_2, &egain[2], ee_config); + } + + ////////////////////////////////R////////////////////////////////////////// + { + value = (R_y[1].s01 + R_y[1].s12) * 0.5f; + de = dot_denoise (value, R_y[0].s01, R_y[0].s12, R_y[2].s01, R_y[2].s12, table, gain_coff0 * GUASS_DELTA_S_2_5); + out_data_r[0].s02 = de * egain[0]; + + value = (R_y[1].s01 + R_y[1].s12 + R_y[2].s01 + R_y[2].s12) * 0.25f; + de = dot_denoise (value, R_y[1].s01, R_y[1].s12, R_y[2].s01, R_y[2].s12, table, gain_coff0 * GUASS_DELTA_S_1_5); + out_data_r[1].s02 = de * egain[2]; + + value = (R_y[1].s12 + R_y[2].s12) * 0.5f; + de = dot_denoise (value, R_y[1].s01, R_y[1].s23, R_y[2].s01, R_y[2].s23, table, gain_coff0 * GUASS_DELTA_S_2_5); + out_data_r[1].s13 = de * egain[3]; + + write_imagef (out, (int2)(out_x, out_y), out_data_r[0]); + write_imagef (out, (int2)(out_x, out_y + 1), out_data_r[1]); + } + + ////////////////////////////////G////////////////////////////////////////// + { + value = (Gr_x1.s12 + Gr_x1.s23 + Gb_w0.s12 + Gb_w1.s12) * 0.25f; + de = dot_denoise(value, Gr_x1.s12, Gr_x1.s23, Gb_w0.s12, Gb_w1.s12, table, gain_coff0 * GUASS_DELTA_S_1); + out_data_g[0].s13 = de * egain[1]; + + value = (Gr_x1.s12 + Gr_x2.s01 + Gb_w1.s01 + Gb_w1.s12) * 0.25f; + de = dot_denoise (value, Gr_x1.s12, Gr_x2.s01, Gb_w1.s01, Gb_w1.s12, table, gain_coff0 * GUASS_DELTA_S_1); + out_data_g[1].s02 = de * egain[2]; + + write_imagef (out, (int2)(out_x, out_y + out_height), out_data_g[0]); + write_imagef (out, (int2)(out_x, out_y + 1 + out_height), out_data_g[1]); + } + + ////////////////////////////////B////////////////////////////////////////// + { + value = (B_z[0].s12 + B_z[1].s12) * 0.5f; + de = dot_denoise (value, B_z[0].s01, B_z[0].s23, B_z[1].s01, B_z[1].s23, table, gain_coff0 * GUASS_DELTA_S_2_5); + out_data_b[0].s02 = de * egain[0]; + + value = (B_z[0].s12 + B_z[0].s23 + + B_z[1].s12 + B_z[1].s23) * 0.25f; + de = dot_denoise (value, B_z[0].s12, B_z[0].s23, B_z[1].s12, B_z[1].s23, table, gain_coff0 * GUASS_DELTA_S_1_5); + out_data_b[0].s13 = de * egain[1]; + + value = (B_z[1].s12 + B_z[1].s23) * 0.5f; + de = dot_denoise (value, B_z[0].s12, B_z[0].s23, B_z[2].s12, B_z[2].s23, table, gain_coff0 * GUASS_DELTA_S_2_5); + out_data_b[1].s13 = de * egain[3]; + + write_imagef (out, (int2)(out_x, out_y + out_height * 2), out_data_b[0]); + write_imagef (out, (int2)(out_x, out_y + 1 + out_height * 2), out_data_b[1]); + } +} + +void shared_demosaic ( + __local float *x_data_in, __local float *y_data_in, __local float *z_data_in, __local float *w_data_in, + int in_x, int in_y, + __write_only image2d_t out, uint output_height, int out_x, int out_y, + uint has_denoise, __local float *table, CLEeConfig ee_config) +{ + if (has_denoise) { + demosaic_denoise_2_cell ( + x_data_in, y_data_in, z_data_in, w_data_in, in_x, in_y, + out, output_height, out_x, out_y, table, ee_config); + } else { + demosaic_2_cell ( + x_data_in, y_data_in, z_data_in, w_data_in, in_x, in_y, + out, output_height, out_x, out_y); + } +} + +__kernel void kernel_bayer_pipe (__read_only image2d_t input, + uint input_height, + __write_only image2d_t output, + uint output_height, + __global float * bnr_table, + uint has_denoise, + CLEeConfig ee_config + ) +{ + int g_id_x = get_global_id (0); + int g_id_y = get_global_id (1); + int g_size_x = get_global_size (0); + int g_size_y = get_global_size (1); + + int l_id_x = get_local_id(0); + int l_id_y = get_local_id(1); + int l_size_x = get_local_size (0); + int l_size_y = get_local_size (1); + + __local float p1_x[SLM_CELL_X_SIZE * SLM_CELL_Y_SIZE], p1_y[SLM_CELL_X_SIZE * SLM_CELL_Y_SIZE], p1_z[SLM_CELL_X_SIZE * SLM_CELL_Y_SIZE], p1_w[SLM_CELL_X_SIZE * SLM_CELL_Y_SIZE]; + __local float SLM_delta_coef_table[64]; + + int out_x_start, out_y_start; + int x_start = get_group_id (0) * WORKGROUP_CELL_WIDTH; + int y_start = get_group_id (1) * WORKGROUP_CELL_HEIGHT; + int i = mad24 (l_id_y, l_size_x, l_id_x); + int j = i; + + i *= 4; + if(i < SLM_CELL_X_SIZE * SLM_CELL_Y_SIZE) + { + grbg_slm_load (p1_x, p1_y, p1_z, p1_w, i, + input, input_height, + x_start - SLM_CELL_X_OFFSET, y_start - SLM_CELL_Y_OFFSET); + } + if(j < 64) + SLM_delta_coef_table[j] = bnr_table[j]; + + barrier(CLK_LOCAL_MEM_FENCE); + + i = mad24 (l_id_y, l_size_x, l_id_x); + int workitem_x_size = (SLM_CELL_X_VALID_SIZE / DEMOSAIC_X_CELL_PER_WORKITEM); + int input_x = (i % workitem_x_size) * DEMOSAIC_X_CELL_PER_WORKITEM; + int input_y = i / workitem_x_size; + + shared_demosaic ( + p1_x, p1_y, p1_z, p1_w, + input_x + SLM_CELL_X_OFFSET, input_y + SLM_CELL_Y_OFFSET, + output, output_height, + (input_x + x_start) * PIXEL_PER_CELL / 4, (input_y + y_start) * PIXEL_PER_CELL, has_denoise, SLM_delta_coef_table, ee_config); +} + diff --git a/cl_kernel/kernel_bi_filter.cl b/cl_kernel/kernel_bi_filter.cl new file mode 100644 index 0000000..4023c12 --- /dev/null +++ b/cl_kernel/kernel_bi_filter.cl @@ -0,0 +1,74 @@ +/* + * function: kernel_bi_filter + * bilateral filter + * input_y: Y channel image2d_t as read only + * input_dark: dark channel image2d_t as read only + * output_dark: dark channel image2d_t as write only + * + * data_type CL_UNSIGNED_INT16 + * channel_order CL_RGBA + */ + +#define PATCH_RADIUS 7 +#define PATCH_DIAMETER (2 * PATCH_RADIUS + 1) + +#define CALC_SUM(y1,y2,y3,dark1,dark2,dark3) \ + cur_y = (float8)(y1, y2, y3); \ + cur_dark = (float8)(dark1, dark2, dark3); \ + calc_sum (cur_y, cur_dark, center_y, &weight_sum, &data_sum); + +__inline void calc_sum (float8 cur_y, float8 cur_dark, float8 center_y, float8 *weight_sum, float8 *data_sum) +{ + float8 delta = (cur_y - center_y) / 28.0f; + delta = -0.5f * delta * delta; + + float8 weight = native_exp(delta); + float8 data = cur_dark * weight; + (*weight_sum) += weight; + (*data_sum) += data; +} + +__kernel void kernel_bi_filter ( + __read_only image2d_t input_y, + __read_only image2d_t input_dark, + __write_only image2d_t output_dark) +{ + int pos_x = get_global_id (0); + int pos_y = get_global_id (1); + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + float8 y1, y2, dark1, dark2; + float8 cur_y, cur_dark; + + float8 weight_sum = 0.0f; + float8 data_sum = 0.0f; + float8 center_y = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_y, sampler, (int2)(pos_x, pos_y))))); + for (int i = 0; i < PATCH_DIAMETER; i++) { + y1 = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_y, sampler, (int2)(pos_x - 1, pos_y - PATCH_RADIUS + i))))); + y2 = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_y, sampler, (int2)(pos_x, pos_y - PATCH_RADIUS + i))))); + dark1 = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_dark, sampler, (int2)(pos_x - 1, pos_y - PATCH_RADIUS + i))))); + dark2 = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_dark, sampler, (int2)(pos_x, pos_y - PATCH_RADIUS + i))))); + CALC_SUM (y1.s1234, y1.s567, y2.s0, dark1.s1234, dark1.s567, dark2.s0); + CALC_SUM (y1.s2345, y1.s67, y2.s01, dark1.s2345, dark1.s67, dark2.s01); + CALC_SUM (y1.s3456, y1.s7, y2.s012, dark1.s3456, dark1.s7, dark2.s012); + CALC_SUM (y1.s4567, y2.s01, y2.s23, dark1.s4567, dark2.s01, dark2.s23); + CALC_SUM (y1.s567, y2.s0123, y2.s4, dark1.s567, dark2.s0123, dark2.s4); + CALC_SUM (y1.s67, y2.s0123, y2.s45, dark1.s67, dark2.s0123, dark2.s45); + CALC_SUM (y1.s7, y2.s0123, y2.s456, dark1.s7, dark2.s0123, dark2.s456); + CALC_SUM (y2.s0123, y2.s45, y2.s67, dark2.s0123, dark2.s45, dark2.s67); + + y1 = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_y, sampler, (int2)(pos_x + 1, pos_y - PATCH_RADIUS + i))))); + dark1 = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_dark, sampler, (int2)(pos_x + 1, pos_y - PATCH_RADIUS + i))))); + CALC_SUM (y2.s1234, y2.s567, y1.s0, dark2.s1234, dark2.s567, dark1.s0); + CALC_SUM (y2.s2345, y2.s67, y1.s01, dark2.s2345, dark2.s67, dark1.s01); + CALC_SUM (y2.s3456, y2.s7, y1.s012, dark2.s3456, dark2.s7, dark1.s012); + CALC_SUM (y2.s4567, y1.s01, y1.s23, dark2.s4567, dark1.s01, dark1.s23); + CALC_SUM (y2.s567, y1.s0123, y1.s4, dark2.s567, dark1.s0123, dark1.s4); + CALC_SUM (y2.s67, y1.s0123, y1.s45, dark2.s67, dark1.s0123, dark1.s45); + CALC_SUM (y2.s7, y1.s0123, y1.s456, dark2.s7, dark1.s0123, dark1.s456); + } + + float8 out_data = data_sum / weight_sum; + write_imageui(output_dark, (int2)(pos_x, pos_y), convert_uint4(as_ushort4(convert_uchar8(out_data)))); +} + diff --git a/cl_kernel/kernel_csc.cl b/cl_kernel/kernel_csc.cl new file mode 100644 index 0000000..1a6739a --- /dev/null +++ b/cl_kernel/kernel_csc.cl @@ -0,0 +1,165 @@ +/* + * function: kernel_csc_rgbatonv12 + * input: image2d_t as read only + * output: image2d_t as write only + * vertical_offset, vertical offset from y to uv + */ + +__kernel void kernel_csc_rgbatonv12 (__read_only image2d_t input, __write_only image2d_t output_y, __write_only image2d_t output_uv, __global float *matrix) +{ + int x = get_global_id (0); + int y = get_global_id (1); + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; + float4 pixel_in1 = read_imagef(input, sampler, (int2)(2 * x, 2 * y)); + float4 pixel_in2 = read_imagef(input, sampler, (int2)(2 * x + 1, 2 * y)); + float4 pixel_in3 = read_imagef(input, sampler, (int2)(2 * x, 2 * y + 1)); + float4 pixel_in4 = read_imagef(input, sampler, (int2)(2 * x + 1, 2 * y + 1)); + float4 pixel_out_y1, pixel_out_y2, pixel_out_y3, pixel_out_y4, pixel_out_u, pixel_out_v; + pixel_out_y1.x = matrix[0] * pixel_in1.x + matrix[1] * pixel_in1.y + matrix[2] * pixel_in1.z; + pixel_out_y1.y = 0.0f; + pixel_out_y1.z = 0.0f; + pixel_out_y1.w = 1.0f; + pixel_out_y2.x = matrix[0] * pixel_in2.x + matrix[1] * pixel_in2.y + matrix[2] * pixel_in2.z; + pixel_out_y2.y = 0.0f; + pixel_out_y2.z = 0.0f; + pixel_out_y2.w = 1.0f; + pixel_out_y3.x = matrix[0] * pixel_in3.x + matrix[1] * pixel_in3.y + matrix[2] * pixel_in3.z; + pixel_out_y3.y = 0.0f; + pixel_out_y3.z = 0.0f; + pixel_out_y3.w = 1.0f; + pixel_out_y4.x = matrix[0] * pixel_in4.x + matrix[1] * pixel_in4.y + matrix[2] * pixel_in4.z; + pixel_out_y4.y = 0.0f; + pixel_out_y4.z = 0.0f; + pixel_out_y4.w = 1.0f; + pixel_out_u.x = matrix[3] * pixel_in1.x + matrix[4] * pixel_in1.y + matrix[5] * pixel_in1.z + 0.5f; + pixel_out_u.y = 0.0f; + pixel_out_u.z = 0.0f; + pixel_out_u.w = 1.0f; + pixel_out_v.x = matrix[6] * pixel_in1.x + matrix[7] * pixel_in1.y + matrix[8] * pixel_in1.z + 0.5f; + pixel_out_v.y = 0.0f; + pixel_out_v.z = 0.0f; + pixel_out_v.w = 1.0f; + write_imagef(output_y, (int2)(2 * x, 2 * y), pixel_out_y1); + write_imagef(output_y, (int2)(2 * x + 1, 2 * y), pixel_out_y2); + write_imagef(output_y, (int2)(2 * x, 2 * y + 1), pixel_out_y3); + write_imagef(output_y, (int2)(2 * x + 1, 2 * y + 1), pixel_out_y4); + write_imagef(output_uv, (int2)(2 * x, y), pixel_out_u); + write_imagef(output_uv, (int2)(2 * x + 1, y), pixel_out_v); +} + + +/* + * function: kernel_csc_rgbatolab + * input: image2d_t as read only + * output: image2d_t as write only + */ + +static float lab_fun(float a) +{ + if (a > 0.008856f) + return pow(a, 1.0f / 3); + else + return (float)(7.787f * a + 16.0f / 116); +} +__kernel void kernel_csc_rgbatolab (__read_only image2d_t input, __write_only image2d_t output) +{ + int x = get_global_id (0); + int y = get_global_id (1); + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; + float4 pixel_in = read_imagef(input, sampler, (int2)(x, y)); + float X, Y, Z, L, a, b; + X = 0.433910f * pixel_in.x + 0.376220f * pixel_in.y + 0.189860f * pixel_in.z; + Y = 0.212649f * pixel_in.x + 0.715169f * pixel_in.y + 0.072182f * pixel_in.z; + Z = 0.017756f * pixel_in.x + 0.109478f * pixel_in.y + 0.872915f * pixel_in.z; + if(Y > 0.008856f) + L = 116 * (pow(Y, 1.0f / 3)); + else + L = 903.3f * Y; + a = 500 * (lab_fun(X) - lab_fun(Y)); + b = 200 * (lab_fun(Y) - lab_fun(Z)); + write_imagef(output, (int2)(3 * x, y), L); + write_imagef(output, (int2)(3 * x + 1, y), a); + write_imagef(output, (int2)(3 * x + 2, y), b); +} + +/* + * function: kernel_csc_rgba64torgba + * input: image2d_t as read only + * output: image2d_t as write only + */ +__kernel void kernel_csc_rgba64torgba (__read_only image2d_t input, __write_only image2d_t output) +{ + int x = get_global_id (0); + int y = get_global_id (1); + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; + float4 pixel_in = read_imagef(input, sampler, (int2)(x, y)); + write_imagef(output, (int2)(x, y), pixel_in); +} + +/* + * function: kernel_csc_yuyvtorgba + * input: image2d_t as read only + * output: image2d_t as write only + */ + +__kernel void kernel_csc_yuyvtorgba (__read_only image2d_t input, __write_only image2d_t output) +{ + int x = get_global_id (0); + int y = get_global_id (1); + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; + float4 pixel_in1 = read_imagef(input, sampler, (int2)(x, y)); + float4 pixel_out1, pixel_out2; + pixel_out1.x = pixel_in1.x + 1.13983f * (pixel_in1.w - 0.5f); + pixel_out1.y = pixel_in1.x - 0.39465f * (pixel_in1.y - 0.5f) - 0.5806f * (pixel_in1.w - 0.5f); + pixel_out1.z = pixel_in1.x + 2.03211f * (pixel_in1.y - 0.5f); + pixel_out1.w = 0.0f; + pixel_out2.x = pixel_in1.z + 1.13983f * (pixel_in1.w - 0.5f); + pixel_out2.y = pixel_in1.z - 0.39465f * (pixel_in1.y - 0.5f) - 0.5806f * (pixel_in1.w - 0.5f); + pixel_out2.z = pixel_in1.z + 2.03211f * (pixel_in1.y - 0.5f); + pixel_out2.w = 0.0f; + write_imagef(output, (int2)(2 * x, y), pixel_out1); + write_imagef(output, (int2)(2 * x + 1, y), pixel_out2); +} + +/* + * function: kernel_csc_nv12torgba + * input: image2d_t as read only + * output: image2d_t as write only + * vertical_offset, vertical offset from y to uv + */ + +__kernel void kernel_csc_nv12torgba ( + __read_only image2d_t input_y, __write_only image2d_t output, __read_only image2d_t input_uv) +{ + int x = get_global_id (0); + int y = get_global_id (1); + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; + float4 pixel_y1 = read_imagef(input_y, sampler, (int2)(2 * x, 2 * y)); + float4 pixel_y2 = read_imagef(input_y, sampler, (int2)(2 * x + 1, 2 * y)); + float4 pixel_y3 = read_imagef(input_y, sampler, (int2)(2 * x, 2 * y + 1)); + float4 pixel_y4 = read_imagef(input_y, sampler, (int2)(2 * x + 1, 2 * y + 1)); + float4 pixel_u = read_imagef(input_uv, sampler, (int2)(2 * x, y)); + float4 pixel_v = read_imagef(input_uv, sampler, (int2)(2 * x + 1, y)); + float4 pixel_out1, pixel_out2, pixel_out3, pixel_out4; + pixel_out1.x = pixel_y1.x + 1.13983f * (pixel_v.x - 0.5f); + pixel_out1.y = pixel_y1.x - 0.39465f * (pixel_u.x - 0.5f) - 0.5806f * (pixel_v.x - 0.5f); + pixel_out1.z = pixel_y1.x + 2.03211f * (pixel_u.x - 0.5f); + pixel_out1.w = 0.0f; + pixel_out2.x = pixel_y2.x + 1.13983f * (pixel_v.x - 0.5f); + pixel_out2.y = pixel_y2.x - 0.39465f * (pixel_u.x - 0.5f) - 0.5806f * (pixel_v.x - 0.5f); + pixel_out2.z = pixel_y2.x + 2.03211f * (pixel_u.x - 0.5f); + pixel_out2.w = 0.0f; + pixel_out3.x = pixel_y3.x + 1.13983f * (pixel_v.x - 0.5f); + pixel_out3.y = pixel_y3.x - 0.39465f * (pixel_u.x - 0.5f) - 0.5806f * (pixel_v.x - 0.5f); + pixel_out3.z = pixel_y3.x + 2.03211f * (pixel_u.x - 0.5f); + pixel_out3.w = 0.0f; + pixel_out4.x = pixel_y4.x + 1.13983f * (pixel_v.x - 0.5f); + pixel_out4.y = pixel_y4.x - 0.39465f * (pixel_u.x - 0.5f) - 0.5806f * (pixel_v.x - 0.5f); + pixel_out4.z = pixel_y4.x + 2.03211f * (pixel_u.x - 0.5f); + pixel_out4.w = 0.0f; + write_imagef(output, (int2)(2 * x, 2 * y), pixel_out1); + write_imagef(output, (int2)(2 * x + 1, 2 * y), pixel_out2); + write_imagef(output, (int2)(2 * x, 2 * y + 1), pixel_out3); + write_imagef(output, (int2)(2 * x + 1, 2 * y + 1), pixel_out4); +} + diff --git a/cl_kernel/kernel_defog_dcp.cl b/cl_kernel/kernel_defog_dcp.cl new file mode 100644 index 0000000..3903da6 --- /dev/null +++ b/cl_kernel/kernel_defog_dcp.cl @@ -0,0 +1,135 @@ +/* + * function: kernel_dark_channel + * input_y: Y channel image2d_t as read only + * input_uv: UV channel image2d_t as read only + * out_dark_channel: dark channel image2d_t as write only + * output_r: R channel image2d_t as write only + * output_g: G channel image2d_t as write only + * output_b: B channel image2d_t as write only + * + * data_type CL_UNSIGNED_INT16 + * channel_order CL_RGBA + */ + +__kernel void kernel_dark_channel ( + __read_only image2d_t input_y, __read_only image2d_t input_uv, + __write_only image2d_t out_dark_channel, + __write_only image2d_t output_r, __write_only image2d_t output_g, __write_only image2d_t output_b) +{ + int pos_x = get_global_id (0); + int pos_y = get_global_id (1); + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + float8 y[2]; + float8 r, g, b; + float8 uv_r, uv_g, uv_b; + uint4 ret; + int2 pos; + + y[0] = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_y, sampler, (int2)(pos_x, pos_y * 2))))); + y[1] = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_y, sampler, (int2)(pos_x, pos_y * 2 + 1))))); + float8 uv = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_uv, sampler, (int2)(pos_x, pos_y))))) - 128.0f; + + uv_r.even = -0.001f * uv.even + 1.402f * uv.odd; + uv_r.odd = uv_r.even; + uv_g.even = -0.344f * uv.even - 0.714f * uv.odd; + uv_g.odd = uv_g.even; + uv_b.even = 1.772f * uv.even + 0.001f * uv.odd; + uv_b.odd = uv_b.even; + +#pragma unroll + for (int i = 0; i < 2; ++i) { + r = y[i] + uv_r; + g = y[i] + uv_g; + b = y[i] + uv_b; + r = clamp (r, 0.0f, 255.0f); + g = clamp (g, 0.0f, 255.0f); + b = clamp (b, 0.0f, 255.0f); + + pos = (int2)(pos_x, 2 * pos_y + i); + + ret = convert_uint4(as_ushort4(convert_uchar8(r))); + write_imageui(output_r, pos, ret); + ret = convert_uint4(as_ushort4(convert_uchar8(g))); + write_imageui(output_g, pos, ret); + ret = convert_uint4(as_ushort4(convert_uchar8(b))); + write_imageui(output_b, pos, ret); + + r = min (r, g); + r = min (r, b); + ret = convert_uint4(as_ushort4(convert_uchar8(r))); + write_imageui(out_dark_channel, pos, ret); + } + +} + + +/* + * function: kernel_defog_recover + * input_dark: dark channel image2d_t as read only + * max_v: atmospheric light + * input_r: R channel image2d_t as read only + * input_g: G channel image2d_t as read only + * input_b: B channel image2d_t as read only + * output_y: Y channel image2d_t as write only + * output_uv: uv channel image2d_t as write only + * + * data_type CL_UNSIGNED_INT16 + * channel_order CL_RGBA + */ + +#define transmit_map_coeff 0.95f + +__kernel void kernel_defog_recover ( + __read_only image2d_t input_dark, float max_v, float max_r, float max_g, float max_b, + __read_only image2d_t input_r, __read_only image2d_t input_g, __read_only image2d_t input_b, + __write_only image2d_t out_y, __write_only image2d_t output_uv) +{ + int g_id_x = get_global_id (0); + int g_id_y = get_global_id (1); + int pos_x = g_id_x; + int pos_y = g_id_y * 2; + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + float8 in_r[2], in_g[2], in_b[2]; + float8 transmit_map[2]; + float8 out_data; + + in_r[0] = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_r, sampler, (int2)(pos_x, pos_y))))); + in_r[1] = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_r, sampler, (int2)(pos_x, pos_y + 1))))); + in_g[0] = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_g, sampler, (int2)(pos_x, pos_y))))); + in_g[1] = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_g, sampler, (int2)(pos_x, pos_y + 1))))); + in_b[0] = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_b, sampler, (int2)(pos_x, pos_y))))); + in_b[1] = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_b, sampler, (int2)(pos_x, pos_y + 1))))); + transmit_map[0] = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_dark, sampler, (int2)(pos_x, pos_y))))); + transmit_map[1] = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_dark, sampler, (int2)(pos_x, pos_y + 1))))); + + transmit_map[0] = 1.0f - transmit_map_coeff * transmit_map[0] / max_v; + transmit_map[1] = 1.0f - transmit_map_coeff * transmit_map[1] / max_v; + + transmit_map[0] = max (transmit_map[0], 0.1f); + transmit_map[1] = max (transmit_map[1], 0.1f); + + float8 gain = 2.0f; // adjust the brightness temporarily + in_r[0] = (max_r + (in_r[0] - max_r) / transmit_map[0]) * gain; + in_r[1] = (max_r + (in_r[1] - max_r) / transmit_map[1]) * gain; + in_g[0] = (max_g + (in_g[0] - max_g) / transmit_map[0]) * gain; + in_g[1] = (max_g + (in_g[1] - max_g) / transmit_map[1]) * gain; + in_b[0] = (max_b + (in_b[0] - max_b) / transmit_map[0]) * gain; + in_b[1] = (max_b + (in_b[1] - max_b) / transmit_map[1]) * gain; + + out_data = 0.299f * in_r[0] + 0.587f * in_g[0] + 0.114f * in_b[0]; + out_data = clamp (out_data, 0.0f, 255.0f); + write_imageui(out_y, (int2)(pos_x, pos_y), convert_uint4(as_ushort4(convert_uchar8(out_data)))); + out_data = 0.299f * in_r[1] + 0.587f * in_g[1] + 0.114f * in_b[1]; + out_data = clamp (out_data, 0.0f, 255.0f); + write_imageui(out_y, (int2)(pos_x, pos_y + 1), convert_uint4(as_ushort4(convert_uchar8(out_data)))); + + float4 r, g, b; + r = (in_r[0].even + in_r[0].odd + in_r[1].even + in_r[1].odd) * 0.25f; + g = (in_g[0].even + in_g[0].odd + in_g[1].even + in_g[1].odd) * 0.25f; + b = (in_b[0].even + in_b[0].odd + in_b[1].even + in_b[1].odd) * 0.25f; + out_data.even = (-0.169f * r - 0.331f * g + 0.5f * b) + 128.0f; + out_data.odd = (0.5f * r - 0.419f * g - 0.081f * b) + 128.0f; + out_data = clamp (out_data, 0.0f, 255.0f); + write_imageui(output_uv, (int2)(g_id_x, g_id_y), convert_uint4(as_ushort4(convert_uchar8(out_data)))); +} + diff --git a/cl_kernel/kernel_demo.cl b/cl_kernel/kernel_demo.cl new file mode 100644 index 0000000..161e6e6 --- /dev/null +++ b/cl_kernel/kernel_demo.cl @@ -0,0 +1,18 @@ +/* + * function: kernel_demo + * sample code of default kernel arguments + * input: image2d_t as read only + * output: image2d_t as write only + */ + +__kernel void kernel_demo (__read_only image2d_t input, __write_only image2d_t output) +{ + int x = get_global_id (0); + int y = get_global_id (1); + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; + + int2 pos = (int2)(x, y); + uint4 pixel = read_imageui(input, sampler, pos); + write_imageui(output, pos, pixel); +} + diff --git a/cl_kernel/kernel_fisheye.cl b/cl_kernel/kernel_fisheye.cl new file mode 100644 index 0000000..3b3f5b5 --- /dev/null +++ b/cl_kernel/kernel_fisheye.cl @@ -0,0 +1,121 @@ +/* + * kernel_fisheye_2_gps + * input_y, input image, CL_R + CL_UNORM_INT8 //sampler + * input_uv, CL_RG + CL_UNORM_INT8 //sampler + * output_y, CL_RGBA + CL_UNSIGNED_INT8, // 4-pixel + * output_uv, CL_RGBA + CL_UNSIGNED_INT8, // 4-pixel + * + * all angles are in radian + */ + +#define PI 3.1415926f +#define PIXEL_PER_WI 4 + +typedef struct { + float center_x; + float center_y; + float wide_angle; + float radius; + float rotate_angle; +} FisheyeInfo; + +__inline float2 calculate_fisheye_pos (float2 gps_pos, const FisheyeInfo *info) +{ + float z = cos (gps_pos.y); + float x = sin (gps_pos.y) * cos (gps_pos.x); + float y = sin (gps_pos.y) * sin (gps_pos.x); + float r_angle = acos (y); + float r = r_angle * (info->radius * 2.0f) / info->wide_angle; + float xz_size = sqrt(x * x + z * z); + + float2 dst; + dst.x = -r * x / xz_size; + dst.y = -r * z / xz_size; + + float2 ret; + ret.x = cos(info->rotate_angle) * dst.x - sin(info->rotate_angle) * dst.y; + ret.y = sin(info->rotate_angle) * dst.x + cos (info->rotate_angle) * dst.y; + + return ret + (float2)(info->center_x, info->center_y); +} + +__kernel void +kernel_fisheye_table ( + const FisheyeInfo info, const float2 fisheye_image_size, + __write_only image2d_t table, const float2 radian_per_pixel, const float2 table_center) +{ + int2 out_pos = (int2)(get_global_id (0), get_global_id (1)); + float2 gps_pos = (convert_float2 (out_pos) - table_center) * radian_per_pixel + PI / 2.0f; + float2 pos = calculate_fisheye_pos (gps_pos, &info); + float2 min_pos = (float2)(info.center_x - info.radius, info.center_y - info.radius); + float2 max_pos = (float2)(info.center_x + info.radius, info.center_y + info.radius); + pos = clamp (pos, min_pos, max_pos); + pos /= fisheye_image_size; + write_imagef (table, out_pos, (float4)(pos, 0.0f, 0.0f)); +} + +__kernel void +kernel_lsc_table ( + __read_only image2d_t geo_table, __write_only image2d_t lsc_table, + __global float *lsc_array, int array_size, const FisheyeInfo info, const float2 fisheye_image_size) +{ + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + int2 pos = (int2) (get_global_id (0), get_global_id (1)); + + float2 geo_data = read_imagef (geo_table, sampler, pos).xy * fisheye_image_size; + float2 dist = geo_data - (float2)(info.center_x, info.center_y); + float r = sqrt (dist.x * dist.x + dist.y * dist.y); + r /= (1.0f * info.radius / array_size); + + int min_idx = r; + int max_idx = r + 1.0f; + float lsc_data = max_idx > (array_size - 1) ? lsc_array[array_size - 1] : + (r - min_idx) * (lsc_array[max_idx] - lsc_array[min_idx]) + lsc_array[min_idx]; + + write_imagef (lsc_table, pos, (float4)(lsc_data, 0.0f, 0.0f, 1.0f)); +} + +__kernel void +kernel_fisheye_2_gps ( + __read_only image2d_t input_y, __read_only image2d_t input_uv, + const float2 input_y_size, const FisheyeInfo info, + __write_only image2d_t output_y, __write_only image2d_t output_uv, + const float2 dst_center, const float2 radian_per_pixel) +{ + const int g_x = get_global_id (0); + const int g_y_uv = get_global_id (1); + const int g_y = get_global_id (1) * 2; + float2 src_pos[4]; + float4 src_data; + float *src_ptr = (float*)(&src_data); + sampler_t sampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR; + + float2 gps_start_pos = + (convert_float2((int2)(g_x * PIXEL_PER_WI, g_y)) - dst_center) * radian_per_pixel + PI / 2.0f; + float2 gps_pos = gps_start_pos; + +#pragma unroll + for (int i = 0; i < PIXEL_PER_WI; ++i) { + float2 pos = calculate_fisheye_pos (gps_pos, &info); + src_pos[i] = pos / input_y_size; + src_ptr[i] = read_imagef (input_y, sampler, src_pos[i]).x; + gps_pos.x += radian_per_pixel.x; + } + write_imageui (output_y, (int2)(g_x, g_y), convert_uint4(convert_uchar4(src_data * 255.0f))); + + src_data.s01 = read_imagef (input_uv, sampler, src_pos[0]).xy; + src_data.s23 = read_imagef (input_uv, sampler, src_pos[2]).xy; + write_imageui (output_uv, (int2)(g_x, g_y_uv), convert_uint4(convert_uchar4(src_data * 255.0f))); + + gps_pos = gps_start_pos; + gps_pos.y += radian_per_pixel.y; +#pragma unroll + for (int i = 0; i < PIXEL_PER_WI; ++i) { + float2 pos = calculate_fisheye_pos (gps_pos, &info); + pos /= input_y_size; + src_ptr[i] = read_imagef (input_y, sampler, pos).x; + gps_pos.x += radian_per_pixel.x; + } + write_imageui (output_y, (int2)(g_x, g_y + 1), convert_uint4(convert_uchar4(src_data * 255.0f))); + +} diff --git a/cl_kernel/kernel_gauss.cl b/cl_kernel/kernel_gauss.cl new file mode 100644 index 0000000..4e66d48 --- /dev/null +++ b/cl_kernel/kernel_gauss.cl @@ -0,0 +1,58 @@ +/* + * function: kernel_gauss + * input: image2d_t as read only + * output: image2d_t as write only + * workitem = 4x2 pixel ouptut + * GAUSS_RADIUS must be defined in build options. + */ + +#ifndef GAUSS_RADIUS +#define GAUSS_RADIUS 2 +#endif + +#define GAUSS_SCALE (2 * GAUSS_RADIUS + 1) + +__kernel void kernel_gauss (__read_only image2d_t input, __write_only image2d_t output, __global float *table) +{ + int x = get_global_id (0); + int y = get_global_id (1); + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + float4 in1; + int i, j; + int index; + float4 out1 = (float4)(0.0f, 0.0f, 0.0f, 0.0f); + float4 out2 = (float4)(0.0f, 0.0f, 0.0f, 0.0f); + + for(i = 0; i < GAUSS_SCALE + 1; i++) + for(j = 0; j < GAUSS_SCALE + 3; j++) { + in1 = read_imagef (input, sampler, (int2)(4 * x - GAUSS_RADIUS + j, 2 * y - GAUSS_RADIUS + i)); + //first line + if (i < GAUSS_SCALE) { + index = i * GAUSS_SCALE + j; + out1.x += (j < GAUSS_SCALE ? table[index] * in1.x : 0.0f); + index -= 1; + out1.y += ((j < GAUSS_SCALE + 1) && j > 0 ? table[index] * in1.x : 0.0f); + index -= 1; + out1.z += ((j < GAUSS_SCALE + 2) && j > 1 ? table[index] * in1.x : 0.0f); + index -= 1; + out1.w += (j > 2 ? table[index] * in1.x : 0.0f); + } + //second line + if (i > 0) { + index = (i - 1) * GAUSS_SCALE + j; + out2.x += (j < GAUSS_SCALE ? table[index] * in1.x : 0.0f); + index -= 1; + out2.y += ((j < GAUSS_SCALE + 1) && j > 0 ? table[index] * in1.x : 0.0f); + index -= 1; + out2.z += ((j < GAUSS_SCALE + 2) && j > 1 ? table[index] * in1.x : 0.0f); + index -= 1; + out2.w += (j > 2 ? table[index] * in1.x : 0.0f); + } + } + + write_imagef(output, (int2)(x, 2 * y), out1); + write_imagef(output, (int2)(x, 2 * y + 1), out2); + +} + diff --git a/cl_kernel/kernel_gauss_lap_pyramid.cl b/cl_kernel/kernel_gauss_lap_pyramid.cl new file mode 100644 index 0000000..b983b57 --- /dev/null +++ b/cl_kernel/kernel_gauss_lap_pyramid.cl @@ -0,0 +1,614 @@ +/* + * kernel_gauss_lap_pyramid.cl + * input0 + * input1 + * output + * window, pos_x, pos_y, width, height + */ + +#ifndef PYRAMID_UV +#define PYRAMID_UV 0 +#endif + +#ifndef CL_PYRAMID_ENABLE_DUMP +#define CL_PYRAMID_ENABLE_DUMP 0 +#endif + +#ifndef ENABLE_MASK_GAUSS_SCALE +#define ENABLE_MASK_GAUSS_SCALE 0 +#endif + +#define fixed_pixels 8 +#define GAUSS_V_R 2 +#define GAUSS_H_R 1 +#define COEFF_MID 4 + +#define zero8 (float8)(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f) + +__constant const float coeffs[9] = {0.0f, 0.0f, 0.152f, 0.222f, 0.252f, 0.222f, 0.152f, 0.0f, 0.0f}; + +#define ARG_FORMAT4 "(%.1f,%.1f,%.1f,%.1f)" +#define ARGS4(a) a.s0, a.s1, a.s2, a.s3 + +#define ARG_FORMAT8 "(%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f)" +#define ARGS8(a) a.s0, a.s1, a.s2, a.s3, a.s4, a.s5, a.s6, a.s7 + +/* + * input: RGBA-CL_UNSIGNED_INT16 + * output_gauss: RGBA-CL_UNSIGNED_INT8 + * output_lap:RGBA-CL_UNSIGNED_INT16 + * each work-item calc 2 lines + */ +__kernel void +kernel_gauss_scale_transform ( + __read_only image2d_t input, int in_offset_x, + __write_only image2d_t output_gauss +#if CL_PYRAMID_ENABLE_DUMP + , __write_only image2d_t dump_orig +#endif +) +{ + int g_x = get_global_id (0); + int in_x = g_x + in_offset_x; + int g_y = get_global_id (1) * 4; + const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + int g_out_x = get_global_id (0); + int g_out_y = get_global_id (1) * 2; + +#if CL_PYRAMID_ENABLE_DUMP + write_imageui (dump_orig, (int2)(g_x, g_y + 0), read_imageui(input, sampler, (int2)(in_x, g_y))); + write_imageui (dump_orig, (int2)(g_x, g_y + 1), read_imageui(input, sampler, (int2)(in_x, g_y + 1))); + write_imageui (dump_orig, (int2)(g_x, g_y + 2), read_imageui(input, sampler, (int2)(in_x, g_y + 2))); + write_imageui (dump_orig, (int2)(g_x, g_y + 3), read_imageui(input, sampler, (int2)(in_x, g_y + 3))); +#endif + + float8 result_pre[2] = {zero8, zero8}; + float8 result_next[2] = {zero8, zero8}; + float8 result_cur[2] = {zero8, zero8}; + float4 final_g[2]; + + float8 tmp_data; + int i_ver; + +#pragma unroll + for (i_ver = -GAUSS_V_R; i_ver <= GAUSS_V_R + 2; i_ver++) { + int cur_g_y = g_y + i_ver; + float coeff0 = coeffs[i_ver + COEFF_MID]; + float coeff1 = coeffs[i_ver + COEFF_MID - 2]; + tmp_data = convert_float8(as_uchar8(convert_ushort4(read_imageui(input, sampler, (int2)(in_x - 1, cur_g_y))))); + result_pre[0] += tmp_data * coeff0; + result_pre[1] += tmp_data * coeff1; + tmp_data = convert_float8(as_uchar8(convert_ushort4(read_imageui(input, sampler, (int2)(in_x, cur_g_y))))); + result_cur[0] += tmp_data * coeff0; + result_cur[1] += tmp_data * coeff1; + tmp_data = convert_float8(as_uchar8(convert_ushort4(read_imageui(input, sampler, (int2)(in_x + 1, cur_g_y))))); + result_next[1] += tmp_data * coeff1; + result_next[0] += tmp_data * coeff0; + } + + int i_line; +#pragma unroll + for (i_line = 0; i_line < 2; ++i_line) { +#if !PYRAMID_UV + final_g[i_line] = result_cur[i_line].even * coeffs[COEFF_MID] + + (float4)(result_pre[i_line].s7, result_cur[i_line].s135) * coeffs[COEFF_MID + 1] + + (float4)(result_pre[i_line].s6, result_cur[i_line].s024) * coeffs[COEFF_MID + 2] + + (float4)(result_cur[i_line].s1357) * coeffs[COEFF_MID + 1] + + (float4)(result_cur[i_line].s246, result_next[i_line].s0) * coeffs[COEFF_MID + 2]; +#else + final_g[i_line] = result_cur[i_line].s0145 * coeffs[COEFF_MID] + + (float4)(result_pre[i_line].s67, result_cur[i_line].s23) * coeffs[COEFF_MID + 1] + + (float4)(result_pre[i_line].s45, result_cur[i_line].s01) * coeffs[COEFF_MID + 2] + + (float4)(result_cur[i_line].s2367) * coeffs[COEFF_MID + 1] + + (float4)(result_cur[i_line].s45, result_next[i_line].s01) * coeffs[COEFF_MID + 2]; +#endif + final_g[i_line] = clamp (final_g[i_line] + 0.5f, 0.0f, 255.0f); + write_imageui (output_gauss, (int2)(g_out_x, g_out_y + i_line), convert_uint4(final_g[i_line])); + } + +} + +inline float8 +read_scale_y (__read_only image2d_t input, const sampler_t sampler, float2 pos_start, float step_x) +{ + float8 data; + data.s0 = read_imagef (input, sampler, pos_start).x; + pos_start.x += step_x; + data.s1 = read_imagef (input, sampler, pos_start).x; + pos_start.x += step_x; + data.s2 = read_imagef (input, sampler, pos_start).x; + pos_start.x += step_x; + data.s3 = read_imagef (input, sampler, pos_start).x; + pos_start.x += step_x; + data.s4 = read_imagef (input, sampler, pos_start).x; + pos_start.x += step_x; + data.s5 = read_imagef (input, sampler, pos_start).x; + pos_start.x += step_x; + data.s6 = read_imagef (input, sampler, pos_start).x; + pos_start.x += step_x; + data.s7 = read_imagef (input, sampler, pos_start).x; + return data; +} + +inline float8 +read_scale_uv (__read_only image2d_t input, const sampler_t sampler, float2 pos_start, float step_x) +{ + float8 data; + data.s01 = read_imagef (input, sampler, pos_start).xy; + pos_start.x += step_x; + data.s23 = read_imagef (input, sampler, pos_start).xy; + pos_start.x += step_x; + data.s45 = read_imagef (input, sampler, pos_start).xy; + pos_start.x += step_x; + data.s67 = read_imagef (input, sampler, pos_start).xy; + return data; +} + +/* + * input_gauss: RGBA-CL_UNSIGNED_INT18 + * input_lap: RGBA-CL_UNSIGNED_INT16 + * output: RGBA-CL_UNSIGNED_INT16 + * each work-item calc 2 lines + */ +__kernel void +kernel_gauss_lap_reconstruct ( + __read_only image2d_t input_gauss, + float in_sampler_offset_x, float in_sampler_offset_y, + __read_only image2d_t input_lap, + __write_only image2d_t output, int out_offset_x, float out_width, float out_height +#if CL_PYRAMID_ENABLE_DUMP + , __write_only image2d_t dump_resize, __write_only image2d_t dump_final +#endif +) +{ + int g_x = get_global_id (0); + int g_y = get_global_id (1); + const sampler_t lap_sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + const sampler_t gauss_sampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR; + + //if (g_x > out_width + 0.9f || g_y > out_height + 0.5f) + // return; + + float8 lap = convert_float8(as_uchar8(convert_ushort4(read_imageui(input_lap, lap_sampler, (int2)(g_x, g_y))))); + lap = (lap - 128.0f) * 2.0f; + + float8 data_g; + float2 input_gauss_pos; + float step_x; + input_gauss_pos.x = g_x / out_width + in_sampler_offset_x; + input_gauss_pos.y = g_y / out_height + in_sampler_offset_y; +#if !PYRAMID_UV + step_x = 0.125f / out_width; + data_g = read_scale_y (input_gauss, gauss_sampler, input_gauss_pos, step_x) * 256.0f; +#else + step_x = 0.25f / out_width; + data_g = read_scale_uv (input_gauss, gauss_sampler, input_gauss_pos, step_x) * 256.0f; +#endif + +#if CL_PYRAMID_ENABLE_DUMP + write_imageui (dump_resize, (int2)(g_x, g_y), convert_uint4(as_ushort4(convert_uchar8(data_g)))); +#endif + + data_g += lap + 0.5f; + data_g = clamp (data_g, 0.0f, 255.0f); + write_imageui (output, (int2)(g_x + out_offset_x, g_y), convert_uint4(as_ushort4(convert_uchar8(data_g)))); +#if CL_PYRAMID_ENABLE_DUMP + write_imageui (dump_final, (int2)(g_x, g_y), convert_uint4(as_ushort4(convert_uchar8(data_g)))); +#endif +} + +__kernel void +kernel_pyramid_blend ( + __read_only image2d_t input0, __read_only image2d_t input1, +#if !PYRAMID_UV + __global const float8 *input0_mask, +#else + __global const float4 *input0_mask, +#endif + __write_only image2d_t output) +{ + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + const int g_x = get_global_id (0); + const int g_y = get_global_id (1); + int2 pos = (int2) (g_x, g_y); + + float8 data0 = convert_float8(as_uchar8(convert_ushort4(read_imageui(input0, sampler, pos)))); + float8 data1 = convert_float8(as_uchar8(convert_ushort4(read_imageui(input1, sampler, pos)))); + float8 out_data; + +#if !PYRAMID_UV + out_data = (data0 - data1) * input0_mask[g_x] + data1; +#else + float8 coeff; + coeff.even = input0_mask[g_x]; + coeff.odd = coeff.even; + out_data = (data0 - data1) * coeff + data1; +#endif + + out_data = clamp (out_data + 0.5f, 0.0f, 255.0f); + + write_imageui(output, pos, convert_uint4(as_ushort4(convert_uchar8(out_data)))); +} + +__kernel void +kernel_pyramid_scale ( + __read_only image2d_t input, __write_only image2d_t output, + int out_offset_x, int output_width, int output_height) +{ + const sampler_t sampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR; + int g_x = get_global_id (0); + int g_y = get_global_id (1); + + float2 normCoor = (float2)(g_x, g_y) / (float2)(output_width, output_height); + float8 out_data; + float step_x; + +#if !PYRAMID_UV + step_x = 0.125f / output_width; + out_data = read_scale_y (input, sampler, normCoor, step_x) * 255.0f; +#else + step_x = 0.25f / output_width; + out_data = read_scale_uv (input, sampler, normCoor, step_x) * 255.0f; +#endif + + out_data = clamp (out_data + 0.5f, 0.0f, 255.0f); + write_imageui (output, (int2)(g_x + out_offset_x, g_y), convert_uint4(as_ushort4(convert_uchar8(out_data)))); +} + +__kernel void +kernel_pyramid_copy ( + __read_only image2d_t input, int in_offset_x, + __write_only image2d_t output, int out_offset_x, + int max_g_x, int max_g_y) +{ + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + const int g_x = get_global_id (0); + const int g_y = get_global_id (1); + + if (g_x >= max_g_x || g_y >= max_g_y) + return; + + uint4 data = read_imageui (input, sampler, (int2)(g_x + in_offset_x, g_y)); + write_imageui (output, (int2)(g_x + out_offset_x, g_y), data); +} + +/* + * input_gauss: RGBA-CL_UNSIGNED_INT18 + * input_lap: RGBA-CL_UNSIGNED_INT16 + * output: RGBA-CL_UNSIGNED_INT16 + * each work-item calc 2 lines + */ +__kernel void +kernel_lap_transform ( + __read_only image2d_t input_gauss0, int gauss0_offset_x, + __read_only image2d_t input_gauss1, + float gauss1_sampler_offset_x, float gauss1_sampler_offset_y, + __write_only image2d_t output, int lap_offset_x, float out_width, float out_height) +{ + int g_x = get_global_id (0); + int g_y = get_global_id (1); + const sampler_t gauss0_sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + const sampler_t gauss1_sampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR; + + float8 orig = convert_float8(as_uchar8(convert_ushort4( + read_imageui(input_gauss0, gauss0_sampler, (int2)(g_x + gauss0_offset_x, g_y))))); + float8 zoom_in; + float2 gauss1_pos; + float sampler_step; + gauss1_pos.y = (g_y / out_height) + gauss1_sampler_offset_y; + gauss1_pos.x = (g_x / out_width) + gauss1_sampler_offset_x; + +#if !PYRAMID_UV + sampler_step = 0.125f / out_width; + zoom_in.s0 = read_imagef (input_gauss1, gauss1_sampler, gauss1_pos).x; + gauss1_pos.x += sampler_step; + zoom_in.s1 = read_imagef (input_gauss1, gauss1_sampler, gauss1_pos).x; + gauss1_pos.x += sampler_step; + zoom_in.s2 = read_imagef (input_gauss1, gauss1_sampler, gauss1_pos).x; + gauss1_pos.x += sampler_step; + zoom_in.s3 = read_imagef (input_gauss1, gauss1_sampler, gauss1_pos).x; + gauss1_pos.x += sampler_step; + zoom_in.s4 = read_imagef (input_gauss1, gauss1_sampler, gauss1_pos).x; + gauss1_pos.x += sampler_step; + zoom_in.s5 = read_imagef (input_gauss1, gauss1_sampler, gauss1_pos).x; + gauss1_pos.x += sampler_step; + zoom_in.s6 = read_imagef (input_gauss1, gauss1_sampler, gauss1_pos).x; + gauss1_pos.x += sampler_step; + zoom_in.s7 = read_imagef (input_gauss1, gauss1_sampler, gauss1_pos).x; +#else + sampler_step = 0.25f / out_width; + zoom_in.s01 = read_imagef (input_gauss1, gauss1_sampler, gauss1_pos).xy; + gauss1_pos.x += sampler_step; + zoom_in.s23 = read_imagef (input_gauss1, gauss1_sampler, gauss1_pos).xy; + gauss1_pos.x += sampler_step; + zoom_in.s45 = read_imagef (input_gauss1, gauss1_sampler, gauss1_pos).xy; + gauss1_pos.x += sampler_step; + zoom_in.s67 = read_imagef (input_gauss1, gauss1_sampler, gauss1_pos).xy; +#endif + float8 lap = (orig - zoom_in * 256.0f) * 0.5f + 128.0f + 0.5f; + lap = clamp (lap, 0.0f, 255.0f); + write_imageui (output, (int2)(g_x + lap_offset_x, g_y), convert_uint4(as_ushort4(convert_uchar8(lap)))); +} + + +/* + * input0: RGBA-CL_UNSIGNED_INT16 + * input1: RGBA-CL_UNSIGNED_INT16 + * out_diff: RGBA-CL_UNSIGNED_INT16 + */ +__kernel void +kernel_image_diff ( + __read_only image2d_t input0, int offset0, + __read_only image2d_t input1, int offset1, + __write_only image2d_t out_diff) +{ + int g_x = get_global_id (0); + int g_y = get_global_id (1); + const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + int8 data0 = convert_int8(as_uchar8(convert_ushort4(read_imageui(input0, sampler, (int2)(g_x + offset0, g_y))))); + int8 data1 = convert_int8(as_uchar8(convert_ushort4(read_imageui(input1, sampler, (int2)(g_x + offset1, g_y))))); + uint8 diff = abs_diff (data0, data1); + write_imageui (out_diff, (int2)(g_x, g_y), convert_uint4(as_ushort4(convert_uchar8(diff)))); +} + + +/* + * input0: RGBA-CL_UNSIGNED_INT16 + */ +#define LEFT_POS (int)(-1) +#define MID_POS (int)(0) +#define RIGHT_POS (int)(1) + +__inline int pos_buf_index (int x, int y, int stride) +{ + return mad24 (stride, y, x); +} + +__kernel void +kernel_seam_dp ( + __read_only image2d_t image, + __global short *pos_buf, __global float *sum_buf, int offset_x, int valid_width, + int max_pos, int seam_height, int seam_stride) +{ + int l_x = get_local_id (0); + int group_id = get_group_id (0); + if (l_x >= valid_width) + return; + + // group0 fill first half slice image curve y = [0, seam_height/2 - 1] + // group1 fill send half slice image curve = [seam_height - 1, seam_height/2] + int first_slice_h = seam_height / 2; + int group_h = (group_id == 0 ? first_slice_h : seam_height - first_slice_h); + + __local float slm_sum[4096]; + float mid, left, right, cur; + int slm_idx; + int default_pos; + + int x = l_x + offset_x; + const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + int y = (group_id == 0 ? 0 : seam_height - 1); + float sum = convert_float(read_imageui(image, sampler, (int2)(x, y)).x); + + default_pos = x; + slm_sum[l_x] = sum; + barrier (CLK_LOCAL_MEM_FENCE); + pos_buf[pos_buf_index(x, y, seam_stride)] = convert_short(default_pos); + + for (int i = 0; i < group_h; ++i) { + y = (group_id == 0 ? i : seam_height - i - 1); + slm_idx = l_x - 1; + slm_idx = (slm_idx > 0 ? slm_idx : 0); + left = slm_sum[slm_idx]; + slm_idx = l_x + 1; + slm_idx = (slm_idx < valid_width ? slm_idx : valid_width - 1); + right = slm_sum[slm_idx]; + + cur = convert_float(read_imageui(image, sampler, (int2)(x, y)).x); + + left = left + cur; + right = right + cur; + mid = sum + cur; + + int pos; + pos = (left < mid) ? LEFT_POS : MID_POS; + sum = min (left, mid); + pos = (sum < right) ? pos : RIGHT_POS; + sum = min (sum, right); + slm_sum[l_x] = sum; + barrier (CLK_LOCAL_MEM_FENCE); + + pos += default_pos; + pos = clamp (pos, offset_x, max_pos); + //if (l_x == 3) + // printf ("s:%f, pos:%d, mid:%f, offset_x:%d\n", sum.s0, pos.s0, mid.s0, offset_x); + pos_buf[pos_buf_index(x, y, seam_stride)] = convert_short(pos); + } + sum_buf[group_id * seam_stride + x] = sum; + //printf ("sum(x):%f(x:%d)\n", sum_buf[x].s0, x); +} + +__kernel void +kernel_seam_mask_blend ( + __read_only image2d_t input0, __read_only image2d_t input1, + __read_only image2d_t seam_mask, + __write_only image2d_t output) +{ + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + const int g_x = get_global_id (0); + const int g_y = get_global_id (1); + int2 pos = (int2) (g_x, g_y); + + float8 data0 = convert_float8(as_uchar8(convert_ushort4(read_imageui(input0, sampler, pos)))); + float8 data1 = convert_float8(as_uchar8(convert_ushort4(read_imageui(input1, sampler, pos)))); + float8 coeff0 = convert_float8(as_uchar8(convert_ushort4(read_imageui(seam_mask, sampler, pos)))) / 255.0f; + float8 out_data; + +#if !PYRAMID_UV + out_data = (data0 - data1) * coeff0 + data1; +#else + coeff0.even = (coeff0.even + coeff0.odd) * 0.5f; + coeff0.odd = coeff0.even; + out_data = (data0 - data1) * coeff0 + data1; +#endif + + out_data = clamp (out_data + 0.5f, 0.0f, 255.0f); + + write_imageui(output, pos, convert_uint4(as_ushort4(convert_uchar8(out_data)))); +} + + + +#define MASK_GAUSS_R 4 +#define MASK_COEFF_MID 7 + +__constant const float mask_coeffs[] = {0.0f, 0.0f, 0.0f, 0.082f, 0.102f, 0.119f, 0.130f, 0.134f, 0.130f, 0.119f, 0.102f, 0.082f, 0.0f, 0.0f, 0.0f}; + +/* + * input: RGBA-CL_UNSIGNED_INT16 + * output_gauss: RGBA-CL_UNSIGNED_INT8 ? + * output_lap:RGBA-CL_UNSIGNED_INT16 + * each work-item calc 2 lines + */ +__kernel void +kernel_mask_gauss_scale_slm ( + __read_only image2d_t input, + __write_only image2d_t output_gauss, + int image_width +#if ENABLE_MASK_GAUSS_SCALE + , __write_only image2d_t output_scale +#endif +) +{ +#define WI_LINES 2 +// input image width MUST < MASK_GAUSS_SLM_WIDTH*4 +#define MASK_GAUSS_SLM_WIDTH 256 +#define CONV_COEFF 128.0f + + int g_x = get_global_id (0); + int g_y = get_global_id (1) * WI_LINES; + const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + __local ushort4 slm_gauss_y[WI_LINES][MASK_GAUSS_SLM_WIDTH]; + + float8 result_cur[WI_LINES] = {zero8, zero8}; + float8 tmp_data; + int i_line; + int cur_g_y; + +#pragma unroll + for (i_line = -MASK_GAUSS_R; i_line <= MASK_GAUSS_R + 1; i_line++) { + cur_g_y = g_y + i_line; + tmp_data = convert_float8(as_uchar8(convert_ushort4(read_imageui(input, sampler, (int2)(g_x, cur_g_y))))); + result_cur[0] += tmp_data * mask_coeffs[i_line + MASK_COEFF_MID]; + result_cur[1] += tmp_data * mask_coeffs[i_line + MASK_COEFF_MID - 1]; + } + ((__local ushort8*)(slm_gauss_y[0]))[g_x] = convert_ushort8(result_cur[0] * CONV_COEFF); + ((__local ushort8*)(slm_gauss_y[1]))[g_x] = convert_ushort8(result_cur[1] * CONV_COEFF); + barrier (CLK_LOCAL_MEM_FENCE); + + float8 final_g[WI_LINES]; + float4 result_pre; + float4 result_next; + +#pragma unroll + for (i_line = 0; i_line < WI_LINES; ++i_line) { + result_pre = convert_float4(slm_gauss_y[i_line][clamp (g_x * 2 - 1, 0, image_width * 2)]) / CONV_COEFF; + result_next = convert_float4(slm_gauss_y[i_line][clamp (g_x * 2 + 2, 0, image_width * 2)]) / CONV_COEFF; + final_g[i_line] = result_cur[i_line] * mask_coeffs[MASK_COEFF_MID] + + (float8)(result_pre.s3, result_cur[i_line].s0123, result_cur[i_line].s456) * + mask_coeffs[MASK_COEFF_MID + 1] + + (float8)(result_cur[i_line].s1234, result_cur[i_line].s567, result_next.s0) * + mask_coeffs[MASK_COEFF_MID + 1] + + (float8)(result_pre.s23, result_cur[i_line].s0123, result_cur[i_line].s45) * + mask_coeffs[MASK_COEFF_MID + 2] + + (float8)(result_cur[i_line].s2345, result_cur[i_line].s67, result_next.s01) * + mask_coeffs[MASK_COEFF_MID + 2] + + (float8)(result_pre.s123, result_cur[i_line].s0123, result_cur[i_line].s4) * + mask_coeffs[MASK_COEFF_MID + 3] + + (float8)(result_cur[i_line].s3456, result_cur[i_line].s7, result_next.s012) * + mask_coeffs[MASK_COEFF_MID + 3] + + (float8)(result_pre.s0123, result_cur[i_line].s0123) * mask_coeffs[MASK_COEFF_MID + 4] + + (float8)(result_cur[i_line].s4567, result_next.s0123) * mask_coeffs[MASK_COEFF_MID + 4]; + final_g[i_line] = clamp (final_g[i_line] + 0.5f, 0.0f, 255.0f); + //if ((g_x == 9 || g_x == 8) && g_y == 0) { + // printf ("(x:%d, y:0), pre:" ARG_FORMAT4 "cur" ARG_FORMAT8 "next" ARG_FORMAT4 "final:" ARG_FORMAT8 "\n", + // g_x, ARGS4(result_pre), ARGS8(result_cur[i_line]), ARGS4(result_next), ARGS8(final_g[i_line])); + //} + write_imageui (output_gauss, (int2)(g_x, g_y + i_line), convert_uint4(as_ushort4(convert_uchar8(final_g[i_line])))); + } + +#if ENABLE_MASK_GAUSS_SCALE + write_imageui (output_scale, (int2)(g_x, get_global_id (1)), convert_uint4(final_g[0].even)); +#endif +} + +__kernel void +kernel_mask_gauss_scale ( + __read_only image2d_t input, + __write_only image2d_t output_gauss +#if ENABLE_MASK_GAUSS_SCALE + , __write_only image2d_t output_scale +#endif +) +{ + int g_x = get_global_id (0); + int in_x = g_x; + int g_y = get_global_id (1) * 2; + const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + float8 result_pre[2] = {zero8, zero8}; + float8 result_next[2] = {zero8, zero8}; + float8 result_cur[2] = {zero8, zero8}; + float8 final_g[2]; + + float8 tmp_data; + int i_line; + int cur_g_y; + float coeff0, coeff1; + +#pragma unroll + for (i_line = -MASK_GAUSS_R; i_line <= MASK_GAUSS_R + 1; i_line++) { + cur_g_y = g_y + i_line; + coeff0 = mask_coeffs[i_line + MASK_COEFF_MID]; + coeff1 = mask_coeffs[i_line + MASK_COEFF_MID - 1]; + tmp_data = convert_float8(as_uchar8(convert_ushort4(read_imageui(input, sampler, (int2)(in_x - 1, cur_g_y))))); + result_pre[0] += tmp_data * coeff0; + result_pre[1] += tmp_data * coeff1; + + tmp_data = convert_float8(as_uchar8(convert_ushort4(read_imageui(input, sampler, (int2)(in_x, cur_g_y))))); + result_cur[0] += tmp_data * coeff0; + result_cur[1] += tmp_data * coeff1; + tmp_data = convert_float8(as_uchar8(convert_ushort4(read_imageui(input, sampler, (int2)(in_x + 1, cur_g_y))))); + result_next[1] += tmp_data * coeff1; + result_next[0] += tmp_data * coeff0; + } + +#pragma unroll + for (i_line = 0; i_line < 2; ++i_line) { + final_g[i_line] = result_cur[i_line] * mask_coeffs[MASK_COEFF_MID] + + (float8)(result_pre[i_line].s7, result_cur[i_line].s0123, result_cur[i_line].s456) * + mask_coeffs[MASK_COEFF_MID + 1] + + (float8)(result_cur[i_line].s1234, result_cur[i_line].s567, result_next[i_line].s0) * + mask_coeffs[MASK_COEFF_MID + 1] + + (float8)(result_pre[i_line].s67, result_cur[i_line].s0123, result_cur[i_line].s45) * + mask_coeffs[MASK_COEFF_MID + 2] + + (float8)(result_cur[i_line].s2345, result_cur[i_line].s67, result_next[i_line].s01) * + mask_coeffs[MASK_COEFF_MID + 2] + + (float8)(result_pre[i_line].s567, result_cur[i_line].s0123, result_cur[i_line].s4) * + mask_coeffs[MASK_COEFF_MID + 3] + + (float8)(result_cur[i_line].s3456,result_cur[i_line].s7, result_next[i_line].s012) * + mask_coeffs[MASK_COEFF_MID + 3] + + (float8)(result_pre[i_line].s4567, result_cur[i_line].s0123) * mask_coeffs[MASK_COEFF_MID + 4] + + (float8)(result_cur[i_line].s4567, result_next[i_line].s0123) * mask_coeffs[MASK_COEFF_MID + 4]; + final_g[i_line] = clamp (final_g[i_line] + 0.5f, 0.0f, 255.0f); + write_imageui (output_gauss, (int2)(g_x, g_y + i_line), convert_uint4(as_ushort4(convert_uchar8(final_g[i_line])))); + } + +#if ENABLE_MASK_GAUSS_SCALE + write_imageui (output_scale, (int2)(g_x, get_global_id (1)), convert_uint4(final_g[0].even)); +#endif + +} + diff --git a/cl_kernel/kernel_geo_map.cl b/cl_kernel/kernel_geo_map.cl new file mode 100644 index 0000000..b696a40 --- /dev/null +++ b/cl_kernel/kernel_geo_map.cl @@ -0,0 +1,111 @@ +/* + * kernel_geo_map + * input_y, input image, CL_R + CL_UNORM_INT8 + * input_uv, CL_RG + CL_UNORM_INT8 + * geo_table, CL_RGBA + CL_FLOAT + * output_y, CL_RGBA + CL_UNSIGNED_INT16 + * output_uv, CL_RGBA + CL_UNSIGNED_INT16 + * + * description: + * the center of geo_table and output positons are both mapped to (0, 0) + */ + +#ifndef ENABLE_LSC +#define ENABLE_LSC 0 +#endif + +#define CONST_DATA_Y 0.0f +#define CONST_DATA_UV (float2)(0.5f, 0.5f) + +// 8 bytes for each pixel +#define PIXEL_RES_STEP_X 8 + +void get_geo_mapped_y ( + __read_only image2d_t input, + __read_only image2d_t geo_table, float2 table_pos, float step_x, + bool *out_of_bound, float2 *input_pos, float8 *out_y) +{ + sampler_t sampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR; + float *output_data = (float*)(out_y); + int i = 0; + + for (i = 0; i < PIXEL_RES_STEP_X; ++i) { + out_of_bound[i] = + (min (table_pos.x, table_pos.y) < 0.0f) || + (max (table_pos.x, table_pos.y) > 1.0f); + input_pos[i] = read_imagef (geo_table, sampler, table_pos).xy; + out_of_bound[i] = + out_of_bound[i] || + (min (input_pos[i].x, input_pos[i].y) < 0.0f) || + (max (input_pos[i].x, input_pos[i].y) > 1.0f); + //need convert input_pos to (0.0 ~ 1.0)???? + output_data[i] = out_of_bound[i] ? CONST_DATA_Y : read_imagef (input, sampler, input_pos[i]).x; + table_pos.x += step_x; + } +} + +void get_lsc_data ( + image2d_t lsc_table, int2 g_pos, float step_x, + float2 gray_threshold, float8 output, float8 *lsc_data) +{ + sampler_t sampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR; + float *lsc_ptr = (float *)(lsc_data); + + float2 pos = convert_float2((int2)(g_pos.x * PIXEL_RES_STEP_X, g_pos.y)) * step_x; + for (int i = 0; i < PIXEL_RES_STEP_X; ++i) { + lsc_ptr[i] = read_imagef (lsc_table, sampler, pos).x; + pos.x += step_x; + } + + float8 diff_ratio = (gray_threshold.y - output * 255.0f) / (gray_threshold.y - gray_threshold.x); + diff_ratio = clamp (diff_ratio, 0.0f, 1.0f); + (*lsc_data) = diff_ratio * diff_ratio * ((*lsc_data) - 1.0f) + 1.0f; +} + +__kernel void +kernel_geo_map ( + __read_only image2d_t input_y, __read_only image2d_t input_uv, + __read_only image2d_t geo_table, float2 table_scale_size, +#if ENABLE_LSC + __read_only image2d_t lsc_table, float2 gray_threshold, +#endif + __write_only image2d_t output_y, __write_only image2d_t output_uv, float2 out_size) +{ + const int g_x = get_global_id (0); + const int g_y_uv = get_global_id (1); + const int g_y = get_global_id (1) * 2; + float8 output_data; + float2 from_pos; + bool out_of_bound[8]; + float2 input_pos[8]; + // map to [-0.5, 0.5) + float2 table_scale_step = 1.0f / table_scale_size; + float2 out_map_pos; + sampler_t sampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR; + + out_map_pos = (convert_float2((int2)(g_x * PIXEL_RES_STEP_X, g_y)) - out_size / 2.0f) * table_scale_step + 0.5f; + + get_geo_mapped_y (input_y, geo_table, out_map_pos, table_scale_step.x, out_of_bound, input_pos, &output_data); + +#if ENABLE_LSC + float8 lsc_data; + get_lsc_data (lsc_table, (int2)(g_x, g_y), table_scale_step.x, gray_threshold, output_data, &lsc_data); + output_data = clamp (output_data * lsc_data, 0.0f, 1.0f); +#endif + write_imageui (output_y, (int2)(g_x, g_y), convert_uint4(as_ushort4(convert_uchar8(output_data * 255.0f)))); + + output_data.s01 = out_of_bound[0] ? CONST_DATA_UV : read_imagef (input_uv, sampler, input_pos[0]).xy; + output_data.s23 = out_of_bound[2] ? CONST_DATA_UV : read_imagef (input_uv, sampler, input_pos[2]).xy; + output_data.s45 = out_of_bound[4] ? CONST_DATA_UV : read_imagef (input_uv, sampler, input_pos[4]).xy; + output_data.s67 = out_of_bound[6] ? CONST_DATA_UV : read_imagef (input_uv, sampler, input_pos[6]).xy; + write_imageui (output_uv, (int2)(g_x, g_y_uv), convert_uint4(as_ushort4(convert_uchar8(output_data * 255.0f)))); + + out_map_pos.y += table_scale_step.y; + get_geo_mapped_y (input_y, geo_table, out_map_pos, table_scale_step.x, out_of_bound, input_pos, &output_data); + +#if ENABLE_LSC + get_lsc_data (lsc_table, (int2)(g_x, g_y + 1), table_scale_step.x, gray_threshold, output_data, &lsc_data); + output_data = clamp (output_data * lsc_data, 0.0f, 1.0f); +#endif + write_imageui (output_y, (int2)(g_x, g_y + 1), convert_uint4(as_ushort4(convert_uchar8(output_data * 255.0f)))); +} diff --git a/cl_kernel/kernel_image_scaler.cl b/cl_kernel/kernel_image_scaler.cl new file mode 100644 index 0000000..c6c1ca3 --- /dev/null +++ b/cl_kernel/kernel_image_scaler.cl @@ -0,0 +1,23 @@ +/** +* \brief Image scaling kernel function. +* \param[in] input Input image object. +* \param[out] output scaled output image object. +* \param[in] output_width: output width +* \param[in] output_height: output height +* \param[in] vertical_offset: vertical offset from y to uv +*/ +__kernel void kernel_image_scaler (__read_only image2d_t input, + __write_only image2d_t output, + const uint output_width, + const uint output_height) +{ + int x = get_global_id(0); + int y = get_global_id(1); + + const sampler_t sampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR; + + float2 normCoor = convert_float2((int2)(x, y)) / (float2)(output_width, output_height); + float4 scaled_pixel = read_imagef(input, sampler, normCoor); + write_imagef(output, (int2)(x, y), scaled_pixel); +} + diff --git a/cl_kernel/kernel_image_warp.cl b/cl_kernel/kernel_image_warp.cl new file mode 100644 index 0000000..22acd39 --- /dev/null +++ b/cl_kernel/kernel_image_warp.cl @@ -0,0 +1,122 @@ +/** +* \brief Image warping kernel function. +* \param[in] input Input image object. +* \param[out] output scaled output image object. +* \param[in] warp_config: image warping parameters +*/ + +#ifndef WARP_Y +#define WARP_Y 1 +#endif + +// 8 bytes for each Y pixel +#define PIXEL_X_STEP 8 + +typedef struct { + int frame_id; + int width; + int height; + float trim_ratio; + float proj_mat[9]; +} CLWarpConfig; + +__kernel void +kernel_image_warp_8_pixel ( + __read_only image2d_t input, + __write_only image2d_t output, + CLWarpConfig warp_config) +{ + // dest coordinate + int d_x = get_global_id(0); + int d_y = get_global_id(1); + + int out_width = get_image_width (output); + int out_height = get_image_height (output); + + const sampler_t sampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR; + + // source coordinate + float s_x = 0.0f; + float s_y = 0.0f; + float warp_x = 0.0f; + float warp_y = 0.0f; + float w = 0.0f; + + float t_x = 0.0f; + float t_y = 0.0f; + + float16 pixel = 0.0f; + float* output_pixel = (float*)(&pixel); + int i = 0; + + t_y = d_y; +#pragma unroll + for (i = 0; i < PIXEL_X_STEP; i++) { + t_x = (float)(PIXEL_X_STEP * d_x + i); + + s_x = warp_config.proj_mat[0] * t_x + + warp_config.proj_mat[1] * t_y + + warp_config.proj_mat[2]; + s_y = warp_config.proj_mat[3] * t_x + + warp_config.proj_mat[4] * t_y + + warp_config.proj_mat[5]; + w = warp_config.proj_mat[6] * t_x + + warp_config.proj_mat[7] * t_y + + warp_config.proj_mat[8]; + w = w != 0.0f ? 1.0f / w : 0.0f; + + warp_x = (s_x * w) / (float)(PIXEL_X_STEP * out_width); + warp_y = (s_y * w) / (float)out_height; + +#if WARP_Y + output_pixel[i] = read_imagef(input, sampler, (float2)(warp_x, warp_y)).x; +#else + float2 temp = read_imagef(input, sampler, (float2)(warp_x, warp_y)).xy; + output_pixel[2 * i] = temp.x; + output_pixel[2 * i + 1] = temp.y; +#endif + } + +#if WARP_Y + write_imageui(output, (int2)(d_x, d_y), convert_uint4(as_ushort4(convert_uchar8(pixel.lo * 255.0f)))); +#else + write_imageui(output, (int2)(d_x, d_y), as_uint4(convert_uchar16(pixel * 255.0f))); +#endif + +} + +__kernel void +kernel_image_warp_1_pixel ( + __read_only image2d_t input, + __write_only image2d_t output, + CLWarpConfig warp_config) +{ + // dest coordinate + int d_x = get_global_id(0); + int d_y = get_global_id(1); + + int out_width = get_image_width (output); + int out_height = get_image_height (output); + + const sampler_t sampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR; + + // source coordinate + float s_x = warp_config.proj_mat[0] * d_x + + warp_config.proj_mat[1] * d_y + + warp_config.proj_mat[2]; + float s_y = warp_config.proj_mat[3] * d_x + + warp_config.proj_mat[4] * d_y + + warp_config.proj_mat[5]; + float w = warp_config.proj_mat[6] * d_x + + warp_config.proj_mat[7] * d_y + + warp_config.proj_mat[8]; + w = w != 0.0f ? 1.0f / w : 0.0f; + + float warp_x = (s_x * w) / (float)out_width; + float warp_y = (s_y * w) / (float)out_height; + + float4 pixel = read_imagef(input, sampler, (float2)(warp_x, warp_y)); + + write_imagef(output, (int2)(d_x, d_y), pixel); +} + diff --git a/cl_kernel/kernel_min_filter.cl b/cl_kernel/kernel_min_filter.cl new file mode 100644 index 0000000..6a30f20 --- /dev/null +++ b/cl_kernel/kernel_min_filter.cl @@ -0,0 +1,191 @@ +/* + * function: kernel_min_filter + * input: image2d_t as read only + * output: image2d_t as write only + * + * data_type CL_UNSIGNED_INT16 + * channel_order CL_RGBA + */ + +//#define VERTICAL_MIN_KERNEL 1 +#define PATCH_RADIUS 8 + +// offset X should be PATCH_RADIUS and aligned by 8 +// offset Y should be PATCH_RADIUS aligned + +#if VERTICAL_MIN_KERNEL // vertical +#define OFFSET_X 0 +#define OFFSET_Y PATCH_RADIUS +#define GROUP_X 128 +#define GROUP_Y 8 +#define LINES_OF_WI 2 + +#else //horizontal +// offset X should be PATCH_RADIUS and aligned with 8 +#define OFFSET_X 8 +#define OFFSET_Y 0 +#define GROUP_X 128 +#define GROUP_Y 4 +#define LINES_OF_WI 1 +#endif + +#define DOT_X_SIZE (GROUP_X + OFFSET_X * 2) +#define DOT_Y_SIZE (GROUP_Y + OFFSET_Y * 2) + +//__constant const int slm_x_size = DOT_X_SIZE / 8; +//__constant const int slm_y_size = DOT_Y_SIZE; +#define slm_x_size (DOT_X_SIZE / 8) +#define slm_y_size DOT_Y_SIZE +__constant int uchar8_offset = OFFSET_X / 8; + +void load_to_slm (__read_only image2d_t input, __local uchar8 *slm, int group_start_x, int group_start_y) +{ + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + int local_x = get_local_id (0); + int local_y = get_local_id (1); + int local_index = local_y * get_local_size (0) + local_x; + + int group_offset_x = group_start_x - uchar8_offset; + int group_offset_y = group_start_y - OFFSET_Y; + + for (; local_index < slm_x_size * slm_y_size; local_index += get_local_size(0) * get_local_size(1)) { + int slm_x = local_index % slm_x_size; + int slm_y = local_index / slm_x_size; + int pos_x = group_offset_x + slm_x; + int pos_y = group_offset_y + slm_y; + uchar8 data = as_uchar8(convert_ushort4(read_imageui(input, sampler, (int2)(pos_x, pos_y)))); + slm[local_index] = data; + } + +} + +void finish_vertical_min ( + __local uchar8 *data_center, __write_only image2d_t output, + int group_start_x, int group_start_y, int local_x, int local_y) +{ + int pos_x, pos_y; + uchar8 min_val = data_center[0]; + int v; + + // process 2 line with each uchar8 pixels by each work-item +#pragma unroll + for (v = 1; v < OFFSET_Y; ++v) { + min_val = min (min_val, data_center[slm_x_size * v]); + min_val = min (min_val, data_center[-slm_x_size * v]); + } + min_val = min (min_val, data_center[slm_x_size * OFFSET_Y]); + + uchar8 min_val_1 = min (min_val, data_center[-slm_x_size * OFFSET_Y]); + uchar8 min_val_2 = min (min_val, data_center[slm_x_size * (OFFSET_Y + 1)]); + + pos_x = group_start_x + local_x; + pos_y = group_start_y + local_y; + + write_imageui(output, (int2)(pos_x, pos_y), convert_uint4(as_ushort4(min_val_1))); + write_imageui(output, (int2)(pos_x, pos_y + 1), convert_uint4(as_ushort4(min_val_2))); +} + + +void finish_horizontal_min ( + __local uchar8 *data_center, __write_only image2d_t output, + int group_start_x, int group_start_y, int local_x, int local_y) +{ + + uchar8 value = data_center[0]; + uchar8 v_left = ((__local uchar8 *)data_center)[-1]; + uchar8 v_right = ((__local uchar8 *)data_center)[1]; + /* + * Order 1st uchar4 + * 1st 4 values's common min, value.lo + * - - - 3 4 5 6 7 X X X X 4 5 6 7 0 - - - - - - - + * 2nd 4 values's common min, value.hi + * - - - - - - - 7 0 1 2 3 X X X X 0 1 2 3 4 - - - + * 1st and 2nd 4 value's shared common + * - - - - - - - 7 0 1 2 3 4 5 6 7 0 - - - - - - - + */ + + uchar4 tmp4; + uchar2 tmp2; + uchar tmp1_left, tmp1_right; + + uchar shared_common; + uchar first_common_min, second_common_min; + uchar8 out_data; + + tmp4 = min (value.lo, value.hi); + tmp2 = min (tmp4.s01, tmp4.s23); + shared_common = min (tmp2.s0, tmp2.s1); + shared_common = min (shared_common, v_left.s7); + shared_common = min (shared_common, v_right.s0); + + tmp2 = min (v_left.s34, v_left.s56); + first_common_min = min (tmp2.s0, tmp2.s1); + first_common_min = min (first_common_min, shared_common); + + tmp2 = min (v_right.s12, v_right.s34); + second_common_min = min (tmp2.s0, tmp2.s1); + second_common_min = min (second_common_min, shared_common); + + //final first 4 values + tmp1_left = min (v_left.s1, v_left.s2); + tmp1_right = min (v_right.s1, v_right.s2); + out_data.s0 = min (tmp1_left, v_left.s0); + out_data.s0 = min (out_data.s0, first_common_min); + + out_data.s1 = min (tmp1_left, first_common_min); + out_data.s1 = min (out_data.s1, v_right.s1); + + out_data.s2 = min (v_left.s2, first_common_min); + out_data.s2 = min (out_data.s2, tmp1_right); + + out_data.s3 = min (first_common_min, tmp1_right); + out_data.s3 = min (out_data.s3, v_right.s3); + + //second 4 values + tmp1_left = min (v_left.s5, v_left.s6); + tmp1_right = min (v_right.s5, v_right.s6); + out_data.s4 = min (tmp1_left, v_left.s4); + out_data.s4 = min (out_data.s4, second_common_min); + + out_data.s5 = min (tmp1_left, second_common_min); + out_data.s5 = min (out_data.s5, v_right.s5); + + out_data.s6 = min (v_left.s6, second_common_min); + out_data.s6 = min (out_data.s6, tmp1_right); + + out_data.s7 = min (second_common_min, tmp1_right); + out_data.s7 = min (out_data.s7, v_right.s7); + + int pos_x = group_start_x + local_x; + int pos_y = group_start_y + local_y; + + write_imageui(output, (int2)(pos_x, pos_y), convert_uint4(as_ushort4(out_data))); +} + +__kernel void kernel_min_filter ( + __read_only image2d_t input, + __write_only image2d_t output) +{ + int group_start_x = get_group_id (0) * (GROUP_X / 8); + int group_start_y = get_group_id (1) * GROUP_Y; + + __local uchar8 slm_cache[slm_x_size * slm_y_size]; + + //load to slm + load_to_slm (input, slm_cache, group_start_x, group_start_y); + barrier (CLK_LOCAL_MEM_FENCE); + + int local_x = get_local_id (0) ; + int local_y = get_local_id (1) * LINES_OF_WI; + int slm_x = local_x + uchar8_offset; + int slm_y = local_y + OFFSET_Y; + int slm_index = slm_x + slm_y * slm_x_size; + __local uchar8 *data_center = slm_cache + slm_index; + +#if VERTICAL_MIN_KERNEL + finish_vertical_min (data_center, output, group_start_x, group_start_y, local_x, local_y); +#else + finish_horizontal_min (data_center, output, group_start_x, group_start_y, local_x, local_y); +#endif +} + diff --git a/cl_kernel/kernel_newtonemapping.cl b/cl_kernel/kernel_newtonemapping.cl new file mode 100755 index 0000000..c66bab4 --- /dev/null +++ b/cl_kernel/kernel_newtonemapping.cl @@ -0,0 +1,101 @@ +/* + * function: kernel_newtonemapping + * implementation of tone mapping + * input: image2d_t as read only + * output: image2d_t as write only + */ + +#define WORK_ITEM_X_SIZE 8 +#define WORK_ITEM_Y_SIZE 8 +#define BLOCK_FACTOR 4 + +__kernel void kernel_newtonemapping ( + __read_only image2d_t input, __write_only image2d_t output, + __global float *y_max, __global float *y_avg, __global float *hist_leq, + int image_width, int image_height) +{ + int g_id_x = get_global_id (0); + int g_id_y = get_global_id (1); + + int group_id_x = get_group_id(0); + int group_id_y = get_group_id(1); + + int local_id_x = get_local_id(0); + int local_id_y = get_local_id(1); + + int g_size_x = get_global_size (0); + int g_size_y = get_global_size (1); + + int local_index = local_id_y * WORK_ITEM_X_SIZE + local_id_x; + int row_per_block = image_height / BLOCK_FACTOR; + int col_per_block = image_width / BLOCK_FACTOR; + int row_block_id = g_id_y / row_per_block; + int col_block_id = g_id_x * 4 / col_per_block; + + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + float4 src_data_Gr = read_imagef (input, sampler, (int2)(g_id_x, g_id_y)); + float4 src_data_R = read_imagef (input, sampler, (int2)(g_id_x, g_id_y + image_height)); + float4 src_data_B = read_imagef (input, sampler, (int2)(g_id_x, g_id_y + image_height * 2)); + float4 src_data_Gb = read_imagef (input, sampler, (int2)(g_id_x, g_id_y + image_height * 3)); + + float4 src_data_G = (src_data_Gr + src_data_Gb) / 2; + + float4 src_y_data = 0.0f; + src_y_data = mad(src_data_R, 0.299f, src_y_data); + src_y_data = mad(src_data_G, 0.587f, src_y_data); + src_y_data = mad(src_data_B, 0.114f, src_y_data); + + float4 dst_y_data; + float4 d, wd, haleq, s, ws; + float4 total_w = 0.0f; + float4 total_haleq = 0.0f; + + float4 corrd_x = mad((float4)g_id_x, 4.0f, (float4)(0.0f, 1.0f, 2.0f, 3.0f)); + float4 src_y = mad(src_y_data, 65535.0f, 0.5f) / 16.0f; + + for(int i = 0; i < BLOCK_FACTOR; i++) + { + for(int j = 0; j < BLOCK_FACTOR; j++) + { + int center_x = mad24(col_per_block, j, col_per_block / 2); + int center_y = mad24(row_per_block, i, row_per_block / 2); + int start_index = mad24(i, BLOCK_FACTOR, j) * 4096; + + float4 dy = (float4)((g_id_y - center_y) * (g_id_y - center_y)); + float4 dx = corrd_x - (float4)center_x; + + d = mad(dx, dx, dy); + + d = sqrt(d) + 100.0f; + //wd = 100.0f / (d + 100.0f); + + s = fabs(src_y_data - (float4)y_avg[mad24(i, BLOCK_FACTOR, j)]) / (float4)y_max[mad24(i, BLOCK_FACTOR, j)] + 1.0f; + //ws = 1.0f / (s + 1.0f); + + float4 w = 100.0f / (d * s); + //w = wd * ws; + + haleq.x = hist_leq[start_index + (int)src_y.x]; + haleq.y = hist_leq[start_index + (int)src_y.y]; + haleq.z = hist_leq[start_index + (int)src_y.z]; + haleq.w = hist_leq[start_index + (int)src_y.w]; + + total_w = total_w + w; + total_haleq = mad(haleq, w, total_haleq); + } + } + + dst_y_data = total_haleq / total_w; + + float4 gain = (dst_y_data + 0.0001f) / (src_y_data + 0.0001f); + src_data_Gr = src_data_Gr * gain; + src_data_R = src_data_R * gain; + src_data_B = src_data_B * gain; + src_data_Gb = src_data_Gb * gain; + + write_imagef(output, (int2)(g_id_x, g_id_y), src_data_Gr); + write_imagef(output, (int2)(g_id_x, g_id_y + image_height), src_data_R); + write_imagef(output, (int2)(g_id_x, g_id_y + image_height * 2), src_data_B); + write_imagef(output, (int2)(g_id_x, g_id_y + image_height * 3), src_data_Gb); +} diff --git a/cl_kernel/kernel_retinex.cl b/cl_kernel/kernel_retinex.cl new file mode 100644 index 0000000..9df3a58 --- /dev/null +++ b/cl_kernel/kernel_retinex.cl @@ -0,0 +1,164 @@ +/* + * function: kernel_retinex + * input: image2d_t as read only + * output: image2d_t as write only + */ + +#ifndef RETINEX_SCALE_SIZE +#define RETINEX_SCALE_SIZE 2 +#endif + +typedef struct { + float gain; + float threshold; + float log_min; + float log_max; + float width; + float height; +} CLRetinexConfig; + +__constant float log_table[256] = { + 0.000000f, 0.693147f, 1.098612f, 1.386294f, 1.609438f, 1.791759f, 1.945910f, 2.079442f, + 2.197225f, 2.302585f, 2.397895f, 2.484907f, 2.564949f, 2.639057f, 2.708050f, 2.772589f, + 2.833213f, 2.890372f, 2.944439f, 2.995732f, 3.044522f, 3.091042f, 3.135494f, 3.178054f, + 3.218876f, 3.258097f, 3.295837f, 3.332205f, 3.367296f, 3.401197f, 3.433987f, 3.465736f, + 3.496508f, 3.526361f, 3.555348f, 3.583519f, 3.610918f, 3.637586f, 3.663562f, 3.688879f, + 3.713572f, 3.737670f, 3.761200f, 3.784190f, 3.806662f, 3.828641f, 3.850148f, 3.871201f, + 3.891820f, 3.912023f, 3.931826f, 3.951244f, 3.970292f, 3.988984f, 4.007333f, 4.025352f, + 4.043051f, 4.060443f, 4.077537f, 4.094345f, 4.110874f, 4.127134f, 4.143135f, 4.158883f, + 4.174387f, 4.189655f, 4.204693f, 4.219508f, 4.234107f, 4.248495f, 4.262680f, 4.276666f, + 4.290459f, 4.304065f, 4.317488f, 4.330733f, 4.343805f, 4.356709f, 4.369448f, 4.382027f, + 4.394449f, 4.406719f, 4.418841f, 4.430817f, 4.442651f, 4.454347f, 4.465908f, 4.477337f, + 4.488636f, 4.499810f, 4.510860f, 4.521789f, 4.532599f, 4.543295f, 4.553877f, 4.564348f, + 4.574711f, 4.584967f, 4.595120f, 4.605170f, 4.615121f, 4.624973f, 4.634729f, 4.644391f, + 4.653960f, 4.663439f, 4.672829f, 4.682131f, 4.691348f, 4.700480f, 4.709530f, 4.718499f, + 4.727388f, 4.736198f, 4.744932f, 4.753590f, 4.762174f, 4.770685f, 4.779123f, 4.787492f, + 4.795791f, 4.804021f, 4.812184f, 4.820282f, 4.828314f, 4.836282f, 4.844187f, 4.852030f, + 4.859812f, 4.867534f, 4.875197f, 4.882802f, 4.890349f, 4.897840f, 4.905275f, 4.912655f, + 4.919981f, 4.927254f, 4.934474f, 4.941642f, 4.948760f, 4.955827f, 4.962845f, 4.969813f, + 4.976734f, 4.983607f, 4.990433f, 4.997212f, 5.003946f, 5.010635f, 5.017280f, 5.023881f, + 5.030438f, 5.036953f, 5.043425f, 5.049856f, 5.056246f, 5.062595f, 5.068904f, 5.075174f, + 5.081404f, 5.087596f, 5.093750f, 5.099866f, 5.105945f, 5.111988f, 5.117994f, 5.123964f, + 5.129899f, 5.135798f, 5.141664f, 5.147494f, 5.153292f, 5.159055f, 5.164786f, 5.170484f, + 5.176150f, 5.181784f, 5.187386f, 5.192957f, 5.198497f, 5.204007f, 5.209486f, 5.214936f, + 5.220356f, 5.225747f, 5.231109f, 5.236442f, 5.241747f, 5.247024f, 5.252273f, 5.257495f, + 5.262690f, 5.267858f, 5.273000f, 5.278115f, 5.283204f, 5.288267f, 5.293305f, 5.298317f, + 5.303305f, 5.308268f, 5.313206f, 5.318120f, 5.323010f, 5.327876f, 5.332719f, 5.337538f, + 5.342334f, 5.347108f, 5.351858f, 5.356586f, 5.361292f, 5.365976f, 5.370638f, 5.375278f, + 5.379897f, 5.384495f, 5.389072f, 5.393628f, 5.398163f, 5.402677f, 5.407172f, 5.411646f, + 5.416100f, 5.420535f, 5.424950f, 5.429346f, 5.433722f, 5.438079f, 5.442418f, 5.446737f, + 5.451038f, 5.455321f, 5.459586f, 5.463832f, 5.468060f, 5.472271f, 5.476464f, 5.480639f, + 5.484797f, 5.488938f, 5.493061f, 5.497168f, 5.501258f, 5.505332f, 5.509388f, 5.513429f, + 5.517453f, 5.521461f, 5.525453f, 5.529429f, 5.533389f, 5.537334f, 5.541264f, 5.545177f +}; + +__kernel void kernel_retinex ( + __read_only image2d_t input_y, __read_only image2d_t input_uv, + __read_only image2d_t ga_input0, +#if RETINEX_SCALE_SIZE > 1 + __read_only image2d_t ga_input1, +#endif +#if RETINEX_SCALE_SIZE > 2 + __read_only image2d_t ga_input2, +#endif + __write_only image2d_t output_y, __write_only image2d_t output_uv, + CLRetinexConfig re_config) +{ + int x = get_global_id (0); + int y = get_global_id (1); + sampler_t sampler_orig = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + sampler_t sampler_ga = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR; + + float4 y_out, uv_in; + float4 y_in, y_ga[RETINEX_SCALE_SIZE]; + float4 y_in_lg, y_lg; + int i; + + y_in = read_imagef(input_y, sampler_orig, (int2)(x, y)) * 255.0f; + y_in_lg.x = log_table[convert_int(y_in.x)]; + y_in_lg.y = log_table[convert_int(y_in.y)]; + y_in_lg.z = log_table[convert_int(y_in.z)]; + y_in_lg.w = log_table[convert_int(y_in.w)]; + + float ga_x_step = 1.0f / re_config.width; + float2 pos_ga = (float2)(x * 4.0f * ga_x_step, y / re_config.height); + y_ga[0].x = read_imagef(ga_input0, sampler_ga, pos_ga).x * 255.0f; + pos_ga.x += ga_x_step; + y_ga[0].y = read_imagef(ga_input0, sampler_ga, pos_ga).x * 255.0f; + pos_ga.x += ga_x_step; + y_ga[0].z = read_imagef(ga_input0, sampler_ga, pos_ga).x * 255.0f; + pos_ga.x += ga_x_step; + y_ga[0].w = read_imagef(ga_input0, sampler_ga, pos_ga).x * 255.0f; + +#if RETINEX_SCALE_SIZE > 1 + y_ga[1].x = read_imagef(ga_input1, sampler_ga, pos_ga).x * 255.0f; + pos_ga.x += ga_x_step; + y_ga[1].y = read_imagef(ga_input1, sampler_ga, pos_ga).x * 255.0f; + pos_ga.x += ga_x_step; + y_ga[1].z = read_imagef(ga_input1, sampler_ga, pos_ga).x * 255.0f; + pos_ga.x += ga_x_step; + y_ga[1].w = read_imagef(ga_input1, sampler_ga, pos_ga).x * 255.0f; +#endif + +#if RETINEX_SCALE_SIZE > 2 + y_ga[2].x = read_imagef(ga_input2, sampler_ga, pos_ga).x * 255.0f; + pos_ga.x += ga_x_step; + y_ga[2].y = read_imagef(ga_input2, sampler_ga, pos_ga).x * 255.0f; + pos_ga.x += ga_x_step; + y_ga[2].z = read_imagef(ga_input2, sampler_ga, pos_ga).x * 255.0f; + pos_ga.x += ga_x_step; + y_ga[2].w = read_imagef(ga_input2, sampler_ga, pos_ga).x * 255.0f; +#endif + + + y_lg = (float4) (0.0f, 0.0f, 0.0f, 0.0f); +#pragma unroll + for (int i = 0; i < RETINEX_SCALE_SIZE; ++i) { + y_lg.x += y_in_lg.x - log_table[convert_int(y_ga[i].x)]; + y_lg.y += y_in_lg.y - log_table[convert_int(y_ga[i].y)]; + y_lg.z += y_in_lg.z - log_table[convert_int(y_ga[i].z)]; + y_lg.w += y_in_lg.w - log_table[convert_int(y_ga[i].w)]; + } + y_lg = y_lg / (float)(RETINEX_SCALE_SIZE); + + //y_out = re_config.gain * (y_in + 20.0f) / 128.0f * (y_lg - re_config.log_min); + y_out = re_config.gain * (y_ga[0] + 20.0f) / 128.0f * (y_lg - re_config.log_min); + write_imagef(output_y, (int2)(x, y), y_out); + + // copy UV + if(y % 2 == 0) { + float2 avg_y_out, avg_y_in, gain_y; + float4 uv_out, gain_uv; + y_in = y_in / 255.0f; + avg_y_in = (float2)((y_in.x + y_in.y) * 0.5f, (y_in.z + y_in.w) * 0.5f); + avg_y_out = (float2)((y_out.x + y_out.y) * 0.5f, (y_out.z + y_out.w) * 0.5f); + avg_y_out = clamp (avg_y_out, 0.0f, 1.0f); + avg_y_in = (avg_y_in > 0.5f) ? (1.0f - avg_y_in) : avg_y_in; + avg_y_out = (avg_y_out > 0.5f) ? (1.0f - avg_y_out) : avg_y_out; + gain_y = (avg_y_out + 0.1f) / (avg_y_in + 0.05f); + gain_y = gain_y * (avg_y_in * 2.0f + 1.0f); + + uv_in = read_imagef(input_uv, sampler_orig, (int2)(x, y / 2)) - 0.5f; + float2 v_coef = 1.01f / (1.13f * uv_in.xz + 0.01f); + float2 v_gain_1 = v_coef - avg_y_in * v_coef; + float2 v_gain_2 = -v_coef; + float2 v_gain_min = (v_gain_1 < v_gain_2) ? v_gain_1 : v_gain_2; + float2 v_gain_max = (v_gain_1 < v_gain_2) ? v_gain_2 : v_gain_1; + v_gain_min = max (v_gain_min, 0.1f); + v_gain_max = max (v_gain_max, 0.1f); + gain_y = clamp (gain_y, v_gain_min, v_gain_max); + + float2 u_coef = 1.01f / (2.03f * uv_in.yw + 0.01f); + float2 u_gain_1 = u_coef - avg_y_in * u_coef; + float2 u_gain_2 = -u_coef; + float2 u_gain_min = (u_gain_1 < u_gain_2) ? u_gain_1 : u_gain_2; + float2 u_gain_max = (u_gain_1 < u_gain_2) ? u_gain_2 : u_gain_1; + u_gain_min = max (u_gain_min, 0.1f); + u_gain_max = max (u_gain_max, 0.1f); + gain_y = clamp (gain_y, u_gain_min, u_gain_max); + gain_uv = (float4) (gain_y, gain_y); + //printf (" (%.2f) ", gain_uv.x); + uv_out = uv_in * gain_uv + 0.5f; + write_imagef(output_uv, (int2)(x, y / 2), uv_out); + } +} diff --git a/cl_kernel/kernel_rgb_pipe.cl b/cl_kernel/kernel_rgb_pipe.cl new file mode 100644 index 0000000..277d9d4 --- /dev/null +++ b/cl_kernel/kernel_rgb_pipe.cl @@ -0,0 +1,97 @@ +/* + * function: kernel_rgb_pipe + * input: image2d_t as read only + * output: image2d_t as write only + */ + +#define WORK_ITEM_X_SIZE 1 +#define WORK_ITEM_Y_SIZE 1 + +#define SHARED_PIXEL_X_OFFSET 1 +#define SHARED_PIXEL_Y_OFFSET 1 + +#define SHARED_PIXEL_WIDTH 8 +#define SHARED_PIXEL_HEIGHT 4 + +#define SHARED_PIXEL_X_SIZE (SHARED_PIXEL_WIDTH * WORK_ITEM_X_SIZE + SHARED_PIXEL_X_OFFSET * 2) +#define SHARED_PIXEL_Y_SIZE (SHARED_PIXEL_HEIGHT * WORK_ITEM_Y_SIZE + SHARED_PIXEL_Y_OFFSET * 2) + +typedef struct { + float thr_r; + float thr_g; + float thr_b; + float gain; +} CLRgbTnrConfig; + +__inline void cl_snr (__local float4 *in, float4 *out, int lx, int ly) +{ + int tmp_id = (SHARED_PIXEL_Y_OFFSET + ly * WORK_ITEM_Y_SIZE) * SHARED_PIXEL_X_SIZE + SHARED_PIXEL_X_OFFSET + lx * WORK_ITEM_X_SIZE; + (*(out)).x = ((*(in + tmp_id)).x + (*(in + tmp_id - SHARED_PIXEL_X_SIZE - 1)).x + (*(in + tmp_id - SHARED_PIXEL_X_SIZE)).x + (*(in + tmp_id - SHARED_PIXEL_Y_OFFSET + 1)).x + (*(in + tmp_id - 1)).x + (*(in + tmp_id + 1)).x + (*(in + tmp_id + SHARED_PIXEL_X_SIZE - 1)).x + (*(in + tmp_id + SHARED_PIXEL_X_SIZE)).x + (*(in + tmp_id + SHARED_PIXEL_X_SIZE + 1)).x) / 9.0f; + + (*(out)).y = ((*(in + tmp_id)).y + (*(in + tmp_id - SHARED_PIXEL_X_SIZE - 1)).y + (*(in + tmp_id - SHARED_PIXEL_X_SIZE)).y + (*(in + tmp_id - SHARED_PIXEL_Y_OFFSET + 1)).y + (*(in + tmp_id - 1)).y + (*(in + tmp_id + 1)).y + (*(in + tmp_id + SHARED_PIXEL_X_SIZE - 1)).y + (*(in + tmp_id + SHARED_PIXEL_X_SIZE)).y + (*(in + tmp_id + SHARED_PIXEL_X_SIZE + 1)).y) / 9.0f; + + (*(out)).z = ((*(in + tmp_id)).z + (*(in + tmp_id - SHARED_PIXEL_X_SIZE - 1)).z + (*(in + tmp_id - SHARED_PIXEL_X_SIZE)).z + (*(in + tmp_id - SHARED_PIXEL_Y_OFFSET + 1)).z + (*(in + tmp_id - 1)).z + (*(in + tmp_id + 1)).z + (*(in + tmp_id + SHARED_PIXEL_X_SIZE - 1)).z + (*(in + tmp_id + SHARED_PIXEL_X_SIZE)).z + (*(in + tmp_id + SHARED_PIXEL_X_SIZE + 1)).z) / 9.0f; + +} + +__inline void cl_tnr (float4 *out, int gx, int gy, __read_only image2d_t inputFrame1, __read_only image2d_t inputFrame2, __read_only image2d_t inputFrame3, CLRgbTnrConfig tnr_config) +{ + float4 var; + float gain; + + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + float4 in1, in2, in3; + + in1 = read_imagef(inputFrame1, sampler, (int2)(gx, gy)); + in2 = read_imagef(inputFrame2, sampler, (int2)(gx, gy)); + in3 = read_imagef(inputFrame3, sampler, (int2)(gx, gy)); + + var.x = (fabs((*(out)).x - in1.x) + fabs(in1.x - in2.x) + fabs(in2.x - in3.x)) / 3.0f; + var.y = (fabs((*(out)).y - in1.y) + fabs(in1.y - in2.y) + fabs(in2.y - in3.y)) / 3.0f; + var.z = (fabs((*(out)).z - in1.z) + fabs(in1.z - in2.z) + fabs(in2.z - in3.z)) / 3.0f; + + int cond = (var.x + var.y + var.z) < (tnr_config.thr_r + tnr_config.thr_g + tnr_config.thr_b); + gain = cond ? 1.0f : 0.0f; + (*(out)).x = (gain * (*(out)).x + gain * in1.x + gain * in2.x + in3.x) / (1.0f + 3 * gain); + (*(out)).y = (gain * (*(out)).y + gain * in1.y + gain * in2.y + in3.y) / (1.0f + 3 * gain); + (*(out)).z = (gain * (*(out)).z + gain * in1.z + gain * in2.z + in3.z) / (1.0f + 3 * gain); +} + +__kernel void kernel_rgb_pipe (__write_only image2d_t output, CLRgbTnrConfig tnr_config, __read_only image2d_t inputFrame0, __read_only image2d_t inputFrame1, __read_only image2d_t inputFrame2, __read_only image2d_t inputFrame3) +{ + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + int g_id_x = get_global_id (0); + int g_id_y = get_global_id (1); + int g_size_x = get_global_size (0); + int g_size_y = get_global_size (1); + + int l_id_x = get_local_id (0); + int l_id_y = get_local_id (1); + int l_size_x = get_local_size (0); + int l_size_y = get_local_size (1); + + __local float4 p[SHARED_PIXEL_X_SIZE * SHARED_PIXEL_Y_SIZE]; + + float4 out; + int i = l_id_x + l_id_y * l_size_x; + int xstart = (g_id_x - l_id_x) - SHARED_PIXEL_X_OFFSET; + int ystart = (g_id_y - l_id_y) - SHARED_PIXEL_Y_OFFSET; + + for(; i < SHARED_PIXEL_X_SIZE * SHARED_PIXEL_Y_SIZE; i += l_size_x * l_size_y) { + + int x0 = i % SHARED_PIXEL_X_SIZE + xstart; + int y0 = i / SHARED_PIXEL_X_SIZE + ystart; + + p[i] = read_imagef(inputFrame0, sampler, (int2)(x0, y0)); + } + + barrier(CLK_LOCAL_MEM_FENCE); + + cl_snr(&p[0], &out, l_id_x, l_id_y); + cl_tnr(&out, g_id_x, g_id_y, inputFrame1, inputFrame2, inputFrame3, tnr_config); + + write_imagef(output, (int2)(g_id_x, g_id_y), out); +} + diff --git a/cl_kernel/kernel_tnr.cl b/cl_kernel/kernel_tnr.cl new file mode 100644 index 0000000..e5c1c36 --- /dev/null +++ b/cl_kernel/kernel_tnr.cl @@ -0,0 +1,159 @@ +/* + * function: kernel_tnr_yuv + * Temporal Noise Reduction + * inputFrame: image2d_t as read only + * inputFrame0: image2d_t as read only + * outputFrame: image2d_t as write only + * vertical_offset: vertical offset from y to uv + * gain: Blending ratio of previous and current frame + * thr_y: Motion sensitivity for Y, higher value can cause more motion blur + * thr_uv: Motion sensitivity for UV, higher value can cause more motion blur + */ + +__kernel void kernel_tnr_yuv( + __read_only image2d_t inputFrame, __read_only image2d_t inputFrame0, + __write_only image2d_t outputFrame, uint vertical_offset, float gain, float thr_y, float thr_uv) +{ + int x = get_global_id(0); + int y = get_global_id(1); + + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; + float4 pixel_t0_Y1 = read_imagef(inputFrame0, sampler, (int2)(2 * x, 2 * y)); + float4 pixel_t0_Y2 = read_imagef(inputFrame0, sampler, (int2)(2 * x + 1, 2 * y)); + float4 pixel_t0_Y3 = read_imagef(inputFrame0, sampler, (int2)(2 * x, 2 * y + 1)); + float4 pixel_t0_Y4 = read_imagef(inputFrame0, sampler, (int2)(2 * x + 1, 2 * y + 1)); + + float4 pixel_t0_U = read_imagef(inputFrame0, sampler, (int2)(2 * x, y + vertical_offset)); + float4 pixel_t0_V = read_imagef(inputFrame0, sampler, (int2)(2 * x + 1, y + vertical_offset)); + + float4 pixel_Y1 = read_imagef(inputFrame, sampler, (int2)(2 * x, 2 * y)); + float4 pixel_Y2 = read_imagef(inputFrame, sampler, (int2)(2 * x + 1, 2 * y)); + float4 pixel_Y3 = read_imagef(inputFrame, sampler, (int2)(2 * x, 2 * y + 1)); + float4 pixel_Y4 = read_imagef(inputFrame, sampler, (int2)(2 * x + 1, 2 * y + 1)); + + float4 pixel_U = read_imagef(inputFrame, sampler, (int2)(2 * x, y + vertical_offset)); + float4 pixel_V = read_imagef(inputFrame, sampler, (int2)(2 * x + 1, y + vertical_offset)); + + float diff_max = 0.8f; + + float diff_Y = 0.25f * (fabs(pixel_Y1.x - pixel_t0_Y1.x) + fabs(pixel_Y2.x - pixel_t0_Y2.x) + + fabs(pixel_Y3.x - pixel_t0_Y3.x) + fabs(pixel_Y4.x - pixel_t0_Y4.x)); + + float coeff_Y = (diff_Y < thr_y) ? gain : + (diff_Y * (1 - gain) + diff_max * gain - thr_y) / (diff_max - thr_y); + coeff_Y = (coeff_Y < 1.0f) ? coeff_Y : 1.0f; + + float4 pixel_outY1; + float4 pixel_outY2; + float4 pixel_outY3; + float4 pixel_outY4; + // X'(K) = (1 - gain) * X'(k-1) + gain * X(k) + pixel_outY1.x = pixel_t0_Y1.x + (pixel_Y1.x - pixel_t0_Y1.x) * coeff_Y; + pixel_outY2.x = pixel_t0_Y2.x + (pixel_Y2.x - pixel_t0_Y2.x) * coeff_Y; + pixel_outY3.x = pixel_t0_Y3.x + (pixel_Y3.x - pixel_t0_Y3.x) * coeff_Y; + pixel_outY4.x = pixel_t0_Y4.x + (pixel_Y4.x - pixel_t0_Y4.x) * coeff_Y; + + float diff_U = fabs(pixel_U.x - pixel_t0_U.x); + float diff_V = fabs(pixel_V.x - pixel_t0_V.x); + + float coeff_U = (diff_U < thr_uv) ? gain : + (diff_U * (1 - gain) + diff_max * gain - thr_uv) / (diff_max - thr_uv); + float coeff_V = (diff_V < thr_uv) ? gain : + (diff_V * (1 - gain) + diff_max * gain - thr_uv) / (diff_max - thr_uv); + coeff_U = (coeff_U < 1.0f) ? coeff_U : 1.0f; + coeff_V = (coeff_V < 1.0f) ? coeff_V : 1.0f; + + float4 pixel_outU; + float4 pixel_outV; + pixel_outU.x = pixel_t0_U.x + (pixel_U.x - pixel_t0_U.x) * coeff_U; + pixel_outV.x = pixel_t0_V.x + (pixel_V.x - pixel_t0_V.x) * coeff_V; + + write_imagef(outputFrame, (int2)(2 * x, 2 * y), pixel_outY1); + write_imagef(outputFrame, (int2)(2 * x + 1, 2 * y), pixel_outY2); + write_imagef(outputFrame, (int2)(2 * x, 2 * y + 1), pixel_outY3); + write_imagef(outputFrame, (int2)(2 * x + 1, 2 * y + 1), pixel_outY4); + write_imagef(outputFrame, (int2)(2 * x, y + vertical_offset), pixel_outU); + write_imagef(outputFrame, (int2)(2 * x + 1, y + vertical_offset), pixel_outV); +} + +/* + * function: kernel_tnr_rgb + * Temporal Noise Reduction + * outputFrame: image2d_t as write only + * thr: Motion sensitivity, higher value can cause more motion blur + * frameCount: input frame count to be processed + * inputFrame: image2d_t as read only + */ + +__kernel void kernel_tnr_rgb( + __write_only image2d_t outputFrame, + float tnr_gain, float thr_r, float thr_g, float thr_b, unsigned char frameCount, + __read_only image2d_t inputFrame0, __read_only image2d_t inputFrame1, + __read_only image2d_t inputFrame2, __read_only image2d_t inputFrame3) +{ + int x = get_global_id(0); + int y = get_global_id(1); + + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; + + float4 pixel_in0; + float4 pixel_in1; + float4 pixel_in2; + float4 pixel_in3; + + float4 pixel_out; + float4 var; + float gain = 0; + int cond; + + pixel_in0 = read_imagef(inputFrame0, sampler, (int2)(x, y)); + pixel_in1 = read_imagef(inputFrame1, sampler, (int2)(x, y)); + + if(frameCount == 4) { + pixel_in2 = read_imagef(inputFrame2, sampler, (int2)(x, y)); + pixel_in3 = read_imagef(inputFrame3, sampler, (int2)(x, y)); + + var.x = (fabs(pixel_in0.x - pixel_in1.x) + fabs(pixel_in1.x - pixel_in2.x) + + fabs(pixel_in2.x - pixel_in3.x)) / 3.0f; + var.y = (fabs(pixel_in0.y - pixel_in1.y) + fabs(pixel_in1.y - pixel_in2.y) + + fabs(pixel_in2.y - pixel_in3.y)) / 3.0f; + var.z = (fabs(pixel_in0.z - pixel_in1.z) + fabs(pixel_in1.z - pixel_in2.z) + + fabs(pixel_in2.z - pixel_in3.z)) / 3.0f; + + cond = (var.x + var.y + var.z) < (thr_r + thr_g + thr_b); + gain = cond ? 1.0f : 0.0f; + + pixel_out.x = (gain * pixel_in0.x + gain * pixel_in1.x + gain * pixel_in2.x + pixel_in3.x) / (1.0f + 3 * gain); + pixel_out.y = (gain * pixel_in0.y + gain * pixel_in1.y + gain * pixel_in2.y + pixel_in3.y) / (1.0f + 3 * gain); + pixel_out.z = (gain * pixel_in0.z + gain * pixel_in1.z + gain * pixel_in2.z + pixel_in3.z) / (1.0f + 3 * gain); + } + else if(frameCount == 3) { + pixel_in2 = read_imagef(inputFrame2, sampler, (int2)(x, y)); + var.x = (fabs(pixel_in0.x - pixel_in1.x) + fabs(pixel_in1.x - pixel_in2.x)) / 2.0f; + var.y = (fabs(pixel_in0.y - pixel_in1.y) + fabs(pixel_in1.y - pixel_in2.y)) / 2.0f; + var.z = (fabs(pixel_in0.z - pixel_in1.z) + fabs(pixel_in1.z - pixel_in2.z)) / 2.0f; + + cond = (var.x + var.y + var.z) < (thr_r + thr_g + thr_b); + gain = cond ? 1.0f : 0.0f; + + pixel_out.x = (gain * pixel_in0.x + gain * pixel_in1.x + pixel_in2.x) / (1.0f + 2 * gain); + pixel_out.y = (gain * pixel_in0.y + gain * pixel_in1.y + pixel_in2.y) / (1.0f + 2 * gain); + pixel_out.z = (gain * pixel_in0.z + gain * pixel_in1.z + pixel_in2.z) / (1.0f + 2 * gain); + } + else if(frameCount == 2) + { + var.x = fabs(pixel_in0.x - pixel_in1.x); + var.y = fabs(pixel_in0.y - pixel_in1.y); + var.z = fabs(pixel_in0.z - pixel_in1.z); + + cond = (var.x + var.y + var.z) < (thr_r + thr_g + thr_b); + gain = cond ? 1.0f : 0.0f; + + pixel_out.x = (gain * pixel_in0.x + pixel_in1.x) / (1.0f + gain); + pixel_out.y = (gain * pixel_in0.y + pixel_in1.y) / (1.0f + gain); + pixel_out.z = (gain * pixel_in0.z + pixel_in1.z) / (1.0f + gain); + } + + write_imagef(outputFrame, (int2)(x, y), pixel_out); +} + diff --git a/cl_kernel/kernel_tonemapping.cl b/cl_kernel/kernel_tonemapping.cl new file mode 100644 index 0000000..2f239ca --- /dev/null +++ b/cl_kernel/kernel_tonemapping.cl @@ -0,0 +1,106 @@ +/* + * function: kernel_tonemapping + * implementation of tone mapping + * input: image2d_t as read only + * output: image2d_t as write only + */ + +#define WORK_ITEM_X_SIZE 8 +#define WORK_ITEM_Y_SIZE 8 + +#define SHARED_PIXEL_X_SIZE 10 +#define SHARED_PIXEL_Y_SIZE 10 + +__kernel void kernel_tonemapping (__read_only image2d_t input, __write_only image2d_t output, float y_max, float y_target, int image_height) +{ + int g_id_x = get_global_id (0); + int g_id_y = get_global_id (1); + + int group_id_x = get_group_id(0); + int group_id_y = get_group_id(1); + + int local_id_x = get_local_id(0); + int local_id_y = get_local_id(1); + + int g_size_x = get_global_size (0); + int g_size_y = get_global_size (1); + + int local_index = local_id_y * WORK_ITEM_X_SIZE + local_id_x; + + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + __local float4 local_src_data[SHARED_PIXEL_X_SIZE * SHARED_PIXEL_Y_SIZE]; + + float4 src_data_Gr = read_imagef (input, sampler, (int2)(g_id_x, g_id_y)); + float4 src_data_R = read_imagef (input, sampler, (int2)(g_id_x, g_id_y + image_height)); + float4 src_data_B = read_imagef (input, sampler, (int2)(g_id_x, g_id_y + image_height * 2)); + float4 src_data_Gb = read_imagef (input, sampler, (int2)(g_id_x, g_id_y + image_height * 3)); + + float4 src_data_G = (src_data_Gr + src_data_Gb) / 2; + + float4 src_y_data = 0.0f; + src_y_data = mad(src_data_R, 255.f * 0.299f, src_y_data); + src_y_data = mad(src_data_G, 255.f * 0.587f, src_y_data); + src_y_data = mad(src_data_B, 255.f * 0.114f, src_y_data); + + local_src_data[(local_id_y + 1) * SHARED_PIXEL_X_SIZE + local_id_x + 1] = src_y_data; + + if(local_index < SHARED_PIXEL_X_SIZE * SHARED_PIXEL_Y_SIZE - WORK_ITEM_X_SIZE * WORK_ITEM_Y_SIZE) + { + int target_index = local_index <= SHARED_PIXEL_X_SIZE ? local_index : (local_index <= (SHARED_PIXEL_X_SIZE * SHARED_PIXEL_Y_SIZE - WORK_ITEM_X_SIZE * WORK_ITEM_Y_SIZE - SHARED_PIXEL_X_SIZE) ? (local_index + WORK_ITEM_X_SIZE + (local_index - (SHARED_PIXEL_X_SIZE + 1)) / 2 * WORK_ITEM_X_SIZE) : (local_index + WORK_ITEM_X_SIZE * WORK_ITEM_Y_SIZE)); + int start_x = mad24(group_id_x, WORK_ITEM_X_SIZE, -1); + int start_y = mad24(group_id_y, WORK_ITEM_Y_SIZE, -1); + int offset_x = target_index % SHARED_PIXEL_X_SIZE; + int offset_y = target_index / SHARED_PIXEL_X_SIZE; + + float4 data_Gr = read_imagef (input, sampler, (int2)(start_x + offset_x, start_y + offset_y)); + float4 data_R = read_imagef (input, sampler, (int2)(start_x + offset_x, start_y + offset_y + image_height)); + float4 data_B = read_imagef (input, sampler, (int2)(start_x + offset_x, start_y + offset_y + image_height * 2)); + float4 data_Gb = read_imagef (input, sampler, (int2)(start_x + offset_x, start_y + offset_y + image_height * 3)); + + float4 data_G = (data_Gr + data_Gb) / 2; + + float4 y_data = 0.0f; + y_data = mad(data_R, 255.f * 0.299f, y_data); + y_data = mad(data_G, 255.f * 0.587f, y_data); + y_data = mad(data_B, 255.f * 0.114f, y_data); + local_src_data[target_index] = y_data; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + float gaussian_table[9] = {0.075f, 0.124f, 0.075f, + 0.124f, 0.204f, 0.124f, + 0.075f, 0.124f, 0.075f + }; + float4 src_ym_data = 0.0f; + + float16 integrate_data = *((__local float16 *)(local_src_data + local_id_y * SHARED_PIXEL_X_SIZE + local_id_x)); + + src_ym_data = mad(integrate_data.s3456, (float4)gaussian_table[0], src_ym_data); + src_ym_data = mad(integrate_data.s4567, (float4)gaussian_table[1], src_ym_data); + src_ym_data = mad(integrate_data.s5678, (float4)gaussian_table[2], src_ym_data); + + integrate_data = *((__local float16 *)(local_src_data + (local_id_y + 1) * SHARED_PIXEL_X_SIZE + local_id_x)); + + src_ym_data = mad(integrate_data.s3456, (float4)gaussian_table[3], src_ym_data); + src_ym_data = mad(src_y_data, (float4)gaussian_table[4], src_ym_data); + src_ym_data = mad(integrate_data.s5678, (float4)gaussian_table[5], src_ym_data); + + integrate_data = *((__local float16 *)(local_src_data + (local_id_y + 2) * SHARED_PIXEL_X_SIZE + local_id_x)); + + src_ym_data = mad(integrate_data.s3456, (float4)gaussian_table[6], src_ym_data); + src_ym_data = mad(integrate_data.s4567, (float4)gaussian_table[7], src_ym_data); + src_ym_data = mad(integrate_data.s5678, (float4)gaussian_table[8], src_ym_data); + + float4 gain = ((float4)(y_max + y_target) + src_ym_data) / (src_y_data + src_ym_data + (float4)y_target); + src_data_Gr = src_data_Gr * gain; + src_data_R = src_data_R * gain; + src_data_B = src_data_B * gain; + src_data_Gb = src_data_Gb * gain; + + write_imagef(output, (int2)(g_id_x, g_id_y), src_data_Gr); + write_imagef(output, (int2)(g_id_x, g_id_y + image_height), src_data_R); + write_imagef(output, (int2)(g_id_x, g_id_y + image_height * 2), src_data_B); + write_imagef(output, (int2)(g_id_x, g_id_y + image_height * 3), src_data_Gb); +} diff --git a/cl_kernel/kernel_wavelet_coeff.cl b/cl_kernel/kernel_wavelet_coeff.cl new file mode 100644 index 0000000..51c3b5f --- /dev/null +++ b/cl_kernel/kernel_wavelet_coeff.cl @@ -0,0 +1,243 @@ +/* + * function: kernel_wavelet_coeff_variance + * Calculate wavelet coefficients variance + * input: Wavelet coefficients as read only + * output: Wavelet coefficients variance + */ + +#ifndef WAVELET_DENOISE_Y +#define WAVELET_DENOISE_Y 1 +#endif + +#ifndef WAVELET_DENOISE_UV +#define WAVELET_DENOISE_UV 0 +#endif + +#define WG_CELL_X_SIZE 8 +#define WG_CELL_Y_SIZE 8 + +#define SLM_CELL_X_OFFSET 1 +#define SLM_CELL_Y_OFFSET 2 + +// 10x12 +#define SLM_CELL_X_SIZE (WG_CELL_X_SIZE + SLM_CELL_X_OFFSET * 2) +#define SLM_CELL_Y_SIZE (WG_CELL_Y_SIZE + SLM_CELL_Y_OFFSET * 2) + +__kernel void kernel_wavelet_coeff_variance (__read_only image2d_t input, __write_only image2d_t output, int layer) +{ + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + int g_id_x = get_global_id (0); + int g_id_y = get_global_id (1); + + int group_id_x = get_group_id(0); + int group_id_y = get_group_id(1); + + int local_id_x = get_local_id(0); + int local_id_y = get_local_id(1); + + int g_size_x = get_global_size (0); + int g_size_y = get_global_size (1); + + int l_size_x = get_local_size (0); + int l_size_y = get_local_size (1); + + int local_index = local_id_y * WG_CELL_X_SIZE + local_id_x; + + float offset = 0.5f; + float4 line_sum[5] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; + float4 line_var = 0.0f; + + __local float4 local_src_data[SLM_CELL_X_SIZE * SLM_CELL_Y_SIZE]; + + int i = local_id_x + local_id_y * WG_CELL_X_SIZE; + int start_x = mad24(group_id_x, WG_CELL_X_SIZE, -SLM_CELL_X_OFFSET); + int start_y = mad24(group_id_y, WG_CELL_Y_SIZE, -SLM_CELL_Y_OFFSET); + + for (int j = i; j < SLM_CELL_X_SIZE * SLM_CELL_Y_SIZE; j += WG_CELL_X_SIZE * WG_CELL_Y_SIZE) + { + int x = start_x + (j % SLM_CELL_X_SIZE); + int y = start_y + (j / SLM_CELL_X_SIZE); + local_src_data[j] = read_imagef (input, sampler, (int2)(x, y)) - offset; + } + barrier(CLK_LOCAL_MEM_FENCE); + + float16 line0 = *((__local float16 *)(local_src_data + local_id_y * SLM_CELL_X_SIZE + local_id_x)); + float16 line1 = *((__local float16 *)(local_src_data + (local_id_y + 1) * SLM_CELL_X_SIZE + local_id_x)); + float16 line2 = *((__local float16 *)(local_src_data + (local_id_y + 2) * SLM_CELL_X_SIZE + local_id_x)); + float16 line3 = *((__local float16 *)(local_src_data + (local_id_y + 3) * SLM_CELL_X_SIZE + local_id_x)); + float16 line4 = *((__local float16 *)(local_src_data + (local_id_y + 4) * SLM_CELL_X_SIZE + local_id_x)); + +#if WAVELET_DENOISE_Y + line_sum[0] = mad(line0.s0123, line0.s0123, line_sum[0]); + line_sum[0] = mad(line0.s1234, line0.s1234, line_sum[0]); + line_sum[0] = mad(line0.s2345, line0.s2345, line_sum[0]); + line_sum[0] = mad(line0.s3456, line0.s3456, line_sum[0]); + line_sum[0] = mad(line0.s4567, line0.s4567, line_sum[0]); + line_sum[0] = mad(line0.s5678, line0.s5678, line_sum[0]); + line_sum[0] = mad(line0.s6789, line0.s6789, line_sum[0]); + line_sum[0] = mad(line0.s789a, line0.s789a, line_sum[0]); + line_sum[0] = mad(line0.s89ab, line0.s89ab, line_sum[0]); + + line_sum[1] = mad(line1.s0123, line1.s0123, line_sum[1]); + line_sum[1] = mad(line1.s1234, line1.s1234, line_sum[1]); + line_sum[1] = mad(line1.s2345, line1.s2345, line_sum[1]); + line_sum[1] = mad(line1.s3456, line1.s3456, line_sum[1]); + line_sum[1] = mad(line1.s4567, line1.s4567, line_sum[1]); + line_sum[1] = mad(line1.s5678, line1.s5678, line_sum[1]); + line_sum[1] = mad(line1.s6789, line1.s6789, line_sum[1]); + line_sum[1] = mad(line1.s789a, line1.s789a, line_sum[1]); + line_sum[1] = mad(line1.s89ab, line1.s89ab, line_sum[1]); + + line_sum[2] = mad(line2.s0123, line2.s0123, line_sum[2]); + line_sum[2] = mad(line2.s1234, line2.s1234, line_sum[2]); + line_sum[2] = mad(line2.s2345, line2.s2345, line_sum[2]); + line_sum[2] = mad(line2.s3456, line2.s3456, line_sum[2]); + line_sum[2] = mad(line2.s4567, line2.s4567, line_sum[2]); + line_sum[2] = mad(line2.s5678, line2.s5678, line_sum[2]); + line_sum[2] = mad(line2.s6789, line2.s6789, line_sum[2]); + line_sum[2] = mad(line2.s789a, line2.s789a, line_sum[2]); + line_sum[2] = mad(line2.s89ab, line2.s89ab, line_sum[2]); + + line_sum[3] = mad(line3.s0123, line3.s0123, line_sum[3]); + line_sum[3] = mad(line3.s1234, line3.s1234, line_sum[3]); + line_sum[3] = mad(line3.s2345, line3.s2345, line_sum[3]); + line_sum[3] = mad(line3.s3456, line3.s3456, line_sum[3]); + line_sum[3] = mad(line3.s4567, line3.s4567, line_sum[3]); + line_sum[3] = mad(line3.s5678, line3.s5678, line_sum[3]); + line_sum[3] = mad(line3.s6789, line3.s6789, line_sum[3]); + line_sum[3] = mad(line3.s789a, line3.s789a, line_sum[3]); + line_sum[3] = mad(line3.s89ab, line3.s89ab, line_sum[3]); + + line_sum[4] = mad(line4.s0123, line4.s0123, line_sum[4]); + line_sum[4] = mad(line4.s1234, line4.s1234, line_sum[4]); + line_sum[4] = mad(line4.s2345, line4.s2345, line_sum[4]); + line_sum[4] = mad(line4.s3456, line4.s3456, line_sum[4]); + line_sum[4] = mad(line4.s4567, line4.s4567, line_sum[4]); + line_sum[4] = mad(line4.s5678, line4.s5678, line_sum[4]); + line_sum[4] = mad(line4.s6789, line4.s6789, line_sum[4]); + line_sum[4] = mad(line4.s789a, line4.s789a, line_sum[4]); + line_sum[4] = mad(line4.s89ab, line4.s89ab, line_sum[4]); + + line_var = (line_sum[0] + line_sum[1] + line_sum[2] + line_sum[3] + line_sum[4]) / 45; +#endif + +#if WAVELET_DENOISE_UV + line_sum[0] = mad(line0.s0123, line0.s0123, line_sum[0]); + line_sum[0] = mad(line0.s2345, line0.s2345, line_sum[0]); + line_sum[0] = mad(line0.s4567, line0.s4567, line_sum[0]); + line_sum[0] = mad(line0.s6789, line0.s6789, line_sum[0]); + line_sum[0] = mad(line0.s89ab, line0.s89ab, line_sum[0]); + line_sum[0] = mad(line0.sabcd, line0.sabcd, line_sum[0]); + line_sum[0] = mad(line0.scdef, line0.scdef, line_sum[0]); + + line_sum[1] = mad(line1.s0123, line1.s0123, line_sum[1]); + line_sum[1] = mad(line1.s2345, line1.s2345, line_sum[1]); + line_sum[1] = mad(line1.s4567, line1.s4567, line_sum[1]); + line_sum[1] = mad(line1.s6789, line1.s6789, line_sum[1]); + line_sum[1] = mad(line1.s89ab, line1.s89ab, line_sum[1]); + line_sum[1] = mad(line1.sabcd, line1.sabcd, line_sum[1]); + line_sum[1] = mad(line1.scdef, line1.scdef, line_sum[1]); + + line_sum[2] = mad(line2.s0123, line2.s0123, line_sum[2]); + line_sum[2] = mad(line2.s2345, line2.s2345, line_sum[2]); + line_sum[2] = mad(line2.s4567, line2.s4567, line_sum[2]); + line_sum[2] = mad(line2.s6789, line2.s6789, line_sum[2]); + line_sum[2] = mad(line2.s89ab, line2.s89ab, line_sum[2]); + line_sum[2] = mad(line2.sabcd, line2.sabcd, line_sum[2]); + line_sum[2] = mad(line2.scdef, line2.scdef, line_sum[2]); + + line_sum[3] = mad(line3.s0123, line3.s0123, line_sum[3]); + line_sum[3] = mad(line3.s2345, line3.s2345, line_sum[3]); + line_sum[3] = mad(line3.s4567, line3.s4567, line_sum[3]); + line_sum[3] = mad(line3.s6789, line3.s6789, line_sum[3]); + line_sum[3] = mad(line3.s89ab, line3.s89ab, line_sum[3]); + line_sum[3] = mad(line3.sabcd, line3.sabcd, line_sum[3]); + line_sum[3] = mad(line3.scdef, line3.scdef, line_sum[3]); + + line_sum[4] = mad(line4.s0123, line4.s0123, line_sum[4]); + line_sum[4] = mad(line4.s2345, line4.s2345, line_sum[4]); + line_sum[4] = mad(line4.s4567, line4.s4567, line_sum[4]); + line_sum[4] = mad(line4.s6789, line4.s6789, line_sum[4]); + line_sum[4] = mad(line4.s89ab, line4.s89ab, line_sum[4]); + line_sum[4] = mad(line4.sabcd, line4.sabcd, line_sum[4]); + line_sum[4] = mad(line4.scdef, line4.scdef, line_sum[4]); + + line_var = ((line_sum[0] + line_sum[1] + line_sum[2] + line_sum[3] + line_sum[4]) / 35); +#endif + + write_imagef(output, (int2)(g_id_x, g_id_y), line_var); +} + +/* + * function: kernel_wavelet_coeff_thresholding + * wavelet coefficient thresholding kernel + * hl/lh/hh: wavelet coefficients + * layer: wavelet decomposition layer + * decomLevels: wavelet decomposition levels + */ + +__kernel void kernel_wavelet_coeff_thresholding (float noise_var1, float noise_var2, + __read_only image2d_t in_hl, __read_only image2d_t var_hl, __write_only image2d_t out_hl, + __read_only image2d_t in_lh, __read_only image2d_t var_lh, __write_only image2d_t out_lh, + __read_only image2d_t in_hh, __read_only image2d_t var_hh, __write_only image2d_t out_hh, + int layer, int decomLevels, + float hardThresh, float softThresh, float ag_weight) +{ + int x = get_global_id (0); + int y = get_global_id (1); + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + float4 input_hl; + float4 input_lh; + float4 input_hh; + + float4 output_hl; + float4 output_lh; + float4 output_hh; + + float4 coeff_var_hl; + float4 coeff_var_lh; + float4 coeff_var_hh; + + float4 stddev_hl; + float4 stddev_lh; + float4 stddev_hh; + + float4 thresh_hl; + float4 thresh_lh; + float4 thresh_hh; + + float4 noise_var = (float4) (noise_var1, noise_var2, noise_var1, noise_var2); + + input_hl = read_imagef(in_hl, sampler, (int2)(x, y)) - 0.5f; + input_lh = read_imagef(in_lh, sampler, (int2)(x, y)) - 0.5f; + input_hh = read_imagef(in_hh, sampler, (int2)(x, y)) - 0.5f; + + coeff_var_hl = 65025 * (1 << 2 * layer) * read_imagef(var_hl, sampler, (int2)(x, y)); + coeff_var_lh = 65025 * (1 << 2 * layer) * read_imagef(var_lh, sampler, (int2)(x, y)); + coeff_var_hh = 65025 * (1 << 2 * layer) * read_imagef(var_hh, sampler, (int2)(x, y)); + + stddev_hl = coeff_var_hl - noise_var; + stddev_hl = (stddev_hl > 0) ? sqrt(stddev_hl) : 0.000001f; + + stddev_lh = coeff_var_lh - noise_var; + stddev_lh = (stddev_lh > 0) ? sqrt(stddev_lh) : 0.000001f; + + stddev_hh = coeff_var_hh - noise_var; + stddev_hh = (stddev_hh > 0) ? sqrt(stddev_hh) : 0.000001f; + + thresh_hl = (ag_weight * noise_var / stddev_hl) / (255 * (1 << layer)); + thresh_lh = (ag_weight * noise_var / stddev_lh) / (255 * (1 << layer)); + thresh_hh = (ag_weight * noise_var / stddev_hh) / (255 * (1 << layer)); + + // Soft thresholding + output_hl = (fabs(input_hl) < thresh_hl) ? 0 : ((input_hl > 0) ? fabs(input_hl) - thresh_hl : thresh_hl - fabs(input_hl)); + output_lh = (fabs(input_lh) < thresh_lh) ? 0 : ((input_lh > 0) ? fabs(input_lh) - thresh_lh : thresh_lh - fabs(input_lh)); + output_hh = (fabs(input_hh) < thresh_hh) ? 0 : ((input_hh > 0) ? fabs(input_hh) - thresh_hh : thresh_hh - fabs(input_hh)); + + write_imagef(out_hl, (int2)(x, y), output_hl + 0.5f); + write_imagef(out_lh, (int2)(x, y), output_lh + 0.5f); + write_imagef(out_hh, (int2)(x, y), output_hh + 0.5f); +} + diff --git a/cl_kernel/kernel_wavelet_denoise.cl b/cl_kernel/kernel_wavelet_denoise.cl new file mode 100644 index 0000000..b0353a1 --- /dev/null +++ b/cl_kernel/kernel_wavelet_denoise.cl @@ -0,0 +1,229 @@ + +/* + * function: kernel_wavelet_denoise + * wavelet filter for denoise usage + * in: input image data as read only + * threshold: noise threshold + * low: + */ + +__constant float threshConst[5] = { 50.430166f, 20.376415f, 10.184031f, 6.640919f, 3.367972f }; + +__kernel void kernel_wavelet_denoise(__global uint *src, __global uint *approxOut, __global float *details, __global uint *dest, + int inputYOffset, int outputYOffset, uint inputUVOffset, uint outputUVOffset, + int layer, int decomLevels, float hardThresh, float softThresh) +{ + int x = get_global_id(0); + int y = get_global_id(1); + size_t width = get_global_size(0); + size_t height = get_global_size(1); + + int imageWidth = width * 16; + int imageHeight = height; + + float stdev = 0.0f; + float thold = 0.0f; + float16 deviation = (float16)0.0f; + + layer = (layer > 1) ? layer : 1; + layer = (layer < decomLevels) ? layer : decomLevels; + + src += inputYOffset; + dest += outputYOffset; + +#if WAVELET_DENOISE_UV + int xScaler = pown(2.0f, layer); + int yScaler = pown(2.0f, (layer - 1)); +#else + int xScaler = pown(2.0f, (layer - 1)); + int yScaler = xScaler; +#endif + + xScaler = ((x == 0) || (x > imageWidth / 16 - xScaler)) ? 0 : xScaler; + yScaler = ((y < yScaler) || (y > imageHeight - yScaler)) ? 0 : yScaler; + + uint4 approx; + float16 detail; + +#if WAVELET_DENOISE_UV + int srcOffset = (layer % 2) ? (inputUVOffset * imageWidth / 4) : 0; + __global uchar *src_p = (__global uchar *)(src + srcOffset); +#else + __global uchar *src_p = (__global uchar *)(src); +#endif + + int pixel_index = x * 16 + y * imageWidth; + int group_index = x * 4 + y * (imageWidth / 4); + +#if WAVELET_DENOISE_UV + uint4 luma; + int luma_index0 = x * 4 + (2 * y) * (imageWidth / 4); + int luma_index1 = x * 4 + (2 * y + 1) * (imageWidth / 4); +#else + uint4 chroma; + int chroma_index = x * 4 + (y / 2) * (imageWidth / 4); +#endif + + ushort16 a; + ushort16 b; + ushort16 c; + ushort16 d; + ushort16 e; + ushort16 f; + ushort16 g; + ushort16 h; + ushort16 i; + + float div = 1.0f / 16.0f; + + a = (ushort16)(convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler]), convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 1]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 2]), convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 3]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 4]), convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 5]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 6]), convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 7]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 8]), convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 9]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 10]), convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 11]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 12]), convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 13]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 14]), convert_ushort(src_p[pixel_index - yScaler * imageWidth - xScaler + 15]) + ); + + b = (ushort16)(convert_ushort(src_p[pixel_index - yScaler * imageWidth]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + 1]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth + 2]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + 3]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth + 4]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + 5]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth + 6]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + 7]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth + 8]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + 9]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth + 10]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + 11]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth + 12]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + 13]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth + 14]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + 15]) + ); + + c = (ushort16)(convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 1]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 2]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 3]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 4]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 5]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 6]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 7]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 8]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 9]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 10]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 11]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 12]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 13]), + convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 14]), convert_ushort(src_p[pixel_index - yScaler * imageWidth + xScaler + 15]) + ); + + d = (ushort16)(convert_ushort(src_p[pixel_index - xScaler]), convert_ushort(src_p[pixel_index - xScaler + 1]), + convert_ushort(src_p[pixel_index - xScaler + 2]), convert_ushort(src_p[pixel_index - xScaler + 3]), + convert_ushort(src_p[pixel_index - xScaler + 4]), convert_ushort(src_p[pixel_index - xScaler + 5]), + convert_ushort(src_p[pixel_index - xScaler + 6]), convert_ushort(src_p[pixel_index - xScaler + 7]), + convert_ushort(src_p[pixel_index - xScaler + 8]), convert_ushort(src_p[pixel_index - xScaler + 9]), + convert_ushort(src_p[pixel_index - xScaler + 10]), convert_ushort(src_p[pixel_index - xScaler + 11]), + convert_ushort(src_p[pixel_index - xScaler + 12]), convert_ushort(src_p[pixel_index - xScaler + 13]), + convert_ushort(src_p[pixel_index - xScaler + 14]), convert_ushort(src_p[pixel_index - xScaler + 15]) + ); + + e = (ushort16)(convert_ushort(src_p[pixel_index]), convert_ushort(src_p[pixel_index + 1]), + convert_ushort(src_p[pixel_index + 2]), convert_ushort(src_p[pixel_index + 3]), + convert_ushort(src_p[pixel_index + 4]), convert_ushort(src_p[pixel_index + 5]), + convert_ushort(src_p[pixel_index + 6]), convert_ushort(src_p[pixel_index + 7]), + convert_ushort(src_p[pixel_index + 8]), convert_ushort(src_p[pixel_index + 9]), + convert_ushort(src_p[pixel_index + 10]), convert_ushort(src_p[pixel_index + 11]), + convert_ushort(src_p[pixel_index + 12]), convert_ushort(src_p[pixel_index + 13]), + convert_ushort(src_p[pixel_index + 14]), convert_ushort(src_p[pixel_index + 15]) + ); + + f = (ushort16)(convert_ushort(src_p[pixel_index + xScaler]), convert_ushort(src_p[pixel_index + xScaler + 1]), + convert_ushort(src_p[pixel_index + xScaler + 2]), convert_ushort(src_p[pixel_index + xScaler + 3]), + convert_ushort(src_p[pixel_index + xScaler + 4]), convert_ushort(src_p[pixel_index + xScaler + 5]), + convert_ushort(src_p[pixel_index + xScaler + 6]), convert_ushort(src_p[pixel_index + xScaler + 7]), + convert_ushort(src_p[pixel_index + xScaler + 8]), convert_ushort(src_p[pixel_index + xScaler + 9]), + convert_ushort(src_p[pixel_index + xScaler + 10]), convert_ushort(src_p[pixel_index + xScaler + 11]), + convert_ushort(src_p[pixel_index + xScaler + 12]), convert_ushort(src_p[pixel_index + xScaler + 13]), + convert_ushort(src_p[pixel_index + xScaler + 14]), convert_ushort(src_p[pixel_index + xScaler + 15]) + ); + + g = (ushort16)(convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler]), convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 1]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 2]), convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 3]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 4]), convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 5]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 6]), convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 7]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 8]), convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 9]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 10]), convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 11]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 12]), convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 13]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 14]), convert_ushort(src_p[pixel_index + yScaler * imageWidth - xScaler + 15]) + ); + + h = (ushort16)(convert_ushort(src_p[pixel_index + yScaler * imageWidth]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + 1]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth + 2]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + 3]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth + 4]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + 5]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth + 6]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + 7]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth + 8]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + 9]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth + 10]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + 11]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth + 12]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + 13]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth + 14]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + 15]) + ); + + i = (ushort16)(convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 1]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 2]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 3]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 4]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 5]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 6]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 7]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 8]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 9]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 10]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 11]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 12]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 13]), + convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 14]), convert_ushort(src_p[pixel_index + yScaler * imageWidth + xScaler + 15]) + ); + + /* + { a, b, c } { 1, 2, 1 } + { d, e, f } { 2, 4, 2 } + { g, h, i } { 1, 2, 1 } + */ + ushort16 sum; + sum = (ushort16)1 * a + (ushort16)2 * b + (ushort16)1 * c + + (ushort16)2 * d + (ushort16)4 * e + (ushort16)2 * f + + (ushort16)1 * g + (ushort16)2 * h + (ushort16)1 * i; + + approx = as_uint4(convert_uchar16(((convert_float16(sum) + 0.5f / div) * div))); + detail = convert_float16(convert_char16(e) - as_char16(approx)); + + thold = hardThresh * threshConst[layer - 1]; + + detail = (detail < -thold) ? detail + (thold - thold * softThresh) : detail; + detail = (detail > thold) ? detail - (thold - thold * softThresh) : detail; + detail = (detail > -thold && detail < thold) ? detail * softThresh : detail; + + __global float16 *details_p = (__global float16 *)(&details[pixel_index]); + if (layer == 1) { + (*details_p) = detail; + +#if WAVELET_DENOISE_UV + // copy Y + luma = vload4(0, src + luma_index0); + vstore4(luma, 0, dest + luma_index0); + luma = vload4(0, src + luma_index1); + vstore4(luma, 0, dest + luma_index1); +#else + // copy UV + if (y % 2 == 0) { + chroma = vload4(0, src + chroma_index + inputUVOffset * (imageWidth / 4)); + vstore4(chroma, 0, dest + chroma_index + outputUVOffset * (imageWidth / 4)); + } +#endif + } else { + (*details_p) += detail; + } + + if (layer < decomLevels) { +#if WAVELET_DENOISE_UV + int approxOffset = (layer % 2) ? 0 : (inputUVOffset * imageWidth / 4); + (*(__global uint4*)(approxOut + group_index + approxOffset)) = approx; +#else + (*(__global uint4*)(approxOut + group_index)) = approx; +#endif + } + else + { + // Reconstruction +#if WAVELET_DENOISE_UV + __global uint4* dest_p = (__global uint4*)(&dest[group_index + outputUVOffset * imageWidth / 4]); + (*dest_p) = as_uint4(convert_uchar16(*details_p + convert_float16(as_uchar16(approx)))); +#else + __global uint4* dest_p = (__global uint4*)(&dest[group_index]); + (*dest_p) = as_uint4(convert_uchar16(*details_p + convert_float16(as_uchar16(approx)))); +#endif + } +} + diff --git a/cl_kernel/kernel_wavelet_haar.cl b/cl_kernel/kernel_wavelet_haar.cl new file mode 100644 index 0000000..bdecd68 --- /dev/null +++ b/cl_kernel/kernel_wavelet_haar.cl @@ -0,0 +1,182 @@ +/* + * function: kernel_wavelet_haar_decomposition + * wavelet haar decomposition kernel + * input: input image data as read only + * ll/hl/lh/hh: wavelet decomposition image + * layer: wavelet decomposition layer + * decomLevels: wavelet decomposition levels + */ +#ifndef WAVELET_DENOISE_Y +#define WAVELET_DENOISE_Y 1 +#endif + +#ifndef WAVELET_DENOISE_UV +#define WAVELET_DENOISE_UV 0 +#endif + +#ifndef WAVELET_BAYES_SHRINK +#define WAVELET_BAYES_SHRINK 1 +#endif + +__kernel void kernel_wavelet_haar_decomposition ( + __read_only image2d_t input, + __write_only image2d_t ll, __write_only image2d_t hl, + __write_only image2d_t lh, __write_only image2d_t hh, + int layer, int decomLevels, + float hardThresh, float softThresh) +{ + int x = get_global_id (0); + int y = get_global_id (1); + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + float8 line[2]; + line[0].lo = read_imagef(input, sampler, (int2)(2 * x, 2 * y)); + line[0].hi = read_imagef(input, sampler, (int2)(2 * x + 1, 2 * y)); + line[1].lo = read_imagef(input, sampler, (int2)(2 * x, 2 * y + 1)); + line[1].hi = read_imagef(input, sampler, (int2)(2 * x + 1, 2 * y + 1)); + + // row transform + float8 row_l; + float8 row_h; + row_l = (float8)(line[0].lo + line[1].lo, line[0].hi + line[1].hi) / 2.0f; + row_h = (float8)(line[0].lo - line[1].lo, line[0].hi - line[1].hi) / 2.0f; + + float4 line_ll; + float4 line_hl; + float4 line_lh; + float4 line_hh; + +#if WAVELET_DENOISE_Y + // column transform + line_ll = (row_l.odd + row_l.even) / 2.0f; + line_hl = (row_l.odd - row_l.even) / 2.0f; + line_lh = (row_h.odd + row_h.even) / 2.0f; + line_hh = (row_h.odd - row_h.even) / 2.0f; +#endif + +#if WAVELET_DENOISE_UV + // U column transform + line_ll.odd = (row_l.odd.odd + row_l.odd.even) / 2.0f; + line_hl.odd = (row_l.odd.odd - row_l.odd.even) / 2.0f; + line_lh.odd = (row_h.odd.odd + row_h.odd.even) / 2.0f; + line_hh.odd = (row_h.odd.odd - row_h.odd.even) / 2.0f; + + // V column transform + line_ll.even = (row_l.even.odd + row_l.even.even) / 2.0f; + line_hl.even = (row_l.even.odd - row_l.even.even) / 2.0f; + line_lh.even = (row_h.even.odd + row_h.even.even) / 2.0f; + line_hh.even = (row_h.even.odd - row_h.even.even) / 2.0f; +#endif + + write_imagef(ll, (int2)(x, y), line_ll); + write_imagef(hl, (int2)(x, y), line_hl + 0.5f); + write_imagef(lh, (int2)(x, y), line_lh + 0.5f); + write_imagef(hh, (int2)(x, y), line_hh + 0.5f); +} + +/* + * function: kernel_wavelet_haar_reconstruction + * wavelet haar reconstruction kernel + * output: output wavelet reconstruction image + * ll/hl/lh/hh: input wavelet transform data as read only + * layer: wavelet reconstruction layer + * decomLevels: wavelet decomposition levels + * threshold: hard/soft denoise thresholding + */ + +__constant float uv_threshConst[5] = { 0.1659f, 0.06719f, 0.03343f, 0.01713f, 0.01043f }; +__constant float y_threshConst[5] = { 0.06129f, 0.027319f, 0.012643f, 0.006513f, 0.003443f }; + +__kernel void kernel_wavelet_haar_reconstruction ( + __write_only image2d_t output, + __read_only image2d_t ll, __read_only image2d_t hl, + __read_only image2d_t lh, __read_only image2d_t hh, + int layer, int decomLevels, + float hardThresh, float softThresh) +{ + int x = get_global_id (0); + int y = get_global_id (1); + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST; + + float thresh = 0.0f; + + float4 line_ll; + float4 line_hl; + float4 line_lh; + float4 line_hh; + + line_ll = read_imagef(ll, sampler, (int2)(x, y)); + line_hl = read_imagef(hl, sampler, (int2)(x, y)) - 0.5f; + line_lh = read_imagef(lh, sampler, (int2)(x, y)) - 0.5f; + line_hh = read_imagef(hh, sampler, (int2)(x, y)) - 0.5f; + +#if WAVELET_DENOISE_Y + thresh = hardThresh * y_threshConst[layer - 1]; +#endif + +#if WAVELET_DENOISE_UV + thresh = hardThresh * uv_threshConst[layer - 1]; +#endif + +#if !WAVELET_BAYES_SHRINK + // thresholding + line_hl = (line_hl < -thresh) ? line_hl + (thresh - thresh * softThresh) : line_hl; + line_hl = (line_hl > thresh) ? line_hl - (thresh - thresh * softThresh) : line_hl; + line_hl = (line_hl > -thresh && line_hl < thresh) ? line_hl * softThresh : line_hl; + + line_lh = (line_lh < -thresh) ? line_lh + (thresh - thresh * softThresh) : line_lh; + line_lh = (line_lh > thresh) ? line_lh - (thresh - thresh * softThresh) : line_lh; + line_lh = (line_lh > -thresh && line_lh < thresh) ? line_lh * softThresh : line_lh; + + line_hh = (line_hh < -thresh) ? line_hh + (thresh - thresh * softThresh) : line_hh; + line_hh = (line_hh > thresh) ? line_hh - (thresh - thresh * softThresh) : line_hh; + line_hh = (line_hh > -thresh && line_hh < thresh) ? line_hh * softThresh : line_hh; +#endif + +#if WAVELET_DENOISE_Y + // row reconstruction + float8 row_l; + float8 row_h; + row_l = (float8)(line_ll + line_lh, line_hl + line_hh); + row_h = (float8)(line_ll - line_lh, line_hl - line_hh); + + // column reconstruction + float8 line[2]; + line[0].odd = row_l.lo + row_l.hi; + line[0].even = row_l.lo - row_l.hi; + line[1].odd = row_h.lo + row_h.hi; + line[1].even = row_h.lo - row_h.hi; + + write_imagef(output, (int2)(2 * x, 2 * y), line[0].lo); + write_imagef(output, (int2)(2 * x + 1, 2 * y), line[0].hi); + write_imagef(output, (int2)(2 * x, 2 * y + 1), line[1].lo); + write_imagef(output, (int2)(2 * x + 1, 2 * y + 1), line[1].hi); +#endif + +#if WAVELET_DENOISE_UV + // row reconstruction + float8 row_l; + float8 row_h; + row_l = (float8)(line_ll + line_lh, line_hl + line_hh); + row_h = (float8)(line_ll - line_lh, line_hl - line_hh); + + float8 line[2]; + + // U column reconstruction + line[0].odd.odd = row_l.lo.odd + row_l.hi.odd; + line[0].odd.even = row_l.lo.odd - row_l.hi.odd; + line[1].odd.odd = row_h.lo.odd + row_h.hi.odd; + line[1].odd.even = row_h.lo.odd - row_h.hi.odd; + + // V column reconstruction + line[0].even.odd = row_l.lo.even + row_l.hi.even; + line[0].even.even = row_l.lo.even - row_l.hi.even; + line[1].even.odd = row_h.lo.even + row_h.hi.even; + line[1].even.even = row_h.lo.even - row_h.hi.even; + + write_imagef(output, (int2)(2 * x, 2 * y), line[0].lo); + write_imagef(output, (int2)(2 * x + 1, 2 * y), line[0].hi); + write_imagef(output, (int2)(2 * x, 2 * y + 1), line[1].lo); + write_imagef(output, (int2)(2 * x + 1, 2 * y + 1), line[1].hi); +#endif +} diff --git a/cl_kernel/kernel_wire_frame.cl b/cl_kernel/kernel_wire_frame.cl new file mode 100644 index 0000000..5862dd5 --- /dev/null +++ b/cl_kernel/kernel_wire_frame.cl @@ -0,0 +1,30 @@ +/* + * function: kernel_wire_frame + * + * output_y: Y channel image2d_t as write only + * output_uv: uv channel image2d_t as write only + * wire_frames_coords: coordinates of wire frames + * coords_num: number of coordinates to be processed + */ + +__kernel void kernel_wire_frame ( + __write_only image2d_t output_y, __write_only image2d_t output_uv, + __global uint2 *wire_frames_coords, uint coords_num, + float border_y, float border_u, float border_v) +{ + if (coords_num == 0) { + return; + } + + int gid = get_global_id (0); + if (gid >= coords_num) { + return; + } + + uint2 coord = wire_frames_coords [gid]; + + write_imagef (output_y, (int2)(coord.x / 2, coord.y), (float4)(border_y)); + if (coord.y % 2 == 0) { + write_imagef (output_uv, (int2)(coord.x / 2, coord.y / 2), (float4)(border_u, border_v, 0.0f, 0.0f)); + } +} diff --git a/cl_kernel/kernel_yuv_pipe.cl b/cl_kernel/kernel_yuv_pipe.cl new file mode 100644 index 0000000..681fa62 --- /dev/null +++ b/cl_kernel/kernel_yuv_pipe.cl @@ -0,0 +1,230 @@ +/* + * function: kernel_yuv_pipe + * input: image2d_t as read only + * output: image2d_t as write only + */ + +#pragma OPENCL FP_CONTRACT OFF + +//#define USE_BUFFER_OBJECT 0 + +unsigned int get_sector_id (float u, float v) +{ + u = fabs(u) > 0.00001f ? u : 0.00001f; + float tg = v / u; + unsigned int se = tg > 1.f ? (tg > 2.f ? 3 : 2) : (tg > 0.5f ? 1 : 0); + unsigned int so = tg > -1.f ? (tg > -0.5f ? 3 : 2) : (tg > -2.f ? 1 : 0); + return tg > 0 ? (u > 0 ? se : (se + 8)) : (u > 0 ? (so + 12) : (so + 4)); +} + +__inline void cl_csc_rgbatonv12(float8 *R, float8 *G, float8 *B, float8 *out, __global float *matrix) +{ + out[0] = mad(matrix[0], R[0], mad(matrix[1], G[0], matrix[2] * B[0])); + out[1] = mad(matrix[0], R[1], mad(matrix[1], G[1], matrix[2] * B[1])); + + out[2].s0 = mad(matrix[3], R[0].s0, mad(matrix[4], G[0].s0, matrix[5] * B[0].s0)); + out[2].s1 = mad(matrix[6], R[0].s0, mad(matrix[7], G[0].s0, matrix[8] * B[0].s0)); + out[2].s2 = mad(matrix[3], R[0].s2, mad(matrix[4], G[0].s2, matrix[5] * B[0].s2)); + out[2].s3 = mad(matrix[6], R[0].s2, mad(matrix[7], G[0].s2, matrix[8] * B[0].s2)); + out[2].s4 = mad(matrix[3], R[0].s4, mad(matrix[4], G[0].s4, matrix[5] * B[0].s4)); + out[2].s5 = mad(matrix[6], R[0].s4, mad(matrix[7], G[0].s4, matrix[8] * B[0].s4)); + out[2].s6 = mad(matrix[3], R[0].s6, mad(matrix[4], G[0].s6, matrix[5] * B[0].s6)); + out[2].s7 = mad(matrix[6], R[0].s6, mad(matrix[7], G[0].s6, matrix[8] * B[0].s6)); + +} + +__inline void cl_macc(float8 *in, __global float *table) +{ + unsigned int table_id[4]; + float8 out; + + table_id[0] = get_sector_id(in[0].s0, in[0].s1); + table_id[1] = get_sector_id(in[0].s2, in[0].s3); + table_id[2] = get_sector_id(in[0].s4, in[0].s5); + table_id[3] = get_sector_id(in[0].s6, in[0].s7); + + out.s0 = mad(in[0].s0, table[4 * table_id[0]], in[0].s1 * table[4 * table_id[0] + 1]) + 0.5f; + out.s1 = mad(in[0].s0, table[4 * table_id[0] + 2], in[0].s1 * table[4 * table_id[0] + 3]) + 0.5f; + out.s2 = mad(in[0].s2, table[4 * table_id[1]], in[0].s3 * table[4 * table_id[1] + 1]) + 0.5f; + out.s3 = mad(in[0].s2, table[4 * table_id[1] + 2], in[0].s3 * table[4 * table_id[1] + 3]) + 0.5f; + out.s4 = mad(in[0].s4, table[4 * table_id[0]], in[0].s5 * table[4 * table_id[0] + 1]) + 0.5f; + out.s5 = mad(in[0].s4, table[4 * table_id[0] + 2], in[0].s5 * table[4 * table_id[0] + 3]) + 0.5f; + out.s6 = mad(in[0].s6, table[4 * table_id[1]], in[0].s7 * table[4 * table_id[1] + 1]) + 0.5f; + out.s7 = mad(in[0].s6, table[4 * table_id[1] + 2], in[0].s7 * table[4 * table_id[1] + 3]) + 0.5f; + + in[0] = out; +} + +#if USE_BUFFER_OBJECT +__inline void cl_tnr_yuv( + float8 *in, __global uchar8 *inputFramePre, + int x, int y, + float gain_yuv, float thr_y, float thr_uv, + uint vertical_offset, uint x_offset) +#else +__inline void cl_tnr_yuv( + float8 *in, + __read_only image2d_t inputFramePre, __read_only image2d_t inputFramePreUV, + int x, int y, + float gain_yuv, float thr_y, float thr_uv, uint x_offset) +#endif +{ + float8 in_prev[3]; + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; + +#if USE_BUFFER_OBJECT + in_prev[0] = convert_float8(inputFramePre[2 * y * x_offset + x]) / 256.0f; + in_prev[1] = convert_float8(inputFramePre[(2 * y + 1) * x_offset + x]) / 256.0f; + in_prev[2] = convert_float8(inputFramePre[(y + vertical_offset) * x_offset + x]) / 256.0f; +#else + in_prev[0] = convert_float8(as_uchar8(convert_ushort4(read_imageui(inputFramePre, sampler, (int2)(x, 2 * y))))) / 256.0f; + in_prev[1] = convert_float8(as_uchar8(convert_ushort4(read_imageui(inputFramePre, sampler, (int2)(x, 2 * y + 1))))) / 256.0f; + in_prev[2] = convert_float8(as_uchar8(convert_ushort4(read_imageui(inputFramePreUV, sampler, (int2)(x, y))))) / 256.0f; +#endif + + float diff_max = 0.8f; + float diff_Y[4], coeff_Y[4]; + + diff_Y[0] = 0.25f * (fabs(in[0].s0 - in_prev[0].s0) + fabs(in[0].s1 - in_prev[0].s1) + fabs(in[1].s0 - in_prev[1].s0) + fabs(in[1].s1 - in_prev[1].s1)); + diff_Y[1] = 0.25f * (fabs(in[0].s2 - in_prev[0].s2) + fabs(in[0].s3 - in_prev[0].s3) + fabs(in[1].s2 - in_prev[1].s2) + fabs(in[1].s3 - in_prev[1].s3)); + diff_Y[2] = 0.25f * (fabs(in[0].s4 - in_prev[0].s4) + fabs(in[0].s5 - in_prev[0].s5) + fabs(in[1].s4 - in_prev[1].s4) + fabs(in[1].s5 - in_prev[1].s5)); + diff_Y[3] = 0.25f * (fabs(in[0].s6 - in_prev[0].s6) + fabs(in[0].s7 - in_prev[0].s7) + fabs(in[1].s6 - in_prev[1].s6) + fabs(in[1].s7 - in_prev[1].s7)); + + coeff_Y[0] = (diff_Y[0] < thr_y) ? gain_yuv : (mad(diff_Y[0], 1 - gain_yuv, diff_max * gain_yuv - thr_y) / (diff_max - thr_y)); + coeff_Y[1] = (diff_Y[1] < thr_y) ? gain_yuv : (mad(diff_Y[1], 1 - gain_yuv, diff_max * gain_yuv - thr_y) / (diff_max - thr_y)); + coeff_Y[2] = (diff_Y[2] < thr_y) ? gain_yuv : (mad(diff_Y[2], 1 - gain_yuv, diff_max * gain_yuv - thr_y) / (diff_max - thr_y)); + coeff_Y[3] = (diff_Y[3] < thr_y) ? gain_yuv : (mad(diff_Y[3], 1 - gain_yuv, diff_max * gain_yuv - thr_y) / (diff_max - thr_y)); + + coeff_Y[0] = (coeff_Y[0] < 1.0f) ? coeff_Y[0] : 1.0f; + coeff_Y[1] = (coeff_Y[1] < 1.0f) ? coeff_Y[1] : 1.0f; + coeff_Y[2] = (coeff_Y[2] < 1.0f) ? coeff_Y[2] : 1.0f; + coeff_Y[3] = (coeff_Y[3] < 1.0f) ? coeff_Y[3] : 1.0f; + + in[0].s01 = mad(in[0].s01 - in_prev[0].s01, coeff_Y[0], in_prev[0].s01); + in[1].s01 = mad(in[1].s01 - in_prev[1].s01, coeff_Y[0], in_prev[1].s01); + in[0].s23 = mad(in[0].s23 - in_prev[0].s23, coeff_Y[1], in_prev[0].s23); + in[1].s23 = mad(in[1].s23 - in_prev[1].s23, coeff_Y[1], in_prev[1].s23); + in[0].s45 = mad(in[0].s45 - in_prev[0].s45, coeff_Y[2], in_prev[0].s45); + in[1].s45 = mad(in[1].s45 - in_prev[1].s45, coeff_Y[2], in_prev[1].s45); + in[0].s67 = mad(in[0].s67 - in_prev[0].s67, coeff_Y[3], in_prev[0].s67); + in[1].s67 = mad(in[1].s67 - in_prev[1].s67, coeff_Y[3], in_prev[1].s67); + + float diff_U[4], diff_V[4], coeff_U[4], coeff_V[4]; + + diff_U[0] = fabs(in[3].s0 - in_prev[3].s0); + diff_U[1] = fabs(in[3].s2 - in_prev[3].s2); + diff_U[2] = fabs(in[3].s4 - in_prev[3].s4); + diff_U[3] = fabs(in[3].s6 - in_prev[3].s6); + + diff_V[0] = fabs(in[3].s1 - in_prev[3].s1); + diff_V[1] = fabs(in[3].s3 - in_prev[3].s3); + diff_V[2] = fabs(in[3].s5 - in_prev[3].s5); + diff_V[3] = fabs(in[3].s7 - in_prev[3].s7); + + coeff_U[0] = (diff_U[0] < thr_uv) ? gain_yuv : (mad(diff_U[0], 1 - gain_yuv, diff_max * gain_yuv - thr_uv) / (diff_max - thr_uv)); + coeff_U[1] = (diff_U[1] < thr_uv) ? gain_yuv : (mad(diff_U[1], 1 - gain_yuv, diff_max * gain_yuv - thr_uv) / (diff_max - thr_uv)); + coeff_U[2] = (diff_U[2] < thr_uv) ? gain_yuv : (mad(diff_U[2], 1 - gain_yuv, diff_max * gain_yuv - thr_uv) / (diff_max - thr_uv)); + coeff_U[3] = (diff_U[3] < thr_uv) ? gain_yuv : (mad(diff_U[3], 1 - gain_yuv, diff_max * gain_yuv - thr_uv) / (diff_max - thr_uv)); + + coeff_V[0] = (diff_V[0] < thr_uv) ? gain_yuv : (mad(diff_V[0], 1 - gain_yuv, diff_max * gain_yuv - thr_uv) / (diff_max - thr_uv)); + coeff_V[1] = (diff_V[1] < thr_uv) ? gain_yuv : (mad(diff_V[1], 1 - gain_yuv, diff_max * gain_yuv - thr_uv) / (diff_max - thr_uv)); + coeff_V[2] = (diff_V[2] < thr_uv) ? gain_yuv : (mad(diff_V[2], 1 - gain_yuv, diff_max * gain_yuv - thr_uv) / (diff_max - thr_uv)); + coeff_V[3] = (diff_V[3] < thr_uv) ? gain_yuv : (mad(diff_V[3], 1 - gain_yuv, diff_max * gain_yuv - thr_uv) / (diff_max - thr_uv)); + + coeff_U[0] = (coeff_U[0] < 1.0f) ? coeff_U[0] : 1.0f; + coeff_U[1] = (coeff_U[1] < 1.0f) ? coeff_U[1] : 1.0f; + coeff_U[2] = (coeff_U[2] < 1.0f) ? coeff_U[2] : 1.0f; + coeff_U[3] = (coeff_U[3] < 1.0f) ? coeff_U[3] : 1.0f; + + coeff_V[0] = (coeff_V[0] < 1.0f) ? coeff_V[0] : 1.0f; + coeff_V[1] = (coeff_V[1] < 1.0f) ? coeff_V[1] : 1.0f; + coeff_V[2] = (coeff_V[2] < 1.0f) ? coeff_V[2] : 1.0f; + coeff_V[3] = (coeff_V[3] < 1.0f) ? coeff_V[3] : 1.0f; + + in[2].s0 = mad(in[2].s0 - in_prev[2].s0, coeff_U[0], in_prev[2].s0); + in[2].s1 = mad(in[2].s1 - in_prev[2].s1, coeff_V[0], in_prev[2].s1); + in[2].s2 = mad(in[2].s2 - in_prev[2].s2, coeff_U[1], in_prev[2].s2); + in[2].s3 = mad(in[2].s3 - in_prev[2].s3, coeff_V[1], in_prev[2].s3); + in[2].s4 = mad(in[2].s4 - in_prev[2].s4, coeff_U[2], in_prev[2].s4); + in[2].s5 = mad(in[2].s5 - in_prev[2].s5, coeff_V[2], in_prev[2].s5); + in[2].s6 = mad(in[2].s6 - in_prev[2].s6, coeff_U[3], in_prev[2].s6); + in[2].s7 = mad(in[2].s7 - in_prev[2].s7, coeff_V[3], in_prev[2].s7); + +} + +#if USE_BUFFER_OBJECT +__kernel void kernel_yuv_pipe ( + __global uchar8 *output, + __global uchar8 *inputFramePre, uint vertical_offset, + uint plannar_offset, + __global float *matrix, __global float *table, + float yuv_gain, float thr_y, float thr_uv, uint tnr_yuv_enable, + __global ushort8 *inputFrame0) + +#else + +__kernel void kernel_yuv_pipe ( + __write_only image2d_t output, __write_only image2d_t output_uv, + __read_only image2d_t inputFramePre, __read_only image2d_t inputFramePreUV, + uint plannar_offset, + __global float *matrix, __global float *table, + float yuv_gain, float thr_y, float thr_uv, uint tnr_yuv_enable, + __read_only image2d_t inputFrame0) + +#endif +{ + int x = get_global_id (0); + int y = get_global_id (1); + int offsetX = get_global_size(0); + sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST; + float8 inR[2], inG[2], inB[2]; + float8 out[3]; + +#if USE_BUFFER_OBJECT + // x [0, 240] + // y [0, 540] + uint offsetE = 2 * y * offsetX + x; + uint offsetO = (2 * y + 1) * offsetX + x; + uint offsetUV = (y + vertical_offset) * offsetX + x; + uint offsetG = offsetX * plannar_offset; + uint offsetB = offsetX * plannar_offset * 2; + + inR[0] = convert_float8(inputFrame0[offsetE]) / 65536.0f; + inR[1] = convert_float8(inputFrame0[offsetO]) / 65536.0f; + inG[0] = convert_float8(inputFrame0[offsetE + offsetG]) / 65536.0f; + inG[1] = convert_float8(inputFrame0[offsetO + offsetG]) / 65536.0f; + inB[0] = convert_float8(inputFrame0[offsetE + offsetB]) / 65536.0f; + inB[1] = convert_float8(inputFrame0[offsetO + offsetB]) / 65536.0f; +#else + inR[0] = convert_float8(as_ushort8(read_imageui(inputFrame0, sampler, (int2)(x, 2 * y)))) / 65536.0f; + inR[1] = convert_float8(as_ushort8(read_imageui(inputFrame0, sampler, (int2)(x, 2 * y + 1)))) / 65536.0f; + inG[0] = convert_float8(as_ushort8(read_imageui(inputFrame0, sampler, (int2)(x, 2 * y + plannar_offset)))) / 65536.0f; + inG[1] = convert_float8(as_ushort8(read_imageui(inputFrame0, sampler, (int2)(x, 2 * y + 1 + plannar_offset)))) / 65536.0f; + inB[0] = convert_float8(as_ushort8(read_imageui(inputFrame0, sampler, (int2)(x, 2 * y + plannar_offset * 2)))) / 65536.0f; + inB[1] = convert_float8(as_ushort8(read_imageui(inputFrame0, sampler, (int2)(x, 2 * y + 1 + plannar_offset * 2)))) / 65536.0f; +#endif + + cl_csc_rgbatonv12(&inR[0], &inG[0], &inB[0], &out[0], matrix); + cl_macc(&out[2], table); + + if (tnr_yuv_enable) { +#if USE_BUFFER_OBJECT + cl_tnr_yuv (&out[0], inputFramePre, x, y, yuv_gain, thr_y, thr_uv, vertical_offset, offsetX); +#else + cl_tnr_yuv (&out[0], inputFramePre, inputFramePreUV, x, y, yuv_gain, thr_y, thr_uv, offsetX); +#endif + + } + +#if USE_BUFFER_OBJECT + output[offsetE] = convert_uchar8(out[0] * 255.0f); + output[offsetO] = convert_uchar8(out[1] * 255.0f); + output[offsetUV] = convert_uchar8(out[2] * 255.0f); +#else + write_imageui(output, (int2)(x, 2 * y), convert_uint4(as_ushort4(convert_uchar8_sat(out[0] * 255.0f)))); + write_imageui(output, (int2)(x, 2 * y + 1), convert_uint4(as_ushort4(convert_uchar8_sat(out[1] * 255.0f)))); + write_imageui(output_uv, (int2)(x, y), convert_uint4(as_ushort4(convert_uchar8_sat(out[2] * 255.0f)))); +#endif + +} + diff --git a/clx_kernel/.gitignore b/clx_kernel/.gitignore new file mode 100644 index 0000000..74cd98e --- /dev/null +++ b/clx_kernel/.gitignore @@ -0,0 +1 @@ +*.clx diff --git a/clx_kernel/Makefile.am b/clx_kernel/Makefile.am new file mode 100644 index 0000000..c87cf1a --- /dev/null +++ b/clx_kernel/Makefile.am @@ -0,0 +1,39 @@ +clx_kernel_sources = \ + kernel_csc.clx \ + kernel_demo.clx \ + kernel_defog_dcp.clx \ + kernel_min_filter.clx \ + kernel_bi_filter.clx \ + kernel_tnr.clx \ + kernel_bayer_pipe.clx \ + kernel_bayer_basic.clx \ + kernel_fisheye.clx \ + kernel_rgb_pipe.clx \ + kernel_yuv_pipe.clx \ + kernel_tonemapping.clx \ + kernel_newtonemapping.clx \ + kernel_image_scaler.clx \ + kernel_retinex.clx \ + kernel_gauss.clx \ + kernel_gauss_lap_pyramid.clx \ + kernel_geo_map.clx \ + kernel_wavelet_denoise.clx \ + kernel_wavelet_haar.clx \ + kernel_wavelet_coeff.clx \ + kernel_wire_frame.clx \ + kernel_3d_denoise.clx \ + kernel_3d_denoise_slm.clx \ + kernel_image_warp.clx \ + $(NULL) + +cl_quotation_sh = \ + $(top_srcdir)/tools/cl-double-quotation.sh + +cl_kernel_dir = $(top_srcdir)/cl_kernel + +all-local: $(clx_kernel_sources) + +$(clx_kernel_sources): %.clx: $(cl_kernel_dir)/%.cl + @$(cl_quotation_sh) $< $@ + +CLEANFILES = $(clx_kernel_sources) diff --git a/code_style.sh b/code_style.sh new file mode 100755 index 0000000..eff2211 --- /dev/null +++ b/code_style.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +git status -s | grep -E "\.cpp$|\.h$" | cut -c4- | xargs astyle --indent=spaces=4 --convert-tabs --pad-oper --suffix=none diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..e98ad18 --- /dev/null +++ b/configure.ac @@ -0,0 +1,405 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +m4_define([xcam_major_version], [1]) +m4_define([xcam_minor_version], [1]) +m4_define([xcam_micro_version], [0]) +m4_define([xcam_version], [xcam_major_version.xcam_minor_version.xcam_micro_version]) + +AC_PREREQ([2.60]) +AC_CONFIG_MACRO_DIR([m4]) +AC_INIT([libxcam], [xcam_version], [feng.yuan@intel.com], [libxcam]) +AC_CONFIG_HEADERS([config.h]) +AM_INIT_AUTOMAKE([foreign subdir-objects]) + +#xcam version +XCAM_MAJOR_VERSION=xcam_major_version +XCAM_MINOR_VERSION=xcam_minor_version +XCAM_MICRO_VERSION=xcam_micro_version +XCAM_VERSION=xcam_version +XCAM_VERSION_HEX="0x$XCAM_MAJOR_VERSION$XCAM_MINOR_VERSION$XCAM_MICRO_VERSION" +AC_DEFINE_UNQUOTED(XCAM_VERSION, $XCAM_VERSION_HEX, + [define libxcam version]) +AC_SUBST(XCAM_VERSION) + +XCAM_LT_VERSION="xcam_major_version:xcam_minor_version:xcam_micro_version" +XCAM_LT_LDFLAGS="-version-number $XCAM_LT_VERSION" +AC_SUBST(XCAM_LT_VERSION) +AC_SUBST(XCAM_LT_LDFLAGS) + +# Checks for programs. +AC_PROG_CC +AC_PROG_CXX +AC_PROG_INSTALL +PKG_PROG_PKG_CONFIG +LT_INIT + +AC_ARG_ENABLE(debug, + AS_HELP_STRING([--enable-debug], + [enable debug, @<:@default=no@:>@]), + [], [enable_debug="no"]) +AM_CONDITIONAL([DEBUG], [test "$enable_debug" = "yes"]) + +AC_ARG_ENABLE(profiling, + AS_HELP_STRING([--enable-profiling], + [enable profiling, @<:@default=no@:>@]), + [], [enable_profiling="no"]) + +AC_ARG_ENABLE(drm, + AS_HELP_STRING([--enable-drm], + [enable drm buffer, @<:@default=no@:>@]), + [], [enable_drm="no"]) + +AC_ARG_ENABLE([aiq], + AS_HELP_STRING([--enable-aiq], + [enable Aiq 3A algorithm build, @<:@default=no@:>@]), + [], [enable_aiq="no"]) + +AC_ARG_ENABLE([gst], + AS_HELP_STRING([--enable-gst], + [enable gstreamer plugin build, @<:@default=no@:>@]), + [], [enable_gst="no"]) + +AC_ARG_ENABLE(libcl, + AS_HELP_STRING([--enable-libcl], + [enable libcl image processor, @<:@default=yes@:>@]), + [], [enable_libcl="yes"]) + +AC_ARG_ENABLE(opencv, + AS_HELP_STRING([--enable-opencv], + [enable opencv library, @<:@default=no@:>@]), + [], [enable_opencv="no"]) + +AC_ARG_ENABLE(capi, + AS_HELP_STRING([--enable-capi], + [enable libxcam-capi library, @<:@default=yes@:>@]), + [], [enable_capi="yes"]) + +# documentation +AC_ARG_ENABLE(docs, + [AC_HELP_STRING([--enable-docs], + [build Doxygen documentation @<:@default=no@:>@])], + [], [enable_docs="no"]) + +AC_ARG_ENABLE([3alib], + AS_HELP_STRING([--enable-3alib], + [enable 3A lib build, @<:@default=no@:>@]), + [], [enable_3alib="no"]) + +AC_ARG_ENABLE([smartlib], + AS_HELP_STRING([--enable-smartlib], + [enable smart analysis lib build, @<:@default=no@:>@]), + [], [enable_smartlib="no"]) + +# Check for Doxygen +if test "$enable_docs" = "yes"; then + AC_CHECK_TOOL([DOXYGEN], [doxygen], [no]) + if test "$DOXYGEN" = "no"; then + enable_docs="no" + fi +fi +AM_CONDITIONAL(ENABLE_DOCS, test "$enable_docs" = "yes") + +# check profiling +ENABLE_PROFILING=0 +if test "$enable_profiling" = "yes"; then + ENABLE_PROFILING=1 +fi + +# check drm +HAVE_LIBDRM=0 +if test "$enable_drm" = "yes"; then + PKG_CHECK_MODULES(LIBDRM, [libdrm], [HAVE_LIBDRM=1], [HAVE_LIBDRM=0]) +fi + +# check libcl +HAVE_LIBCL=0 +if test "$enable_libcl" = "yes"; then + PKG_CHECK_MODULES(LIBCL, [libcl], [HAVE_LIBCL=1], [HAVE_LIBCL=0]) +fi + +if test "$enable_libcl" = "yes" && test "$HAVE_LIBCL" -eq 0; then + PKG_CHECK_MODULES(LIBCL, [OpenCL], [HAVE_LIBCL=1], [HAVE_LIBCL=0]) +fi + +if test "$HAVE_LIBCL" -eq 1; then + AC_CHECK_PROGS([GAWK], [gawk], [no]) + if test "x$GAWK" = "xno"; then + AC_MSG_ERROR([gawk not found]) + fi + + if test "$HAVE_LIBDRM" -eq 1; then + HAVE_CL_INTEL_H=1 + AC_CHECK_HEADERS([CL/cl_intel.h], [HAVE_CL_INTEL_H=1], [HAVE_CL_INTEL_H=0]) + if test "$HAVE_CL_INTEL_H" -eq 0; then + # https://raw.githubusercontent.com/intel/beignet/Release_v1.3/include/CL/cl_intel.h + XCAM_WGET( + [https://cgit.freedesktop.org/beignet/plain/include/CL/cl_intel.h?id=Release_v1.3.0], + [./ext/beignet/include/CL/cl_intel.h], + [6a6619073cb35e6987b7379a5a1a1497]) + + CPPFLAGS="$CPPFLAGS -I\$(top_srcdir)/ext/beignet/include" + fi + fi +fi + +# check opencv minimum version number +HAVE_OPENCV=0 +if test "$enable_opencv" = "yes"; then + OPENCV_VERSION_STR=`$PKG_CONFIG --modversion opencv` + PKG_CHECK_MODULES([OPENCV], [opencv >= 3.0.0], [HAVE_OPENCV=1], [HAVE_OPENCV=0]) + echo "OpenCV version:"$OPENCV_VERSION_STR "minimum required version:3.0.0" "have opencv:"$HAVE_OPENCV +fi + +# check opencv videostab module +ENABLE_DVS=0 +if test "$HAVE_OPENCV" -eq 1; then + AC_LANG(C++) + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $OPENCV_CFLAGS" + saved_LIBS="$LIBS" + LIBS="$LIBS $OPENCV_LIBS" + AC_CHECK_HEADER([opencv2/videostab.hpp], [ENABLE_DVS=1], [ENABLE_DVS=0]) + CPPFLAGS="$saved_CPPFLAGS" + LIBS="$saved_LIBS" +fi + +# check dvs opencl path +ENABLE_DVS_CL_PATH=0 +if test "$HAVE_OPENCV" -eq 1; then + AC_LANG(C++) + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $OPENCV_CFLAGS" + saved_LIBS="$LIBS" + LIBS="$LIBS $OPENCV_LIBS" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include <opencv2/core.hpp> + #include <opencv2/opencv.hpp> + ]], + [[cv::UMat frame0; + cv::UMat frame1; + cv::videostab::MotionEstimatorRansacL2 est; + cv::videostab::KeypointBasedMotionEstimator kpest(&est); + kpest.estimate(frame0, frame1); + ]] + )], + [ENABLE_DVS_CL_PATH=1], + [ENABLE_DVS_CL_PATH=0] + ) + CPPFLAGS="$saved_CPPFLAGS" + LIBS="$saved_LIBS" +fi + +# check capi build +ENABLE_CAPI=0 +if test "$enable_capi" = "yes"; then + ENABLE_CAPI=1 +fi + +# check AIQ +ENABLE_IA_AIQ=0 +USE_LOCAL_AIQ=0 +if test "$enable_aiq" = "yes"; then + ENABLE_IA_AIQ=1 + PKG_CHECK_MODULES(IA_AIQ, ia_imaging, + PKG_CHECK_EXISTS(ia_imaging >= 2.7, + AC_DEFINE(HAVE_AIQ_2_7, 1, [defined if module ia_imaging >= v2.0_007 is found]) + ), + [USE_LOCAL_AIQ=1] + ) + + if test "$USE_LOCAL_AIQ" -eq 1; then + #check HAVE_AIQ_2_7 + AC_CACHE_CHECK([for ext/ia_imaging >=v2.0_007], + ac_cv_have_aiq_2_7, [ + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS -I./ext/ia_imaging/include" + saved_LIBS="$LIBS" + LIBS="$LIBS" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include <stdint.h> + #include <stdio.h> + #include "ia_aiq_types.h" + ]], + [[ia_aiq_ae_results ae_result; + ae_result.flashes = NULL; + ]] + )], + [ac_cv_have_aiq_2_7="yes"], + [ac_cv_have_aiq_2_7="no"] + ) + CPPFLAGS="$saved_CPPFLAGS" + LIBS="$saved_LIBS" + ]) + + if test "$ac_cv_have_aiq_2_7" = "yes"; then + AC_DEFINE(HAVE_AIQ_2_7, 1, [defined if ia_imaging >= v2.0_007 is found]) + fi + fi + + if test "$USE_LOCAL_AIQ" -eq 0; then + IA_IMAGING_CFLAGS="$IA_AIQ_CFLAGS" + IA_IMAGING_LIBS="$IA_AIQ_LIBS" + else + IA_IMAGING_CFLAGS="-I\$(top_srcdir)/ext/ia_imaging/include" + IA_IMAGING_LIBS="-L\$(top_srcdir)/ext/ia_imaging/lib -lia_aiq -lia_isp_2_2 -lia_cmc_parser -lia_mkn -lia_nvm -lia_exc -lia_log" + fi + AC_SUBST(IA_IMAGING_CFLAGS) + AC_SUBST(IA_IMAGING_LIBS) + LIBS="$LIBS $IA_IMAGING_LIBS" +fi + +# check 3a lib build +ENABLE_3ALIB=0 +if test "$enable_3alib" = "yes"; then + ENABLE_3ALIB=1 +fi +AM_CONDITIONAL([ENABLE_3ALIB], [test "$ENABLE_3ALIB" -eq 1]) + +# check smart analysis lib build +ENABLE_SMART_LIB=0 +if test "$enable_smartlib" = "yes"; then + ENABLE_SMART_LIB=1 +fi +AM_CONDITIONAL([ENABLE_SMART_LIB], [test "$ENABLE_SMART_LIB" -eq 1]) + +# check atomisp headers +USE_LOCAL_ATOMISP=0 +#AC_CHECK_HEADERS([linux/atomisp.h], [USE_LOCAL_ATOMISP=0], [USE_LOCAL_ATOMISP=1]) +AC_CACHE_CHECK([for linux/atomisp.h], + ac_cv_have_atomisp_headers, [ + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS" + saved_LIBS="$LIBS" + LIBS="$LIBS" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#ifndef __user + #define __user + #endif + #include <stdint.h> + #include <stdio.h> + #include <linux/atomisp.h>]], + [[struct atomisp_parm param;]] + )], + [ac_cv_have_atomisp_headers="yes"], + [ac_cv_have_atomisp_headers="no" USE_LOCAL_ATOMISP=1] + ) + CPPFLAGS="$saved_CPPFLAGS" + LIBS="$saved_LIBS" +]) + + +# build gstreamer plugin +GST_API_VERSION=1.0 +GST_VERSION_REQUIRED=1.2.3 +ENABLE_GST=0 +if test "$enable_gst" = "yes"; then + ENABLE_GST=1 + PKG_CHECK_MODULES([GST], [gstreamer-$GST_API_VERSION >= $GST_VERSION_REQUIRED]) + PKG_CHECK_MODULES([GST_ALLOCATOR], [gstreamer-allocators-$GST_API_VERSION >= $GST_VERSION_REQUIRED]) + PKG_CHECK_MODULES([GST_VIDEO], [gstreamer-video-$GST_API_VERSION >= $GST_VERSION_REQUIRED]) +fi +AM_CONDITIONAL([ENABLE_GST], [test "$ENABLE_GST" -eq 1]) + +dnl set XCAM_CFLAGS and XCAM_CXXFLAGS +XCAM_CFLAGS=" -fPIC -DSTDC99 -W -Wall -D_REENTRANT -Wformat -Wformat-security -fstack-protector" +if test "$enable_debug" = "yes"; then + XCAM_CFLAGS="$XCAM_CFLAGS -g -DDEBUG" +fi +XCAM_CXXFLAGS="$XCAM_CFLAGS -std=c++0x" +AC_SUBST(XCAM_CFLAGS) +AC_SUBST(XCAM_CXXFLAGS) + +PTHREAD_LDFLAGS="$PTHREAD_LDFLAGS -pthread" +AC_SUBST(PTHREAD_LDFLAGS) + +# define macor in config.h +AC_DEFINE_UNQUOTED([ENABLE_PROFILING], $ENABLE_PROFILING, + [enable profiling]) + +AC_DEFINE_UNQUOTED([HAVE_LIBDRM], $HAVE_LIBDRM, + [have libdrm]) +AM_CONDITIONAL([HAVE_LIBDRM], [test "$HAVE_LIBDRM" -eq 1]) + +AC_DEFINE_UNQUOTED([HAVE_LIBCL], $HAVE_LIBCL, + [have libcl]) +AM_CONDITIONAL([HAVE_LIBCL], [test "$HAVE_LIBCL" -eq 1]) + +AC_DEFINE_UNQUOTED([HAVE_OPENCV], $HAVE_OPENCV, + [have opencv]) +AM_CONDITIONAL([HAVE_OPENCV], [test "$HAVE_OPENCV" -eq 1]) + +AC_DEFINE_UNQUOTED([ENABLE_DVS], $ENABLE_DVS, + [enable dvs]) +AM_CONDITIONAL([ENABLE_DVS], [test "$ENABLE_DVS" -eq 1]) + +AC_DEFINE_UNQUOTED([ENABLE_DVS_CL_PATH], $ENABLE_DVS_CL_PATH, + [enable dvs cl path]) +AM_CONDITIONAL([ENABLE_DVS_CL_PATH], [test "$ENABLE_DVS_CL_PATH" -eq 1]) + +AC_DEFINE_UNQUOTED([ENABLE_CAPI], $ENABLE_CAPI, + [enable capi build]) +AM_CONDITIONAL([ENABLE_CAPI], [test "$ENABLE_CAPI" -eq 1]) + +#atomisp +AM_CONDITIONAL([USE_LOCAL_ATOMISP], [test "$USE_LOCAL_ATOMISP" -eq 1]) + +# aiq (ia_imaging) +AC_DEFINE_UNQUOTED([HAVE_IA_AIQ], $ENABLE_IA_AIQ, + [have aiq binary]) +AM_CONDITIONAL([ENABLE_IA_AIQ], [test "$ENABLE_IA_AIQ" -eq 1]) +AM_CONDITIONAL([USE_LOCAL_AIQ], [test "$USE_LOCAL_AIQ" -eq 1]) + +AC_CONFIG_FILES([Makefile + clx_kernel/Makefile + xcore/Makefile + modules/Makefile + modules/soft/Makefile + modules/isp/Makefile + modules/ocl/Makefile + wrapper/Makefile + wrapper/gstreamer/Makefile + wrapper/gstreamer/interface/Makefile + plugins/Makefile + plugins/3a/hybrid/Makefile + plugins/3a/aiq/Makefile + plugins/3a/Makefile + plugins/smart/Makefile + plugins/smart/dvs/Makefile + plugins/smart/dvs/libdvs/Makefile + plugins/smart/sample/Makefile + capi/Makefile + tests/Makefile + pkgconfig/Makefile + pkgconfig/libxcam.pc + ]) + +AC_OUTPUT + +if test "$HAVE_LIBDRM" -eq 1; then have_drm="yes"; else have_drm="no"; fi +if test "$USE_LOCAL_AIQ" -eq 1; then use_local_aiq="yes"; else use_local_aiq="no"; fi +if test "$USE_LOCAL_ATOMISP" -eq 1; then use_local_atomisp="yes"; else use_local_atomisp="no"; fi +if test "$HAVE_LIBCL" -eq 1; then have_libcl="yes"; else have_libcl="no"; fi +if test "$HAVE_OPENCV" -eq 1; then have_opencv="yes"; else have_opencv="no"; fi +if test "$ENABLE_DVS" -eq 1; then enable_dvs="yes"; else enable_dvs="no"; fi + +echo " + libxcam configuration summary + version : $XCAM_VERSION + enable debug : $enable_debug + enable profiling : $enable_profiling + enable drm lib : $have_drm + build GStreamer plugin : $enable_gst + build aiq analyzer : $enable_aiq + use local aiq : $use_local_aiq + use local atomisp : $use_local_atomisp + have opencl lib : $have_libcl + have opencv lib : $have_opencv + enable 3a lib : $enable_3alib + enable smart analysis lib : $enable_smartlib + enable dvs : $enable_dvs + enable libxcam-capi lib : $enable_capi +" diff --git a/doc/Doxyfile b/doc/Doxyfile new file mode 100644 index 0000000..6f18c04 --- /dev/null +++ b/doc/Doxyfile @@ -0,0 +1,2303 @@ +# Doxyfile 1.8.6 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "LibXCam" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = $(XCAM_HEADER_DIR) + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. Do not use file names with spaces, bibtex cannot handle them. See +# also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = $(XCAM_HEADER_FILES) + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = 3rd-party + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- +# defined cascading style sheet that is included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet file to the output directory. For an example +# see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. There +# are two flavours of web server based searching depending on the +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for +# searching and an index file used by the script. When EXTERNAL_SEARCH is +# enabled the indexing and searching needs to be provided by external tools. See +# the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer ( doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer ( doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Searching" for details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when enabling USE_PDFLATEX this option is only used for generating +# bitmaps for formulas in the HTML output, but not in the Makefile that is +# written to the output directory. +# The default file is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. To get the times font for +# instance you can specify +# EXTRA_PACKAGES=times +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the +# generated LaTeX document. The header should contain everything until the first +# chapter. If it is left blank doxygen will generate a standard header. See +# section "Doxygen usage" for information on how to let doxygen write the +# default header to a separate file. +# +# Note: Only use a user-defined header if you know what you are doing! The +# following commands have a special meaning inside the header: $title, +# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will +# replace them by respectively the title of the page, the current date and time, +# only the current date, the version number of doxygen, the project name (see +# PROJECT_NAME), or the project number (see PROJECT_NUMBER). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the +# generated LaTeX document. The footer should contain everything after the last +# chapter. If it is left blank doxygen will generate a standard footer. +# +# Note: Only use a user-defined footer if you know what you are doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES to get a +# higher quality PDF documentation. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. This option is also used +# when generating formulas in HTML. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source +# code with syntax highlighting in the LaTeX output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = YES + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = YES + +# Load stylesheet definitions from file. Syntax is similar to doxygen's config +# file, i.e. a series of assignments. You only have to provide replacements, +# missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's config file. A template extensions file can be generated +# using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a +# validating XML parser to check the syntax of the XML files. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify a XML DTD, which can be used by a +# validating XML parser to check the syntax of the XML files. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen +# Definitions (see http://autogen.sf.net) file that captures the structure of +# the code including all documentation. Note that this feature is still +# experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names +# in the source code. If set to NO only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES the includes files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all refrences to function-like macros that are alone on a line, have an +# all uppercase name, and do not end with a semicolon. Such function macros are +# typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have an unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external class will be listed in the +# class index. If set to NO only the inherited external classes will be listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in +# the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of 'which perl'). +# The default file (with absolute path) is: /usr/bin/perl. + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to +# NO turns the diagrams off. Note that this option also works with HAVE_DOT +# disabled, but it is recommended to install and use dot, since it yields more +# powerful graphs. +# The default value is: YES. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see: +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font n the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for +# each documented class showing the direct and indirect inheritance relations. +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, gif and svg. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = NO + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot +# files that are used to generate the various graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_CLEANUP = YES diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..3647c90 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,65 @@ +# Copyright (c) 2007-2011 Intel Corporation. All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +all: html +install-data-local: install-html + +EXTRA_DIST = \ + Doxyfile \ + $(NULL) + +XCAM_HEADER_DIR = $(top_srcdir)/src +XCAM_HEADER_FILES = \ + $(XCAM_HEADER_DIR)/xcam_3a.h \ + $(XCAM_HEADER_DIR)/xcam_3athread.h \ + $(XCAM_HEADER_DIR)/xcam_3a_types.h \ + $(XCAM_HEADER_DIR)/xcam_v4l2subdev.h \ + $(top_srcdir)/interface/gstxcaminterface.h \ + $(NULL) + +XCAM_HTML_FOOTER = xcam_footer.html +XCAM_HTML_FRAGMENTS = $(XCAM_HTML_FOOTER) + +export XCAM_HEADER_DIR +export XCAM_HEADER_FILES +export XCAM_HTML_FOOTER +html-out/index.html: Doxyfile $(XCAM_HEADER_FILES) $(XCAM_HTML_FRAGMENTS) + $(DOXYGEN) $< + +if ENABLE_DOCS +html: html-out/index.html +install-html-local: + install -d $(DESTDIR)$(docdir)/html + for file in `ls html-out/` ; do \ + if test -f html-out/$$file ; then \ + install -m 0644 html-out/$$file $(DESTDIR)$(docdir)/html ; \ + else \ + install -d $(DESTDIR)$(docdir)/html/$$file ; \ + install -m 0644 html-out/$$file/* $(DESTDIR)$(docdir)/html/$$file; \ + fi ; \ + done +uninstall-local: + rm -rf $(DESTDIR)$(docdir)/html +endif + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/doc/xcam_cl_pipeline_20170407.png b/doc/xcam_cl_pipeline_20170407.png Binary files differnew file mode 100644 index 0000000..2763d2d --- /dev/null +++ b/doc/xcam_cl_pipeline_20170407.png diff --git a/doc/xcam_dataflow_20160930.png b/doc/xcam_dataflow_20160930.png Binary files differnew file mode 100644 index 0000000..cfde1f8 --- /dev/null +++ b/doc/xcam_dataflow_20160930.png diff --git a/doc/xcam_footer.html b/doc/xcam_footer.html new file mode 100644 index 0000000..3580c2e --- /dev/null +++ b/doc/xcam_footer.html @@ -0,0 +1,6 @@ +<hr class="footer"/><address class="footer"> +<small> +Generated for $projectname by <a href="http://www.doxygen.org/index.html">Doxygen</a> $doxygenversion +</small></address> +</body> +</html> diff --git a/doc/xcam_framework_20170407.png b/doc/xcam_framework_20170407.png Binary files differnew file mode 100644 index 0000000..ea7b7ee --- /dev/null +++ b/doc/xcam_framework_20170407.png diff --git a/doc/yocto/libxcam_sample.bb b/doc/yocto/libxcam_sample.bb new file mode 100644 index 0000000..0ebdd31 --- /dev/null +++ b/doc/yocto/libxcam_sample.bb @@ -0,0 +1,47 @@ +SUMMARY = "Libxcam" +DESCRIPTION = "Libxcam: Extended camera features and cross platform computer vision project" +HOMEPAGE = "https://github.com/01org/libxcam/wiki" +LICENSE = "Apache-2.0" + +PR = "r0" +S = "${WORKDIR}/git" + +LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=a739187a9544e0731270d11a8f5be792" + +SRC_URI = "git://github.com/01org/libxcam.git;branch=master" +SRCREV = "${AUTOREV}" + +DEPENDS = "glib-2.0 libdrm beignet opencv gstreamer1.0 gstreamer1.0-plugins-base" + +inherit autotools pkgconfig + +EXTRA_OECONF = "--enable-gst --enable-drm --enable-libcl --enable-smartlib --enable-opencv" + +CFLAGS += "-fPIE -fPIC" +CFLAGS += "-O2 -D_FORTIFY_SOURCE=2" +CFLAGS += "-Wformat -Wformat-security" +CFLAGS += "-fstack-protector" + +LDFLAGS += "-z noexecstack" +LDFLAGS += "-z relro -z now" + +PACKAGES += "${PN}-test" + +FILES_${PN} += "${libdir}/libxcam_core.so.*" +FILES_${PN} += "${libdir}/libxcam_ocl.so.*" +FILES_${PN} += "${libdir}/gstreamer-1.0/libgstxcamfilter.*" + +FILES_${PN}-dev += "${includedir}/xcam/*" +FILES_${PN}-dev += "${libdir}/pkgconfig/libxcam.pc" +FILES_${PN}-dev += "${libdir}/libxcam_core.so" +FILES_${PN}-dev += "${libdir}/libxcam_core.la" +FILES_${PN}-dev += "${libdir}/libxcam_core.a" +FILES_${PN}-dev += "${libdir}/libxcam_ocl.so" +FILES_${PN}-dev += "${libdir}/libxcam_ocl.la" + +FILES_${PN}-test = "${bindir}/test-*" + +FILES_${PN}-dbg += "${libdir}/gstreamer-1.0/.debug/*" +FILES_${PN}-dbg += "${libdir}/.debug/" +FILES_${PN}-dbg += "${bindir}/.debug/" + diff --git a/ext/atomisp b/ext/atomisp new file mode 160000 +Subproject 79cf910fb8d8f547c80c3ceb3188b319c55c98d diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 0000000..590d59b --- /dev/null +++ b/m4/.gitignore @@ -0,0 +1,7 @@ +# http://www.gnu.org/software/automake + +libtool.m4 +lt~obsolete.m4 +ltoptions.m4 +ltsugar.m4 +ltversion.m4 diff --git a/m4/xcam-utils.m4 b/m4/xcam-utils.m4 new file mode 100644 index 0000000..2de7deb --- /dev/null +++ b/m4/xcam-utils.m4 @@ -0,0 +1,30 @@ +# XCAM_MD5SUM([file], [md5sum], [if-true], [if-false]) +AC_DEFUN([XCAM_MD5SUM], +[ + AS_IF([test -f $1], + [ + md5=`md5sum $1 | cut --delimiter=' ' --fields=1` + AS_IF([test "x$md5" = "x$2"], [$3], [$4]) + ], + [$4]) +]) + +# XCAM_WGET([url], [output-file], [md5sum]) +AC_DEFUN([XCAM_WGET], +[ + MD5_CORRECT=yes + XCAM_MD5SUM([$2], [$3], [MD5_CORRECT=yes], [MD5_CORRECT=no]) + AS_IF([test "x$MD5_CORRECT" = "xyes"], + [AC_MSG_NOTICE([checking $2 md5sum ... ok])], + [ + AC_MSG_NOTICE([downloading $2...]) + dir=`dirname $2` + AS_IF([test ! -d $dir], [mkdir -p $dir]) + + wget --tries=2 --timeout=5 -q --no-use-server-timestamps $1 -O $2 + AS_IF([test "$?" != 0], [AC_MSG_ERROR([download/wget $2 failed])]) + + XCAM_MD5SUM([$2], [$3], [AC_MSG_NOTICE([checking $2 md5sum ... ok])], [AC_MSG_ERROR([checking $2 md5sum ... failed])]) + ]) +]) + diff --git a/modules/Makefile.am b/modules/Makefile.am new file mode 100644 index 0000000..fd362f8 --- /dev/null +++ b/modules/Makefile.am @@ -0,0 +1,13 @@ +if HAVE_LIBCL +OCL_DIR = ocl +else +OCL_DIR = +endif + +if ENABLE_IA_AIQ +ISP_DIR = isp +else +ISP_DIR = +endif + +SUBDIRS = soft $(ISP_DIR) $(OCL_DIR) diff --git a/modules/isp/Makefile.am b/modules/isp/Makefile.am new file mode 100644 index 0000000..9ad978c --- /dev/null +++ b/modules/isp/Makefile.am @@ -0,0 +1,81 @@ +lib_LTLIBRARIES = libxcam_isp.la + +XCAMISP_CXXFLAGS = $(XCAM_CXXFLAGS) +XCAMISP_LIBS = \ + $(NULL) + +if USE_LOCAL_ATOMISP +XCAMISP_CXXFLAGS += \ + -I$(top_srcdir)/ext/atomisp \ + $(NULL) +endif + +if ENABLE_IA_AIQ +XCAMISP_CXXFLAGS += \ + $(IA_IMAGING_CFLAGS) \ + $(NULL) + +XCAMISP_LIBS += \ + $(IA_IMAGING_LIBS) \ + $(NULL) +endif + +xcam_isp_sources = \ + aiq3a_utils.cpp \ + atomisp_device.cpp \ + isp_poll_thread.cpp \ + isp_image_processor.cpp \ + isp_controller.cpp \ + isp_config_translator.cpp \ + x3a_isp_config.cpp \ + sensor_descriptor.cpp \ + iq/x3a_analyze_tuner.cpp \ + iq/x3a_ciq_tuning_handler.cpp \ + iq/x3a_ciq_tnr_tuning_handler.cpp \ + iq/x3a_ciq_bnr_ee_tuning_handler.cpp \ + iq/x3a_ciq_wavelet_tuning_handler.cpp \ + x3a_statistics_queue.cpp \ + libtbd.c \ + xcam_cpf_reader.c \ + $(NULL) + +if ENABLE_IA_AIQ +xcam_isp_sources += \ + aiq_handler.cpp \ + hybrid_analyzer.cpp \ + hybrid_analyzer_loader.cpp \ + x3a_analyzer_aiq.cpp \ + $(NULL) +endif + +if HAVE_LIBDRM +XCAMISP_CXXFLAGS += $(LIBDRM_CFLAGS) +XCAMISP_LIBS += \ + -ldrm_intel \ + $(LIBDRM_LIBS) \ + $(NULL) +endif + +libxcam_isp_la_SOURCES = \ + $(xcam_isp_sources) \ + $(NULL) + +libxcam_isp_la_CXXFLAGS = \ + $(XCAMISP_CXXFLAGS) \ + -I$(top_srcdir)/xcore \ + -I$(top_srcdir)/modules/isp \ + $(NULL) + +libxcam_isp_la_CFLAGS = $(libxcam_isp_la_CXXFLAGS) + +libxcam_isp_la_LIBADD = \ + $(top_builddir)/xcore/libxcam_core.la \ + $(XCAMISP_LIBS) \ + $(NULL) + +libxcam_isp_la_LDFLAGS = \ + $(XCAM_LT_LDFLAGS) \ + $(PTHREAD_LDFLAGS) \ + $(NULL) + +libxcam_isp_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/modules/isp/aiq3a_utils.cpp b/modules/isp/aiq3a_utils.cpp new file mode 100644 index 0000000..d78c115 --- /dev/null +++ b/modules/isp/aiq3a_utils.cpp @@ -0,0 +1,314 @@ +/* + * aiq3a_util.cpp - aiq 3a utility: + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Shincy Tu <shincy.tu@intel.com> + */ + +#include "aiq3a_utils.h" +#include "x3a_isp_config.h" + +namespace XCam { + +bool +translate_3a_stats (XCam3AStats *from, struct atomisp_3a_statistics *to) +{ + XCAM_ASSERT (from); + XCAM_ASSERT (to); + + struct atomisp_grid_info &to_info = to->grid_info; + XCam3AStatsInfo &from_info = from->info; + uint32_t color_count = (from_info.grid_pixel_size / 2) * (from_info.grid_pixel_size / 2); + + XCAM_ASSERT (to_info.bqs_per_grid_cell == 8); + + for (uint32_t i = 0; i < from_info.height; ++i) + for (uint32_t j = 0; j < from_info.width; ++j) { + to->data [i * to_info.aligned_width + j].ae_y = + from->stats [i * from_info.aligned_width + j].avg_y * color_count; + to->data [i * to_info.aligned_width + j].awb_gr = + from->stats [i * from_info.aligned_width + j].avg_gr * color_count; + to->data [i * to_info.aligned_width + j].awb_r = + from->stats [i * from_info.aligned_width + j].avg_r * color_count; + to->data [i * to_info.aligned_width + j].awb_b = + from->stats [i * from_info.aligned_width + j].avg_b * color_count; + to->data [i * to_info.aligned_width + j].awb_gb = + from->stats [i * from_info.aligned_width + j].avg_gb * color_count; + to->data [i * to_info.aligned_width + j].awb_cnt = + from->stats [i * from_info.aligned_width + j].valid_wb_count; + to->data [i * to_info.aligned_width + j].af_hpf1 = + from->stats [i * from_info.aligned_width + j].f_value1; + to->data [i * to_info.aligned_width + j].af_hpf2 = + from->stats [i * from_info.aligned_width + j].f_value2; + } + return true; +} + +static void +matrix_3x3_mutiply (double *dest, const double *src1, const double *src2) +{ + dest[0] = src1[0] * src2[0] + src1[1] * src2[3] + src1[2] * src2[6]; + dest[1] = src1[0] * src2[1] + src1[1] * src2[4] + src1[2] * src2[7]; + dest[2] = src1[0] * src2[2] + src1[1] * src2[5] + src1[2] * src2[8]; + + dest[3] = src1[3] * src2[0] + src1[4] * src2[3] + src1[5] * src2[6]; + dest[4] = src1[3] * src2[1] + src1[4] * src2[4] + src1[5] * src2[7]; + dest[5] = src1[3] * src2[2] + src1[4] * src2[5] + src1[5] * src2[8]; + + dest[6] = src1[6] * src2[0] + src1[7] * src2[3] + src1[8] * src2[6]; + dest[7] = src1[6] * src2[1] + src1[7] * src2[4] + src1[8] * src2[7]; + dest[8] = src1[6] * src2[2] + src1[7] * src2[5] + src1[8] * src2[8]; +} + +static uint32_t +translate_atomisp_parameters ( + const struct atomisp_parameters &atomisp_params, + XCam3aResultHead *results[], uint32_t max_count) +{ + uint32_t result_count = 0; + double coefficient = 0.0; + + /* Translation for white balance */ + XCAM_ASSERT (result_count < max_count); + if (atomisp_params.wb_config) { + XCam3aResultWhiteBalance *wb = xcam_malloc0_type (XCam3aResultWhiteBalance); + XCAM_ASSERT (wb); + wb->head.type = XCAM_3A_RESULT_WHITE_BALANCE; + wb->head.process_type = XCAM_IMAGE_PROCESS_ALWAYS; + wb->head.version = xcam_version (); + coefficient = pow (2, (16 - atomisp_params.wb_config->integer_bits)); + wb->r_gain = atomisp_params.wb_config->r / coefficient; + wb->gr_gain = atomisp_params.wb_config->gr / coefficient; + wb->gb_gain = atomisp_params.wb_config->gb / coefficient; + wb->b_gain = atomisp_params.wb_config->b / coefficient; + results[result_count++] = (XCam3aResultHead*)wb; + } + + /* Translation for black level correction */ + XCAM_ASSERT (result_count < max_count); + if (atomisp_params.ob_config) { + XCam3aResultBlackLevel *blc = xcam_malloc0_type (XCam3aResultBlackLevel); + XCAM_ASSERT (blc); + blc->head.type = XCAM_3A_RESULT_BLACK_LEVEL; + blc->head.process_type = XCAM_IMAGE_PROCESS_ALWAYS; + blc->head.version = xcam_version (); + if (atomisp_params.ob_config->mode == atomisp_ob_mode_fixed) { + blc->r_level = atomisp_params.ob_config->level_r / (double)65536; + blc->gr_level = atomisp_params.ob_config->level_gr / (double)65536; + blc->gb_level = atomisp_params.ob_config->level_gb / (double)65536; + blc->b_level = atomisp_params.ob_config->level_b / (double)65536; + } + results[result_count++] = (XCam3aResultHead*)blc; + } + + /* Translation for color correction */ + XCAM_ASSERT (result_count < max_count); + if (atomisp_params.yuv2rgb_cc_config) { + static const double rgb2yuv_matrix [XCAM_COLOR_MATRIX_SIZE] = { + 0.299, 0.587, 0.114, + -0.14713, -0.28886, 0.436, + 0.615, -0.51499, -0.10001 + }; + static const double r_ycgco_matrix [XCAM_COLOR_MATRIX_SIZE] = { + 0.25, 0.5, 0.25, + -0.25, 0.5, -0.25, + 0.5, 0, -0.5 + }; + + double tmp_matrix [XCAM_COLOR_MATRIX_SIZE] = {0.0}; + double cc_matrix [XCAM_COLOR_MATRIX_SIZE] = {0.0}; + XCam3aResultColorMatrix *cm = xcam_malloc0_type (XCam3aResultColorMatrix); + XCAM_ASSERT (cm); + cm->head.type = XCAM_3A_RESULT_RGB2YUV_MATRIX; + cm->head.process_type = XCAM_IMAGE_PROCESS_ALWAYS; + cm->head.version = xcam_version (); + coefficient = pow (2, atomisp_params.yuv2rgb_cc_config->fraction_bits); + for (int i = 0; i < XCAM_COLOR_MATRIX_SIZE; i++) { + tmp_matrix [i] = atomisp_params.yuv2rgb_cc_config->matrix [i] / coefficient; + } + matrix_3x3_mutiply (cc_matrix, tmp_matrix, r_ycgco_matrix); + matrix_3x3_mutiply (cm->matrix, rgb2yuv_matrix, cc_matrix); + //results = yuv2rgb_matrix * tmp_matrix * r_ycgco_matrix + results[result_count++] = (XCam3aResultHead*)cm; + } + + /* Translation for gamma table */ + XCAM_ASSERT (result_count < max_count); + if (atomisp_params.g_gamma_table) { + XCam3aResultGammaTable *gt = xcam_malloc0_type (XCam3aResultGammaTable); + XCAM_ASSERT (gt); + gt->head.type = XCAM_3A_RESULT_G_GAMMA; + gt->head.process_type = XCAM_IMAGE_PROCESS_ALWAYS; + gt->head.version = xcam_version (); + for (int i = 0; i < XCAM_GAMMA_TABLE_SIZE; i++) { + gt->table[i] = (double)atomisp_params.g_gamma_table->data.vamem_2[i] / 16; + } + results[result_count++] = (XCam3aResultHead*)gt; + } + + /* Translation for macc matrix table */ + XCAM_ASSERT (result_count < max_count); + if (atomisp_params.macc_config) { + XCam3aResultMaccMatrix *macc = xcam_malloc0_type (XCam3aResultMaccMatrix); + XCAM_ASSERT (macc); + macc->head.type = XCAM_3A_RESULT_MACC; + macc->head.process_type = XCAM_IMAGE_PROCESS_ALWAYS; + macc->head.version = xcam_version (); + coefficient = pow (2, (13 - atomisp_params.macc_config->color_effect)); + for (int i = 0; i < XCAM_CHROMA_AXIS_SIZE * XCAM_CHROMA_MATRIX_SIZE; i++) { + macc->table[i] = (double)atomisp_params.macc_table->data[i] / coefficient; + } + results[result_count++] = (XCam3aResultHead*)macc; + } + + /* Translation for defect pixel correction */ + XCAM_ASSERT (result_count < max_count); + if (atomisp_params.dp_config) { + XCam3aResultDefectPixel *dpc = xcam_malloc0_type (XCam3aResultDefectPixel); + XCAM_ASSERT (dpc); + dpc->head.type = XCAM_3A_RESULT_DEFECT_PIXEL_CORRECTION; + dpc->head.process_type = XCAM_IMAGE_PROCESS_ALWAYS; + dpc->head.version = xcam_version (); + coefficient = pow (2, 16); + dpc->gr_threshold = atomisp_params.dp_config->threshold / coefficient; + dpc->r_threshold = atomisp_params.dp_config->threshold / coefficient; + dpc->b_threshold = atomisp_params.dp_config->threshold / coefficient; + dpc->gb_threshold = atomisp_params.dp_config->threshold / coefficient; + results[result_count++] = (XCam3aResultHead*)dpc; + } + + /* OCL has defined BNR config, no need to translate ISP BNR config */ +#if 0 + /* Translation for bnr config */ + XCAM_ASSERT (result_count < max_count); + if (atomisp_params.nr_config) { + XCam3aResultBayerNoiseReduction *bnr = xcam_malloc0_type (XCam3aResultBayerNoiseReduction); + XCAM_ASSERT (bnr); + bnr->head.type = XCAM_3A_RESULT_BAYER_NOISE_REDUCTION; + bnr->head.process_type = XCAM_IMAGE_PROCESS_ALWAYS; + bnr->head.version = xcam_version (); + bnr->bnr_gain = (double)atomisp_params.nr_config->bnr_gain / pow(2, 16); + bnr->direction = (double)atomisp_params.nr_config->direction / pow(2, 16); + results[result_count++] = (XCam3aResultHead*)bnr; + } +#endif + + return result_count; +} + +uint32_t +translate_3a_results_to_xcam (X3aResultList &list, + XCam3aResultHead *results[], uint32_t max_count) +{ + uint32_t result_count = 0; + for (X3aResultList::iterator iter = list.begin (); iter != list.end (); ++iter) { + SmartPtr<X3aResult> &isp_result = *iter; + + switch (isp_result->get_type()) { + case X3aIspConfig::IspExposureParameters: { + SmartPtr<X3aIspExposureResult> isp_exposure = + isp_result.dynamic_cast_ptr<X3aIspExposureResult> (); + XCAM_ASSERT (isp_exposure.ptr ()); + const XCam3aResultExposure &exposure = isp_exposure->get_standard_result (); + XCam3aResultExposure *new_exposure = xcam_malloc0_type (XCam3aResultExposure); + XCAM_ASSERT (new_exposure); + *new_exposure = exposure; + new_exposure->head.type = XCAM_3A_RESULT_EXPOSURE; + new_exposure->head.process_type = XCAM_IMAGE_PROCESS_ALWAYS; + new_exposure->head.version = xcam_version (); + results[result_count++] = (XCam3aResultHead*)new_exposure; + break; + } + case X3aIspConfig::IspAllParameters: { + SmartPtr<X3aAtomIspParametersResult> isp_3a_all = + isp_result.dynamic_cast_ptr<X3aAtomIspParametersResult> (); + XCAM_ASSERT (isp_3a_all.ptr ()); + const struct atomisp_parameters &atomisp_params = isp_3a_all->get_isp_config (); + result_count += translate_atomisp_parameters (atomisp_params, &results[result_count], max_count - result_count); + break; + } + case XCAM_3A_RESULT_BRIGHTNESS: { + SmartPtr<X3aBrightnessResult> xcam_brightness = + isp_result.dynamic_cast_ptr<X3aBrightnessResult>(); + const XCam3aResultBrightness &brightness = xcam_brightness->get_standard_result(); + XCam3aResultBrightness *new_brightness = xcam_malloc0_type(XCam3aResultBrightness); + XCAM_ASSERT (new_brightness); + *new_brightness = brightness; + results[result_count++] = (XCam3aResultHead*)new_brightness; + break; + } + case XCAM_3A_RESULT_3D_NOISE_REDUCTION: + case XCAM_3A_RESULT_TEMPORAL_NOISE_REDUCTION_YUV: + { + SmartPtr<X3aTemporalNoiseReduction> xcam_tnr = + isp_result.dynamic_cast_ptr<X3aTemporalNoiseReduction> (); + const XCam3aResultTemporalNoiseReduction &tnr = xcam_tnr->get_standard_result(); + XCam3aResultTemporalNoiseReduction *new_tnr = xcam_malloc0_type(XCam3aResultTemporalNoiseReduction); + XCAM_ASSERT (new_tnr); + *new_tnr = tnr; + results[result_count++] = (XCam3aResultHead*)new_tnr; + break; + } + case XCAM_3A_RESULT_EDGE_ENHANCEMENT: + { + SmartPtr<X3aEdgeEnhancementResult> xcam_ee = + isp_result.dynamic_cast_ptr<X3aEdgeEnhancementResult> (); + const XCam3aResultEdgeEnhancement &ee = xcam_ee->get_standard_result(); + XCam3aResultEdgeEnhancement *new_ee = xcam_malloc0_type(XCam3aResultEdgeEnhancement); + XCAM_ASSERT (new_ee); + *new_ee = ee; + results[result_count++] = (XCam3aResultHead*)new_ee; + break; + } + case XCAM_3A_RESULT_BAYER_NOISE_REDUCTION: + { + SmartPtr<X3aBayerNoiseReduction> xcam_bnr = + isp_result.dynamic_cast_ptr<X3aBayerNoiseReduction> (); + const XCam3aResultBayerNoiseReduction &bnr = xcam_bnr->get_standard_result(); + XCam3aResultBayerNoiseReduction *new_bnr = xcam_malloc0_type(XCam3aResultBayerNoiseReduction); + XCAM_ASSERT (new_bnr); + *new_bnr = bnr; + results[result_count++] = (XCam3aResultHead*)new_bnr; + break; + } + case XCAM_3A_RESULT_WAVELET_NOISE_REDUCTION: + { + SmartPtr<X3aWaveletNoiseReduction> xcam_wavelet = + isp_result.dynamic_cast_ptr<X3aWaveletNoiseReduction> (); + const XCam3aResultWaveletNoiseReduction &wavelet = xcam_wavelet->get_standard_result(); + XCam3aResultWaveletNoiseReduction *new_wavelet = xcam_malloc0_type(XCam3aResultWaveletNoiseReduction); + XCAM_ASSERT (new_wavelet); + *new_wavelet = wavelet; + results[result_count++] = (XCam3aResultHead*)new_wavelet; + break; + } + default: { + XCAM_LOG_WARNING ("unknown type(%d) in translation", isp_result->get_type()); + break; + } + } + } + return result_count; +} + +void +free_3a_result (XCam3aResultHead *result) +{ + xcam_free (result); +} + +} diff --git a/modules/isp/aiq3a_utils.h b/modules/isp/aiq3a_utils.h new file mode 100644 index 0000000..41d4bc0 --- /dev/null +++ b/modules/isp/aiq3a_utils.h @@ -0,0 +1,40 @@ +/* + * aiq3a_utils.h - aiq 3a utility: + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Shincy Tu <shincy.tu@intel.com> + */ + +#ifndef XCAM_AIQ_UTILS_H +#define XCAM_AIQ_UTILS_H + + +#include <xcam_std.h> +#include "x3a_result.h" + +#include <base/xcam_3a_stats.h> +#include <linux/atomisp.h> + +namespace XCam { +bool translate_3a_stats (XCam3AStats *from, struct atomisp_3a_statistics *to); +uint32_t translate_3a_results_to_xcam (XCam::X3aResultList &list, + XCam3aResultHead *results[], uint32_t max_count); + +void free_3a_result (XCam3aResultHead *result); +} + +#endif //XCAM_AIQ_UTILS_H diff --git a/modules/isp/aiq_handler.cpp b/modules/isp/aiq_handler.cpp new file mode 100644 index 0000000..3a4d89b --- /dev/null +++ b/modules/isp/aiq_handler.cpp @@ -0,0 +1,1702 @@ +/* + * aiq_handler.cpp - AIQ handler + * + * Copyright (c) 2012-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yan Zhang <yan.y.zhang@intel.com> + */ + +#include "aiq_handler.h" +#include "x3a_isp_config.h" + +#include <string.h> +#include <math.h> + +#include "ia_isp_2_2.h" + +#define MAX_STATISTICS_WIDTH 150 +#define MAX_STATISTICS_HEIGHT 150 + +//#define USE_RGBS_GRID_WEIGHTING +#define USE_HIST_GRID_WEIGHTING + +namespace XCam { + +struct IspInputParameters { + ia_aiq_frame_use frame_use; + ia_aiq_frame_params *sensor_frame_params; + ia_aiq_exposure_parameters *exposure_results; + ia_aiq_awb_results *awb_results; + ia_aiq_gbce_results *gbce_results; + ia_aiq_pa_results *pa_results; +#ifdef HAVE_AIQ_2_7 + ia_aiq_sa_results *sa_results; +#endif + int8_t manual_brightness; + int8_t manual_contrast; + int8_t manual_hue; + int8_t manual_saturation; + int8_t manual_sharpness; + int8_t manual_nr_level; + ia_isp_effect effects; + + IspInputParameters () + : frame_use (ia_aiq_frame_use_preview) + , sensor_frame_params (NULL) + , exposure_results (NULL) + , awb_results (NULL) + , gbce_results (NULL) + , pa_results (NULL) +#ifdef HAVE_AIQ_2_7 + , sa_results (NULL) +#endif + , manual_brightness (0) + , manual_contrast (0) + , manual_hue (0) + , manual_saturation (0) + , manual_sharpness (0) + , manual_nr_level (0) + , effects (ia_isp_effect_none) + {} +}; + +class IaIspAdaptor22 + : public IaIspAdaptor +{ +public: + IaIspAdaptor22 () { + xcam_mem_clear (_input_params); + } + ~IaIspAdaptor22 () { + if (_handle) + ia_isp_2_2_deinit (_handle); + } + + virtual bool init ( + const ia_binary_data *cpf, + unsigned int max_width, + unsigned int max_height, + ia_cmc_t *cmc, + ia_mkn *mkn); + + virtual bool convert_statistics ( + void *statistics, + ia_aiq_rgbs_grid **out_rgbs_grid, + ia_aiq_af_grid **out_af_grid); + + virtual bool run ( + const IspInputParameters *isp_input_params, + ia_binary_data *output_data); + +private: + ia_isp_2_2_input_params _input_params; + +}; + +bool +IaIspAdaptor22::init ( + const ia_binary_data *cpf, + unsigned int max_width, + unsigned int max_height, + ia_cmc_t *cmc, + ia_mkn *mkn) +{ + xcam_mem_clear (_input_params); + _input_params.isp_vamem_type = 1; + _handle = ia_isp_2_2_init (cpf, max_width, max_height, cmc, mkn); + XCAM_FAIL_RETURN (ERROR, _handle, false, "ia_isp 2.2 init failed"); + return true; +} + +bool +IaIspAdaptor22::convert_statistics ( + void *statistics, + ia_aiq_rgbs_grid **out_rgbs_grid, + ia_aiq_af_grid **out_af_grid) +{ + ia_err err; + err = ia_isp_2_2_statistics_convert (_handle, statistics, out_rgbs_grid, out_af_grid); + XCAM_FAIL_RETURN (ERROR, err == ia_err_none, false, "ia_isp 2.2 convert stats failed"); + return true; +} + +bool +IaIspAdaptor22::run ( + const IspInputParameters *isp_input_params, + ia_binary_data *output_data) +{ + ia_err err; + + _input_params.frame_use = isp_input_params->frame_use; + _input_params.sensor_frame_params = isp_input_params->sensor_frame_params; + _input_params.exposure_results = isp_input_params->exposure_results; + _input_params.awb_results = isp_input_params->awb_results; + _input_params.gbce_results = isp_input_params->gbce_results; + _input_params.pa_results = isp_input_params->pa_results; +#ifdef HAVE_AIQ_2_7 + _input_params.sa_results = isp_input_params->sa_results; +#endif + _input_params.manual_brightness = isp_input_params->manual_brightness; + _input_params.manual_contrast = isp_input_params->manual_contrast; + _input_params.manual_hue = isp_input_params->manual_hue; + _input_params.manual_saturation = isp_input_params->manual_saturation; + _input_params.nr_setting.feature_level = ia_isp_feature_level_high; + _input_params.nr_setting.strength = isp_input_params->manual_nr_level; + _input_params.ee_setting.feature_level = ia_isp_feature_level_high; + _input_params.ee_setting.strength = isp_input_params->manual_sharpness; + _input_params.effects = isp_input_params->effects; + + err = ia_isp_2_2_run (_handle, &_input_params, output_data); + XCAM_FAIL_RETURN (ERROR, err == ia_err_none, false, "ia_isp 2.2 run failed"); + return true; +} + +#if 0 + +class IaIspAdaptor15 + : public IaIspAdaptor +{ +public: + IaIspAdaptor15 () { + xcam_mem_clear (&_input_params); + } + ~IaIspAdaptor15 () { + if (_handle) + ia_isp_1_5_deinit (_handle); + } + virtual bool init ( + const ia_binary_data *cpf, + unsigned int max_width, + unsigned int max_height, + ia_cmc_t *cmc, + ia_mkn *mkn); + virtual bool convert_statistics ( + void *statistics, + ia_aiq_rgbs_grid **out_rgbs_grid, + ia_aiq_af_grid **out_af_grid); + virtual bool run ( + const IspInputParameters *isp_input_params, + ia_binary_data *output_data); + +private: + ia_isp_1_5_input_params _input_params; + +}; + +bool +IaIspAdaptor15::init ( + const ia_binary_data *cpf, + unsigned int max_width, + unsigned int max_height, + ia_cmc_t *cmc, + ia_mkn *mkn) +{ + xcam_mem_clear (&_input_params); + _input_params.isp_vamem_type = 1; + _handle = ia_isp_1_5_init (cpf, max_width, max_height, cmc, mkn); + XCAM_FAIL_RETURN (ERROR, _handle, false, "ia_isp 1.5 init failed"); + return true; +} + +bool +IaIspAdaptor15::convert_statistics ( + void *statistics, + ia_aiq_rgbs_grid **out_rgbs_grid, + ia_aiq_af_grid **out_af_grid) +{ + ia_err err; + err = ia_isp_1_5_statistics_convert (_handle, statistics, out_rgbs_grid, out_af_grid); + XCAM_FAIL_RETURN (ERROR, err == ia_err_none, false, "ia_isp 1.5 convert stats failed"); + return true; +} + +bool +IaIspAdaptor15::run ( + const IspInputParameters *isp_input_params, + ia_binary_data *output_data) +{ + ia_err err; + + _input_params.frame_use = isp_input_params->frame_use; + _input_params.sensor_frame_params = isp_input_params->sensor_frame_params; + _input_params.exposure_results = isp_input_params->exposure_results; + _input_params.awb_results = isp_input_params->awb_results; + _input_params.gbce_results = isp_input_params->gbce_results; + _input_params.pa_results = isp_input_params->pa_results; + _input_params.manual_brightness = isp_input_params->manual_brightness; + _input_params.manual_contrast = isp_input_params->manual_contrast; + _input_params.manual_hue = isp_input_params->manual_hue; + _input_params.manual_saturation = isp_input_params->manual_saturation; + _input_params.nr_setting.feature_level = ia_isp_feature_level_high; + _input_params.nr_setting.strength = isp_input_params->manual_nr_level; + _input_params.ee_setting.feature_level = ia_isp_feature_level_high; + _input_params.ee_setting.strength = isp_input_params->manual_sharpness; + _input_params.effects = isp_input_params->effects; + + err = ia_isp_1_5_run (_handle, &_input_params, output_data); + XCAM_FAIL_RETURN (ERROR, err == ia_err_none, false, "ia_isp 1.5 run failed"); + return true; +} + +#endif + +static double +_calculate_new_value_by_speed (double start, double end, double speed) +{ + XCAM_ASSERT (speed >= 0.0 && speed <= 1.0); + static const double value_equal_range = 0.000001; + + if (fabs (end - start) <= value_equal_range) + return end; + return (start * (1.0 - speed) + end * speed); +} + +static double +_imx185_sensor_gain_code_to_mutiplier (uint32_t code) +{ + /* 185 sensor code : DB = 160 : 48 */ + double db; + db = code * 48.0 / 160.0; + return pow (10.0, db / 20.0); +} + +static uint32_t +_mutiplier_to_imx185_sensor_gain_code (double mutiplier) +{ + double db = log10 (mutiplier) * 20; + if (db > 48) + db = 48; + return (uint32_t) (db * 160 / 48); +} + +static uint32_t +_time_to_coarse_line (const ia_aiq_exposure_sensor_descriptor *desc, uint32_t time_us) +{ + float value = time_us * desc->pixel_clock_freq_mhz; + + value = (value + desc->pixel_periods_per_line / 2) / desc->pixel_periods_per_line; + return (uint32_t)(value); +} + +static uint32_t +_coarse_line_to_time (const ia_aiq_exposure_sensor_descriptor *desc, uint32_t coarse_line) +{ + return coarse_line * desc->pixel_periods_per_line / desc->pixel_clock_freq_mhz; +} + +AiqAeHandler::AiqAeResult::AiqAeResult() +{ + xcam_mem_clear (ae_result); + xcam_mem_clear (ae_exp_ret); + xcam_mem_clear (aiq_exp_param); + xcam_mem_clear (sensor_exp_param); + xcam_mem_clear (weight_grid); + xcam_mem_clear (flash_param); +} + +void +AiqAeHandler::AiqAeResult::copy (ia_aiq_ae_results *result) +{ + XCAM_ASSERT (result); + + this->ae_result = *result; + this->aiq_exp_param = *result->exposures[0].exposure; + this->sensor_exp_param = *result->exposures[0].sensor_exposure; + this->weight_grid = *result->weight_grid; +#ifdef HAVE_AIQ_2_7 + this->flash_param = result->flashes[0]; +#else + this->flash_param = *result->flash; +#endif + + this->ae_exp_ret.exposure = &this->aiq_exp_param; + this->ae_exp_ret.sensor_exposure = &this->sensor_exp_param; + this->ae_result.exposures = &this->ae_exp_ret; + this->ae_result.weight_grid = &this->weight_grid; +#ifdef HAVE_AIQ_2_7 + this->ae_result.flashes[0] = this->flash_param; +#else + this->ae_result.flash = &this->flash_param; +#endif + this->ae_result.num_exposures = 1; +} + +AiqAeHandler::AiqAeHandler (SmartPtr<AiqCompositor> &aiq_compositor) + : _aiq_compositor (aiq_compositor) + , _started (false) +{ + xcam_mem_clear (_ia_ae_window); + xcam_mem_clear (_sensor_descriptor); + xcam_mem_clear (_manual_limits); + xcam_mem_clear (_input); + _input.num_exposures = 1; + _input.frame_use = _aiq_compositor->get_frame_use(); + _input.flash_mode = ia_aiq_flash_mode_off; + _input.operation_mode = ia_aiq_ae_operation_mode_automatic; + _input.metering_mode = ia_aiq_ae_metering_mode_evaluative; + _input.priority_mode = ia_aiq_ae_priority_mode_normal; + _input.flicker_reduction_mode = ia_aiq_ae_flicker_reduction_auto; + _input.sensor_descriptor = NULL; + _input.exposure_window = NULL; + _input.exposure_coordinate = NULL; + _input.ev_shift = 0.0; + _input.manual_exposure_time_us = -1; + _input.manual_analog_gain = -1.0; + _input.manual_iso = -1.0; + _input.aec_features = NULL; + _input.manual_limits = &_manual_limits; +} + +bool +AiqAeHandler::set_description (struct atomisp_sensor_mode_data *sensor_data) +{ + XCAM_ASSERT (sensor_data); + + _sensor_descriptor.pixel_clock_freq_mhz = sensor_data->vt_pix_clk_freq_mhz / 1000000.0f; + _sensor_descriptor.pixel_periods_per_line = sensor_data->line_length_pck; + _sensor_descriptor.line_periods_per_field = sensor_data->frame_length_lines; + _sensor_descriptor.line_periods_vertical_blanking = sensor_data->frame_length_lines + - (sensor_data->crop_vertical_end - sensor_data->crop_vertical_start + 1) + / sensor_data->binning_factor_y; + _sensor_descriptor.fine_integration_time_min = sensor_data->fine_integration_time_def; + _sensor_descriptor.fine_integration_time_max_margin = sensor_data->line_length_pck - sensor_data->fine_integration_time_def; + _sensor_descriptor.coarse_integration_time_min = sensor_data->coarse_integration_time_min; + _sensor_descriptor.coarse_integration_time_max_margin = sensor_data->coarse_integration_time_max_margin; + + return true; +} + +bool +AiqAeHandler::ensure_ia_parameters () +{ + bool ret = true; + ret = ret && ensure_ae_mode (); + ret = ret && ensure_ae_metering_mode (); + ret = ret && ensure_ae_priority_mode (); + ret = ret && ensure_ae_flicker_mode (); + ret = ret && ensure_ae_manual (); + ret = ret && ensure_ae_ev_shift (); + _input.sensor_descriptor = &_sensor_descriptor; + return ret; +} + +bool AiqAeHandler::ensure_ae_mode () +{ + XCamAeMode mode = this->get_mode_unlock(); + switch (mode) { + case XCAM_AE_MODE_AUTO: + case XCAM_AE_MODE_MANUAL: + _input.operation_mode = ia_aiq_ae_operation_mode_automatic; + break; + + case XCAM_AE_MODE_NOT_SET: + default: + XCAM_LOG_ERROR("unsupported ae mode:%d", mode); + return false; + } + return true; +} +bool AiqAeHandler::ensure_ae_metering_mode () +{ + XCamAeMeteringMode mode = this->get_metering_mode_unlock(); + + _input.exposure_window = NULL; + + switch (mode) { + case XCAM_AE_METERING_MODE_AUTO: + _input.metering_mode = ia_aiq_ae_metering_mode_evaluative; + break; + case XCAM_AE_METERING_MODE_SPOT: + { + _input.metering_mode = ia_aiq_ae_metering_mode_evaluative; + const XCam3AWindow & window = this->get_window_unlock(); + if (window.x_end > window.x_start && + window.y_end > window.y_start) { + _aiq_compositor->convert_window_to_ia(window, _ia_ae_window); + _input.exposure_window = &_ia_ae_window; + } + } + break; + case XCAM_AE_METERING_MODE_CENTER: + _input.metering_mode = ia_aiq_ae_metering_mode_center; + break; + case XCAM_AE_METERING_MODE_WEIGHTED_WINDOW: + { + _input.metering_mode = ia_aiq_ae_metering_mode_evaluative; + const XCam3AWindow & weighted_window = this->get_window_unlock(); + + XCAM_LOG_DEBUG ("ensure_ae_metering_mode weighted_window x_start = %d, y_start = %d, x_end = %d, y_end = %d ", + weighted_window.x_start, weighted_window.y_start, weighted_window.x_end, weighted_window.y_end); + + if (weighted_window.x_end > weighted_window.x_start && + weighted_window.y_end > weighted_window.y_start) { + _aiq_compositor->convert_window_to_ia(weighted_window, _ia_ae_window); + _input.exposure_window = &_ia_ae_window; + } + } + break; + default: + XCAM_LOG_ERROR("unsupported ae mode:%d", mode); + return false; + } + return true; +} + +bool AiqAeHandler::ensure_ae_priority_mode () +{ + _input.priority_mode = ia_aiq_ae_priority_mode_normal; + return true; +} + +bool AiqAeHandler::ensure_ae_flicker_mode () +{ + XCamFlickerMode mode = this->get_flicker_mode_unlock (); + switch (mode) { + case XCAM_AE_FLICKER_MODE_AUTO: + _input.flicker_reduction_mode = ia_aiq_ae_flicker_reduction_auto; + break; + case XCAM_AE_FLICKER_MODE_50HZ: + _input.flicker_reduction_mode = ia_aiq_ae_flicker_reduction_50hz; + break; + case XCAM_AE_FLICKER_MODE_60HZ: + _input.flicker_reduction_mode = ia_aiq_ae_flicker_reduction_60hz; + break; + case XCAM_AE_FLICKER_MODE_OFF: + _input.flicker_reduction_mode = ia_aiq_ae_flicker_reduction_off; + break; + default: + XCAM_LOG_ERROR ("flicker mode(%d) unknown", mode); + return false; + } + return true; +} + +bool AiqAeHandler::ensure_ae_manual () +{ + if (this->get_mode_unlock () == XCAM_AE_MODE_MANUAL) { + _input.manual_exposure_time_us = get_manual_exposure_time_unlock (); + _input.manual_analog_gain = get_manual_analog_gain_unlock (); + } + else { + _input.manual_exposure_time_us = -1; + _input.manual_analog_gain = -1; + } + + _input.manual_limits->manual_exposure_time_min = + _sensor_descriptor.coarse_integration_time_min + * _sensor_descriptor.pixel_periods_per_line + / _sensor_descriptor.pixel_clock_freq_mhz; + _input.manual_limits->manual_exposure_time_max = + (_sensor_descriptor.line_periods_per_field - _sensor_descriptor.coarse_integration_time_max_margin) + * _sensor_descriptor.pixel_periods_per_line + / _sensor_descriptor.pixel_clock_freq_mhz; + + uint64_t exp_min_us = 0, exp_max_us = 0; + get_exposure_time_range_unlock (exp_min_us, exp_max_us); + if (exp_min_us && (int64_t)exp_min_us > _input.manual_limits->manual_exposure_time_min) { + _input.manual_limits->manual_exposure_time_min = exp_min_us; + } + if (exp_max_us && (int64_t)exp_max_us < _input.manual_limits->manual_exposure_time_max) { + _input.manual_limits->manual_exposure_time_max = exp_max_us; + } + + _input.manual_limits->manual_frame_time_us_min = -1; + _input.manual_limits->manual_frame_time_us_max = 1000000 / _aiq_compositor->get_framerate (); + _input.manual_limits->manual_iso_min = -1; + _input.manual_limits->manual_iso_max = -1; + + return true; +} + +bool AiqAeHandler::ensure_ae_ev_shift () +{ + _input.ev_shift = this->get_ev_shift_unlock(); + return true; +} + +SmartPtr<X3aResult> +AiqAeHandler::pop_result () +{ + //AnalyzerHandler::HandlerLock lock(this); + + X3aIspExposureResult *result = new X3aIspExposureResult(XCAM_IMAGE_PROCESS_ONCE); + struct atomisp_exposure sensor; + XCam3aResultExposure exposure; + + xcam_mem_clear (sensor); + sensor.integration_time[0] = _result.sensor_exp_param.coarse_integration_time; + sensor.integration_time[1] = _result.sensor_exp_param.fine_integration_time; + sensor.gain[0] = _result.sensor_exp_param.analog_gain_code_global; + sensor.gain[1] = _result.sensor_exp_param.digital_gain_global; + result->set_isp_config (sensor); + + xcam_mem_clear (exposure); + exposure.exposure_time = _result.aiq_exp_param.exposure_time_us; + exposure.analog_gain = _result.aiq_exp_param.analog_gain; + exposure.digital_gain = _result.aiq_exp_param.digital_gain; + exposure.aperture = _result.aiq_exp_param.aperture_fn; + result->set_standard_result (exposure); + + return result; +} + +XCamReturn +AiqAeHandler::analyze (X3aResultList &output) +{ + ia_aiq *ia_handle = NULL; + ia_aiq_ae_results *ae_result = NULL; + ia_aiq_exposure_sensor_parameters *cur_sensor_result = NULL; + ia_err ia_error = ia_err_none; + bool need_apply = false; + SmartPtr<X3aResult> result; + + AnalyzerHandler::HandlerLock lock(this); + + if (!ensure_ia_parameters ()) { + XCAM_LOG_ERROR ("AIQ AE ensure ia parameters failed"); + return XCAM_RETURN_ERROR_PARAM; + } + + ia_handle = _aiq_compositor->get_handle (); + XCAM_ASSERT (ia_handle); + ia_error = ia_aiq_ae_run (ia_handle, &_input, &ae_result); + XCAM_FAIL_RETURN (ERROR, ia_error == ia_err_none, XCAM_RETURN_ERROR_AIQ, "AIQ run AE failed"); + + cur_sensor_result = ae_result->exposures[0].sensor_exposure; + + if (!_started) { + _result.copy (ae_result); + _started = true; + need_apply = true; + } else { + //TODO + ia_aiq_exposure_sensor_parameters *last_sensor_res = &_result.sensor_exp_param; + if (last_sensor_res->coarse_integration_time != cur_sensor_result->coarse_integration_time || + last_sensor_res->fine_integration_time != cur_sensor_result->fine_integration_time || + last_sensor_res->analog_gain_code_global != cur_sensor_result->analog_gain_code_global || + last_sensor_res->digital_gain_global != cur_sensor_result->digital_gain_global) { + ia_aiq_exposure_sensor_parameters cur_cp_res = *cur_sensor_result; + ia_aiq_exposure_parameters cur_aiq_exp = *ae_result->exposures[0].exposure; + if (!manual_control_result (cur_cp_res, cur_aiq_exp, *last_sensor_res)) { + XCAM_LOG_WARNING ("manual control AE result failed"); + } + _result.copy (ae_result); + _result.sensor_exp_param = cur_cp_res; + _result.aiq_exp_param = cur_aiq_exp; + + need_apply = true; + } + } + + if (need_apply) { + result = pop_result (); + if (result.ptr()) + output.push_back (result); + } + + return XCAM_RETURN_NO_ERROR; +} + +bool +AiqAeHandler::manual_control_result ( + ia_aiq_exposure_sensor_parameters &cur_res, + ia_aiq_exposure_parameters &cur_aiq_exp, + const ia_aiq_exposure_sensor_parameters &last_res) +{ + adjust_ae_speed (cur_res, cur_aiq_exp, last_res, this->get_speed_unlock()); + adjust_ae_limitation (cur_res, cur_aiq_exp); + + return true; +} + +void +AiqAeHandler::adjust_ae_speed ( + ia_aiq_exposure_sensor_parameters &cur_res, + ia_aiq_exposure_parameters &cur_aiq_exp, + const ia_aiq_exposure_sensor_parameters &last_res, + double ae_speed) +{ + double last_gain, input_gain, ret_gain; + ia_aiq_exposure_sensor_parameters tmp_res; + + if (XCAM_DOUBLE_EQUAL_AROUND(ae_speed, 1.0 )) + return; + xcam_mem_clear (tmp_res); + tmp_res.coarse_integration_time = _calculate_new_value_by_speed ( + last_res.coarse_integration_time, + cur_res.coarse_integration_time, + ae_speed); + + last_gain = _imx185_sensor_gain_code_to_mutiplier (last_res.analog_gain_code_global); + input_gain = _imx185_sensor_gain_code_to_mutiplier (cur_res.analog_gain_code_global); + ret_gain = _calculate_new_value_by_speed (last_gain, input_gain, ae_speed); + + tmp_res.analog_gain_code_global = _mutiplier_to_imx185_sensor_gain_code (ret_gain); + + XCAM_LOG_DEBUG ("AE speed: from (shutter:%d, gain:%d[%.03f]) to (shutter:%d, gain:%d[%.03f])", + cur_res.coarse_integration_time, cur_res.analog_gain_code_global, input_gain, + tmp_res.coarse_integration_time, tmp_res.analog_gain_code_global, ret_gain); + + cur_res.coarse_integration_time = tmp_res.coarse_integration_time; + cur_res.analog_gain_code_global = tmp_res.analog_gain_code_global; + cur_aiq_exp.exposure_time_us = _coarse_line_to_time (&_sensor_descriptor, + cur_res.coarse_integration_time); + cur_aiq_exp.analog_gain = ret_gain; +} + +void +AiqAeHandler::adjust_ae_limitation (ia_aiq_exposure_sensor_parameters &cur_res, + ia_aiq_exposure_parameters &cur_aiq_exp) +{ + ia_aiq_exposure_sensor_descriptor * desc = &_sensor_descriptor; + uint64_t exposure_min = 0, exposure_max = 0; + double analog_max = get_max_analog_gain_unlock (); + uint32_t min_coarse_value = desc->coarse_integration_time_min; + uint32_t max_coarse_value = desc->line_periods_per_field - desc->coarse_integration_time_max_margin; + uint32_t value; + + get_exposure_time_range_unlock (exposure_min, exposure_max); + + if (exposure_min) { + value = _time_to_coarse_line (desc, (uint32_t)exposure_min); + min_coarse_value = (value > min_coarse_value) ? value : min_coarse_value; + } + if (cur_res.coarse_integration_time < min_coarse_value) { + cur_res.coarse_integration_time = min_coarse_value; + cur_aiq_exp.exposure_time_us = _coarse_line_to_time (desc, min_coarse_value); + } + + if (exposure_max) { + value = _time_to_coarse_line (desc, (uint32_t)exposure_max); + max_coarse_value = (value < max_coarse_value) ? value : max_coarse_value; + } + if (cur_res.coarse_integration_time > max_coarse_value) { + cur_res.coarse_integration_time = max_coarse_value; + cur_aiq_exp.exposure_time_us = _coarse_line_to_time (desc, max_coarse_value); + } + + if (analog_max >= 1.0) { + /* limit gains */ + double gain = _imx185_sensor_gain_code_to_mutiplier (cur_res.analog_gain_code_global); + if (gain > analog_max) { + cur_res.analog_gain_code_global = _mutiplier_to_imx185_sensor_gain_code (analog_max); + cur_aiq_exp.analog_gain = analog_max; + } + } +} + +XCamFlickerMode +AiqAeHandler::get_flicker_mode () +{ + { + AnalyzerHandler::HandlerLock lock(this); + } + return AeHandler::get_flicker_mode (); +} + +int64_t +AiqAeHandler::get_current_exposure_time () +{ + AnalyzerHandler::HandlerLock lock(this); + + return (int64_t)_result.aiq_exp_param.exposure_time_us; +} + +double +AiqAeHandler::get_current_analog_gain () +{ + AnalyzerHandler::HandlerLock lock(this); + return (double)_result.aiq_exp_param.analog_gain; +} + +double +AiqAeHandler::get_max_analog_gain () +{ + { + AnalyzerHandler::HandlerLock lock(this); + } + return AeHandler::get_max_analog_gain (); +} + +XCamReturn +AiqAeHandler::set_RGBS_weight_grid (ia_aiq_rgbs_grid **out_rgbs_grid) +{ + AnalyzerHandler::HandlerLock lock(this); + + rgbs_grid_block *rgbs_grid_ptr = (*out_rgbs_grid)->blocks_ptr; + uint32_t rgbs_grid_index = 0; + uint16_t rgbs_grid_width = (*out_rgbs_grid)->grid_width; + uint16_t rgbs_grid_height = (*out_rgbs_grid)->grid_height; + + XCAM_LOG_DEBUG ("rgbs_grid_width = %d, rgbs_grid_height = %d", rgbs_grid_width, rgbs_grid_height); + + uint64_t weight_sum = 0; + + uint32_t image_width = 0; + uint32_t image_height = 0; + _aiq_compositor->get_size (image_width, image_height); + XCAM_LOG_DEBUG ("image_width = %d, image_height = %d", image_width, image_height); + + uint32_t hor_pixels_per_grid = (image_width + (rgbs_grid_width >> 1)) / rgbs_grid_width; + uint32_t vert_pixels_per_gird = (image_height + (rgbs_grid_height >> 1)) / rgbs_grid_height; + XCAM_LOG_DEBUG ("rgbs grid: %d x %d pixels per grid cell", hor_pixels_per_grid, vert_pixels_per_gird); + + XCam3AWindow weighted_window = this->get_window_unlock (); + uint32_t weighted_grid_width = ((weighted_window.x_end - weighted_window.x_start + 1) + + (hor_pixels_per_grid >> 1)) / hor_pixels_per_grid; + uint32_t weighted_grid_height = ((weighted_window.y_end - weighted_window.y_start + 1) + + (vert_pixels_per_gird >> 1)) / vert_pixels_per_gird; + XCAM_LOG_DEBUG ("weighted_grid_width = %d, weighted_grid_height = %d", weighted_grid_width, weighted_grid_height); + + uint32_t *weighted_avg_gr = (uint32_t*)xcam_malloc0 (5 * weighted_grid_width * weighted_grid_height * sizeof(uint32_t)); + if (NULL == weighted_avg_gr) { + return XCAM_RETURN_ERROR_MEM; + } + uint32_t *weighted_avg_r = weighted_avg_gr + (weighted_grid_width * weighted_grid_height); + uint32_t *weighted_avg_b = weighted_avg_r + (weighted_grid_width * weighted_grid_height); + uint32_t *weighted_avg_gb = weighted_avg_b + (weighted_grid_width * weighted_grid_height); + uint32_t *weighted_sat = weighted_avg_gb + (weighted_grid_width * weighted_grid_height); + + for (uint32_t win_index = 0; win_index < XCAM_AE_MAX_METERING_WINDOW_COUNT; win_index++) { + XCAM_LOG_DEBUG ("window start point(%d, %d), end point(%d, %d), weight = %d", + _params.window_list[win_index].x_start, _params.window_list[win_index].y_start, + _params.window_list[win_index].x_end, _params.window_list[win_index].y_end, + _params.window_list[win_index].weight); + + if ((_params.window_list[win_index].weight <= 0) || + (_params.window_list[win_index].x_start < 0) || + ((uint32_t)_params.window_list[win_index].x_end > image_width) || + (_params.window_list[win_index].y_start < 0) || + ((uint32_t)_params.window_list[win_index].y_end > image_height) || + (_params.window_list[win_index].x_start >= _params.window_list[win_index].x_end) || + (_params.window_list[win_index].y_start >= _params.window_list[win_index].y_end) || + ((uint32_t)_params.window_list[win_index].x_end - (uint32_t)_params.window_list[win_index].x_start > image_width) || + ((uint32_t)_params.window_list[win_index].y_end - (uint32_t)_params.window_list[win_index].y_start > image_height)) { + XCAM_LOG_DEBUG ("skip window index = %d ", win_index); + continue; + } + + rgbs_grid_index = (_params.window_list[win_index].x_start + + (hor_pixels_per_grid >> 1)) / hor_pixels_per_grid + + ((_params.window_list[win_index].y_start + (vert_pixels_per_gird >> 1)) + / vert_pixels_per_gird) * rgbs_grid_width; + + weight_sum += _params.window_list[win_index].weight; + + XCAM_LOG_DEBUG ("cumulate rgbs grid statistic, window index = %d ", win_index); + for (uint32_t i = 0; i < weighted_grid_height; i++) { + for (uint32_t j = 0; j < weighted_grid_width; j++) { + weighted_avg_gr[j + i * weighted_grid_width] += rgbs_grid_ptr[rgbs_grid_index + j + + i * rgbs_grid_width].avg_gr * _params.window_list[win_index].weight; + weighted_avg_r[j + i * weighted_grid_width] += rgbs_grid_ptr[rgbs_grid_index + j + + i * rgbs_grid_width].avg_r * _params.window_list[win_index].weight; + weighted_avg_b[j + i * weighted_grid_width] += rgbs_grid_ptr[rgbs_grid_index + j + + i * rgbs_grid_width].avg_b * _params.window_list[win_index].weight; + weighted_avg_gb[j + i * weighted_grid_width] += rgbs_grid_ptr[rgbs_grid_index + j + + i * rgbs_grid_width].avg_gb * _params.window_list[win_index].weight; + weighted_sat[j + i * weighted_grid_width] += rgbs_grid_ptr[rgbs_grid_index + j + + i * rgbs_grid_width].sat * _params.window_list[win_index].weight; + } + } + } + XCAM_LOG_DEBUG ("sum of weighing factor = %" PRIu64, weight_sum); + + rgbs_grid_index = (weighted_window.x_start + (hor_pixels_per_grid >> 1)) / hor_pixels_per_grid + + (weighted_window.y_start + (vert_pixels_per_gird >> 1)) / vert_pixels_per_gird * rgbs_grid_width; + for (uint32_t i = 0; i < weighted_grid_height; i++) { + for (uint32_t j = 0; j < weighted_grid_width; j++) { + rgbs_grid_ptr[rgbs_grid_index + j + i * rgbs_grid_width].avg_gr = + weighted_avg_gr[j + i * weighted_grid_width] / weight_sum; + rgbs_grid_ptr[rgbs_grid_index + j + i * rgbs_grid_width].avg_r = + weighted_avg_r[j + i * weighted_grid_width] / weight_sum; + rgbs_grid_ptr[rgbs_grid_index + j + i * rgbs_grid_width].avg_b = + weighted_avg_b[j + i * weighted_grid_width] / weight_sum; + rgbs_grid_ptr[rgbs_grid_index + j + i * rgbs_grid_width].avg_gb = + weighted_avg_gb[j + i * weighted_grid_width] / weight_sum; + rgbs_grid_ptr[rgbs_grid_index + j + i * rgbs_grid_width].sat = + weighted_sat[j + i * weighted_grid_width] / weight_sum; + } + } + + xcam_free (weighted_avg_gr); + + return XCAM_RETURN_NO_ERROR; +} + + +XCamReturn +AiqAeHandler::set_hist_weight_grid (ia_aiq_hist_weight_grid **out_weight_grid) +{ + AnalyzerHandler::HandlerLock lock(this); + + uint16_t hist_grid_width = (*out_weight_grid)->width; + uint16_t hist_grid_height = (*out_weight_grid)->height; + uint32_t hist_grid_index = 0; + + unsigned char* weights_map_ptr = (*out_weight_grid)->weights; + + uint32_t image_width = 0; + uint32_t image_height = 0; + _aiq_compositor->get_size (image_width, image_height); + + uint32_t hor_pixels_per_grid = (image_width + (hist_grid_width >> 1)) / hist_grid_width; + uint32_t vert_pixels_per_gird = (image_height + (hist_grid_height >> 1)) / hist_grid_height; + XCAM_LOG_DEBUG ("hist weight grid: %d x %d pixels per grid cell", hor_pixels_per_grid, vert_pixels_per_gird); + + memset (weights_map_ptr, 0, hist_grid_width * hist_grid_height); + + for (uint32_t win_index = 0; win_index < XCAM_AE_MAX_METERING_WINDOW_COUNT; win_index++) { + XCAM_LOG_DEBUG ("window start point(%d, %d), end point(%d, %d), weight = %d", + _params.window_list[win_index].x_start, _params.window_list[win_index].y_start, + _params.window_list[win_index].x_end, _params.window_list[win_index].y_end, + _params.window_list[win_index].weight); + + if ((_params.window_list[win_index].weight <= 0) || + (_params.window_list[win_index].weight > 15) || + (_params.window_list[win_index].x_start < 0) || + ((uint32_t)_params.window_list[win_index].x_end > image_width) || + (_params.window_list[win_index].y_start < 0) || + ((uint32_t)_params.window_list[win_index].y_end > image_height) || + (_params.window_list[win_index].x_start >= _params.window_list[win_index].x_end) || + (_params.window_list[win_index].y_start >= _params.window_list[win_index].y_end) || + ((uint32_t)_params.window_list[win_index].x_end - (uint32_t)_params.window_list[win_index].x_start > image_width) || + ((uint32_t)_params.window_list[win_index].y_end - (uint32_t)_params.window_list[win_index].y_start > image_height)) { + XCAM_LOG_DEBUG ("skip window index = %d ", win_index); + continue; + } + + uint32_t weighted_grid_width = + ((_params.window_list[win_index].x_end - _params.window_list[win_index].x_start + 1) + + (hor_pixels_per_grid >> 1)) / hor_pixels_per_grid; + uint32_t weighted_grid_height = + ((_params.window_list[win_index].y_end - _params.window_list[win_index].y_start + 1) + + (vert_pixels_per_gird >> 1)) / vert_pixels_per_gird; + + hist_grid_index = (_params.window_list[win_index].x_start + (hor_pixels_per_grid >> 1)) / hor_pixels_per_grid + + ((_params.window_list[win_index].y_start + (vert_pixels_per_gird >> 1)) / + vert_pixels_per_gird) * hist_grid_width; + + for (uint32_t i = 0; i < weighted_grid_height; i++) { + for (uint32_t j = 0; j < weighted_grid_width; j++) { + weights_map_ptr[hist_grid_index + j + i * hist_grid_width] = _params.window_list[win_index].weight; + } + } + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +AiqAeHandler::dump_hist_weight_grid (const ia_aiq_hist_weight_grid *weight_grid) +{ + XCAM_LOG_DEBUG ("E dump_hist_weight_grid"); + if (NULL == weight_grid) { + return XCAM_RETURN_ERROR_PARAM; + } + + uint16_t grid_width = weight_grid->width; + uint16_t grid_height = weight_grid->height; + + for (uint32_t i = 0; i < grid_height; i++) { + for (uint32_t j = 0; j < grid_width; j++) { + printf ("%d ", weight_grid->weights[j + i * grid_width]); + } + printf("\n"); + } + + XCAM_LOG_DEBUG ("X dump_hist_weight_grid"); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +AiqAeHandler::dump_RGBS_grid (const ia_aiq_rgbs_grid *rgbs_grid) +{ + XCAM_LOG_DEBUG ("E dump_RGBS_grid"); + if (NULL == rgbs_grid) { + return XCAM_RETURN_ERROR_PARAM; + } + + uint16_t grid_width = rgbs_grid->grid_width; + uint16_t grid_height = rgbs_grid->grid_height; + + printf("AVG B\n"); + for (uint32_t i = 0; i < grid_height; i++) { + for (uint32_t j = 0; j < grid_width; j++) { + printf ("%d ", rgbs_grid->blocks_ptr[j + i * grid_width].avg_b); + } + printf("\n"); + } + printf("AVG Gb\n"); + for (uint32_t i = 0; i < grid_height; i++) { + for (uint32_t j = 0; j < grid_width; j++) { + printf ("%d ", rgbs_grid->blocks_ptr[j + i * grid_width].avg_gb); + } + printf("\n"); + } + printf("AVG Gr\n"); + for (uint32_t i = 0; i < grid_height; i++) { + for (uint32_t j = 0; j < grid_width; j++) { + printf ("%d ", rgbs_grid->blocks_ptr[j + i * grid_width].avg_gr); + } + printf("\n"); + } + printf("AVG R\n"); + for (uint32_t i = 0; i < grid_height; i++) { + for (uint32_t j = 0; j < grid_width; j++) { + printf ("%d ", rgbs_grid->blocks_ptr[j + i * grid_width].avg_r); + //printf ("%d ", rgbs_grid->blocks_ptr[j + i * grid_width].sat); + } + printf("\n"); + } + + XCAM_LOG_DEBUG ("X dump_RGBS_grid"); + return XCAM_RETURN_NO_ERROR; +} + +AiqAwbHandler::AiqAwbHandler (SmartPtr<AiqCompositor> &aiq_compositor) + : _aiq_compositor (aiq_compositor) + , _started (false) +{ + xcam_mem_clear (_cct_range); + xcam_mem_clear (_result); + xcam_mem_clear (_history_result); + xcam_mem_clear (_cct_range); + xcam_mem_clear (_input); + + _input.frame_use = aiq_compositor->get_frame_use (); + _input.scene_mode = ia_aiq_awb_operation_mode_auto; + _input.manual_cct_range = NULL; + _input.manual_white_coordinate = NULL; +} + +XCamReturn +AiqAwbHandler::analyze (X3aResultList &output) +{ + ia_aiq *ia_handle = NULL; + ia_aiq_awb_results *awb_ret = NULL; + ia_err ia_error = ia_err_none; + + XCAM_UNUSED (output); + + AnalyzerHandler::HandlerLock lock(this); + + if (!ensure_ia_parameters ()) { + XCAM_LOG_ERROR ("AIQ AE ensure ia parameters failed"); + return XCAM_RETURN_ERROR_PARAM; + } + + ia_handle = _aiq_compositor->get_handle (); + XCAM_ASSERT (ia_handle); + ia_error = ia_aiq_awb_run (ia_handle, &_input, &awb_ret); + XCAM_FAIL_RETURN (ERROR, ia_error == ia_err_none, XCAM_RETURN_ERROR_AIQ, "AIQ run AWB failed"); + + _result = *awb_ret; + if (!_started) { + _history_result = _result; + _started = true; + } + adjust_speed (_history_result); + _history_result = _result; + + return XCAM_RETURN_NO_ERROR; +} + +bool +AiqAwbHandler::ensure_ia_parameters () +{ + bool ret = true; + + _input.frame_use = _aiq_compositor->get_frame_use (); + ret = ret && ensure_awb_mode (); + return ret; +} + +bool +AiqAwbHandler::ensure_awb_mode () +{ + XCamAwbMode mode = get_mode_unlock(); + + _input.manual_cct_range = NULL; + _input.scene_mode = ia_aiq_awb_operation_mode_auto; + + switch (mode) { + case XCAM_AWB_MODE_AUTO: + _input.scene_mode = ia_aiq_awb_operation_mode_auto; + break; + case XCAM_AWB_MODE_MANUAL: { + uint32_t cct_min = 0, cct_max = 0; + get_cct_range_unlock (cct_min, cct_max); + if (cct_min && cct_max) { + _input.scene_mode = ia_aiq_awb_operation_mode_manual_cct_range; + _cct_range.max_cct = cct_min; + _cct_range.min_cct = cct_max; + _input.manual_cct_range = &_cct_range; + } else + _input.scene_mode = ia_aiq_awb_operation_mode_auto; + break; + } + case XCAM_AWB_MODE_DAYLIGHT: + _input.scene_mode = ia_aiq_awb_operation_mode_daylight; + break; + case XCAM_AWB_MODE_SUNSET: + _input.scene_mode = ia_aiq_awb_operation_mode_sunset; + break; + case XCAM_AWB_MODE_CLOUDY: + _input.scene_mode = ia_aiq_awb_operation_mode_partly_overcast; + break; + case XCAM_AWB_MODE_TUNGSTEN: + _input.scene_mode = ia_aiq_awb_operation_mode_incandescent; + break; + case XCAM_AWB_MODE_FLUORESCENT: + _input.scene_mode = ia_aiq_awb_operation_mode_fluorescent; + break; + case XCAM_AWB_MODE_WARM_FLUORESCENT: + _input.scene_mode = ia_aiq_awb_operation_mode_incandescent; + break; + case XCAM_AWB_MODE_SHADOW: + _input.scene_mode = ia_aiq_awb_operation_mode_fully_overcast; + break; + case XCAM_AWB_MODE_WARM_INCANDESCENT: + _input.scene_mode = ia_aiq_awb_operation_mode_incandescent; + break; + case XCAM_AWB_MODE_NOT_SET: + break; + + default: + XCAM_LOG_ERROR ("unknown or unsupported AWB mode(%d)", mode); + return false; + } + return true; +} + +void +AiqAwbHandler::adjust_speed (const ia_aiq_awb_results &last_ret) +{ + _result.final_r_per_g = + _calculate_new_value_by_speed ( + last_ret.final_r_per_g, _result.final_r_per_g, get_speed_unlock ()); + _result.final_b_per_g = + _calculate_new_value_by_speed ( + last_ret.final_b_per_g, _result.final_b_per_g, get_speed_unlock ()); +} + +uint32_t +AiqAwbHandler::get_current_estimate_cct () +{ + AnalyzerHandler::HandlerLock lock(this); + return (uint32_t)_result.cct_estimate; +} + +XCamReturn +AiqAfHandler::analyze (X3aResultList &output) +{ + // TODO + XCAM_UNUSED (output); + return XCAM_RETURN_NO_ERROR; +} + +AiqCommonHandler::AiqCommonHandler (SmartPtr<AiqCompositor> &aiq_compositor) + : _aiq_compositor (aiq_compositor) + , _gbce_result (NULL) +{ +} + + +XCamReturn +AiqCommonHandler::analyze (X3aResultList &output) +{ + ia_aiq *ia_handle = NULL; + ia_aiq_gbce_results *gbce_result = NULL; + ia_err ia_error = ia_err_none; + + XCAM_UNUSED (output); + + AnalyzerHandler::HandlerLock lock(this); + + ia_aiq_gbce_input_params gbce_input; + xcam_mem_clear (gbce_input); + if (has_gbce_unlock()) { + gbce_input.gbce_level = ia_aiq_gbce_level_use_tuning; + } + else { + gbce_input.gbce_level = ia_aiq_gbce_level_bypass; + } + gbce_input.frame_use = _aiq_compositor->get_frame_use (); + gbce_input.ev_shift = _aiq_compositor->get_ae_ev_shift_unlock (); + ia_handle = _aiq_compositor->get_handle (); + XCAM_ASSERT (ia_handle); + ia_error = ia_aiq_gbce_run (ia_handle, &gbce_input, &gbce_result); + + XCAM_FAIL_RETURN (ERROR, ia_error == ia_err_none, XCAM_RETURN_ERROR_AIQ, "AIQ run GBCE failed"); + + //TODO, need copy GBCE result out, not just assign + _gbce_result = gbce_result; + + return XCAM_RETURN_NO_ERROR; +} + +class CmcParser { +public: + explicit CmcParser (ia_binary_data &cpf) + { + _cmc = ia_cmc_parser_init (&cpf); + } + ~CmcParser () + { + if (_cmc) + ia_cmc_parser_deinit (_cmc); + } + ia_cmc_t *get() { + return _cmc; + } + +private: + ia_cmc_t *_cmc; +}; + +void +AiqCompositor::convert_window_to_ia (const XCam3AWindow &window, ia_rectangle &ia_window) +{ + ia_rectangle source; + ia_coordinate_system source_system; + ia_coordinate_system target_system = {IA_COORDINATE_TOP, IA_COORDINATE_LEFT, IA_COORDINATE_BOTTOM, IA_COORDINATE_RIGHT}; + + source_system.left = 0; + source_system.top = 0; + source_system.right = this->_width; + source_system.bottom = this->_height; + XCAM_ASSERT (_width && _height); + + source.left = window.x_start; + source.top = window.y_start; + source.right = window.x_end; + source.bottom = window.y_end; + ia_coordinate_convert_rect (&source_system, &source, &target_system, &ia_window); +} + +AiqCompositor::AiqCompositor () + : _ia_handle (NULL) + , _ia_mkn (NULL) + , _pa_result (NULL) +#ifdef HAVE_AIQ_2_7 + , _sa_result (NULL) +#endif + , _frame_use (ia_aiq_frame_use_video) + , _width (0) + , _height (0) +{ + xcam_mem_clear (_frame_params); +} + +AiqCompositor::~AiqCompositor () +{ +} + +bool +AiqCompositor::open (ia_binary_data &cpf) +{ + CmcParser cmc (cpf); + + _ia_mkn = ia_mkn_init (ia_mkn_cfg_compression, 32000, 100000); + _ia_handle = + ia_aiq_init ( + &cpf, NULL, NULL, + MAX_STATISTICS_WIDTH, MAX_STATISTICS_HEIGHT, + 1, //max_num_stats_in + cmc.get(), + _ia_mkn); + + if (_ia_handle == NULL) { + XCAM_LOG_WARNING ("AIQ init failed"); + return false; + } + + _adaptor = new IaIspAdaptor22; + XCAM_ASSERT (_adaptor.ptr()); + if (!_adaptor->init (&cpf, MAX_STATISTICS_WIDTH, MAX_STATISTICS_HEIGHT, cmc.get(), _ia_mkn)) { + XCAM_LOG_WARNING ("AIQ isp adaptor init failed"); + return false; + } + + _pa_result = NULL; +#ifdef HAVE_AIQ_2_7 + _sa_result = NULL; +#endif + + XCAM_LOG_DEBUG ("Aiq compositor opened"); + return true; +} + +void +AiqCompositor::close () +{ + _adaptor.release (); + if (_ia_handle) { + ia_aiq_deinit (_ia_handle); + _ia_handle = NULL; + } + + if (_ia_mkn) { + ia_mkn_uninit (_ia_mkn); + _ia_mkn = NULL; + } + + _ae_handler.release (); + _awb_handler.release (); + _af_handler.release (); + _common_handler.release (); + + _pa_result = NULL; +#ifdef HAVE_AIQ_2_7 + _sa_result = NULL; +#endif + + XCAM_LOG_DEBUG ("Aiq compositor closed"); +} + +bool +AiqCompositor::set_sensor_mode_data (struct atomisp_sensor_mode_data *sensor_mode) +{ + _frame_params.horizontal_crop_offset = sensor_mode->crop_horizontal_start; + _frame_params.vertical_crop_offset = sensor_mode->crop_vertical_start; + _frame_params.cropped_image_height = sensor_mode->crop_vertical_end - sensor_mode->crop_vertical_start + 1; + _frame_params.cropped_image_width = sensor_mode->crop_horizontal_end - sensor_mode->crop_horizontal_start + 1; + + /* hard code to 254? */ + _frame_params.horizontal_scaling_denominator = 254; + _frame_params.vertical_scaling_denominator = 254; + + if ((_frame_params.cropped_image_width == 0) || (_frame_params.cropped_image_height == 0)) { + _frame_params.horizontal_scaling_numerator = 0; + _frame_params.vertical_scaling_numerator = 0; + } else { + _frame_params.horizontal_scaling_numerator = + sensor_mode->output_width * 254 * sensor_mode->binning_factor_x / _frame_params.cropped_image_width; + _frame_params.vertical_scaling_numerator = + sensor_mode->output_height * 254 * sensor_mode->binning_factor_y / _frame_params.cropped_image_height; + } + + if (!_ae_handler->set_description (sensor_mode)) { + XCAM_LOG_WARNING ("AIQ set ae description failed"); + return XCAM_RETURN_ERROR_AIQ; + } + return true; +} + +bool +AiqCompositor::set_3a_stats (SmartPtr<X3aIspStatistics> &stats) +{ + ia_aiq_statistics_input_params aiq_stats_input; + ia_aiq_rgbs_grid *rgbs_grids = NULL; + ia_aiq_af_grid *af_grids = NULL; + + xcam_mem_clear (aiq_stats_input); + aiq_stats_input.frame_timestamp = stats->get_timestamp(); + aiq_stats_input.frame_id = stats->get_timestamp() + 1; + aiq_stats_input.rgbs_grids = (const ia_aiq_rgbs_grid **)&rgbs_grids; + aiq_stats_input.num_rgbs_grids = 1; + aiq_stats_input.af_grids = (const ia_aiq_af_grid **)(&af_grids); + aiq_stats_input.num_af_grids = 1; + + aiq_stats_input.frame_af_parameters = NULL; + aiq_stats_input.external_histograms = NULL; + aiq_stats_input.num_external_histograms = 0; + aiq_stats_input.camera_orientation = ia_aiq_camera_orientation_unknown; + + if (_pa_result) + aiq_stats_input.frame_pa_parameters = _pa_result; + +#ifdef HAVE_AIQ_2_7 + if (_sa_result) + aiq_stats_input.frame_sa_parameters = _sa_result; +#endif + + if (_ae_handler->is_started()) { +#ifdef USE_HIST_GRID_WEIGHTING + if (XCAM_AE_METERING_MODE_WEIGHTED_WINDOW == _ae_handler->get_metering_mode ()) { + ia_aiq_ae_results* ae_result = _ae_handler->get_result (); + + if (XCAM_RETURN_NO_ERROR != _ae_handler->set_hist_weight_grid (&(ae_result->weight_grid))) { + XCAM_LOG_ERROR ("ae handler set hist weight grid failed"); + } + } +#endif + aiq_stats_input.frame_ae_parameters = _ae_handler->get_result (); + //_ae_handler->dump_hist_weight_grid (aiq_stats_input.frame_ae_parameters->weight_grid); + } + //if (_awb_handler->is_started()) + // aiq_stats_input.frame_awb_parameters = _awb_handler->get_result(); + + if (!_adaptor->convert_statistics (stats->get_isp_stats(), &rgbs_grids, &af_grids)) { + XCAM_LOG_WARNING ("ia isp adaptor convert 3a stats failed"); + return false; + } + + if (XCAM_AE_METERING_MODE_WEIGHTED_WINDOW == _ae_handler->get_metering_mode ()) { +#ifdef USE_RGBS_GRID_WEIGHTING + if (XCAM_RETURN_NO_ERROR != _ae_handler->set_RGBS_weight_grid(&rgbs_grids)) { + XCAM_LOG_ERROR ("ae handler update RGBS weighted statistic failed"); + } + //_ae_handler->dump_RGBS_grid (*(aiq_stats_input.rgbs_grids)); +#endif + } + XCAM_LOG_DEBUG ("statistics grid info, width:%u, height:%u, blk_r:%u, blk_b:%u, blk_gr:%u, blk_gb:%u", + aiq_stats_input.rgbs_grids[0]->grid_width, + aiq_stats_input.rgbs_grids[0]->grid_height, + aiq_stats_input.rgbs_grids[0]->blocks_ptr->avg_r, + aiq_stats_input.rgbs_grids[0]->blocks_ptr->avg_b, + aiq_stats_input.rgbs_grids[0]->blocks_ptr->avg_gr, + aiq_stats_input.rgbs_grids[0]->blocks_ptr->avg_gb); + + if (ia_aiq_statistics_set(get_handle (), &aiq_stats_input) != ia_err_none) { + XCAM_LOG_ERROR ("Aiq set statistic failed"); + return false; + } + return true; +} + +XCamReturn AiqCompositor::convert_color_effect (IspInputParameters &isp_input) +{ + AiqCommonHandler *aiq_common = _common_handler.ptr(); + + switch (aiq_common->get_color_effect()) { + case XCAM_COLOR_EFFECT_NONE: + isp_input.effects = ia_isp_effect_none; + break; + case XCAM_COLOR_EFFECT_SKY_BLUE: + isp_input.effects = ia_isp_effect_sky_blue; + break; + case XCAM_COLOR_EFFECT_SKIN_WHITEN_LOW: + isp_input.effects = ia_isp_effect_skin_whiten_low; + break; + case XCAM_COLOR_EFFECT_SKIN_WHITEN: + isp_input.effects = ia_isp_effect_skin_whiten; + break; + case XCAM_COLOR_EFFECT_SKIN_WHITEN_HIGH: + isp_input.effects = ia_isp_effect_skin_whiten_high; + break; + case XCAM_COLOR_EFFECT_SEPIA: + isp_input.effects = ia_isp_effect_sepia; + break; + case XCAM_COLOR_EFFECT_NEGATIVE: + isp_input.effects = ia_isp_effect_negative; + break; + case XCAM_COLOR_EFFECT_GRAYSCALE: + isp_input.effects = ia_isp_effect_grayscale; + break; + default: + isp_input.effects = ia_isp_effect_none; + break; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +AiqCompositor::apply_gamma_table (struct atomisp_parameters *isp_param) +{ + if (_common_handler->_params.is_manual_gamma) { + int i; + + if (isp_param->r_gamma_table) { + isp_param->r_gamma_table->vamem_type = 1; //IA_CSS_VAMEM_TYPE_2 = 1; + for (i = 0; i < XCAM_GAMMA_TABLE_SIZE; ++i) { + // change from double to u0.12 + isp_param->r_gamma_table->data.vamem_2[i] = + (uint32_t) (_common_handler->_params.r_gamma[i] * 4096.0); + } + isp_param->r_gamma_table->data.vamem_2[256] = 4091; + } + + if (isp_param->g_gamma_table) { + isp_param->g_gamma_table->vamem_type = 1; //IA_CSS_VAMEM_TYPE_2 = 1; + for (i = 0; i < XCAM_GAMMA_TABLE_SIZE; ++i) { + // change from double to u0.12 + isp_param->g_gamma_table->data.vamem_2[i] = + (uint32_t) (_common_handler->_params.g_gamma[i] * 4096.0); + } + isp_param->g_gamma_table->data.vamem_2[256] = 4091; + } + + if (isp_param->b_gamma_table) { + isp_param->b_gamma_table->vamem_type = 1; //IA_CSS_VAMEM_TYPE_2 = 1; + for (i = 0; i < XCAM_GAMMA_TABLE_SIZE; ++i) { + // change from double to u0.12 + isp_param->b_gamma_table->data.vamem_2[i] = + (uint32_t) (_common_handler->_params.b_gamma[i] * 4096.0); + } + isp_param->b_gamma_table->data.vamem_2[256] = 4091; + } + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +AiqCompositor::apply_night_mode (struct atomisp_parameters *isp_param) +{ + static const struct atomisp_cc_config night_yuv2rgb_cc_config = { + 10, + { 1 << 10, 0, 0, /* 1.0, 0, 0 */ + 1 << 10, 0, 0, /* 1.0, 0, 0 */ + 1 << 10, 0, 0 + } + }; /* 1.0, 0, 0 */ + static const struct atomisp_wb_config night_wb_config = { + 1, + 1 << 15, 1 << 15, 1 << 15, 1 << 15 + }; /* 1.0, 1.0, 1.0, 1.0*/ + + if (isp_param->ctc_config) + isp_param->ctc_config = NULL; + + *isp_param->wb_config = night_wb_config; + *isp_param->yuv2rgb_cc_config = night_yuv2rgb_cc_config; + + return XCAM_RETURN_NO_ERROR; +} + +double +AiqCompositor::calculate_value_by_factor (double factor, double min, double mid, double max) +{ + XCAM_ASSERT (factor >= -1.0 && factor <= 1.0); + XCAM_ASSERT (min <= mid && max >= mid); + + if (factor >= 0.0) + return (mid * (1.0 - factor) + max * factor); + else + return (mid * (1.0 + factor) + min * (-factor)); +} + +XCamReturn +AiqCompositor::limit_nr_levels (struct atomisp_parameters *isp_param) +{ +#define NR_MIN_FACOTR 0.1 +#define NR_MAX_FACOTR 6.0 +#define NR_MID_FACOTR 1.0 + SmartPtr<AiqCommonHandler> aiq_common = _common_handler; + + if (!XCAM_DOUBLE_EQUAL_AROUND (aiq_common->_params.nr_level, 0.0)) { + double nr_factor; + nr_factor = calculate_value_by_factor ( + aiq_common->_params.nr_level, NR_MIN_FACOTR, NR_MID_FACOTR, NR_MAX_FACOTR); + if (isp_param->nr_config) { + isp_param->nr_config->bnr_gain = + XCAM_MIN (isp_param->nr_config->bnr_gain * nr_factor, 65535); + isp_param->nr_config->ynr_gain = + XCAM_MIN (isp_param->nr_config->ynr_gain * nr_factor, 65535); + } + if (isp_param->cnr_config) { + isp_param->cnr_config->sense_gain_vy = + XCAM_MIN (isp_param->cnr_config->sense_gain_vy * nr_factor, 8191); + isp_param->cnr_config->sense_gain_vu = + XCAM_MIN (isp_param->cnr_config->sense_gain_vu * nr_factor, 8191); + isp_param->cnr_config->sense_gain_vv = + XCAM_MIN (isp_param->cnr_config->sense_gain_vv * nr_factor, 8191); + isp_param->cnr_config->sense_gain_hy = + XCAM_MIN (isp_param->cnr_config->sense_gain_hy * nr_factor, 8191); + isp_param->cnr_config->sense_gain_hu = + XCAM_MIN (isp_param->cnr_config->sense_gain_hu * nr_factor, 8191); + isp_param->cnr_config->sense_gain_hv = + XCAM_MIN (isp_param->cnr_config->sense_gain_hv * nr_factor, 8191); + } + } + + if (!XCAM_DOUBLE_EQUAL_AROUND (aiq_common->_params.tnr_level, 0.0)) { + double tnr_factor; + tnr_factor = calculate_value_by_factor ( + aiq_common->_params.tnr_level, NR_MIN_FACOTR, NR_MID_FACOTR, NR_MAX_FACOTR); + if (isp_param->tnr_config) { + isp_param->tnr_config->gain = + XCAM_MIN (isp_param->tnr_config->gain * tnr_factor, 65535); + if (XCAM_DOUBLE_EQUAL_AROUND (aiq_common->_params.tnr_level, 1.0)) { + isp_param->tnr_config->gain = 65535; + isp_param->tnr_config->threshold_y = 0; + isp_param->tnr_config->threshold_uv = 0; + } + } + XCAM_LOG_DEBUG ("set TNR gain:%u", isp_param->tnr_config->gain); + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn AiqCompositor::integrate (X3aResultList &results) +{ + IspInputParameters isp_params; + ia_aiq_pa_input_params pa_input; + ia_aiq_pa_results *pa_result = NULL; +#ifdef HAVE_AIQ_2_7 + ia_aiq_sa_input_params sa_input; + ia_aiq_sa_results *sa_result = NULL; +#endif + ia_err ia_error = ia_err_none; + ia_binary_data output; + AiqAeHandler *aiq_ae = _ae_handler.ptr(); + AiqAwbHandler *aiq_awb = _awb_handler.ptr(); + AiqAfHandler *aiq_af = _af_handler.ptr(); + AiqCommonHandler *aiq_common = _common_handler.ptr(); + struct atomisp_parameters *isp_3a_result = NULL; + SmartPtr<X3aResult> isp_results; + + XCAM_FAIL_RETURN ( + ERROR, + aiq_ae && aiq_awb && aiq_af && aiq_common, + XCAM_RETURN_ERROR_PARAM, + "handlers are not AIQ inherited"); + + xcam_mem_clear (pa_input); +#ifndef HAVE_AIQ_2_7 + pa_input.frame_use = _frame_use; + pa_input.sensor_frame_params = &_frame_params; +#endif + if (aiq_ae->is_started()) + pa_input.exposure_params = (aiq_ae->get_result ())->exposures[0].exposure; + pa_input.color_gains = NULL; + + if (aiq_common->_params.enable_night_mode) { + pa_input.awb_results = NULL; + isp_params.effects = ia_isp_effect_grayscale; + } + else { + pa_input.awb_results = aiq_awb->get_result (); + } + + ia_error = ia_aiq_pa_run (_ia_handle, &pa_input, &pa_result); + if (ia_error != ia_err_none) { + XCAM_LOG_WARNING ("AIQ pa run failed"); // but not return error + } + _pa_result = pa_result; + + if (aiq_awb->get_mode_unlock () == XCAM_AWB_MODE_MANUAL) { + if (XCAM_DOUBLE_EQUAL_AROUND (aiq_awb->_params.gr_gain, 0.0) || + XCAM_DOUBLE_EQUAL_AROUND (aiq_awb->_params.r_gain, 0.0) || + XCAM_DOUBLE_EQUAL_AROUND (aiq_awb->_params.b_gain, 0.0) || + XCAM_DOUBLE_EQUAL_AROUND (aiq_awb->_params.gb_gain, 0.0)) { + XCAM_LOG_DEBUG ("Zero gain would cause ISP division fatal error"); + } + else { +#ifdef HAVE_AIQ_2_7 + _pa_result->color_gains.gr = aiq_awb->_params.gr_gain; + _pa_result->color_gains.r = aiq_awb->_params.r_gain; + _pa_result->color_gains.b = aiq_awb->_params.b_gain; + _pa_result->color_gains.gb = aiq_awb->_params.gb_gain; +#else + _pa_result->color_gains[0] = aiq_awb->_params.gr_gain; + _pa_result->color_gains[1] = aiq_awb->_params.r_gain; + _pa_result->color_gains[2] = aiq_awb->_params.b_gain; + _pa_result->color_gains[3] = aiq_awb->_params.gb_gain; +#endif + } + } + +#ifdef HAVE_AIQ_2_7 + xcam_mem_clear (sa_input); + sa_input.frame_use = _frame_use; + sa_input.sensor_frame_params = &_frame_params; + if (aiq_common->_params.enable_night_mode) { + sa_input.awb_results = NULL; + } + else { + sa_input.awb_results = aiq_awb->get_result (); + } + + ia_error = ia_aiq_sa_run (_ia_handle, &sa_input, &sa_result); + if (ia_error != ia_err_none) { + XCAM_LOG_WARNING ("AIQ sa run failed"); // but not return error + } + _sa_result = sa_result; +#endif + + isp_params.frame_use = _frame_use; + isp_params.awb_results = aiq_awb->get_result (); + if (aiq_ae->is_started()) + isp_params.exposure_results = (aiq_ae->get_result ())->exposures[0].exposure; + isp_params.gbce_results = aiq_common->get_gbce_result (); + isp_params.sensor_frame_params = &_frame_params; + isp_params.pa_results = pa_result; +#ifdef HAVE_AIQ_2_7 + isp_params.sa_results = sa_result; +#endif + + isp_params.manual_brightness = (int8_t)(aiq_common->get_brightness_unlock() * 128.0); + isp_params.manual_contrast = (int8_t)(aiq_common->get_contrast_unlock() * 128.0); + isp_params.manual_saturation = (int8_t)(aiq_common->get_saturation_unlock() * 128.0); + isp_params.manual_hue = (int8_t)(aiq_common->get_hue_unlock() * 128.0); + isp_params.manual_sharpness = (int8_t)(aiq_common->get_sharpness_unlock() * 128.0); + isp_params.manual_nr_level = (int8_t)(aiq_common->get_nr_level_unlock() * 128.0); + + convert_color_effect(isp_params); + + xcam_mem_clear (output); + if (!_adaptor->run (&isp_params, &output)) { + XCAM_LOG_ERROR("Aiq to isp adaptor running failed"); + return XCAM_RETURN_ERROR_ISP; + } + isp_3a_result = ((struct atomisp_parameters *)output.data); + apply_gamma_table (isp_3a_result); + limit_nr_levels (isp_3a_result); + if (aiq_common->_params.enable_night_mode) + { + apply_night_mode (isp_3a_result); + } + + isp_results = generate_3a_configs (isp_3a_result); + results.push_back (isp_results); + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<X3aResult> +AiqCompositor::generate_3a_configs (struct atomisp_parameters *parameters) +{ + SmartPtr<X3aResult> ret; + + X3aAtomIspParametersResult *x3a_result = + new X3aAtomIspParametersResult (XCAM_IMAGE_PROCESS_ONCE); + x3a_result->set_isp_config (*parameters); + ret = x3a_result; + return ret; +} + +void +AiqCompositor::set_ae_handler (SmartPtr<AiqAeHandler> &handler) +{ + XCAM_ASSERT (!_ae_handler.ptr()); + _ae_handler = handler; +} + +void +AiqCompositor::set_awb_handler (SmartPtr<AiqAwbHandler> &handler) +{ + XCAM_ASSERT (!_awb_handler.ptr()); + _awb_handler = handler; +} + +void +AiqCompositor::set_af_handler (SmartPtr<AiqAfHandler> &handler) +{ + XCAM_ASSERT (!_af_handler.ptr()); + _af_handler = handler; +} + +void +AiqCompositor::set_common_handler (SmartPtr<AiqCommonHandler> &handler) +{ + XCAM_ASSERT (!_common_handler.ptr()); + _common_handler = handler; +} + + +}; diff --git a/modules/isp/aiq_handler.h b/modules/isp/aiq_handler.h new file mode 100644 index 0000000..222c311 --- /dev/null +++ b/modules/isp/aiq_handler.h @@ -0,0 +1,321 @@ +/* + * aiq_handler.h - AIQ handler + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_AIQ_HANDLER_H +#define XCAM_AIQ_HANDLER_H + +#include <xcam_std.h> +#include "handler_interface.h" +#include "x3a_statistics_queue.h" +#include "ia_types.h" +#include "ia_aiq_types.h" +#include "ia_cmc_parser.h" +#include "ia_mkn_encoder.h" +#include "ia_aiq.h" +#include "ia_coordinate.h" + +typedef struct ia_isp_t ia_isp; + +namespace XCam { + +class AiqCompositor; +struct IspInputParameters; + +class IaIspAdaptor { +public: + explicit IaIspAdaptor() + : _handle (NULL) + {} + virtual ~IaIspAdaptor() {} + + virtual bool init ( + const ia_binary_data *cpf, + unsigned int max_width, + unsigned int max_height, + ia_cmc_t *cmc, + ia_mkn *mkn) = 0; + virtual bool convert_statistics ( + void *statistics, + ia_aiq_rgbs_grid **out_rgbs_grid, + ia_aiq_af_grid **out_af_grid) = 0; + virtual bool run ( + const IspInputParameters *isp_input_params, + ia_binary_data *output_data) = 0; + +private: + XCAM_DEAD_COPY (IaIspAdaptor); + +protected: + ia_isp *_handle; +}; + +class AiqAeHandler + : public AeHandler +{ + friend class AiqCompositor; +private: + struct AiqAeResult { + ia_aiq_ae_results ae_result; + ia_aiq_ae_exposure_result ae_exp_ret; + ia_aiq_exposure_parameters aiq_exp_param; + ia_aiq_exposure_sensor_parameters sensor_exp_param; + ia_aiq_hist_weight_grid weight_grid; + ia_aiq_flash_parameters flash_param; + + AiqAeResult(); + void copy (ia_aiq_ae_results *result); + + XCAM_DEAD_COPY (AiqAeResult); + }; + +public: + explicit AiqAeHandler (SmartPtr<AiqCompositor> &aiq_compositor); + ~AiqAeHandler () {} + + bool is_started () const { + return _started; + } + + bool set_description (struct atomisp_sensor_mode_data *sensor_mode_data); + + ia_aiq_ae_results *get_result () { + return &_result.ae_result; + } + + //virtual functions from AnalyzerHandler + virtual XCamReturn analyze (X3aResultList &output); + + // virtual functions from AeHandler + virtual XCamFlickerMode get_flicker_mode (); + virtual int64_t get_current_exposure_time (); + virtual double get_current_analog_gain (); + virtual double get_max_analog_gain (); + + XCamReturn set_RGBS_weight_grid (ia_aiq_rgbs_grid **out_rgbs_grid); + XCamReturn set_hist_weight_grid (ia_aiq_hist_weight_grid **out_weight_grid); + XCamReturn dump_hist_weight_grid (const ia_aiq_hist_weight_grid *weight_grid); + XCamReturn dump_RGBS_grid (const ia_aiq_rgbs_grid *rgbs_grid); + +private: + bool ensure_ia_parameters (); + bool ensure_ae_mode (); + bool ensure_ae_metering_mode (); + bool ensure_ae_priority_mode (); + bool ensure_ae_flicker_mode (); + bool ensure_ae_manual (); + bool ensure_ae_ev_shift (); + + void adjust_ae_speed ( + ia_aiq_exposure_sensor_parameters &cur_res, + ia_aiq_exposure_parameters &cur_aiq_exp, + const ia_aiq_exposure_sensor_parameters &last_res, double ae_speed); + void adjust_ae_limitation (ia_aiq_exposure_sensor_parameters &cur_res, + ia_aiq_exposure_parameters &cur_aiq_exp); + bool manual_control_result ( + ia_aiq_exposure_sensor_parameters &cur_res, + ia_aiq_exposure_parameters &cur_aiq_exp, + const ia_aiq_exposure_sensor_parameters &last_res); + + SmartPtr<X3aResult> pop_result (); + + static void convert_xcam_window_to_ia (const XCam3AWindow &window, ia_rectangle &ia_window); + +private: + XCAM_DEAD_COPY (AiqAeHandler); + +protected: + SmartPtr<AiqCompositor> _aiq_compositor; + /* AIQ */ + ia_rectangle _ia_ae_window; + ia_aiq_exposure_sensor_descriptor _sensor_descriptor; + ia_aiq_ae_manual_limits _manual_limits; + + ia_aiq_ae_input_params _input; + + /* result */ + AiqAeResult _result; + uint32_t _calculate_period; + bool _started; +}; + +class AiqAwbHandler + : public AwbHandler +{ + friend class AiqCompositor; +public: + explicit AiqAwbHandler (SmartPtr<AiqCompositor> &aiq_compositor); + ~AiqAwbHandler () {} + + virtual XCamReturn analyze (X3aResultList &output); + + // virtual functions from AwbHandler + virtual uint32_t get_current_estimate_cct (); + + ia_aiq_awb_results *get_result () { + return &_result; + } + bool is_started () const { + return _started; + } + +private: + bool ensure_ia_parameters (); + bool ensure_awb_mode (); + void adjust_speed (const ia_aiq_awb_results &last_ret); + + XCAM_DEAD_COPY (AiqAwbHandler); + +protected: + SmartPtr<AiqCompositor> _aiq_compositor; + /*aiq*/ + ia_aiq_awb_input_params _input; + ia_aiq_awb_manual_cct_range _cct_range; + + ia_aiq_awb_results _result; + ia_aiq_awb_results _history_result; + bool _started; +}; + +class AiqAfHandler + : public AfHandler +{ +public: + explicit AiqAfHandler (SmartPtr<AiqCompositor> &aiq_compositor) + : _aiq_compositor (aiq_compositor) + {} + ~AiqAfHandler () {} + + virtual XCamReturn analyze (X3aResultList &output); + +private: + XCAM_DEAD_COPY (AiqAfHandler); + +protected: + SmartPtr<AiqCompositor> _aiq_compositor; +}; + +class AiqCommonHandler + : public CommonHandler +{ + friend class AiqCompositor; +public: + explicit AiqCommonHandler (SmartPtr<AiqCompositor> &aiq_compositor); + ~AiqCommonHandler () {} + + virtual XCamReturn analyze (X3aResultList &output); + ia_aiq_gbce_results *get_gbce_result () { + return _gbce_result; + } + XCamColorEffect get_color_effect() { + return _params.color_effect; + } + +private: + XCAM_DEAD_COPY (AiqCommonHandler); + +protected: + SmartPtr<AiqCompositor> _aiq_compositor; + ia_aiq_gbce_results *_gbce_result; +}; + +class AiqCompositor { +public: + explicit AiqCompositor (); + ~AiqCompositor (); + + void set_ae_handler (SmartPtr<AiqAeHandler> &handler); + void set_awb_handler (SmartPtr<AiqAwbHandler> &handler); + void set_af_handler (SmartPtr<AiqAfHandler> &handler); + void set_common_handler (SmartPtr<AiqCommonHandler> &handler); + + void set_frame_use (ia_aiq_frame_use value) { + _frame_use = value; + } + void set_size (uint32_t width, uint32_t height) { + _width = width; + _height = height; + } + void get_size (uint32_t &out_width, uint32_t &out_height) const { + out_width = _width; + out_height = _height; + } + void set_framerate (double framerate) { + _framerate = framerate; + } + double get_framerate () { + return _framerate; + } + bool open (ia_binary_data &cpf); + void close (); + + bool set_sensor_mode_data (struct atomisp_sensor_mode_data *sensor_mode); + bool set_3a_stats (SmartPtr<X3aIspStatistics> &stats); + + ia_aiq * get_handle () { + return _ia_handle; + } + ia_aiq_frame_use get_frame_use () const { + return _frame_use; + } + + XCamReturn integrate ( X3aResultList &results); + + SmartPtr<X3aResult> generate_3a_configs (struct atomisp_parameters *parameters); + void convert_window_to_ia (const XCam3AWindow &window, ia_rectangle &ia_window); + XCamReturn convert_color_effect (IspInputParameters &isp_input); + + double get_ae_ev_shift_unlock () { + return _ae_handler->get_ev_shift_unlock(); + } + +private: + XCamReturn apply_gamma_table (struct atomisp_parameters *isp_param); + XCamReturn apply_night_mode (struct atomisp_parameters *isp_param); + XCamReturn limit_nr_levels (struct atomisp_parameters *isp_param); + double calculate_value_by_factor (double factor, double min, double mid, double max); + + XCAM_DEAD_COPY (AiqCompositor); + +private: + SmartPtr<IaIspAdaptor> _adaptor; + SmartPtr<AiqAeHandler> _ae_handler; + SmartPtr<AiqAwbHandler> _awb_handler; + SmartPtr<AiqAfHandler> _af_handler; + SmartPtr<AiqCommonHandler> _common_handler; + ia_aiq *_ia_handle; + ia_mkn *_ia_mkn; + ia_aiq_pa_results *_pa_result; +#ifdef HAVE_AIQ_2_7 + ia_aiq_sa_results *_sa_result; +#endif + ia_aiq_frame_use _frame_use; + ia_aiq_frame_params _frame_params; + + /*grids*/ + ; + + uint32_t _width; + uint32_t _height; + double _framerate; +}; + +}; + +#endif //XCAM_AIQ_HANDLER_H diff --git a/modules/isp/atomisp_device.cpp b/modules/isp/atomisp_device.cpp new file mode 100755 index 0000000..3f09d53 --- /dev/null +++ b/modules/isp/atomisp_device.cpp @@ -0,0 +1,121 @@ +/* + * atomisp_device.cpp - atomisp device + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "atomisp_device.h" +#include "v4l2_buffer_proxy.h" +#include <linux/v4l2-subdev.h> + +namespace XCam { + +AtomispDevice::AtomispDevice (const char *name) + : V4l2Device (name) +{ +} + +AtomispDevice::~AtomispDevice () +{ +} + +XCamReturn +AtomispDevice::pre_set_format (struct v4l2_format &format) +{ + uint32_t fps_n = 0, fps_d = 0; + struct v4l2_subdev_format subdev_fmt; + + // set framerate by subdev + this->get_framerate (fps_n, fps_d); + if (fps_n != 0 && fps_d != 0) { + struct v4l2_subdev_frame_interval frame_intvl; + xcam_mem_clear (frame_intvl); + if (io_control (VIDIOC_SUBDEV_G_FRAME_INTERVAL, &frame_intvl) < 0) { + XCAM_LOG_WARNING ("atomisp device(%s) get framerate failed ", XCAM_STR (get_device_name())); + } else { + frame_intvl.interval.denominator = fps_n; + frame_intvl.interval.numerator = fps_d; + if (io_control (VIDIOC_SUBDEV_S_FRAME_INTERVAL, &frame_intvl) < 0) { + XCAM_LOG_WARNING ("atomisp device(%s) set framerate failed", XCAM_STR (get_device_name())); + } + } + } + + // negotiate and set sensor output format by subdev + xcam_mem_clear (subdev_fmt); + subdev_fmt.pad = 0; + subdev_fmt.which = V4L2_SUBDEV_FORMAT_TRY; + subdev_fmt.format.width = format.fmt.pix.width; + subdev_fmt.format.height = format.fmt.pix.height; + subdev_fmt.format.field = V4L2_FIELD_NONE; + if (format.fmt.pix.pixelformat == V4L2_PIX_FMT_SGRBG12) { + subdev_fmt.format.code = V4L2_MBUS_FMT_SRGGB12_1X12; + } else { + subdev_fmt.format.code = V4L2_MBUS_FMT_SRGGB10_1X10; + } + + if (io_control(VIDIOC_SUBDEV_S_FMT, &subdev_fmt) < 0) { + XCAM_LOG_ERROR ("atomisp device(%s) try subdev format failed", XCAM_STR (get_device_name())); + return XCAM_RETURN_ERROR_IOCTL; + } + XCAM_LOG_INFO ("target subdev format (%dx%d, code %d)", + subdev_fmt.format.width, + subdev_fmt.format.height, + subdev_fmt.format.code); + + subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + if (io_control (VIDIOC_SUBDEV_G_FMT, &subdev_fmt) < 0) { + XCAM_LOG_ERROR ("atomisp device(%s) get subdev format failed", XCAM_STR (get_device_name())); + } + XCAM_LOG_INFO ("negotiated subdev format (%dx%d, code %d)", + subdev_fmt.format.width, + subdev_fmt.format.height, + subdev_fmt.format.code); + + if (io_control(VIDIOC_SUBDEV_S_FMT, &subdev_fmt) < 0) { + XCAM_LOG_ERROR ("atomisp device(%s) set subdev format failed", XCAM_STR (get_device_name())); + return XCAM_RETURN_ERROR_IOCTL; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +AtomispDevice::allocate_buffer ( + SmartPtr<V4l2Buffer> &buf, + const struct v4l2_format &format, + const uint32_t index) +{ +#if HAVE_LIBDRM + if (!_drm_disp.ptr()) { + _drm_disp = DrmDisplay::instance (); + } + + if (get_mem_type () == V4L2_MEMORY_DMABUF && _drm_disp.ptr () != NULL) { + buf = _drm_disp->create_drm_buf (format, index, get_capture_buf_type ()); + if (!buf.ptr()) { + XCAM_LOG_WARNING ("atomisp device(%s) allocate buffer failed", XCAM_STR (get_device_name())); + return XCAM_RETURN_ERROR_MEM; + } + return XCAM_RETURN_NO_ERROR; + } +#endif + + return V4l2Device::allocate_buffer (buf, format, index); +} + +}; diff --git a/modules/isp/atomisp_device.h b/modules/isp/atomisp_device.h new file mode 100644 index 0000000..ac9ddf8 --- /dev/null +++ b/modules/isp/atomisp_device.h @@ -0,0 +1,69 @@ +/* + * atomisp_device.h - atomisp device + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_ATOMISP_DEVICE_H +#define XCAM_ATOMISP_DEVICE_H + +#include <xcam_std.h> +#include "v4l2_device.h" +#if HAVE_LIBDRM +#include "drm_display.h" +#endif + +namespace XCam { + +#if HAVE_LIBDRM +class DrmDisplay; +#endif + +class AtomispDevice + : public V4l2Device +{ + friend class DrmV4l2Buffer; + +public: + explicit AtomispDevice (const char *name = NULL); + ~AtomispDevice (); + +#if HAVE_LIBDRM + void set_drm_display(SmartPtr<DrmDisplay> &drm_disp) { + _drm_disp = drm_disp; + }; +#endif + +protected: + virtual XCamReturn pre_set_format (struct v4l2_format &format); + virtual XCamReturn allocate_buffer ( + SmartPtr<V4l2Buffer> &buf, + const struct v4l2_format &format, + const uint32_t index); + +private: + XCAM_DEAD_COPY (AtomispDevice); + +#if HAVE_LIBDRM +private: + SmartPtr<DrmDisplay> _drm_disp; +#endif +}; + +}; + +#endif //XCAM_ATOMISP_DEVICE_H diff --git a/modules/isp/hybrid_analyzer.cpp b/modules/isp/hybrid_analyzer.cpp new file mode 100644 index 0000000..9e0a0f6 --- /dev/null +++ b/modules/isp/hybrid_analyzer.cpp @@ -0,0 +1,232 @@ +/* + * hybrid_analyzer.h - hybrid analyzer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Jia Meng <jia.meng@intel.com> + */ + +#include "hybrid_analyzer.h" +#include "isp_controller.h" +#include "x3a_analyzer_aiq.h" +#include "x3a_statistics_queue.h" +#include "aiq3a_utils.h" +#include <math.h> + +namespace XCam { +HybridAnalyzer::HybridAnalyzer (XCam3ADescription *desc, + SmartPtr<AnalyzerLoader> &loader, + SmartPtr<IspController> &isp, + const char *cpf_path) + : DynamicAnalyzer (desc, loader, "HybridAnalyzer") + , _isp (isp) + , _cpf_path (cpf_path) +{ + _analyzer_aiq = new X3aAnalyzerAiq (isp, cpf_path); + XCAM_ASSERT (_analyzer_aiq.ptr ()); + _analyzer_aiq->prepare_handlers (); + _analyzer_aiq->set_results_callback (this); + _analyzer_aiq->set_sync_mode (true); +} + +XCamReturn +HybridAnalyzer::internal_init (uint32_t width, uint32_t height, double framerate) +{ + if (_analyzer_aiq->init (width, height, framerate) != XCAM_RETURN_NO_ERROR) { + return XCAM_RETURN_ERROR_AIQ; + } + + return create_context (); +} + +XCamReturn +HybridAnalyzer::internal_deinit () +{ + if (_analyzer_aiq->deinit () != XCAM_RETURN_NO_ERROR) { + return XCAM_RETURN_ERROR_AIQ; + } + + return DynamicAnalyzer::internal_deinit (); +} + +XCamReturn +HybridAnalyzer::setup_stats_pool (const XCam3AStats *stats) +{ + XCAM_ASSERT (stats); + + XCam3AStatsInfo stats_info = stats->info; + struct atomisp_grid_info grid_info; + grid_info.enable = 1; + grid_info.use_dmem = 0; + grid_info.has_histogram = 0; + grid_info.width = stats_info.width; + grid_info.height = stats_info.height; + grid_info.aligned_width = stats_info.aligned_width; + grid_info.aligned_height = stats_info.aligned_height; + grid_info.bqs_per_grid_cell = stats_info.grid_pixel_size >> 1; + grid_info.deci_factor_log2 = log2 (grid_info.bqs_per_grid_cell); + grid_info.elem_bit_depth = stats_info.bit_depth; + + _stats_pool = new X3aStatisticsQueue; + XCAM_ASSERT (_stats_pool.ptr ()); + + _stats_pool->set_grid_info (grid_info); + if (!_stats_pool->reserve (6)) { + XCAM_LOG_WARNING ("setup_stats_pool failed to reserve stats buffer."); + return XCAM_RETURN_ERROR_MEM; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +HybridAnalyzer::configure_3a () +{ + if (_analyzer_aiq->start () != XCAM_RETURN_NO_ERROR) { + return XCAM_RETURN_ERROR_AIQ; + } + + return DynamicAnalyzer::configure_3a (); +} + +XCamReturn +HybridAnalyzer::pre_3a_analyze (SmartPtr<X3aStats> &stats) +{ + _analyzer_aiq->update_common_parameters (get_common_params ()); + + return DynamicAnalyzer::pre_3a_analyze (stats); +} + +SmartPtr<X3aIspStatistics> +HybridAnalyzer::convert_to_isp_stats (SmartPtr<X3aStats>& stats) +{ + SmartPtr<X3aIspStatistics> isp_stats = + _stats_pool->get_buffer (_stats_pool).dynamic_cast_ptr<X3aIspStatistics> (); + + XCAM_FAIL_RETURN ( + WARNING, + isp_stats.ptr (), + NULL, + "get isp stats buffer failed"); + + struct atomisp_3a_statistics *to = isp_stats->get_isp_stats (); + XCam3AStats *from = stats->get_stats (); + translate_3a_stats (from, to); + isp_stats->set_timestamp (stats->get_timestamp ()); + return isp_stats; +} + +XCamReturn +HybridAnalyzer::post_3a_analyze (X3aResultList &results) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<X3aStats> stats = get_cur_stats (); + + if ((ret = DynamicAnalyzer::post_3a_analyze (results)) != XCAM_RETURN_NO_ERROR) { + return ret; + } + + for (X3aResultList::iterator i_res = results.begin (); + i_res != results.end (); ++i_res) { + SmartPtr<X3aResult> result = *i_res; + + switch (result->get_type ()) { + case XCAM_3A_RESULT_EXPOSURE: { + XCam3aResultExposure *res = (XCam3aResultExposure *) result->get_ptr (); + _analyzer_aiq->set_ae_mode (XCAM_AE_MODE_MANUAL); + _analyzer_aiq->set_ae_manual_exposure_time (res->exposure_time); + _analyzer_aiq->set_ae_manual_analog_gain (res->analog_gain); + break; + } + case XCAM_3A_RESULT_WHITE_BALANCE: { + _analyzer_aiq->set_awb_mode (XCAM_AWB_MODE_MANUAL); + XCam3aResultWhiteBalance *res = (XCam3aResultWhiteBalance *) result->get_ptr (); + _analyzer_aiq->set_awb_manual_gain (res->gr_gain, res->r_gain, res->b_gain, res->gb_gain); + break; + } + default: + break; + } + } + results.clear (); + + SmartPtr<X3aIspStatistics> isp_stats = stats.dynamic_cast_ptr<X3aIspStatistics> (); + if (!isp_stats.ptr ()) { + if (!_stats_pool.ptr () && setup_stats_pool (stats->get_stats ()) != XCAM_RETURN_NO_ERROR) + return XCAM_RETURN_ERROR_MEM; + isp_stats = convert_to_isp_stats (stats); + } + return _analyzer_aiq->push_3a_stats (isp_stats); +} + +XCamReturn +HybridAnalyzer::analyze_ae (XCamAeParam ¶m) +{ + if (!_analyzer_aiq->update_ae_parameters (param)) + return XCAM_RETURN_ERROR_AIQ; + + return DynamicAnalyzer::analyze_ae (param); +} + +XCamReturn +HybridAnalyzer::analyze_awb (XCamAwbParam ¶m) +{ + if (!_analyzer_aiq->update_awb_parameters (param)) + return XCAM_RETURN_ERROR_AIQ; + + return DynamicAnalyzer::analyze_awb (param); +} + +XCamReturn +HybridAnalyzer::analyze_af (XCamAfParam ¶m) +{ + if (!_analyzer_aiq->update_af_parameters (param)) + return XCAM_RETURN_ERROR_AIQ; + + return DynamicAnalyzer::analyze_af (param); +} + +void +HybridAnalyzer::x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results) +{ + XCAM_UNUSED (analyzer); + + static XCam3aResultHead *res_heads[XCAM_3A_MAX_RESULT_COUNT]; + xcam_mem_clear (res_heads); + XCAM_ASSERT (results.size () < XCAM_3A_MAX_RESULT_COUNT); + + uint32_t result_count = translate_3a_results_to_xcam (results, + res_heads, XCAM_3A_MAX_RESULT_COUNT); + convert_results (res_heads, result_count, results); + for (uint32_t i = 0; i < result_count; ++i) { + if (res_heads[i]) + free_3a_result (res_heads[i]); + } + + notify_calculation_done (results); +} + +HybridAnalyzer::~HybridAnalyzer () +{ + destroy_context (); +} + +void +HybridAnalyzer::x3a_calculation_failed (XAnalyzer *analyzer, int64_t timestamp, const char *msg) +{ + XCAM_UNUSED (analyzer); + notify_calculation_failed (NULL, timestamp, msg); +} +} diff --git a/modules/isp/hybrid_analyzer.h b/modules/isp/hybrid_analyzer.h new file mode 100644 index 0000000..e2b0a2b --- /dev/null +++ b/modules/isp/hybrid_analyzer.h @@ -0,0 +1,72 @@ +/* + * hybrid_analyzer.h - hybrid analyzer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Jia Meng <jia.meng@intel.com> + */ + +#ifndef XCAM_HYBRID_ANALYZER_H +#define XCAM_HYBRID_ANALYZER_H + +#include "dynamic_analyzer.h" +#include "hybrid_analyzer_loader.h" + +namespace XCam { +class IspController; +class X3aAnalyzerAiq; +class X3aStatisticsQueue; +class X3aIspStatistics; + +class HybridAnalyzer + : public DynamicAnalyzer + , public AnalyzerCallback +{ +public: + explicit HybridAnalyzer (XCam3ADescription *desc, + SmartPtr<AnalyzerLoader> &loader, + SmartPtr<IspController> &isp, + const char *cpf_path); + ~HybridAnalyzer (); + + virtual XCamReturn analyze_ae (XCamAeParam ¶m); + virtual XCamReturn analyze_awb (XCamAwbParam ¶m); + virtual XCamReturn analyze_af (XCamAfParam ¶m); + + virtual void x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results); + virtual void x3a_calculation_failed (XAnalyzer *analyzer, int64_t timestamp, const char *msg); + +protected: + virtual XCamReturn internal_init (uint32_t width, uint32_t height, double framerate); + virtual XCamReturn internal_deinit (); + + virtual XCamReturn configure_3a (); + virtual XCamReturn pre_3a_analyze (SmartPtr<X3aStats> &stats); + virtual XCamReturn post_3a_analyze (X3aResultList &results); + +private: + XCAM_DEAD_COPY (HybridAnalyzer); + XCamReturn setup_stats_pool (const XCam3AStats *stats); + SmartPtr<X3aIspStatistics> convert_to_isp_stats (SmartPtr<X3aStats>& stats); + + SmartPtr<IspController> _isp; + const char *_cpf_path; + SmartPtr<X3aAnalyzerAiq> _analyzer_aiq; + SmartPtr<X3aStatisticsQueue> _stats_pool; +}; + +} + +#endif //XCAM_HYBRID_ANALYZER_H diff --git a/modules/isp/hybrid_analyzer_loader.cpp b/modules/isp/hybrid_analyzer_loader.cpp new file mode 100644 index 0000000..4d0f4b8 --- /dev/null +++ b/modules/isp/hybrid_analyzer_loader.cpp @@ -0,0 +1,110 @@ +/* + * hybrid_analyzer_loader.cpp - hybrid analyzer loader + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Zong Wei <wei.zong@intel.com> + */ + +#include "hybrid_analyzer_loader.h" +#include "handler_interface.h" +#include "hybrid_analyzer.h" +#include <dlfcn.h> + +namespace XCam { + +HybridAnalyzerLoader::HybridAnalyzerLoader (const char *lib_path, const char *symbol) + : AnalyzerLoader (lib_path, symbol) + , _cpf_path (NULL) +{ +} + +HybridAnalyzerLoader::~HybridAnalyzerLoader () +{ + _isp.release (); +} + +bool +HybridAnalyzerLoader::set_cpf_path (const char *cpf_path) +{ + XCAM_ASSERT (cpf_path && !_cpf_path); + _cpf_path = cpf_path; + return true; +} + +bool +HybridAnalyzerLoader::set_isp_controller (SmartPtr<IspController> &isp) +{ + XCAM_ASSERT (isp.ptr() && !_isp.ptr()); + _isp = isp; + return true; +} + +SmartPtr<X3aAnalyzer> +HybridAnalyzerLoader::load_analyzer (SmartPtr<AnalyzerLoader> &self) +{ + XCAM_ASSERT (self.ptr () == this); + + SmartPtr<X3aAnalyzer> analyzer; + +#if HAVE_IA_AIQ + XCam3ADescription *desc = (XCam3ADescription*)load_library (get_lib_path ()); + analyzer = new HybridAnalyzer (desc, self, _isp, _cpf_path); +#endif + + if (!analyzer.ptr ()) { + XCAM_LOG_WARNING ("create HybridAnalyzer from lib failed"); + close_handle (); + return NULL; + } + + XCAM_LOG_INFO ("analyzer(%s) created from 3a lib", XCAM_STR (analyzer->get_name())); + return analyzer; +} + +void * +HybridAnalyzerLoader::load_symbol (void* handle) +{ + XCam3ADescription *desc = NULL; + + desc = (XCam3ADescription *)AnalyzerLoader::get_symbol (handle); + if (!desc) { + XCAM_LOG_DEBUG ("get symbol failed from lib"); + return NULL; + } + if (desc->version < xcam_version ()) { + XCAM_LOG_DEBUG ("get symbolfailed. version is:0x%04x, but expect:0x%04x", + desc->version, xcam_version ()); + return NULL; + } + if (desc->size < sizeof (XCam3ADescription)) { + XCAM_LOG_DEBUG ("get symbol failed, XCam3ADescription size is:%" PRIu32 ", but expect:%" PRIuS, + desc->size, sizeof (XCam3ADescription)); + return NULL; + } + + if (!desc->create_context || !desc->destroy_context || + !desc->configure_3a || !desc->set_3a_stats || + !desc->analyze_awb || !desc->analyze_ae || + !desc->analyze_af || !desc->combine_analyze_results || + !desc->free_results) { + XCAM_LOG_DEBUG ("some functions in symbol not set from lib"); + return NULL; + } + return (void*)desc; +} + +}; diff --git a/modules/isp/hybrid_analyzer_loader.h b/modules/isp/hybrid_analyzer_loader.h new file mode 100644 index 0000000..e683b10 --- /dev/null +++ b/modules/isp/hybrid_analyzer_loader.h @@ -0,0 +1,58 @@ +/* + * hybrid_analyzer_loader.h - hybrid analyzer loader + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Zong Wei <wei.zong@intel.com> + */ + +#ifndef XCAM_HYBRID_ANALYZER_LOADER_H +#define XCAM_HYBRID_ANALYZER_LOADER_H + +#include <xcam_std.h> +#include <base/xcam_3a_description.h> +#include "dynamic_analyzer_loader.h" +#include "isp_controller.h" + +namespace XCam { +class IspController; +class X3aAnalyzer; + +class HybridAnalyzerLoader + : public AnalyzerLoader +{ +public: + HybridAnalyzerLoader (const char *lib_path, const char *symbol = XCAM_3A_LIB_DESCRIPTION); + virtual ~HybridAnalyzerLoader (); + + virtual bool set_cpf_path (const char *cpf_path); + virtual bool set_isp_controller (SmartPtr<IspController> &isp); + virtual SmartPtr<X3aAnalyzer> load_analyzer (SmartPtr<AnalyzerLoader> &self); + +protected: + virtual void *load_symbol (void* handle); + +private: + XCAM_DEAD_COPY(HybridAnalyzerLoader); + +private: + const char *_cpf_path; + SmartPtr<IspController> _isp; +}; + +}; + +#endif // XCAM_HYBRID_ANALYZER_LOADER_H
\ No newline at end of file diff --git a/modules/isp/iq/x3a_analyze_tuner.cpp b/modules/isp/iq/x3a_analyze_tuner.cpp new file mode 100644 index 0000000..4430edf --- /dev/null +++ b/modules/isp/iq/x3a_analyze_tuner.cpp @@ -0,0 +1,244 @@ +/* + * x3a_analyze_tuner.cpp - x3a analyzer Common IQ tuning adaptor + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include "xcam_utils.h" +#include "x3a_stats_pool.h" +#include "x3a_analyzer.h" +#include "x3a_analyze_tuner.h" +#include "x3a_ciq_tuning_handler.h" +#include "x3a_ciq_tnr_tuning_handler.h" +#include "x3a_ciq_bnr_ee_tuning_handler.h" +#include "x3a_ciq_wavelet_tuning_handler.h" + +namespace XCam { + +X3aAnalyzeTuner::X3aAnalyzeTuner () + : X3aAnalyzer ("X3aAnalyzeTuner") +{ +} + +X3aAnalyzeTuner::~X3aAnalyzeTuner () +{ +} + +void +X3aAnalyzeTuner::set_analyzer (SmartPtr<X3aAnalyzer> &analyzer) +{ + XCAM_ASSERT (analyzer.ptr () && !_analyzer.ptr ()); + _analyzer = analyzer; + + _analyzer->set_results_callback (this); + _analyzer->prepare_handlers (); + _analyzer->set_sync_mode (true); +} + +XCamReturn +X3aAnalyzeTuner::create_tuning_handlers () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + SmartPtr<AeHandler> ae_handler = _analyzer->get_ae_handler (); + SmartPtr<AwbHandler> awb_handler = _analyzer->get_awb_handler(); + + SmartPtr<X3aCiqTuningHandler> tnr_tuning = new X3aCiqTnrTuningHandler (); + SmartPtr<X3aCiqTuningHandler> bnr_ee_tuning = new X3aCiqBnrEeTuningHandler (); + SmartPtr<X3aCiqTuningHandler> wavelet_tuning = new X3aCiqWaveletTuningHandler (); + + if (tnr_tuning.ptr ()) { + tnr_tuning->set_ae_handler (ae_handler); + tnr_tuning->set_awb_handler (awb_handler); + add_handler (tnr_tuning); + } else { + ret = XCAM_RETURN_ERROR_PARAM; + } + + if (bnr_ee_tuning.ptr ()) { + bnr_ee_tuning->set_ae_handler (ae_handler); + bnr_ee_tuning->set_awb_handler (awb_handler); + add_handler (bnr_ee_tuning); + } else { + ret = XCAM_RETURN_ERROR_PARAM; + } + + if (wavelet_tuning.ptr ()) { + wavelet_tuning->set_ae_handler (ae_handler); + wavelet_tuning->set_awb_handler (awb_handler); + add_handler (wavelet_tuning); + } else { + ret = XCAM_RETURN_ERROR_PARAM; + } + + return ret; +} + +bool +X3aAnalyzeTuner::add_handler (SmartPtr<X3aCiqTuningHandler> &handler) +{ + XCAM_ASSERT (handler.ptr ()); + _handlers.push_back (handler); + return true; +} + +XCamReturn +X3aAnalyzeTuner::analyze_ae (XCamAeParam ¶m) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (_analyzer.ptr ()); + _analyzer->update_ae_parameters (param); + return ret; +} + +XCamReturn +X3aAnalyzeTuner::analyze_awb (XCamAwbParam ¶m) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (_analyzer.ptr ()); + _analyzer->update_awb_parameters (param); + return ret; +} + +XCamReturn +X3aAnalyzeTuner::analyze_af (XCamAfParam ¶m) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (_analyzer.ptr ()); + _analyzer->update_af_parameters (param); + return ret; +} + +XCamReturn +X3aAnalyzeTuner::analyze_common (XCamCommonParam ¶m) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (_analyzer.ptr ()); + _analyzer->update_common_parameters (param); + return ret; +} + +SmartPtr<AeHandler> +X3aAnalyzeTuner::create_ae_handler () +{ + SmartPtr<AeHandler> ae_handler = new X3aCiqTuningAeHandler (this); + return ae_handler; +} + +SmartPtr<AwbHandler> +X3aAnalyzeTuner::create_awb_handler () +{ + SmartPtr<AwbHandler> awb_handler = new X3aCiqTuningAwbHandler (this); + return awb_handler; +} + +SmartPtr<AfHandler> +X3aAnalyzeTuner::create_af_handler () +{ + SmartPtr<AfHandler> af_handler = new X3aCiqTuningAfHandler (this); + return af_handler; +} + +SmartPtr<CommonHandler> +X3aAnalyzeTuner::create_common_handler () +{ + SmartPtr<CommonHandler> common_handler = new X3aCiqTuningCommonHandler (this); + return common_handler; +} + +XCamReturn +X3aAnalyzeTuner::internal_init (uint32_t width, uint32_t height, double framerate) +{ + XCAM_ASSERT (_analyzer.ptr ()); + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + _analyzer->init (width, height, framerate); + + if (XCAM_RETURN_NO_ERROR == ret) { + ret = create_tuning_handlers (); + } + return ret; +} + +XCamReturn +X3aAnalyzeTuner::internal_deinit () +{ + XCAM_ASSERT (_analyzer.ptr ()); + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + ret = _analyzer->deinit (); + + return ret; +} + +XCamReturn +X3aAnalyzeTuner::configure_3a () +{ + XCAM_ASSERT (_analyzer.ptr ()); + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + ret = _analyzer->start (); + + return ret; +} + +XCamReturn +X3aAnalyzeTuner::pre_3a_analyze (SmartPtr<X3aStats> &stats) +{ + // save stats for aiq analyzer + XCamReturn ret = XCAM_RETURN_NO_ERROR; + if (stats.ptr ()) { + _stats = stats; + } + return ret; +} + +XCamReturn +X3aAnalyzeTuner::post_3a_analyze (X3aResultList &results) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (_analyzer.ptr ()); + ret = _analyzer->push_3a_stats (_stats); + _stats.release (); + + results.insert (results.end (), _results.begin (), _results.end ()); + _results.clear (); + + X3aCiqTuningHandlerList::iterator i_handler = _handlers.begin (); + for (; i_handler != _handlers.end (); ++i_handler) + { + (*i_handler)->analyze (results); + } + + return ret; +} + +void +X3aAnalyzeTuner::x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results) +{ + XCAM_UNUSED (analyzer); + _results.clear (); + _results.assign (results.begin (), results.end ()); +} + +}; + diff --git a/modules/isp/iq/x3a_analyze_tuner.h b/modules/isp/iq/x3a_analyze_tuner.h new file mode 100644 index 0000000..2c0b252 --- /dev/null +++ b/modules/isp/iq/x3a_analyze_tuner.h @@ -0,0 +1,151 @@ +/* + * x3a_analyze_tuner.h - x3a Common IQ tuner + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#ifndef XCAM_3A_ANALYZE_TUNER_H +#define XCAM_3A_ANALYZE_TUNER_H + +namespace XCam { + +class X3aCiqTuningHandler; +class X3aAnalyzer; + +class X3aAnalyzeTuner + : public X3aAnalyzer + , public AnalyzerCallback +{ + typedef std::list<SmartPtr<X3aCiqTuningHandler>> X3aCiqTuningHandlerList; + +public: + explicit X3aAnalyzeTuner (); + virtual ~X3aAnalyzeTuner (); + + void enable_handler (); + void set_analyzer (SmartPtr<X3aAnalyzer> &analyzer); + + XCamReturn analyze_ae (XCamAeParam ¶m); + XCamReturn analyze_awb (XCamAwbParam ¶m); + XCamReturn analyze_af (XCamAfParam ¶m); + XCamReturn analyze_common (XCamCommonParam ¶m); + +protected: + virtual SmartPtr<AeHandler> create_ae_handler (); + virtual SmartPtr<AwbHandler> create_awb_handler (); + virtual SmartPtr<AfHandler> create_af_handler (); + virtual SmartPtr<CommonHandler> create_common_handler (); + + virtual XCamReturn internal_init (uint32_t width, uint32_t height, double framerate); + virtual XCamReturn internal_deinit (); + + virtual XCamReturn configure_3a (); + virtual XCamReturn pre_3a_analyze (SmartPtr<X3aStats> &stats); + virtual XCamReturn post_3a_analyze (X3aResultList &results); + + // derive from AnalyzerCallback + virtual void x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results); + +private: + XCAM_DEAD_COPY (X3aAnalyzeTuner); + + XCamReturn create_tuning_handlers (); + bool add_handler (SmartPtr<X3aCiqTuningHandler> &handler); + +protected: + +private: + SmartPtr<X3aAnalyzer> _analyzer; + X3aCiqTuningHandlerList _handlers; + SmartPtr<X3aStats> _stats; + X3aResultList _results; +}; + +class X3aCiqTuningAeHandler + : public AeHandler +{ +public: + explicit X3aCiqTuningAeHandler (X3aAnalyzeTuner *analyzer) + : _analyzer (analyzer) + {} + virtual XCamReturn analyze (X3aResultList &output) { + XCAM_UNUSED (output); + AnalyzerHandler::HandlerLock lock(this); + XCamAeParam param = this->get_params_unlock (); + return _analyzer->analyze_ae (param); + } + +private: + X3aAnalyzeTuner *_analyzer; +}; + +class X3aCiqTuningAwbHandler + : public AwbHandler +{ +public: + explicit X3aCiqTuningAwbHandler (X3aAnalyzeTuner *analyzer) + : _analyzer (analyzer) + {} + virtual XCamReturn analyze (X3aResultList &output) { + XCAM_UNUSED (output); + AnalyzerHandler::HandlerLock lock(this); + XCamAwbParam param = this->get_params_unlock (); + return _analyzer->analyze_awb (param); + } + +private: + X3aAnalyzeTuner *_analyzer; +}; + +class X3aCiqTuningAfHandler + : public AfHandler +{ +public: + explicit X3aCiqTuningAfHandler (X3aAnalyzeTuner *analyzer) + : _analyzer (analyzer) + {} + virtual XCamReturn analyze (X3aResultList &output) { + XCAM_UNUSED (output); + AnalyzerHandler::HandlerLock lock(this); + XCamAfParam param = this->get_params_unlock (); + return _analyzer->analyze_af (param); + } + +private: + X3aAnalyzeTuner *_analyzer; +}; + +class X3aCiqTuningCommonHandler + : public CommonHandler +{ +public: + explicit X3aCiqTuningCommonHandler (X3aAnalyzeTuner *analyzer) + : _analyzer (analyzer) + {} + virtual XCamReturn analyze (X3aResultList &output) { + XCAM_UNUSED (output); + AnalyzerHandler::HandlerLock lock(this); + XCamCommonParam param = this->get_params_unlock (); + return _analyzer->analyze_common (param); + } + +private: + X3aAnalyzeTuner *_analyzer; +}; + +}; +#endif // XCAM_3A_ANALYZE_TUNER_H diff --git a/modules/isp/iq/x3a_ciq_bnr_ee_tuning_handler.cpp b/modules/isp/iq/x3a_ciq_bnr_ee_tuning_handler.cpp new file mode 100644 index 0000000..9888f9e --- /dev/null +++ b/modules/isp/iq/x3a_ciq_bnr_ee_tuning_handler.cpp @@ -0,0 +1,124 @@ +/* + * x3a_ciq_bnr_ee_tuning_handler.cpp - x3a Common IQ Bayer NR EE tuning handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wangfei <feix.w.wang@intel.com> + */ + +#include "x3a_analyzer.h" +#include "x3a_ciq_tuning_handler.h" +#include "x3a_ciq_bnr_ee_tuning_handler.h" + +namespace XCam { + +typedef struct _X3aCiqBnrEeTuningStaticData { + double analog_gain; + double ee_gain; + double ee_threshold; +} X3aCiqBnrEeTuningStaticData; + +double table_2_0[XCAM_BNR_TABLE_SIZE] = { + 3.978874, 3.966789, 3.930753, 3.871418, 3.789852, 3.687501, 3.566151, 3.427876, 3.274977, 3.109920, + 2.935268, 2.753622, 2.567547, 2.379525, 2.191896, 2.006815, 1.826218, 1.651792, 1.484965, 1.326889, + 1.178449, 1.040267, 0.912718, 0.795950, 0.689911, 0.594371, 0.508957, 0.433173, 0.366437, 0.308103, + 0.257483, 0.213875, 0.176575, 0.144896, 0.118179, 0.095804, 0.077194, 0.061822, 0.049210, 0.038934, + 0.030617, 0.023930, 0.018591, 0.014355, 0.011017, 0.008404, 0.006372, 0.004802, 0.003597, 0.002678, + 0.001981, 0.001457, 0.001065, 0.000774, 0.000559, 0.000401, 0.000286, 0.000203, 0.000143, 0.000100, + 0.000070, 0.000048, 0.000033, 0.000023 +}; + +double table_0_0_5[XCAM_BNR_TABLE_SIZE] = { + 63.661991, 60.628166, 52.366924, 41.023067, 29.146584, 18.781729, 10.976704, 6.000000, 6.000000, 6.000000, + 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, + 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, + 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, + 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, + 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, 6.000000, + 6.000000, 6.000000, 6.000000, 6.000000 +}; + +const X3aCiqBnrEeTuningStaticData imx185_tuning[X3A_CIQ_EE_GAIN_STEPS] = { + {1.0, 2.5, 0.008}, + {4.0, 1.8, 0.012}, + {16.98, 1.1, 0.02}, + {49.55, 0.8, 0.06}, + {139.63, 0.07, 0.1}, + {X3A_CIQ_GAIN_MAX, 0.03, 0.4}, +}; + +X3aCiqBnrEeTuningHandler::X3aCiqBnrEeTuningHandler () + : X3aCiqTuningHandler ("X3aCiqBnrEeTuningHandler") +{ +} + +X3aCiqBnrEeTuningHandler::~X3aCiqBnrEeTuningHandler () +{ +} + +XCamReturn +X3aCiqBnrEeTuningHandler::analyze (X3aResultList &output) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + const X3aCiqBnrEeTuningStaticData* tuning = imx185_tuning; + if (NULL != _tuning_data) { + tuning = (X3aCiqBnrEeTuningStaticData*)_tuning_data;; + } + + XCam3aResultBayerNoiseReduction bnr_config; + XCam3aResultEdgeEnhancement ee_config; + SmartPtr<X3aBayerNoiseReduction> bnr_result = new X3aBayerNoiseReduction (XCAM_3A_RESULT_BAYER_NOISE_REDUCTION); + SmartPtr<X3aEdgeEnhancementResult> ee_result = new X3aEdgeEnhancementResult (XCAM_3A_RESULT_EDGE_ENHANCEMENT); + + double analog_gain = get_current_analog_gain (); + + uint8_t i_curr = 0; + uint8_t i_prev = 0; + for (i_curr = 0; i_curr < X3A_CIQ_EE_GAIN_STEPS; i_curr++) { + if (analog_gain <= tuning[i_curr].analog_gain) { + break; + } + i_prev = i_curr; + } + if (i_curr >= X3A_CIQ_EE_GAIN_STEPS) { + i_curr = X3A_CIQ_EE_GAIN_STEPS - 1; + } + + xcam_mem_clear (bnr_config); + xcam_mem_clear (ee_config); + + ee_config.gain = linear_interpolate_p2 (tuning[i_prev].ee_gain, tuning[i_curr].ee_gain, + tuning[i_prev].analog_gain, tuning[i_curr].analog_gain, analog_gain); + + ee_config.threshold = linear_interpolate_p2 (tuning[i_prev].ee_threshold, tuning[i_curr].ee_threshold, + tuning[i_prev].analog_gain, tuning[i_curr].analog_gain, analog_gain); + + ee_result->set_standard_result (ee_config); + output.push_back (ee_result); + + if(i_curr < 3) + memcpy(bnr_config.table, table_0_0_5, XCAM_BNR_TABLE_SIZE * sizeof(double)); + else + memcpy(bnr_config.table, table_2_0, XCAM_BNR_TABLE_SIZE * sizeof(double)); + + bnr_result->set_standard_result (bnr_config); + output.push_back (bnr_result); + + return ret; +} + +}; + diff --git a/modules/isp/iq/x3a_ciq_bnr_ee_tuning_handler.h b/modules/isp/iq/x3a_ciq_bnr_ee_tuning_handler.h new file mode 100644 index 0000000..96a3383 --- /dev/null +++ b/modules/isp/iq/x3a_ciq_bnr_ee_tuning_handler.h @@ -0,0 +1,44 @@ +/* + * x3a_ciq_bnr_tuning_handler.h - x3a Common IQ bayer NR EE tuning handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wangfei <feix.w.wang@intel.com> + */ + +#ifndef XCAM_3A_CIQ_BNR_EE_TUNING_HANDLER_H +#define XCAM_3A_CIQ_BNR_EE_TUNING_HANDLER_H + +#include "xcam_utils.h" + +namespace XCam { + +class X3aCiqBnrEeTuningHandler + : public X3aCiqTuningHandler +{ +public: + explicit X3aCiqBnrEeTuningHandler (); + virtual ~X3aCiqBnrEeTuningHandler (); + + virtual XCamReturn analyze (X3aResultList &output); + +private: + XCAM_DEAD_COPY (X3aCiqBnrEeTuningHandler); + +}; + +}; + +#endif // XCAM_3A_CIQ_BNR_EE_TUNING_HANDLER_H diff --git a/modules/isp/iq/x3a_ciq_tnr_tuning_handler.cpp b/modules/isp/iq/x3a_ciq_tnr_tuning_handler.cpp new file mode 100644 index 0000000..f4ad846 --- /dev/null +++ b/modules/isp/iq/x3a_ciq_tnr_tuning_handler.cpp @@ -0,0 +1,129 @@ +/* + * x3a_ciq_tnr_tuning_handler.cpp - x3a Common IQ TNR tuning handler + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include "x3a_analyzer.h" +#include "x3a_ciq_tuning_handler.h" +#include "x3a_ciq_tnr_tuning_handler.h" + +namespace XCam { + +typedef struct _X3aCiqTnrTuningStaticData { + double analog_gain; + double yuv_gain; + double y_threshold; + double uv_threshold; + double rgb_gain; + double r_threshold; + double g_threshold; + double b_threshold; +} X3aCiqTnrTuningStaticData; + +const X3aCiqTnrTuningStaticData imx185_tuning[X3A_CIQ_GAIN_STEPS] = { + {1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0}, + {16.98, 0.8, 0.0081, 0.00725, 0.2, 0.0253, 0.0158, 0.0168}, + {49.55, 0.5, 0.0146, 0.0128, 0.4, 0.0434, 0.0274, 0.0317}, + {139.63, 0.3, 0.0247, 0.0253, 0.8, 0.0602, 0.0377, 0.0445}, + {X3A_CIQ_GAIN_MAX, 0.2, 0.0358, 0.0329, 1.0, 0.0994, 0.0696, 0.0924}, +}; + +X3aCiqTnrTuningHandler::X3aCiqTnrTuningHandler () + : X3aCiqTuningHandler ("X3aCiqTnrTuningHandler") +{ +} + +X3aCiqTnrTuningHandler::~X3aCiqTnrTuningHandler () +{ +} + +XCamReturn +X3aCiqTnrTuningHandler::analyze (X3aResultList &output) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + const X3aCiqTnrTuningStaticData* tuning = imx185_tuning; + if (NULL != _tuning_data) { + tuning = (X3aCiqTnrTuningStaticData*)_tuning_data;; + } + + XCam3aResultTemporalNoiseReduction config; + SmartPtr<X3aTemporalNoiseReduction> nr_result = new X3aTemporalNoiseReduction (XCAM_3A_RESULT_3D_NOISE_REDUCTION); + SmartPtr<X3aTemporalNoiseReduction> yuv_result = new X3aTemporalNoiseReduction (XCAM_3A_RESULT_TEMPORAL_NOISE_REDUCTION_YUV); + + int64_t et = get_current_exposure_time (); + double analog_gain = get_current_analog_gain (); + double max_analog_gain = get_max_analog_gain (); + XCAM_UNUSED (et); + XCAM_UNUSED (max_analog_gain); + XCAM_LOG_DEBUG ("get current AG = (%f), max AG = (%f), et = (%" PRId64 ")", analog_gain, max_analog_gain, et); + + uint8_t i_curr = 0; + uint8_t i_prev = 0; + for (i_curr = 0; i_curr < X3A_CIQ_GAIN_STEPS; i_curr++) { + if (analog_gain <= tuning[i_curr].analog_gain) { + break; + } + i_prev = i_curr; + } + if (i_curr >= X3A_CIQ_GAIN_STEPS) { + i_curr = X3A_CIQ_GAIN_STEPS - 1; + } + + //Calculate YUV config + xcam_mem_clear (config); + config.gain = linear_interpolate_p2 (tuning[i_prev].yuv_gain, tuning[i_curr].yuv_gain, + tuning[i_prev].analog_gain, tuning[i_curr].analog_gain, analog_gain); + + config.threshold[0] = linear_interpolate_p2 (tuning[i_prev].y_threshold, tuning[i_curr].y_threshold, + tuning[i_prev].analog_gain, tuning[i_curr].analog_gain, analog_gain); + + config.threshold[1] = linear_interpolate_p2 (tuning[i_prev].uv_threshold, tuning[i_curr].uv_threshold, + tuning[i_prev].analog_gain, tuning[i_curr].analog_gain, analog_gain); + + config.threshold[2] = 0.0; + XCAM_LOG_DEBUG ("Calculate YUV temporal noise reduction config: yuv_gain(%f), y_threshold(%f), uv_threshold(%f)", + config.gain, config.threshold[0], config.threshold[1]); + + yuv_result->set_standard_result (config); + output.push_back (yuv_result); + + //Calculate 3D NR config + xcam_mem_clear (config); + config.gain = linear_interpolate_p2 (tuning[i_prev].rgb_gain, tuning[i_curr].rgb_gain, + tuning[i_prev].analog_gain, tuning[i_curr].analog_gain, analog_gain); + + config.threshold[0] = linear_interpolate_p2 (tuning[i_prev].r_threshold, tuning[i_curr].r_threshold, + tuning[i_prev].analog_gain, tuning[i_curr].analog_gain, analog_gain); + + config.threshold[1] = linear_interpolate_p2 (tuning[i_prev].g_threshold, tuning[i_curr].g_threshold, + tuning[i_prev].analog_gain, tuning[i_curr].analog_gain, analog_gain); + + config.threshold[2] = linear_interpolate_p2 (tuning[i_prev].b_threshold, tuning[i_curr].b_threshold, + tuning[i_prev].analog_gain, tuning[i_curr].analog_gain, analog_gain); + + XCAM_LOG_DEBUG ("Calculate 3D noise reduction config: gain(%f), y_threshold(%f), uv_threshold(%f)", + config.gain, config.threshold[0], config.threshold[1]); + + nr_result->set_standard_result (config); + output.push_back (nr_result); + + return ret; +} + +}; diff --git a/modules/isp/iq/x3a_ciq_tnr_tuning_handler.h b/modules/isp/iq/x3a_ciq_tnr_tuning_handler.h new file mode 100644 index 0000000..462ea73 --- /dev/null +++ b/modules/isp/iq/x3a_ciq_tnr_tuning_handler.h @@ -0,0 +1,44 @@ +/* + * x3a_ciq_tnr_tuning_handler.h - x3a Common IQ TNR tuning handler + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#ifndef XCAM_3A_CIQ_TNR_TUNING_HANDLER_H +#define XCAM_3A_CIQ_TNR_TUNING_HANDLER_H + +#include "xcam_utils.h" + +namespace XCam { + +class X3aCiqTnrTuningHandler + : public X3aCiqTuningHandler +{ +public: + explicit X3aCiqTnrTuningHandler (); + virtual ~X3aCiqTnrTuningHandler (); + + virtual XCamReturn analyze (X3aResultList &output); + +private: + XCAM_DEAD_COPY (X3aCiqTnrTuningHandler); + +}; + +}; + +#endif // XCAM_3A_CIQ_TNR_TUNING_HANDLER_H diff --git a/modules/isp/iq/x3a_ciq_tuning_handler.cpp b/modules/isp/iq/x3a_ciq_tuning_handler.cpp new file mode 100644 index 0000000..8dce73b --- /dev/null +++ b/modules/isp/iq/x3a_ciq_tuning_handler.cpp @@ -0,0 +1,110 @@ +/* + * x3a_ciq_tuning_handler.cpp - x3a Common IQ tuning handler + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include "x3a_analyzer.h" +#include "x3a_ciq_tuning_handler.h" + +#define X3A_CIQ_CAMERA_ID "IMX185" + +namespace XCam { + +X3aCiqTuningHandler::X3aCiqTuningHandler (const char *name) + : _tuning_data (NULL) + , _name (NULL) +{ + if (name) + _name = strndup (name, XCAM_MAX_STR_SIZE); +} + +X3aCiqTuningHandler::~X3aCiqTuningHandler () +{ + if (_name) + xcam_free (_name); +} + +void +X3aCiqTuningHandler::set_tuning_data (void* data) +{ + if (NULL != data) { + _tuning_data = data; + } +} + +void +X3aCiqTuningHandler::set_ae_handler (SmartPtr<AeHandler> &handler) +{ + if (!_ae_handler.ptr ()) { + _ae_handler = handler; + } +} + +void +X3aCiqTuningHandler::set_awb_handler (SmartPtr<AwbHandler> &handler) +{ + if (!_awb_handler.ptr ()) { + _awb_handler = handler; + } +} + +double +X3aCiqTuningHandler::get_max_analog_gain() +{ + AnalyzerHandler::HandlerLock lock(this); + + if (_ae_handler.ptr ()) { + return _ae_handler->get_max_analog_gain (); + } + return 0.0; +} + +double +X3aCiqTuningHandler::get_current_analog_gain () +{ + AnalyzerHandler::HandlerLock lock(this); + + if (_ae_handler.ptr ()) { + return _ae_handler->get_current_analog_gain (); + } + return 0.0; +} + +int64_t +X3aCiqTuningHandler::get_current_exposure_time () +{ + AnalyzerHandler::HandlerLock lock(this); + + if (_ae_handler.ptr ()) { + return _ae_handler->get_current_exposure_time (); + } + return 0.0; +} + +uint32_t +X3aCiqTuningHandler::get_current_estimate_cct () +{ + AnalyzerHandler::HandlerLock lock(this); + + if (_awb_handler.ptr ()) { + return _awb_handler->get_current_estimate_cct (); + } + return 0; +} + +}; diff --git a/modules/isp/iq/x3a_ciq_tuning_handler.h b/modules/isp/iq/x3a_ciq_tuning_handler.h new file mode 100644 index 0000000..9cfb350 --- /dev/null +++ b/modules/isp/iq/x3a_ciq_tuning_handler.h @@ -0,0 +1,105 @@ +/* + * x3a_ciq_tuning_handler.h - x3a Common IQ tuning handler + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#ifndef XCAM_3A_CIQ_TUNING_HANDLER_H +#define XCAM_3A_CIQ_TUNING_HANDLER_H + +#include "handler_interface.h" + +namespace XCam { + +#define X3A_CIQ_PIXEL_DEPTH 10 + +#define X3A_CIQ_EXPOSURE_TIME_STEPS 4 //Number of Exposure Time steps +#define X3A_CIQ_EXPOSURE_TIME_MAX 40000 //Max ET in microseconds (40ms) +#define X3A_CIQ_EXPOSURE_TIME_TICK (X3A_CIQ_EXPOSURE_TIME_MAX / X3A_CIQ_EXPOSURE_TIME_STEPS) + +#define X3A_CIQ_EE_GAIN_STEPS 6 //Number of EE Gain steps +#define X3A_CIQ_GAIN_STEPS 5 //Number of Gain steps +#define X3A_CIQ_GAIN_MAX 249 //Max Gain + +#define X3A_CIQ_LSC_LUT_WIDTH 16 +#define X3A_CIQ_LSC_LUT_HEIGHT 9 +#define X3A_CIQ_LSC_LUT_SIZE (16 * 9) + +typedef enum _X3aCiqBayerOrder { + X3A_CIQ_RGrGbB = 0, + X3A_CIQ_GrRBGb = 1, + X3A_CIQ_GbBRGr = 2, + X3A_CIQ_BGbGrR = 3, +} X3aCiqBayerOrder; + +typedef enum _X3aCiqCIEIlluminants { + X3A_CIQ_ILLUMINANT_HALO = 0, // Incandescent / Tungsten + X3A_CIQ_ILLUMINANT_F2 = 1, // Cool White Fluorescent + X3A_CIQ_ILLUMINANT_F11 = 2, // Philips TL84 + X3A_CIQ_ILLUMINANT_D50 = 3, // Horizon Light + X3A_CIQ_ILLUMINANT_D65 = 4, // Noon Daylight + X3A_CIQ_ILLUMINANT_D75 = 5, // North sky Daylight + X3A_CIQ_ILLUMINANT_COUNT +} X3aCiqCIEIlluminants; + +typedef struct _X3aCiqCIEIlluminantsTable +{ + X3aCiqCIEIlluminants CIEIlluminantIndex; + uint16_t CCT; +} X3aCiqCIEIlluminantsTable; + +static const X3aCiqCIEIlluminantsTable X3a_Ciq_illuminants_table[X3A_CIQ_ILLUMINANT_COUNT] = +{ + {X3A_CIQ_ILLUMINANT_HALO, 2100}, + {X3A_CIQ_ILLUMINANT_F2, 3000}, + {X3A_CIQ_ILLUMINANT_F11, 4051}, + {X3A_CIQ_ILLUMINANT_D50, 5000}, + {X3A_CIQ_ILLUMINANT_D65, 6500}, + {X3A_CIQ_ILLUMINANT_D75, 7500}, +}; + +class X3aCiqTuningHandler + : public AnalyzerHandler +{ +public: + explicit X3aCiqTuningHandler (const char *name = NULL); + virtual ~X3aCiqTuningHandler (); + + void set_tuning_data (void* data); + void set_ae_handler (SmartPtr<AeHandler> &handler); + void set_awb_handler (SmartPtr<AwbHandler> &handler); + + double get_max_analog_gain (); + double get_current_analog_gain (); + int64_t get_current_exposure_time (); + uint32_t get_current_estimate_cct (); + +private: + XCAM_DEAD_COPY (X3aCiqTuningHandler); + +protected: + const void *_tuning_data; + +private: + char *_name; + SmartPtr<AeHandler> _ae_handler; + SmartPtr<AwbHandler> _awb_handler; +}; + +}; + +#endif // XCAM_3A_CIQ_TUNING_HANDLER_H diff --git a/modules/isp/iq/x3a_ciq_wavelet_tuning_handler.cpp b/modules/isp/iq/x3a_ciq_wavelet_tuning_handler.cpp new file mode 100644 index 0000000..9eeed2b --- /dev/null +++ b/modules/isp/iq/x3a_ciq_wavelet_tuning_handler.cpp @@ -0,0 +1,105 @@ +/* + * x3a_ciq_wavelet_tuning_handler.cpp - x3a Common IQ Wavelet denoise tuning handler + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include "x3a_analyzer.h" +#include "x3a_ciq_tuning_handler.h" +#include "x3a_ciq_wavelet_tuning_handler.h" + +namespace XCam { + +typedef struct _X3aCiqWaveletTuningStaticData { + double analog_gain; + double hard_threshold; + double soft_threshold; + uint8_t decom_levels; +} X3aCiqWaveletTuningStaticData; + +const X3aCiqWaveletTuningStaticData imx185_tuning[X3A_CIQ_GAIN_STEPS] = { + {1.0, 0.01, 1.0, 5}, + {16.98, 0.02, 0.7, 5}, + {49.55, 0.2, 0.5, 5}, + {139.63, 0.3, 0.3, 5}, + {X3A_CIQ_GAIN_MAX, 0.5, 0.2, 5}, +}; + +X3aCiqWaveletTuningHandler::X3aCiqWaveletTuningHandler () + : X3aCiqTuningHandler ("X3aCiqWaveletTuningHandler") +{ +} + +X3aCiqWaveletTuningHandler::~X3aCiqWaveletTuningHandler () +{ +} + +XCamReturn +X3aCiqWaveletTuningHandler::analyze (X3aResultList &output) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + const X3aCiqWaveletTuningStaticData* tuning = imx185_tuning; + if (NULL != _tuning_data) { + tuning = (X3aCiqWaveletTuningStaticData*)_tuning_data;; + } + + XCam3aResultWaveletNoiseReduction config; + SmartPtr<X3aWaveletNoiseReduction> settings = new X3aWaveletNoiseReduction (XCAM_3A_RESULT_WAVELET_NOISE_REDUCTION); + + int64_t et = get_current_exposure_time (); + double analog_gain = get_current_analog_gain (); + double max_analog_gain = get_max_analog_gain (); + XCAM_UNUSED (et); + XCAM_UNUSED (max_analog_gain); + XCAM_LOG_DEBUG ("get current AG = (%f), max AG = (%f), et = (%" PRId64 ")", analog_gain, max_analog_gain, et); + + uint8_t i_curr = 0; + uint8_t i_prev = 0; + for (i_curr = 0; i_curr < X3A_CIQ_GAIN_STEPS; i_curr++) { + if (analog_gain <= tuning[i_curr].analog_gain) { + break; + } + i_prev = i_curr; + } + if (i_curr >= X3A_CIQ_GAIN_STEPS) { + i_curr = X3A_CIQ_GAIN_STEPS - 1; + } + + //Calculate Wavelet denoise config + xcam_mem_clear (config); + + /* [0]:soft threshold / [1]:hard threshold */ + config.threshold[0] = linear_interpolate_p2 (tuning[i_prev].soft_threshold, tuning[i_curr].soft_threshold, + tuning[i_prev].analog_gain, tuning[i_curr].analog_gain, analog_gain); + + config.threshold[1] = linear_interpolate_p2 (tuning[i_prev].hard_threshold, tuning[i_curr].hard_threshold, + tuning[i_prev].analog_gain, tuning[i_curr].analog_gain, analog_gain); + + config.decomposition_levels = 1; + + config.analog_gain = analog_gain / X3A_CIQ_GAIN_MAX; + XCAM_LOG_DEBUG ("Calculate Wavelet noise reduction config: soft threshold(%f), hard threshold(%f), decomposition levels(%d)", + config.threshold[0], config.threshold[1], config.decomposition_levels); + + settings->set_standard_result (config); + output.push_back (settings); + + return ret; +} + +}; diff --git a/modules/isp/iq/x3a_ciq_wavelet_tuning_handler.h b/modules/isp/iq/x3a_ciq_wavelet_tuning_handler.h new file mode 100644 index 0000000..a7042cc --- /dev/null +++ b/modules/isp/iq/x3a_ciq_wavelet_tuning_handler.h @@ -0,0 +1,44 @@ +/* + * x3a_ciq_wavelet_tuning_handler.h - x3a Common IQ Wavelet denoise tuning handler + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#ifndef XCAM_3A_CIQ_WAVELET_TUNING_HANDLER_H +#define XCAM_3A_CIQ_WAVELET_TUNING_HANDLER_H + +#include "xcam_utils.h" + +namespace XCam { + +class X3aCiqWaveletTuningHandler + : public X3aCiqTuningHandler +{ +public: + explicit X3aCiqWaveletTuningHandler (); + virtual ~X3aCiqWaveletTuningHandler (); + + virtual XCamReturn analyze (X3aResultList &output); + +private: + XCAM_DEAD_COPY (X3aCiqWaveletTuningHandler); + +}; + +}; + +#endif // XCAM_3A_CIQ_WAVELET_TUNING_HANDLER_H diff --git a/modules/isp/isp_config_translator.cpp b/modules/isp/isp_config_translator.cpp new file mode 100644 index 0000000..d370579 --- /dev/null +++ b/modules/isp/isp_config_translator.cpp @@ -0,0 +1,144 @@ +/* + * isp_config_translator.cpp - isp config translator + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "isp_config_translator.h" +#include <math.h> + +namespace XCam { + +static uint32_t +_get_max_bits (double value) +{ + uint32_t max_int = 0; + uint32_t interger_bits = 0; + + max_int = (uint32_t)value; + while (max_int) { + ++interger_bits; + max_int = (max_int >> 1); + } + return interger_bits; +} + +IspConfigTranslator::IspConfigTranslator (SmartPtr<SensorDescriptor> &sensor) + : _sensor (sensor) +{ + XCAM_ASSERT (_sensor.ptr()); +} + +IspConfigTranslator::~IspConfigTranslator () +{ +} + +XCamReturn +IspConfigTranslator::translate_white_balance ( + const XCam3aResultWhiteBalance &from, + struct atomisp_wb_config &to) +{ + uint32_t interger_bits = 0; + double multiplier = 0.0; + double max_gain = XCAM_MAX (from.b_gain, from.r_gain); + max_gain = XCAM_MAX (max_gain, from.gr_gain); + max_gain = XCAM_MAX (max_gain, from.gb_gain); + + interger_bits = _get_max_bits (max_gain); + multiplier = (double)(1 << (16 - interger_bits)); + to.integer_bits = interger_bits; + to.gr = (uint32_t)(from.gr_gain * multiplier + 0.5); + to.r = (uint32_t)(from.r_gain * multiplier + 0.5); + to.b = (uint32_t)(from.b_gain * multiplier + 0.5); + to.gb = (uint32_t)(from.gb_gain * multiplier + 0.5); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +IspConfigTranslator::translate_black_level ( + const XCam3aResultBlackLevel &from, struct atomisp_ob_config &to) +{ + double multiplier = (double)(1 << 16); + + to.mode = atomisp_ob_mode_fixed; + to.level_gr = (uint32_t)(from.gr_level * multiplier + 0.5); + to.level_r = (uint32_t)(from.r_level * multiplier + 0.5); + to.level_b = (uint32_t)(from.b_level * multiplier + 0.5); + to.level_gb = (uint32_t)(from.gb_level * multiplier + 0.5); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +IspConfigTranslator::translate_color_matrix ( + const XCam3aResultColorMatrix &from, struct atomisp_cc_config &to) +{ + double max_value = 0.0; + uint32_t interger_bits = 0; + double multiplier = 0.0; + bool have_minus = false; + uint32_t i = 0; + + for (i = 0; i < XCAM_COLOR_MATRIX_SIZE; ++i) { + if (fabs(from.matrix [i]) > max_value) + max_value = fabs(from.matrix [i]); + if (from.matrix [i] < 0) + have_minus = true; + } + interger_bits = _get_max_bits (max_value); + if (have_minus) + ++interger_bits; + + XCAM_ASSERT (interger_bits < 13); + to.fraction_bits = 13 - interger_bits; + multiplier = (double)(1 << (13 - interger_bits)); + for (i = 0; i < XCAM_COLOR_MATRIX_SIZE; ++i) { + to.matrix[i] = (int32_t)(from.matrix [i] * multiplier); + } + return XCAM_RETURN_NO_ERROR; +} + + +XCamReturn +IspConfigTranslator::translate_exposure ( + const XCam3aResultExposure &from, + struct atomisp_exposure &to) +{ + uint32_t coarse_time = 0, fine_time = 0; + int32_t analog_code = 0, digital_code = 0; + if (!_sensor->is_ready ()) { + XCAM_LOG_WARNING ("translate exposure failed since sensor not ready"); + return XCAM_RETURN_ERROR_SENSOR; + } + if (!_sensor->exposure_time_to_integration (from.exposure_time, coarse_time, fine_time)) { + XCAM_LOG_WARNING ("translate exposure time failed"); + return XCAM_RETURN_ERROR_SENSOR; + } + to.integration_time[0] = coarse_time; + to.integration_time[1] = fine_time; + + if (!_sensor->exposure_gain_to_code (from.analog_gain, from.digital_gain, analog_code, digital_code)) { + XCAM_LOG_WARNING ("translate exposure gain failed"); + return XCAM_RETURN_ERROR_SENSOR; + } + to.gain[0] = analog_code; + to.gain[1] = digital_code; + return XCAM_RETURN_NO_ERROR; +} + +}; diff --git a/modules/isp/isp_config_translator.h b/modules/isp/isp_config_translator.h new file mode 100644 index 0000000..02cc10a --- /dev/null +++ b/modules/isp/isp_config_translator.h @@ -0,0 +1,57 @@ +/* + * isp_config_translator.h - isp config translator + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_ISP_CONFIG_TRANSLATOR_H +#define XCAM_ISP_CONFIG_TRANSLATOR_H + +#include <xcam_std.h> +#include <linux/atomisp.h> +#include "x3a_result.h" +#include "sensor_descriptor.h" + +namespace XCam { + +class IspConfigTranslator { +public: + explicit IspConfigTranslator (SmartPtr<SensorDescriptor> &sensor); + ~IspConfigTranslator (); + + XCamReturn translate_white_balance (const XCam3aResultWhiteBalance &from, struct atomisp_wb_config &to); + XCamReturn translate_black_level (const XCam3aResultBlackLevel &from, struct atomisp_ob_config &to); + XCamReturn translate_color_matrix (const XCam3aResultColorMatrix &from, struct atomisp_cc_config &to); + XCamReturn translate_exposure (const XCam3aResultExposure &from, struct atomisp_exposure &to); + XCamReturn translate_demosaicing (const X3aDemosaicResult &from, struct atomisp_de_config &to); + XCamReturn translate_defect_pixel (const XCam3aResultDefectPixel &from, struct atomisp_dp_config &to); + XCamReturn translate_noise_reduction (const XCam3aResultNoiseReduction &from, struct atomisp_nr_config &to); + XCamReturn translate_edge_enhancement (const XCam3aResultEdgeEnhancement &from, struct atomisp_ee_config &to); + XCamReturn translate_gamma_table (const XCam3aResultGammaTable &from, struct atomisp_gamma_table &to); + XCamReturn translate_macc (const XCam3aResultMaccMatrix &from, struct atomisp_macc_table &to); + XCamReturn translate_ctc (const XCam3aResultChromaToneControl &from, struct atomisp_ctc_table &to); + +private: + XCAM_DEAD_COPY (IspConfigTranslator); + +private: + SmartPtr<SensorDescriptor> _sensor; +}; + +} + +#endif //XCAM_ISP_CONFIG_TRANSLATOR_H diff --git a/modules/isp/isp_controller.cpp b/modules/isp/isp_controller.cpp new file mode 100644 index 0000000..7bb9e6f --- /dev/null +++ b/modules/isp/isp_controller.cpp @@ -0,0 +1,151 @@ +/* + * isp_controller.cpp - isp controller + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "isp_controller.h" +#include "v4l2_device.h" +#include "x3a_statistics_queue.h" +#include "x3a_isp_config.h" + +#include <linux/atomisp.h> + +namespace XCam { + +IspController::IspController (SmartPtr<V4l2Device> & device) + : _device (device) +{ +} +IspController::~IspController () +{ +} + +void +IspController::init_sensor_mode_data (struct atomisp_sensor_mode_data *sensor_mode_data) +{ + sensor_mode_data->coarse_integration_time_min = 1; + sensor_mode_data->coarse_integration_time_max_margin = 1; + sensor_mode_data->fine_integration_time_min = 0; + sensor_mode_data->fine_integration_time_max_margin = 0; + sensor_mode_data->fine_integration_time_def = 0; + sensor_mode_data->frame_length_lines = 1125; + sensor_mode_data->line_length_pck = 1320; + sensor_mode_data->read_mode = 0; + sensor_mode_data->vt_pix_clk_freq_mhz = 37125000; + sensor_mode_data->crop_horizontal_start = 0; + sensor_mode_data->crop_vertical_start = 0; + sensor_mode_data->crop_horizontal_end = 1920; + sensor_mode_data->crop_vertical_end = 1080; + sensor_mode_data->output_width = 1920; + sensor_mode_data->output_height = 1080; + sensor_mode_data->binning_factor_x = 1; + sensor_mode_data->binning_factor_y = 1; +} + + +XCamReturn +IspController::get_sensor_mode_data (struct atomisp_sensor_mode_data &sensor_mode_data) +{ + init_sensor_mode_data (&sensor_mode_data); + if (_device->io_control (ATOMISP_IOC_G_SENSOR_MODE_DATA, &sensor_mode_data) < 0) { + XCAM_LOG_WARNING (" get ISP sensor mode data failed, use initialized sensor mode data"); + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +IspController::get_isp_parameter (struct atomisp_parm ¶meters) +{ + if ( _device->io_control (ATOMISP_IOC_G_ISP_PARM, ¶meters) < 0) { + XCAM_LOG_WARNING (" get ISP parameters failed"); + return XCAM_RETURN_ERROR_IOCTL; + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +IspController::get_3a_statistics (SmartPtr<X3aIspStatistics> &stats) +{ + struct atomisp_3a_statistics *isp_stats = NULL; + + XCAM_ASSERT (stats.ptr()); + XCAM_FAIL_RETURN (WARNING, stats.ptr(), + XCAM_RETURN_ERROR_PARAM, "stats empty"); + + isp_stats = stats->get_isp_stats (); + + if ( _device->io_control (ATOMISP_IOC_G_3A_STAT, isp_stats) < 0) { + XCAM_LOG_WARNING (" get 3a stats failed from ISP"); + return XCAM_RETURN_ERROR_IOCTL; + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +IspController::set_3a_config (X3aIspConfig *config) +{ + struct atomisp_parameters &isp_config = config->get_isp_configs (); + if ( _device->io_control (ATOMISP_IOC_S_PARAMETERS, &isp_config) < 0) { + XCAM_LOG_WARNING (" set 3a config failed to ISP"); + return XCAM_RETURN_ERROR_IOCTL; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +IspController::set_3a_exposure (X3aIspExposureResult *res) +{ + const struct atomisp_exposure &exposure = res->get_isp_config (); + return set_3a_exposure (exposure); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +IspController::set_3a_exposure (const struct atomisp_exposure &exposure) +{ + if ( _device->io_control (ATOMISP_IOC_S_EXPOSURE, (struct atomisp_exposure*)(&exposure)) < 0) { + XCAM_LOG_WARNING (" set exposure result failed to device"); + return XCAM_RETURN_ERROR_IOCTL; + } + XCAM_LOG_DEBUG ("isp set exposure result, integration_time:%d, gain code:%d", + exposure.integration_time[0], exposure.gain[0]); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +IspController::set_3a_focus (const XCam3aResultFocus &focus) +{ + int position = focus.position; + struct v4l2_control control; + + xcam_mem_clear (control); + control.id = V4L2_CID_FOCUS_ABSOLUTE; + control.value = position; + + if (_device->io_control (VIDIOC_S_CTRL, &control) < 0) { + XCAM_LOG_WARNING (" set focus result failed to device"); + return XCAM_RETURN_ERROR_IOCTL; + } + return XCAM_RETURN_NO_ERROR; +} + + +}; diff --git a/modules/isp/isp_controller.h b/modules/isp/isp_controller.h new file mode 100644 index 0000000..7e8d083 --- /dev/null +++ b/modules/isp/isp_controller.h @@ -0,0 +1,57 @@ +/* + * isp_controller.h - isp controller + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ +#ifndef XCAM_ISP_CONTROLLER_H +#define XCAM_ISP_CONTROLLER_H + +#include <xcam_std.h> +#include "x3a_isp_config.h" + +namespace XCam { + +class V4l2Device; +class X3aIspStatistics; +class X3aIspConfig; + +class IspController { +public: + explicit IspController (SmartPtr<V4l2Device> & device); + ~IspController (); + + void init_sensor_mode_data (struct atomisp_sensor_mode_data *sensor_mode_data); + XCamReturn get_sensor_mode_data (struct atomisp_sensor_mode_data &sensor_mode_data); + XCamReturn get_isp_parameter (struct atomisp_parm ¶meters); + + XCamReturn get_3a_statistics (SmartPtr<X3aIspStatistics> &stats); + XCamReturn set_3a_config (X3aIspConfig *config); + XCamReturn set_3a_exposure (X3aIspExposureResult *res); + XCamReturn set_3a_exposure (const struct atomisp_exposure &exposure); + XCamReturn set_3a_focus (const XCam3aResultFocus &focus); + +private: + + XCAM_DEAD_COPY (IspController); + +private: + SmartPtr<V4l2Device> _device; +}; + +}; + +#endif //XCAM_ISP_CONTROLLER_H diff --git a/modules/isp/isp_image_processor.cpp b/modules/isp/isp_image_processor.cpp new file mode 100644 index 0000000..0ed67a6 --- /dev/null +++ b/modules/isp/isp_image_processor.cpp @@ -0,0 +1,205 @@ +/* + * isp_image_processor.cpp - isp image processor + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "isp_image_processor.h" +#include "x3a_isp_config.h" +#include "isp_controller.h" +#include "isp_config_translator.h" + +namespace XCam { + +IspImageProcessor::IspImageProcessor (SmartPtr<IspController> &controller) + : ImageProcessor ("IspImageProcessor") + , _controller (controller) + , _3a_config (new X3aIspConfig) +{ + _sensor = new SensorDescriptor; + _translator = new IspConfigTranslator (_sensor); + XCAM_LOG_DEBUG ("IspImageProcessor construction"); +} + +IspImageProcessor::~IspImageProcessor () +{ + XCAM_LOG_DEBUG ("~IspImageProcessor destruction"); +} + +XCamReturn +IspImageProcessor::process_buffer(SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + output = input; + return XCAM_RETURN_NO_ERROR; +} + +bool +IspImageProcessor::can_process_result (SmartPtr<X3aResult> &result) +{ + if (result.ptr() == NULL) + return false; + + switch (result->get_type()) { + case X3aIspConfig::IspExposureParameters: + case X3aIspConfig::IspAllParameters: + case XCAM_3A_RESULT_WHITE_BALANCE: + case XCAM_3A_RESULT_EXPOSURE: + case XCAM_3A_RESULT_BLACK_LEVEL: + case XCAM_3A_RESULT_YUV2RGB_MATRIX: + case XCAM_3A_RESULT_RGB2YUV_MATRIX: + case XCAM_3A_RESULT_R_GAMMA: + case XCAM_3A_RESULT_G_GAMMA: + case XCAM_3A_RESULT_B_GAMMA: + case XCAM_3A_RESULT_MACC: + case XCAM_3A_RESULT_BAYER_NOISE_REDUCTION: + return true; + default: + return false; + } + + return false; +} + +XCamReturn +IspImageProcessor::apply_3a_results (X3aResultList &results) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + if (results.empty()) + return XCAM_RETURN_ERROR_PARAM; + + // activate sensor to make translator work + if (!_sensor->is_ready()) { + struct atomisp_sensor_mode_data sensor_data; + xcam_mem_clear (sensor_data); + if (_controller->get_sensor_mode_data(sensor_data) != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("ispimageprocessor initiliaze sensor failed"); + } else + _sensor->set_sensor_data (sensor_data); + XCAM_ASSERT (_sensor->is_ready()); + } + + if ((ret = merge_results (results)) != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("merge 3a result to isp config failed"); + return XCAM_RETURN_ERROR_UNKNOWN; + } + + if ((ret = apply_exposure_result (results)) != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("set 3a exposure to sensor failed"); + } + + // check _3a_config + XCAM_ASSERT (_3a_config.ptr()); + XCAM_ASSERT (_controller.ptr()); + ret = _controller->set_3a_config (_3a_config.ptr()); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("set 3a config to isp failed"); + } + _3a_config->clear (); + return ret; +} + +XCamReturn +IspImageProcessor::apply_3a_result (SmartPtr<X3aResult> &result) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + X3aResultList results; + results.push_back (result); + ret = apply_3a_results (results); + return ret; +} + +XCamReturn +IspImageProcessor::merge_results (X3aResultList &results) +{ + if (results.empty()) + return XCAM_RETURN_ERROR_PARAM; + + for (X3aResultList::iterator iter = results.begin (); + iter != results.end ();) + { + SmartPtr<X3aResult> &x3a_result = *iter; + if (_3a_config->attach (x3a_result, _translator.ptr())) { + x3a_result->set_done (true); + results.erase (iter++); + } else + ++iter; + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +IspImageProcessor::apply_exposure_result (X3aResultList &results) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + for (X3aResultList::iterator iter = results.begin (); + iter != results.end ();) + { + if ((*iter)->get_type() == X3aIspConfig::IspExposureParameters) { + SmartPtr<X3aIspExposureResult> res = (*iter).dynamic_cast_ptr<X3aIspExposureResult> (); + if (!res.ptr () || + ((ret = _controller->set_3a_exposure (res.ptr ())) != XCAM_RETURN_NO_ERROR)) { + XCAM_LOG_WARNING ("set 3a exposure to sensor failed"); + } + if (res.ptr ()) + res->set_done (true); + results.erase (iter++); + } else if ((*iter)->get_type() == XCAM_3A_RESULT_EXPOSURE) { + SmartPtr<X3aExposureResult> res = (*iter).dynamic_cast_ptr<X3aExposureResult> (); + struct atomisp_exposure isp_exposure; + xcam_mem_clear (isp_exposure); + XCAM_ASSERT (res.ptr ()); + ret = _translator->translate_exposure (res->get_standard_result (), isp_exposure); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("translate 3a exposure to sensor failed"); + } + if ((ret = _controller->set_3a_exposure (isp_exposure)) != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("set 3a exposure to sensor failed"); + } + res->set_done (true); + results.erase (iter++); + } else + ++iter; + } + return XCAM_RETURN_NO_ERROR; +} + +IspExposureImageProcessor::IspExposureImageProcessor (SmartPtr<IspController> &controller) + : IspImageProcessor (controller) +{ +} + +bool +IspExposureImageProcessor::can_process_result (SmartPtr<X3aResult> &result) +{ + if (result.ptr() == NULL) + return false; + + switch (result->get_type()) { + case XCAM_3A_RESULT_EXPOSURE: + return true; + + default: + return false; + } + + return false; +} + +}; diff --git a/modules/isp/isp_image_processor.h b/modules/isp/isp_image_processor.h new file mode 100644 index 0000000..4997502 --- /dev/null +++ b/modules/isp/isp_image_processor.h @@ -0,0 +1,76 @@ +/* + * isp_image_processor.h - isp image processor + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_ISP_IMAGE_PROCESSOR_H +#define XCAM_ISP_IMAGE_PROCESSOR_H + +#include <xcam_std.h> +#include "image_processor.h" + +namespace XCam { + +class X3aIspConfig; +class IspController; +class IspConfigTranslator; +class SensorDescriptor; + +class IspImageProcessor + : public ImageProcessor +{ +public: + explicit IspImageProcessor (SmartPtr<IspController> &controller); + virtual ~IspImageProcessor (); + +protected: + //derive from ImageProcessor + virtual bool can_process_result (SmartPtr<X3aResult> &result); + virtual XCamReturn apply_3a_results (X3aResultList &results); + virtual XCamReturn apply_3a_result (SmartPtr<X3aResult> &result); + virtual XCamReturn process_buffer (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + XCamReturn merge_results (X3aResultList &results); + XCamReturn apply_exposure_result (X3aResultList &results); + + XCAM_DEAD_COPY (IspImageProcessor); + +private: + SmartPtr<IspController> _controller; + SmartPtr<SensorDescriptor> _sensor; + SmartPtr<IspConfigTranslator> _translator; + SmartPtr<X3aIspConfig> _3a_config; +}; + +class IspExposureImageProcessor + : public IspImageProcessor +{ +public: + explicit IspExposureImageProcessor (SmartPtr<IspController> &controller); + +protected: + virtual bool can_process_result (SmartPtr<X3aResult> &result); + +private: + XCAM_DEAD_COPY (IspExposureImageProcessor); +}; + +}; + +#endif //XCAM_ISP_IMAGE_PROCESSOR_H diff --git a/modules/isp/isp_poll_thread.cpp b/modules/isp/isp_poll_thread.cpp new file mode 100644 index 0000000..754452e --- /dev/null +++ b/modules/isp/isp_poll_thread.cpp @@ -0,0 +1,136 @@ +/* + * isp_poll_thread.cpp - isp poll thread for event and buffer + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include "isp_poll_thread.h" +#include "x3a_statistics_queue.h" +#include <unistd.h> + +namespace XCam { + +class IspPollThread; + +IspPollThread::IspPollThread () +{ + XCAM_LOG_DEBUG ("IspPollThread constructed"); +} + +IspPollThread::~IspPollThread () +{ + stop(); + + XCAM_LOG_DEBUG ("~IspPollThread destructed"); +} + +bool +IspPollThread::set_isp_controller (SmartPtr<IspController> &isp) +{ + XCAM_ASSERT (!_isp_controller.ptr()); + _isp_controller = isp; + return true; +} + +XCamReturn +IspPollThread::start () +{ + _3a_stats_pool = new X3aStatisticsQueue; + + return PollThread::start (); +} + +XCamReturn +IspPollThread::stop () +{ + if (_3a_stats_pool.ptr ()) + _3a_stats_pool->stop (); + + return PollThread::stop (); +} + +XCamReturn +IspPollThread::init_3a_stats_pool () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + struct atomisp_parm parameters; + + xcam_mem_clear (parameters); + ret = _isp_controller->get_isp_parameter (parameters); + if (ret != XCAM_RETURN_NO_ERROR ) { + XCAM_LOG_WARNING ("get isp parameters failed"); + return ret; + } + if (!parameters.info.width || !parameters.info.height) { + XCAM_LOG_WARNING ("get isp parameters width or height wrong"); + return XCAM_RETURN_ERROR_ISP; + } + _3a_stats_pool.dynamic_cast_ptr<X3aStatisticsQueue>()->set_grid_info (parameters.info); + if (!_3a_stats_pool->reserve (6)) { + XCAM_LOG_WARNING ("init_3a_stats_pool failed to reserve stats buffer."); + return XCAM_RETURN_ERROR_MEM; + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +IspPollThread::capture_3a_stats (SmartPtr<X3aStats> &stats) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<X3aIspStatistics> new_stats = + _3a_stats_pool->get_buffer (_3a_stats_pool).dynamic_cast_ptr<X3aIspStatistics> (); + + if (!new_stats.ptr()) { + XCAM_LOG_WARNING ("request stats buffer failed."); + return XCAM_RETURN_ERROR_MEM; + } + + ret = _isp_controller->get_3a_statistics (new_stats); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("get 3a stats from ISP failed"); + return ret; + } + + if (!new_stats->fill_standard_stats ()) { + XCAM_LOG_WARNING ("isp 3a stats failed to fill standard stats but continued"); + } + + stats = new_stats; + return ret; +} + + +XCamReturn +IspPollThread::handle_events (struct v4l2_event &event) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + switch (event.type) { + case V4L2_EVENT_ATOMISP_3A_STATS_READY: + ret = handle_3a_stats_event (event); + break; + case V4L2_EVENT_FRAME_SYNC: + break; + default: + ret = XCAM_RETURN_ERROR_UNKNOWN; + break; + } + + return ret; +} + +}; diff --git a/modules/isp/isp_poll_thread.h b/modules/isp/isp_poll_thread.h new file mode 100644 index 0000000..e5f9b67 --- /dev/null +++ b/modules/isp/isp_poll_thread.h @@ -0,0 +1,59 @@ +/* + * isp_poll_thread.h - isp poll thread for event and buffer + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#ifndef XCAM_ISP_POLL_THREAD_H +#define XCAM_ISP_POLL_THREAD_H + +#include "poll_thread.h" +#include "isp_controller.h" + +namespace XCam { + +class IspPollThread + : public PollThread +{ +public: + explicit IspPollThread (); + virtual ~IspPollThread (); + + bool set_isp_controller (SmartPtr<IspController> &isp); + + virtual XCamReturn start(); + virtual XCamReturn stop (); + +protected: + virtual XCamReturn handle_events (struct v4l2_event &event); + +private: + virtual XCamReturn init_3a_stats_pool (); + virtual XCamReturn capture_3a_stats (SmartPtr<X3aStats> &stats); + +private: + XCAM_DEAD_COPY (IspPollThread); + +private: + SmartPtr<X3aStatsPool> _3a_stats_pool; + SmartPtr<IspController> _isp_controller; +}; + +}; + +#endif // XCAM_ISP_POLL_THREAD_H diff --git a/modules/isp/libtbd.c b/modules/isp/libtbd.c new file mode 100644 index 0000000..dbf98d5 --- /dev/null +++ b/modules/isp/libtbd.c @@ -0,0 +1,647 @@ +/* +** Copyright 2012-2013 Intel Corporation +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <stdbool.h> /* defines bool type */ +#include <stddef.h> /* defines size_t */ +#include <stdint.h> /* defines integer types with specified widths */ +#include <stdio.h> /* defines FILE */ +#include <string.h> /* defines memcpy and memset */ + +#include "libtbd.h" /* our own header file */ + +/*! +* \brief Debug messages. +*/ +#ifdef __ANDROID__ +#define LOG_TAG "libtbd" +#include <utils/Log.h> +#define MSG_LOG(...) LOGD(__VA_ARGS__) +#define MSG_ERR(...) LOGE(__VA_ARGS__) +#else +#include <stdio.h> +#define MSG_LOG(...) fprintf(stdout, __VA_ARGS__); fprintf(stdout, "\n"); +#define MSG_ERR(...) fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); +#endif + +/* + * Checks the validity of the pointer + * param[in] a_ptr Pointer to be examined + * return True if pointer ok + */ +bool is_valid_pointer(void* a_ptr) +{ + if ((!a_ptr) || ((unsigned long)(a_ptr) % sizeof(uint32_t))) { + return false; + } else { + return true; + } +} + +/* + * Calculates checksum for a data block. + * param[in] a_data_ptr Data from where to calculate the checksum + * param[in] a_data_size Size of the data + * return The checksum + */ +uint32_t get_checksum(void *a_data_ptr, size_t a_data_size) +{ + uint32_t *ptr32 = a_data_ptr; + int size32 = a_data_size / sizeof(uint32_t); + + /* Simple checksum algorithm: summing up the data content + * as 32-bit numbers */ + uint32_t checksum32 = 0; + if (size32) { + if (size32 & 0x01) { + checksum32 += *ptr32++; + size32 -= 1; + } + if (size32 & 0x02) { + checksum32 += *ptr32++; + checksum32 += *ptr32++; + size32 -= 2; + } + for (; size32 > 0; size32 -= 4) { + checksum32 += *ptr32++; + checksum32 += *ptr32++; + checksum32 += *ptr32++; + checksum32 += *ptr32++; + } + } + + return checksum32; +} + +/* + * Common subroutine to validate Tagged Binary Data container, without + * paying attention to checksum or data tagging. This function assumes + * that the data resides in "legal" memory area as there is no size + * given together with input pointer. + * param[in] a_data_ptr Pointer to container + * return Return code indicating possible errors + */ +tbd_error_t validate_anysize(void *a_data_ptr) +{ + uint8_t *byte_ptr, *eof_ptr; + tbd_record_header_t *record_ptr; + uint32_t record_size; + + /* Container should begin with a header */ + tbd_header_t *header_ptr = a_data_ptr; + + /* Check against illegal pointers */ + if (!is_valid_pointer(header_ptr)) { + MSG_ERR("LIBTBD ERROR: Cannot access data!"); + return tbd_err_data; + } + + /* Check that the indicated data size makes sense, + * and is not too much or too little */ + if (header_ptr->size % sizeof(uint32_t)) { + MSG_ERR("LIBTBD ERROR: Size in header should be multiple of 4 bytes!"); + return tbd_err_data; + } + if (header_ptr->size < sizeof(tbd_header_t)) { + MSG_ERR("LIBTBD ERROR: Invalid data header!"); + return tbd_err_data; + } + + /* First record is just after header, a byte pointer is needed + * to do math with sizes and pointers */ + byte_ptr = (uint8_t *)(header_ptr + 1); + eof_ptr = (uint8_t *)(a_data_ptr) + header_ptr->size; + + /* Loop until there are no more records to go */ + while (byte_ptr < eof_ptr) { + /* At least one more record is expected */ + + /* Record header must be within the given data size */ + if (byte_ptr + sizeof(tbd_record_header_t) > eof_ptr) { + MSG_ERR("LIBTBD ERROR: Invalid data header!"); + return tbd_err_data; + } + + record_ptr = (tbd_record_header_t *)(byte_ptr); + record_size = record_ptr->size; + + /* Check that the indicated record size makes sense, + * and is not too much or too little */ + if (record_size % sizeof(uint32_t)) { + MSG_ERR("LIBTBD ERROR: Size in record should be multiple of 4 bytes!"); + return tbd_err_data; + } + if (record_size < sizeof(tbd_record_header_t)) { + MSG_ERR("LIBTBD ERROR: Invalid record header!"); + return tbd_err_data; + } + if (byte_ptr + record_size > eof_ptr) { + MSG_ERR("LIBTBD ERROR: Invalid record header!"); + return tbd_err_data; + } + + /* This record ok, continue the while loop... */ + byte_ptr += record_size; + } + + /* Seems that we have a valid data with no more headers */ + return tbd_err_none; +} + +/* + * Common subroutine to validate Tagged Binary Data, without paying + * attention to checksum or data tagging. Also, this function does + * check that the data fits in the given buffer size. + * param[in] a_data_ptr Pointer to data buffer + * param[in] a_data_size Size of the data buffer + * return Return code indicating possible errors + */ +tbd_error_t validate(void *a_data_ptr, size_t a_data_size) +{ + /* Container should begin with a header */ + tbd_header_t *header_ptr = a_data_ptr; + + /* Check against illegal pointers */ + if (!is_valid_pointer(header_ptr)) { + MSG_ERR("LIBTBD ERROR: Cannot access data!"); + return tbd_err_data; + } + + /* Check that the TBD header fits into given data */ + if (sizeof(tbd_header_t) > a_data_size) { + MSG_ERR("TBD ERROR: #1 Too small data buffer given!"); + return tbd_err_data; + } + + /* Check that the indicated data fits in the buffer */ + if (header_ptr->size > a_data_size) { + MSG_ERR("TBD ERROR: #2 Too small data buffer given!"); + return tbd_err_data; + } + + /* Check the the content is ok */ + return validate_anysize(a_data_ptr); +} + +/* + * Creates a new, empty Tagged Binary Data container with the tag + * that was given. Also updates the checksum and size accordingly. + * Note that the buffer size must be large enough for the header + * to fit in, the exact amount being 24 bytes (for tbd_header_t). + * param[in] a_data_ptr Pointer to modifiable container buffer + * param[in] a_data_size Size of the container buffer + * param[in] a_tag Tag the container shall have + * param[out] a_new_size Updated container size + * return Return code indicating possible errors + */ +tbd_error_t tbd_create(void *a_data_ptr, size_t a_data_size + , tbd_tag_t a_tag, size_t *a_new_size) +{ + tbd_header_t *header_ptr; + + /* Check that the TBD header fits into given data */ + if (sizeof(tbd_header_t) > a_data_size) { + MSG_ERR("LIBTBD ERROR: Not enough data given!"); + return tbd_err_argument; + } + + /* Nullify everything */ + memset(a_data_ptr, 0, sizeof(tbd_header_t)); + + /* The header is what we need */ + header_ptr = a_data_ptr; + + header_ptr->tag = a_tag; + + header_ptr->size = sizeof(tbd_header_t); + header_ptr->version = IA_TBD_VERSION; + header_ptr->revision = IA_TBD_REVISION; + header_ptr->config_bits = 0; + header_ptr->checksum = get_checksum(header_ptr, sizeof(tbd_header_t)); + + *a_new_size = sizeof(tbd_header_t); + + return tbd_err_none; +} + +/* + * Performs number of checks to given Tagged Binary Data container, + * including the verification of the checksum. The function does not + * care about the tag type of the container. + * param[in] a_data_ptr Pointer to container buffer + * param[in] a_data_size Size of the container buffer + * return Return code indicating possible errors + */ +tbd_error_t tbd_validate_anytag(void *a_data_ptr, size_t a_data_size) +{ + tbd_header_t *header_ptr; + + /* Check the the content is ok */ + int r; + if ((r = validate(a_data_ptr, a_data_size))) { + return r; + } + + /* Container should begin with a header */ + header_ptr = a_data_ptr; + + /* Check that the checksum is correct */ + + /* When calculating the checksum for the original data, the checksum + * field has been filled with zero value - so after inserting the + * checksum in its place, the new calculated checksum is actually + * two times the original */ + + if (get_checksum(header_ptr, header_ptr->size) - header_ptr->checksum != header_ptr->checksum) { + MSG_ERR("LIBTBD ERROR: Checksum doesn't match!"); + return tbd_err_data; + } + + /* Seems that we have valid data */ + return tbd_err_none; +} + +/* + * Performs number of checks to given Tagged Binary Data container, + * including the verification of the checksum. Also, the data must have + * been tagged properly. The tag is further used to check endianness, + * and if it seems wrong, a specific debug message is printed out. + * param[in] a_data_ptr Pointer to container buffer + * param[in] a_data_size Size of the container buffer + * param[in] a_tag Tag the data must have + * return Return code indicating possible errors + */ +tbd_error_t tbd_validate(void *a_data_ptr, size_t a_data_size + , tbd_tag_t a_tag) +{ + tbd_header_t *header_ptr; + + /* Check the the content is ok */ + int r; + if ((r = validate(a_data_ptr, a_data_size))) { + return r; + } + + /* Container should begin with a header */ + header_ptr = a_data_ptr; + + /* Check that the tag is correct */ + if (header_ptr->tag != a_tag) { + /* See if we have wrong endianness or incorrect tag */ + uint32_t reverse_tag = ( (((a_tag) >> 24) & 0x000000FF) + | (((a_tag) >> 8) & 0x0000FF00) + | (((a_tag) << 8) & 0x00FF0000) + | (((a_tag) << 24) & 0xFF000000) ); + + if (reverse_tag == header_ptr->tag) { + MSG_ERR("LIBTBD ERROR: Wrong endianness of data!"); + } else { + MSG_ERR("LIBTBD ERROR: Data is not tagged properly!"); + } + return tbd_err_data; + } + + /* Check that the checksum is correct */ + + /* When calculating the checksum for the original data, the checksum + * field has been filled with zero value - so after inserting the + * checksum in its place, the new calculated checksum is actually + * two times the original */ + + if (get_checksum(header_ptr, header_ptr->size) - header_ptr->checksum != header_ptr->checksum) { + MSG_ERR("LIBTBD ERROR: Checksum doesn't match!"); + return tbd_err_data; + } + + /* Seems that we have valid data */ + return tbd_err_none; +} + +/* + * Checks if a given kind of record exists in the Tagged Binary Data, + * and if yes, tells the location of such record as well as its size. + * If there are multiple records that match the query, the indicated + * record is the first one. + * param[in] a_data_ptr Pointer to container buffer + * param[in] a_record_class Class the record must have + * param[in] a_record_format Format the record must have + * param[out] a_record_data Record data (or NULL if not found) + * param[out] a_record_size Record size (or 0 if not found) + * return Return code indicating possible errors + */ +tbd_error_t tbd_get_record(void *a_data_ptr + , tbd_class_t a_record_class, tbd_format_t a_record_format + , void **a_record_data, uint32_t *a_record_size) +{ + tbd_header_t *header_ptr; + uint8_t *byte_ptr, *eof_ptr; + + /* Check the the content is ok */ + int r; + if ((r = validate_anysize(a_data_ptr))) { + return r; + } + + /* Container should begin with a header */ + header_ptr = a_data_ptr; + + /* First record is just after header */ + byte_ptr = (uint8_t *)(header_ptr + 1); + eof_ptr = (uint8_t *)(a_data_ptr) + header_ptr->size; + + /* Loop until there are no more records to go */ + while (byte_ptr < eof_ptr) { + /* At least one more record is expected */ + tbd_record_header_t *record_ptr = (tbd_record_header_t *)(byte_ptr); + + uint16_t record_class = record_ptr->class_id; + uint8_t record_format = record_ptr->format_id; + uint32_t record_size = record_ptr->size; + + if (((a_record_class == tbd_class_any) || (a_record_class == record_class)) + && ((a_record_format == tbd_format_any) || (a_record_format == record_format))) { + + /* Match found */ + *a_record_data = record_ptr + 1; + *a_record_size = record_size - sizeof(tbd_record_header_t); + + return tbd_err_none; + + } + + /* Match not found yet, continue the while loop... */ + byte_ptr += record_size; + } + + MSG_LOG("libtbd: Record not found!"); + *a_record_data = NULL; + *a_record_size = 0; + return tbd_err_none; +} + +/* + * The given record is inserted into the Tagged Binary Data container + * that must exist already. New records are always added to the end, + * regardless if a record with the same class and format field already + * exists in the data. Also updates the checksum and size accordingly. + * Note that the buffer size must be large enough for the inserted + * record to fit in, the exact amount being the size of original + * Tagged Binary Data container plus the size of record data to be + * inserted plus 8 bytes (for tbd_record_header_t). + * param[in] a_data_ptr Pointer to modifiable container buffer + * param[in] a_data_size Size of buffer (surplus included) + * param[in] a_record_class Class the record shall have + * param[in] a_record_format Format the record shall have + * param[in] a_record_data Record data + * param[in] a_record_size Record size + * param[out] a_new_size Updated container size + * return Return code indicating possible errors + */ +tbd_error_t tbd_insert_record(void *a_data_ptr, size_t a_data_size + , tbd_class_t a_record_class, tbd_format_t a_record_format + , void *a_record_data, size_t a_record_size + , size_t *a_new_size) +{ + tbd_header_t *header_ptr; + size_t new_size; + tbd_record_header_t *record_ptr; + int r; + + /* Check the the content is ok */ + if ((r = validate(a_data_ptr, a_data_size))) { + return r; + } + + /* Container should begin with a header */ + header_ptr = a_data_ptr; + + /* Check that the new record fits into given data */ + new_size = header_ptr->size + sizeof(tbd_record_header_t) + a_record_size; + + if (new_size > a_data_size) { + MSG_ERR("LIBTBD ERROR: #3 Too small data buffer given!"); + return tbd_err_argument; + } + + /* Check against illegal pointers */ + if (!is_valid_pointer(a_record_data)) { + MSG_ERR("LIBTBD ERROR: Cannot access data!"); + return tbd_err_data; + } + + /* Check that the indicated data size makes sense */ + if (a_record_size % sizeof(uint32_t)) { + MSG_ERR("LIBTBD ERROR: Size in record should be multiple of 4 bytes!"); + return tbd_err_data; + } + + /* Where our record should go */ + record_ptr = (tbd_record_header_t *)((char *)(a_data_ptr) + header_ptr->size); + + /* Create record header and store the record itself */ + record_ptr->size = sizeof(tbd_record_header_t) + a_record_size; + record_ptr->format_id = a_record_format; + record_ptr->packing_key = 0; + record_ptr->class_id = a_record_class; + record_ptr++; + memcpy(record_ptr, a_record_data, a_record_size); + + /* Update the header */ + header_ptr->size = new_size; + header_ptr->checksum = 0; + header_ptr->checksum = get_checksum(header_ptr, new_size); + + *a_new_size = new_size; + + return tbd_err_none; +} + +/* + * The indicated record is removed from the Tagged Binary Data, after + * which the checksum and size are updated accordingly. If there are + * multiple records that match the class and format, only the first + * instance is removed. If no record is found, nothing will be done. + * Note that the resulting Tagged Binary Data container will + * be smaller than the original, but it does not harm to store the + * resulting container in its original length, either. + * param[in] a_data_ptr Pointer to modifiable container buffer + * param[in] a_record_class Class the record should have + * param[in] a_record_format Format the record should have + * param[out] a_new_size Updated container size + * return Return code indicating possible errors + */ +tbd_error_t tbd_remove_record(void *a_data_ptr + , tbd_class_t a_record_class, tbd_format_t a_record_format + , size_t *a_new_size) +{ + tbd_header_t *header_ptr; + uint8_t *byte_ptr, *eof_ptr; + size_t new_size; + + /* Check the the content is ok */ + int r; + if ((r = validate_anysize(a_data_ptr))) { + return r; + } + + /* Container should begin with a header */ + header_ptr = a_data_ptr; + + /* First record is just after header */ + byte_ptr = (uint8_t *)(header_ptr + 1); + eof_ptr = (uint8_t *)(a_data_ptr) + header_ptr->size; + + /* Loop until there are no more records to go */ + while (byte_ptr < eof_ptr) { + /* At least one more record is expected */ + tbd_record_header_t *record_ptr = (tbd_record_header_t *)(byte_ptr); + + uint16_t record_class = record_ptr->class_id; + uint8_t record_format = record_ptr->format_id; + uint32_t record_size = record_ptr->size; + + if (((a_record_class == tbd_class_any) || (a_record_class == record_class)) + && ((a_record_format == tbd_format_any) || (a_record_format == record_format))) { + + /* Match found, remove the record */ + memcpy(byte_ptr, byte_ptr + record_size, eof_ptr - (byte_ptr + record_size)); + + /* Update the header */ + new_size = header_ptr->size - record_size; + header_ptr->size = new_size; + header_ptr->checksum = 0; + header_ptr->checksum = get_checksum(header_ptr, new_size); + + *a_new_size = new_size; + + return tbd_err_none; + + } + + /* Match not found yet, continue the while loop... */ + byte_ptr += record_size; + } + + MSG_LOG("libtbd: Record not found!"); + *a_new_size = header_ptr->size; + return tbd_err_none; +} + +/* + * Validates the Tagged Binary data container and generates a human + * readable detailed report on the content, including information about + * the records contained. + * param[in] a_data_ptr Pointer to container buffer + * param[in] a_data_size Size of the container buffer + * param[in] a_outfile Pointer to open file (may be stdout) + * return Return code indicating possible errors + */ +tbd_error_t tbd_infoprint(void *a_data_ptr, size_t a_data_size + , FILE *a_outfile) +{ + tbd_header_t *header_ptr; + uint8_t *byte_ptr, *eof_ptr, record_format, record_packing; + int num_of_records = 0, total_data = 0; + uint16_t record_class; + uint32_t record_size; + + /* Check the the content is ok */ + int r; + if ((r = validate(a_data_ptr, a_data_size))) { + return r; + } + + /* Container should begin with a header */ + header_ptr = a_data_ptr; + + fprintf(a_outfile, "Data tag: 0x%08x (\'%c\' \'%c\' \'%c\' \'%c\')\n", header_ptr->tag, ((char *)(&header_ptr->tag))[0], ((char *)(&header_ptr->tag))[1], ((char *)(&header_ptr->tag))[2], ((char *)(&header_ptr->tag))[3]); + fprintf(a_outfile, "Data size: %d (0x%x), buffer size %d (0x%x)\n", header_ptr->size, header_ptr->size, (uint32_t)a_data_size, (uint32_t)a_data_size); + fprintf(a_outfile, "Data version: 0x%08x\n", header_ptr->version); + fprintf(a_outfile, "Data revision: 0x%08x\n", header_ptr->revision); + fprintf(a_outfile, "Data config: 0x%08x\n", header_ptr->config_bits); + fprintf(a_outfile, "Data checksum: 0x%08x\n", header_ptr->checksum); + + fprintf(a_outfile, "\n"); + + /* First record is just after header */ + byte_ptr = (uint8_t *)(header_ptr + 1); + eof_ptr = (uint8_t *)(a_data_ptr) + header_ptr->size; + + /* Loop until there are no more records to go */ + while (byte_ptr < eof_ptr) { + /* At least one more record is expected */ + tbd_record_header_t *record_ptr = (tbd_record_header_t *)(byte_ptr); + num_of_records++; + + record_class = record_ptr->class_id; + record_format = record_ptr->format_id; + record_packing = record_ptr->packing_key; + record_size = record_ptr->size; + total_data += record_size - sizeof(tbd_record_header_t); + + fprintf(a_outfile, "Record size: %d (0x%x)\n", record_size, record_size); + fprintf(a_outfile, "Size w/o header: %d (0x%x)\n", record_size - (uint32_t)sizeof(tbd_record_header_t), record_size - (uint32_t)sizeof(tbd_record_header_t)); + fprintf(a_outfile, "Record class: %d", record_class); + switch (record_class) { + case tbd_class_any: + fprintf(a_outfile, " \"tbd_class_any\"\n"); + break; + case tbd_class_aiq: + fprintf(a_outfile, " \"tbd_class_aiq\"\n"); + break; + case tbd_class_drv: + fprintf(a_outfile, " \"tbd_class_drv\"\n"); + break; + case tbd_class_hal: + fprintf(a_outfile, " \"tbd_class_hal\"\n"); + break; + default: + fprintf(a_outfile, " (unknown class)\n"); + break; + } + fprintf(a_outfile, "Record format: %d", record_format); + switch (record_format) { + case tbd_format_any: + fprintf(a_outfile, " \"tbd_format_any\"\n"); + break; + case tbd_format_custom: + fprintf(a_outfile, " \"tbd_format_custom\"\n"); + break; + case tbd_format_container: + fprintf(a_outfile, " \"tbd_format_container\"\n"); + break; + default: + fprintf(a_outfile, " (unknown format)\n"); + break; + } + fprintf(a_outfile, "Packing: %d", record_packing); + if (record_packing == 0) { + fprintf(a_outfile, " (no packing)\n"); + } else { + fprintf(a_outfile, "\n"); + } + + fprintf(a_outfile, "\n"); + + /* Continue the while loop... */ + byte_ptr += record_size; + } + + fprintf(a_outfile, "Number of records found: %d\n", num_of_records); + fprintf(a_outfile, "Total data in records: %d bytes (without headers)\n", total_data); + fprintf(a_outfile, "\n"); + return tbd_err_none; +} + diff --git a/modules/isp/libtbd.h b/modules/isp/libtbd.h new file mode 100644 index 0000000..0b682f0 --- /dev/null +++ b/modules/isp/libtbd.h @@ -0,0 +1,250 @@ +/* +** Copyright 2012-2013 Intel Corporation +** +** 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 libtbd.h + * \brief Tagged Binary Data handling + */ + +#ifndef __LIBTBD_H__ +#define __LIBTBD_H__ + +#include <stddef.h> /* defines size_t */ +#include <stdint.h> /* defines integer types with specified widths */ +#include <stdio.h> /* defines FILE */ + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * Revision of TBD System, format 0xYYMMDDVV, where: + * - YY: year, + * - MM: month, + * - DD: day, + * - VV: version ('01','02' etc.) + */ +#define IA_TBD_VERSION 0x12032201 + +/*! + * Revision of TBD data set, format 0xYYMMDDVV, where: + * - YY: year, + * - MM: month, + * - DD: day, + * - VV: version ('01','02' etc.) + */ +#define IA_TBD_REVISION 0x13091001 + +/*! +* \brief Error codes for libtbd. +*/ +typedef enum +{ + tbd_err_none = 0 , /*!< No errors */ + tbd_err_general = (1 << 1), /*!< General error */ + tbd_err_nomemory = (1 << 2), /*!< Out of memory */ + tbd_err_data = (1 << 3), /*!< Corrupted data */ + tbd_err_internal = (1 << 4), /*!< Error in code */ + tbd_err_argument = (1 << 5) /*!< Invalid argument for a function */ +} tbd_error_t; + +/*! + * \brief Header structure for TBD container, followed by actual records. + */ +typedef struct +{ + uint32_t tag; /*!< Tag identifier, also checks endianness */ + uint32_t size; /*!< Container size including this header */ + uint32_t version; /*!< Version of TBD system, format 0xYYMMDDVV */ + uint32_t revision; /*!< Revision of TBD data set, format 0xYYMMDDVV */ + uint32_t config_bits; /*!< Configuration flag bits set */ + uint32_t checksum; /*!< Global checksum, header included */ +} tbd_header_t; + +/*! + * \brief Tag identifiers used in TBD container header. + */ +#define CHTOU32(a,b,c,d) ((uint32_t)(a)|((uint32_t)(b)<<8)|((uint32_t)(c)<<16)|((uint32_t)(d)<<24)) +typedef enum +{ + tbd_tag_cpff = CHTOU32('C', 'P', 'F', 'F'), /*!< CPF File */ + tbd_tag_aiqb = CHTOU32('A', 'I', 'Q', 'B'), /*!< AIQ configuration */ + tbd_tag_aiqd = CHTOU32('A', 'I', 'Q', 'D'), /*!< AIQ data */ + tbd_tag_halb = CHTOU32('H', 'A', 'L', 'B'), /*!< CameraHAL configuration */ + tbd_tag_drvb = CHTOU32('D', 'R', 'V', 'B') /*!< Sensor driver configuration */ +} tbd_tag_t; + +/*! + * \brief Record structure. Data is located right after this header. + */ +typedef struct +{ + uint32_t size; /*!< Size of record including header */ + uint8_t format_id; /*!< tbd_format_t enumeration values used */ + uint8_t packing_key; /*!< Packing method; 0 = no packing */ + uint16_t class_id; /*!< tbd_class_t enumeration values used */ +} tbd_record_header_t; + +/*! + * \brief Format ID enumeration describes the data format of the record. + */ +typedef enum +{ + tbd_format_any = 0, /*!< Unspecified format */ + tbd_format_custom, /*!< User specified format */ + tbd_format_container /*!< Record is actually another TBD container */ +} tbd_format_t; + +/*! + * \brief Class ID enumeration describes the data class of the record. + */ +typedef enum +{ + tbd_class_any = 0, /*!< Unspecified record class */ + tbd_class_aiq, /*!< Used for AIC and 3A records */ + tbd_class_drv, /*!< Used for driver records */ + tbd_class_hal /*!< Used for HAL records */ +} tbd_class_t; + +/*! + * \brief Creates a new Tagged Binary Data container. + * Creates a new, empty Tagged Binary Data container with the tag + * that was given. Also updates the checksum and size accordingly. + * Note that the buffer size must be large enough for the header + * to fit in, the exact amount being 24 bytes (for tbd_header_t). + * @param[in] a_data_ptr Pointer to modifiable container buffer + * @param[in] a_data_size Size of the container buffer + * @param[in] a_tag Tag the container shall have + * @param[out] a_new_size Updated container size + * @return Return code indicating possible errors + */ +tbd_error_t tbd_create(void *a_data_ptr, + size_t a_data_size, + tbd_tag_t a_tag, + size_t *a_new_size); + +/*! + * \brief Checks if Tagged Binary Data is valid. All tags are accepted. + * Performs number of checks to given Tagged Binary Data container, + * including the verification of the checksum. The function does not + * care about the tag type of the container. + * @param[in] a_data_ptr Pointer to container buffer + * @param[in] a_data_size Size of the container buffer + * @return Return code indicating possible errors + */ +tbd_error_t tbd_validate_anytag(void *a_data_ptr, + size_t a_data_size); + +/*! + * \brief Checks if Tagged Binary Data is valid, and tagged properly. + * Performs number of checks to given Tagged Binary Data container, + * including the verification of the checksum. Also, the data must have + * been tagged properly. The tag is further used to check endianness, + * and if it seems wrong, a specific debug message is printed out. + * @param[in] a_data_ptr Pointer to container buffer + * @param[in] a_data_size Size of the container buffer + * @param[in] a_tag Tag the data must have + * @return Return code indicating possible errors + */ +tbd_error_t tbd_validate(void *a_data_ptr, + size_t a_data_size, + tbd_tag_t a_tag); + +/*! + * \brief Finds a record of given kind from within the container. + * Checks if a given kind of record exists in the Tagged Binary Data, + * and if yes, tells the location of such record as well as its size. + * If there are multiple records that match the query, the indicated + * record is the first one. + * @param[in] a_data_ptr Pointer to container buffer + * @param[in] a_record_class Class the record must have + * @param[in] a_record_format Format the record must have + * @param[out] a_record_data Record data (or NULL if not found) + * @param[out] a_record_size Record size (or 0 if not found) + * @return Return code indicating possible errors + */ +tbd_error_t tbd_get_record(void *a_data_ptr, + tbd_class_t a_record_class, + tbd_format_t a_record_format, + void **a_record_data, + uint32_t *a_record_size); + +/*! + * \brief Updates the Tagged Binary Data with the given record inserted. + * The given record is inserted into the Tagged Binary Data container + * that must exist already. New records are always added to the end, + * regardless if a record with the same class and format field already + * exists in the data. Also updates the checksum and size accordingly. + * Note that the buffer size must be large enough for the inserted + * record to fit in, the exact amount being the size of original + * Tagged Binary Data container plus the size of record data to be + * inserted plus 8 bytes (for tbd_record_header_t). + * @param[in] a_data_ptr Pointer to modifiable container buffer + * @param[in] a_data_size Size of buffer (surplus included) + * @param[in] a_record_class Class the record shall have + * @param[in] a_record_format Format the record shall have + * @param[in] a_record_data Record data + * @param[in] a_record_size Record size + * @param[out] a_new_size Updated container size + * @return Return code indicating possible errors + */ +tbd_error_t tbd_insert_record(void *a_data_ptr, + size_t a_data_size, + tbd_class_t a_record_class, + tbd_format_t a_record_format, + void *a_record_data, + size_t a_record_size, + size_t *a_new_size); + +/*! + * \brief Updates the Tagged Binary Data with the given record removed. + * The indicated record is removed from the Tagged Binary Data, after + * which the checksum and size are updated accordingly. If there are + * multiple records that match the class and format, only the first + * instance is removed. If no record is found, nothing will be done. + * Note that the resulting Tagged Binary Data container will + * be smaller than the original, but it does not harm to store the + * resulting container in its original length, either. + * @param[in] a_data_ptr Pointer to modifiable container buffer + * @param[in] a_record_class Class the record should have + * @param[in] a_record_format Format the record should have + * @param[out] a_new_size Updated container size + * @return Return code indicating possible errors + */ +tbd_error_t tbd_remove_record(void *a_data_ptr, + tbd_class_t a_record_class, + tbd_format_t a_record_format, + size_t *a_new_size); + +/*! + * \brief Writes all possible information about the Tagged Binary Data. + * Validates the Tagged Binary data container and generates a human + * readable detailed report on the content, including information about + * the records contained. + * @param[in] a_data_ptr Pointer to container buffer + * @param[in] a_data_size Size of the container buffer + * @param[in] a_outfile Pointer to open file (may be stdout) + * @return Return code indicating possible errors + */ +tbd_error_t tbd_infoprint(void *a_data_ptr, + size_t a_data_size, + FILE *a_outfile); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBTBD_H__ */ diff --git a/modules/isp/sensor_descriptor.cpp b/modules/isp/sensor_descriptor.cpp new file mode 100644 index 0000000..367117b --- /dev/null +++ b/modules/isp/sensor_descriptor.cpp @@ -0,0 +1,100 @@ +/* + * sensor_descriptor.h - sensor descriptor + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "sensor_descriptor.h" +#include <math.h> + +namespace XCam { + +SensorDescriptor::SensorDescriptor () +{ + xcam_mem_clear (_sensor_data); +} + +SensorDescriptor::~SensorDescriptor () +{ +} + +bool +SensorDescriptor::is_ready () +{ + return (_sensor_data.line_length_pck > 0); +} + +void +SensorDescriptor::set_sensor_data (struct atomisp_sensor_mode_data &data) +{ + _sensor_data = data; +} + +bool +SensorDescriptor::exposure_time_to_integration ( + int32_t exposure_time, uint32_t &coarse_time, uint32_t &fine_time) +{ + if (exposure_time < 0 || !is_ready ()) + return false; + + uint32_t pixel_periods = ((uint64_t)exposure_time) * _sensor_data.vt_pix_clk_freq_mhz / XCAM_SECONDS_2_TIMESTAMP (1); + + coarse_time = pixel_periods / _sensor_data.line_length_pck; + fine_time = pixel_periods % _sensor_data.line_length_pck; + return true; +} + +bool +SensorDescriptor::exposure_integration_to_time ( + uint32_t coarse_time, uint32_t fine_time, int32_t &exposure_time) +{ + if (!is_ready ()) + return false; + + uint64_t pixel_periods = coarse_time * _sensor_data.line_length_pck + fine_time; + exposure_time = pixel_periods * XCAM_SECONDS_2_TIMESTAMP(1) / _sensor_data.vt_pix_clk_freq_mhz; + return true; +} + +bool +SensorDescriptor::exposure_gain_to_code ( + double analog_gain, double digital_gain, + int32_t &analog_code, int32_t &digital_code) +{ + XCAM_ASSERT (digital_gain == 1.0); + double db = log10 (analog_gain * digital_gain) * 20; + if (db > 48) + db = 48; + analog_code = (uint32_t) (db * 160.0 / 48); + digital_code = 0; + return true; +} + +bool +SensorDescriptor::exposure_code_to_gain ( + int32_t analog_code, int32_t digital_code, + double &analog_gain, double &digital_gain) +{ + XCAM_UNUSED (digital_code); + double db = analog_code * 48.0 / 160.0; + analog_gain = pow (10.0, db / 20.0); + digital_gain = 1.0; + + return true; +} + +}; diff --git a/modules/isp/sensor_descriptor.h b/modules/isp/sensor_descriptor.h new file mode 100644 index 0000000..a49ab67 --- /dev/null +++ b/modules/isp/sensor_descriptor.h @@ -0,0 +1,66 @@ +/* + * sensor_descriptor.h - sensor descriptor + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_SENSOR_DESCRIPTOR_H +#define XCAM_SENSOR_DESCRIPTOR_H + +#include <xcam_std.h> +#include <linux/atomisp.h> + +namespace XCam { + +class SensorDescriptor { +public: + explicit SensorDescriptor (); + virtual ~SensorDescriptor (); + + void set_sensor_data (struct atomisp_sensor_mode_data &data); + virtual bool is_ready (); + + // Input: exposure_time + // Output: coarse_time, fine_time + virtual bool exposure_time_to_integration ( + int32_t exposure_time, uint32_t &coarse_time, uint32_t &fine_time); + // Input: coarse_time, fine_time + // Output: exposure_time + virtual bool exposure_integration_to_time ( + uint32_t coarse_time, uint32_t fine_time, int32_t &exposure_time); + + // Input : analog_gain, digital_gain + // Output: analog_code, digital_code + virtual bool exposure_gain_to_code ( + double analog_gain, double digital_gain, + int32_t &analog_code, int32_t &digital_code); + + // Input : analog_code, digital_code + // Output : analog_gain, digital_gain + virtual bool exposure_code_to_gain ( + int32_t analog_code, int32_t digital_code, + double &analog_gain, double &digital_gain); + +private: + XCAM_DEAD_COPY (SensorDescriptor); + +private: + struct atomisp_sensor_mode_data _sensor_data; +}; + +}; +#endif //XCAM_SENSOR_DESCRIPTOR_H diff --git a/modules/isp/x3a_analyzer_aiq.cpp b/modules/isp/x3a_analyzer_aiq.cpp new file mode 100644 index 0000000..666574d --- /dev/null +++ b/modules/isp/x3a_analyzer_aiq.cpp @@ -0,0 +1,265 @@ +/* + * x3a_analyzer_aiq.h - 3a analyzer from AIQ + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "x3a_analyzer_aiq.h" +#include "aiq_handler.h" +#include "isp_controller.h" +#include "xcam_cpf_reader.h" +#include "ia_types.h" + +namespace XCam { + +class CpfReader { +public: + explicit CpfReader (const char *name); + ~CpfReader(); + bool read (ia_binary_data &binary); +private: + XCAM_DEAD_COPY (CpfReader); + +private: + XCamCpfBlob *_aiq_cpf; + char *_name; +}; + +CpfReader::CpfReader (const char *name) + : _name (strndup(name, XCAM_MAX_STR_SIZE)) +{ + _aiq_cpf = xcam_cpf_blob_new (); + XCAM_ASSERT (name); +} +CpfReader::~CpfReader() +{ + if (_aiq_cpf) + xcam_cpf_blob_free (_aiq_cpf); + if (_name) + xcam_free (_name); +} + +bool CpfReader::read (ia_binary_data &binary) +{ + if (!xcam_cpf_read (_name, _aiq_cpf, NULL)) { + XCAM_LOG_ERROR ("parse CPF(%s) failed", XCAM_STR (_name)); + return false; + } + binary.data = _aiq_cpf->data; + binary.size = _aiq_cpf->size; + XCAM_LOG_INFO ("read cpf(%s) ok", XCAM_STR (_name)); + return true; +} + +X3aAnalyzerAiq::X3aAnalyzerAiq (SmartPtr<IspController> &isp, const char *cpf_path) + : X3aAnalyzer ("X3aAnalyzerAiq") + , _isp (isp) + , _sensor_data_ready (false) + , _cpf_path (NULL) +{ + if (cpf_path) + _cpf_path = strndup (cpf_path, XCAM_MAX_STR_SIZE); + + _aiq_compositor = new AiqCompositor (); + XCAM_ASSERT (_aiq_compositor.ptr()); + xcam_mem_clear (_sensor_mode_data); + + XCAM_LOG_DEBUG ("X3aAnalyzerAiq constructed"); +} + +X3aAnalyzerAiq::X3aAnalyzerAiq (struct atomisp_sensor_mode_data &sensor_data, const char *cpf_path) + : X3aAnalyzer ("X3aAnalyzerAiq") + , _sensor_mode_data (sensor_data) + , _sensor_data_ready (true) + , _cpf_path (NULL) +{ + if (cpf_path) + _cpf_path = strndup (cpf_path, XCAM_MAX_STR_SIZE); + + _aiq_compositor = new AiqCompositor (); + XCAM_ASSERT (_aiq_compositor.ptr()); + + XCAM_LOG_DEBUG ("X3aAnalyzerAiq constructed"); +} + +X3aAnalyzerAiq::~X3aAnalyzerAiq() +{ + if (_cpf_path) + xcam_free (_cpf_path); + + XCAM_LOG_DEBUG ("~X3aAnalyzerAiq destructed"); +} + +SmartPtr<AeHandler> +X3aAnalyzerAiq::create_ae_handler () +{ + SmartPtr<AiqAeHandler> ae_handler = new AiqAeHandler (_aiq_compositor); + _aiq_compositor->set_ae_handler (ae_handler); + return ae_handler; +} + +SmartPtr<AwbHandler> +X3aAnalyzerAiq::create_awb_handler () +{ + SmartPtr<AiqAwbHandler> awb_handler = new AiqAwbHandler (_aiq_compositor); + _aiq_compositor->set_awb_handler (awb_handler); + return awb_handler; +} + +SmartPtr<AfHandler> +X3aAnalyzerAiq::create_af_handler () +{ + + SmartPtr<AiqAfHandler> af_handler = new AiqAfHandler (_aiq_compositor); + _aiq_compositor->set_af_handler (af_handler); + return af_handler; +} + +SmartPtr<CommonHandler> +X3aAnalyzerAiq::create_common_handler () +{ + SmartPtr<AiqCommonHandler> common_handler = new AiqCommonHandler (_aiq_compositor); + _aiq_compositor->set_common_handler (common_handler); + return common_handler; +} + +XCamReturn +X3aAnalyzerAiq::internal_init (uint32_t width, uint32_t height, double framerate) +{ + XCAM_ASSERT (_cpf_path); + CpfReader reader (_cpf_path); + ia_binary_data binary; + + XCAM_ASSERT (_aiq_compositor.ptr ()); + + _aiq_compositor->set_framerate (framerate); + + xcam_mem_clear (binary); + XCAM_FAIL_RETURN ( + ERROR, + reader.read(binary), + XCAM_RETURN_ERROR_AIQ, + "read cpf file(%s) failed", _cpf_path); + + _aiq_compositor->set_size (width, height); + XCAM_FAIL_RETURN ( + ERROR, + _aiq_compositor->open (binary), + XCAM_RETURN_ERROR_AIQ, + "AIQ open failed"); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +X3aAnalyzerAiq::internal_deinit () +{ + if (_aiq_compositor.ptr ()) + _aiq_compositor->close (); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +X3aAnalyzerAiq::configure_3a () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + X3aResultList first_results; + + if (!_sensor_data_ready) { + struct atomisp_sensor_mode_data sensor_mode_data; + xcam_mem_clear (sensor_mode_data); + XCAM_ASSERT (_isp.ptr()); + + ret = _isp->get_sensor_mode_data (sensor_mode_data); + XCAM_FAIL_RETURN (WARNING, ret == XCAM_RETURN_NO_ERROR, ret, "get sensor mode data failed"); + _sensor_mode_data = sensor_mode_data; + _sensor_data_ready = true; + } + + if (!_aiq_compositor->set_sensor_mode_data (&_sensor_mode_data)) { + XCAM_LOG_WARNING ("AIQ configure 3a failed"); + return XCAM_RETURN_ERROR_AIQ; + } + + XCAM_LOG_DEBUG ("X3aAnalyzerAiq got sensor mode data, coarse_time_min:%u, " + "coarse_time_max_margin:%u, " + "fine_time_min:%u, fine_time_max_margin:%u, " + "fine_time_def:%u, " + "frame_length_lines:%u, line_length_pck:%u, " + "vt_pix_clk_freq_mhz:%u, " + "crop_horizontal_start:%u, crop_vertical_start:%u, " + "crop_horizontal_end:%u, crop_vertical_end:%u, " + "output_width:%u, output_height:%u, " + "binning_factor_x:%u, binning_factor_y:%u", + _sensor_mode_data.coarse_integration_time_min, + _sensor_mode_data.coarse_integration_time_max_margin, + _sensor_mode_data.fine_integration_time_min, + _sensor_mode_data.fine_integration_time_max_margin, + _sensor_mode_data.fine_integration_time_def, + _sensor_mode_data.frame_length_lines, + _sensor_mode_data.line_length_pck, + _sensor_mode_data.vt_pix_clk_freq_mhz, + _sensor_mode_data.crop_horizontal_start, + _sensor_mode_data.crop_vertical_start, + _sensor_mode_data.crop_horizontal_end, + _sensor_mode_data.crop_vertical_end, + _sensor_mode_data.output_width, + _sensor_mode_data.output_height, + (uint32_t)_sensor_mode_data.binning_factor_x, + (uint32_t)_sensor_mode_data.binning_factor_y); + + // initialize ae and awb + get_ae_handler ()->analyze (first_results); + get_awb_handler ()->analyze (first_results); + + ret = _aiq_compositor->integrate (first_results); + XCAM_FAIL_RETURN (WARNING, ret == XCAM_RETURN_NO_ERROR, ret, "AIQ configure_3a failed on integrate results"); + + if (!first_results.empty()) { + notify_calculation_done (first_results); + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +X3aAnalyzerAiq::pre_3a_analyze (SmartPtr<X3aStats> &stats) +{ + SmartPtr<X3aIspStatistics> isp_stats = stats.dynamic_cast_ptr<X3aIspStatistics> (); + + XCAM_ASSERT (isp_stats.ptr ()); + if (!_aiq_compositor->set_3a_stats (isp_stats)) { + XCAM_LOG_WARNING ("Aiq compositor set 3a stats failed"); + return XCAM_RETURN_ERROR_UNKNOWN; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +X3aAnalyzerAiq::post_3a_analyze (X3aResultList &results) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + ret = _aiq_compositor->integrate (results); + XCAM_FAIL_RETURN (WARNING, ret == XCAM_RETURN_NO_ERROR, ret, "AIQ integrate 3A results failed"); + + return XCAM_RETURN_NO_ERROR; +} + +}; diff --git a/modules/isp/x3a_analyzer_aiq.h b/modules/isp/x3a_analyzer_aiq.h new file mode 100644 index 0000000..0478230 --- /dev/null +++ b/modules/isp/x3a_analyzer_aiq.h @@ -0,0 +1,68 @@ +/* + * x3a_analyzer_aiq.h - 3a analyzer from AIQ + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_3A_ANALYZER_AIQ_H +#define XCAM_3A_ANALYZER_AIQ_H + +#include <xcam_std.h> +#include "x3a_analyzer.h" +#include <linux/atomisp.h> + +namespace XCam { + +class AiqCompositor; +class IspController; + +class X3aAnalyzerAiq + : public X3aAnalyzer +{ +public: + explicit X3aAnalyzerAiq (SmartPtr<IspController> &isp, const char *cpf_path); + explicit X3aAnalyzerAiq (struct atomisp_sensor_mode_data &sensor_data, const char *cpf_path); + ~X3aAnalyzerAiq (); + +private: + + XCAM_DEAD_COPY (X3aAnalyzerAiq); + +protected: + virtual SmartPtr<AeHandler> create_ae_handler (); + virtual SmartPtr<AwbHandler> create_awb_handler (); + virtual SmartPtr<AfHandler> create_af_handler (); + virtual SmartPtr<CommonHandler> create_common_handler (); + + virtual XCamReturn internal_init (uint32_t width, uint32_t height, double framerate); + virtual XCamReturn internal_deinit (); + + virtual XCamReturn configure_3a (); + virtual XCamReturn pre_3a_analyze (SmartPtr<X3aStats> &stats); + virtual XCamReturn post_3a_analyze (X3aResultList &results); + +private: + SmartPtr <AiqCompositor> _aiq_compositor; + + SmartPtr <IspController> _isp; + struct atomisp_sensor_mode_data _sensor_mode_data; + bool _sensor_data_ready; + char *_cpf_path; +}; + +}; +#endif //XCAM_3A_ANALYZER_AIQ_H diff --git a/modules/isp/x3a_isp_config.cpp b/modules/isp/x3a_isp_config.cpp new file mode 100644 index 0000000..a5eafef --- /dev/null +++ b/modules/isp/x3a_isp_config.cpp @@ -0,0 +1,286 @@ +/* + * x3a_isp_config.h - 3A ISP config + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "x3a_isp_config.h" +#include "isp_config_translator.h" + +namespace XCam { + +void AtomIspConfigContent::clear () +{ + memset (this, 0, sizeof (AtomIspConfigContent)); +} + +void +AtomIspConfigContent::copy (const struct atomisp_parameters &config) +{ + xcam_mem_clear (isp_config); + if (config.wb_config) { + wb = *config.wb_config; + isp_config.wb_config = &wb; + } + if (config.cc_config) { + cc = *config.cc_config; + isp_config.cc_config = &cc; + } + if (config.tnr_config) { + tnr = *config.tnr_config; + isp_config.tnr_config = &tnr; + } + if (config.ecd_config) { + ecd_config = *config.ecd_config; + isp_config.ecd_config = &ecd_config; + } + if (config.ynr_config) { + ynr = *config.ynr_config; + isp_config.ynr_config = &ynr; + } + if (config.fc_config) { + fc_config = *config.fc_config; + isp_config.fc_config = &fc_config; + } + if (config.cnr_config) { + cnr = *config.cnr_config; + isp_config.cnr_config = &cnr; + } + if (config.macc_config) { + macc_config = *config.macc_config; + isp_config.macc_config = &macc_config; + } + if (config.ctc_config) { + ctc_config = *config.ctc_config; + isp_config.ctc_config = &ctc_config; + } + if (config.formats_config) { + formats = *config.formats_config; + isp_config.formats_config = &formats; + } + if (config.aa_config) { + aa = *config.aa_config; + isp_config.aa_config = &aa; + } + if (config.baa_config) { + baa = *config.baa_config; + isp_config.baa_config = &baa; + } + if (config.ce_config) { + ce = *config.ce_config; + isp_config.ce_config = &ce; + } + if (config.dvs_6axis_config) { + dvs_6axis = *config.dvs_6axis_config; + isp_config.dvs_6axis_config = &dvs_6axis; + } + if (config.ob_config) { + ob = *config.ob_config; + isp_config.ob_config = &ob; + } + if (config.nr_config) { + nr = *config.nr_config; + isp_config.nr_config = &nr; + } + if (config.dp_config) { + dp = *config.dp_config; + isp_config.dp_config = &dp; + } + if (config.ee_config) { + ee = *config.ee_config; + isp_config.ee_config = ⅇ + } + if (config.de_config) { + de = *config.de_config; + isp_config.de_config = &de; + } + if (config.ctc_table) { + ctc_table = *config.ctc_table; + isp_config.ctc_table = &ctc_table; + } + if (config.gc_config) { + gc_config = *config.gc_config; + isp_config.gc_config = &gc_config; + } + if (config.anr_config) { + anr = *config.anr_config; + isp_config.anr_config = &anr; + } + if (config.a3a_config) { + a3a = *config.a3a_config; + isp_config.a3a_config = &a3a; + } + if (config.xnr_config) { + xnr = *config.xnr_config; + isp_config.xnr_config = &xnr; + } + if (config.dz_config) { + dz_config = *config.dz_config; + isp_config.dz_config = &dz_config; + } + if (config.yuv2rgb_cc_config) { + yuv2rgb_cc = *config.yuv2rgb_cc_config; + isp_config.yuv2rgb_cc_config = &yuv2rgb_cc; + } + if (config.rgb2yuv_cc_config) { + rgb2yuv_cc = *config.rgb2yuv_cc_config; + isp_config.rgb2yuv_cc_config = &rgb2yuv_cc; + } + if (config.macc_table) { + macc_table = *config.macc_table; + isp_config.macc_table = &macc_table; + } + if (config.gamma_table) { + gamma_table = *config.gamma_table; + isp_config.gamma_table = &gamma_table; + } + if (config.r_gamma_table) { + r_gamma_table = *config.r_gamma_table; + isp_config.r_gamma_table = &r_gamma_table; + } + if (config.g_gamma_table) { + g_gamma_table = *config.g_gamma_table; + isp_config.g_gamma_table = &g_gamma_table; + } + if (config.b_gamma_table) { + b_gamma_table = *config.b_gamma_table; + isp_config.b_gamma_table = &b_gamma_table; + } + if (config.shading_table) { + shading_table = *config.shading_table; + isp_config.shading_table = &shading_table; + } + if (config.morph_table) { + morph_table = *config.morph_table; + isp_config.morph_table = &morph_table; + } + if (config.xnr_table) { + xnr_table = *config.xnr_table; + isp_config.xnr_table = &xnr_table; + } + if (config.anr_thres) { + anr_thres = *config.anr_thres; + isp_config.anr_thres = &anr_thres; + } + if (config.motion_vector) { + motion_vector = *config.motion_vector; + isp_config.motion_vector = &motion_vector; + } +} + +X3aIspConfig::X3aIspConfig () +{ +} + +X3aIspConfig::~X3aIspConfig() +{ + clear (); +} + + +bool X3aIspConfig::clear() +{ + _isp_content.clear (); + _3a_results.clear (); + return true; +} + +bool +X3aIspConfig::attach (SmartPtr<X3aResult> &result, IspConfigTranslator *translator) +{ + if (result.ptr() == NULL) + return false; + + uint32_t type = result->get_type (); + + XCAM_ASSERT (translator); + + if (!result.ptr() || !result->get_ptr ()) { + XCAM_LOG_ERROR ("3A result empty"); + return false; + } + switch (type) { + case X3aIspConfig::IspAllParameters: { + SmartPtr<X3aAtomIspParametersResult> isp_3a = + result.dynamic_cast_ptr<X3aAtomIspParametersResult> (); + XCAM_ASSERT (isp_3a.ptr ()); + _isp_content.copy (isp_3a->get_isp_config()); + } + break; + + case XCAM_3A_RESULT_WHITE_BALANCE: { + struct atomisp_wb_config wb; + SmartPtr<X3aWhiteBalanceResult> wb_res = + result.dynamic_cast_ptr<X3aWhiteBalanceResult> (); + XCAM_ASSERT (wb_res.ptr ()); + xcam_mem_clear (wb); + if (translator->translate_white_balance (wb_res->get_standard_result(), wb) + != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("translate white balance failed"); + return false; + } + _isp_content.wb = wb; + _isp_content.isp_config.wb_config = &_isp_content.wb; + } + break; + case XCAM_3A_RESULT_BLACK_LEVEL: { + struct atomisp_ob_config ob; + SmartPtr<X3aBlackLevelResult> bl_res = + result.dynamic_cast_ptr<X3aBlackLevelResult> (); + XCAM_ASSERT (bl_res.ptr ()); + xcam_mem_clear (ob); + if (translator->translate_black_level (bl_res->get_standard_result(), ob) + != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("translate black level failed"); + return false; + } + _isp_content.ob = ob; + _isp_content.isp_config.ob_config = &_isp_content.ob; + } + break; + case XCAM_3A_RESULT_YUV2RGB_MATRIX: + case XCAM_3A_RESULT_RGB2YUV_MATRIX: + { + struct atomisp_cc_config cc; + SmartPtr<X3aColorMatrixResult> cc_res = + result.dynamic_cast_ptr<X3aColorMatrixResult> (); + XCAM_ASSERT (cc_res.ptr ()); + xcam_mem_clear (cc); + if (translator->translate_color_matrix (cc_res->get_standard_result(), cc) + != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("translate color matrix failed"); + return false; + } + if (type == XCAM_3A_RESULT_YUV2RGB_MATRIX) { + _isp_content.yuv2rgb_cc = cc; + _isp_content.isp_config.yuv2rgb_cc_config = &_isp_content.yuv2rgb_cc; + } else { + _isp_content.rgb2yuv_cc = cc; + _isp_content.isp_config.rgb2yuv_cc_config = &_isp_content.rgb2yuv_cc; + } + } + break; + default: + return false; + } + + _3a_results.push_back (result); + return true; +} + +}; + diff --git a/modules/isp/x3a_isp_config.h b/modules/isp/x3a_isp_config.h new file mode 100644 index 0000000..e2ac024 --- /dev/null +++ b/modules/isp/x3a_isp_config.h @@ -0,0 +1,189 @@ +/* + * x3a_isp_config.h - 3A ISP config + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_3A_ISP_CONFIG_H +#define XCAM_3A_ISP_CONFIG_H + +#include <xcam_std.h> +#include <x3a_result.h> +#include <linux/atomisp.h> +#include <base/xcam_3a_result.h> + +namespace XCam { + +#define XCAM_3A_ISP_RESULT_TYPE_START (XCAM_3A_RESULT_USER_DEFINED_TYPE + 0x1000) + +struct AtomIspConfigContent { + struct atomisp_parameters isp_config; + //content + struct atomisp_wb_config wb; + struct atomisp_ob_config ob; //black level + struct atomisp_cc_config cc; + struct atomisp_cc_config yuv2rgb_cc; + struct atomisp_cc_config rgb2yuv_cc; + struct atomisp_nr_config nr; + struct atomisp_tnr_config tnr; + struct atomisp_ynr_config ynr; + struct atomisp_cnr_config cnr; + struct atomisp_anr_config anr; + struct atomisp_xnr_config xnr; + struct atomisp_xnr_table xnr_table; + struct atomisp_ee_config ee; + struct atomisp_dp_config dp; + struct atomisp_de_config de; + struct atomisp_ecd_config ecd_config; + struct atomisp_fc_config fc_config; + struct atomisp_ctc_config ctc_config; + struct atomisp_ctc_table ctc_table; + struct atomisp_macc_config macc_config; + struct atomisp_macc_table macc_table; + struct atomisp_gamma_table gamma_table; + struct atomisp_rgb_gamma_table r_gamma_table; + struct atomisp_rgb_gamma_table g_gamma_table; + struct atomisp_rgb_gamma_table b_gamma_table; + struct atomisp_gc_config gc_config; + struct atomisp_shading_table shading_table; + struct atomisp_3a_config a3a; + + struct atomisp_dvs_6axis_config dvs_6axis; + + + struct atomisp_formats_config formats; + struct atomisp_aa_config aa; + struct atomisp_aa_config baa; + struct atomisp_ce_config ce; + struct atomisp_morph_table morph_table; + struct atomisp_anr_thres anr_thres; + + struct atomisp_dz_config dz_config; + struct atomisp_vector motion_vector; + + void clear (); + void copy (const struct atomisp_parameters &config); + + AtomIspConfigContent () { + clear (); + } +}; + +class IspConfigTranslator; + +class X3aIspConfig +{ +public: + enum X3aIspConfigType { + IspAllParameters = XCAM_3A_ISP_RESULT_TYPE_START, + IspExposureParameters, + }; + + struct X3aIspResultDummy { + XCam3aResultHead head; + }; +public: + explicit X3aIspConfig (); + virtual ~X3aIspConfig(); + +public: + const struct atomisp_parameters &get_isp_configs () const { + return _isp_content.isp_config; + } + struct atomisp_parameters &get_isp_configs () { + return _isp_content.isp_config; + } + bool clear (); + bool attach (SmartPtr<X3aResult> &result, IspConfigTranslator *translator); + +private: + XCAM_DEAD_COPY (X3aIspConfig); + +protected: + AtomIspConfigContent _isp_content; + std::list< SmartPtr<X3aResult> > _3a_results; +}; + +template <typename IspConfig, typename StandardResult, uint32_t type> +class X3aIspResultT + : public X3aStandardResultT<StandardResult> +{ +public: + X3aIspResultT ( + XCamImageProcessType process_type = XCAM_IMAGE_PROCESS_ALWAYS + ) + : X3aStandardResultT<StandardResult> (type, process_type) + { + X3aResult::set_ptr((void*)&_isp_config); + } + + ~X3aIspResultT () {} + + // set config + void set_isp_config (IspConfig &config) { + _isp_config = config; + } + const IspConfig &get_isp_config () const { + return _isp_config; + } + +private: + IspConfig _isp_config; +}; + + +/* special X3aAtomIspParametersResult type */ +template <> +class X3aIspResultT<struct atomisp_parameters, X3aIspConfig::X3aIspResultDummy, X3aIspConfig::IspAllParameters> + : public X3aStandardResultT<X3aIspConfig::X3aIspResultDummy> + { +public: + X3aIspResultT ( + XCamImageProcessType process_type = XCAM_IMAGE_PROCESS_ALWAYS) + : X3aStandardResultT<X3aIspConfig::X3aIspResultDummy> ((uint32_t)X3aIspConfig::IspAllParameters, process_type) + { + X3aResult::set_ptr((void*)&_content.isp_config); + } + + ~X3aIspResultT () {} + + // get config + struct atomisp_parameters &get_isp_config () { + return _content.isp_config; + } + const struct atomisp_parameters &get_isp_config () const { + return _content.isp_config; + } + + // set config + void set_isp_config (struct atomisp_parameters &config) { + _content.copy (config); + } + +private: + AtomIspConfigContent _content; + }; + +typedef +X3aIspResultT<struct atomisp_parameters, X3aIspConfig::X3aIspResultDummy, X3aIspConfig::IspAllParameters> X3aAtomIspParametersResult; +typedef +X3aIspResultT<struct atomisp_exposure, XCam3aResultExposure, X3aIspConfig::IspExposureParameters> X3aIspExposureResult; + +}; + +#endif //XCAM_3A_ISP_CONFIG_H + diff --git a/modules/isp/x3a_statistics_queue.cpp b/modules/isp/x3a_statistics_queue.cpp new file mode 100644 index 0000000..787cdde --- /dev/null +++ b/modules/isp/x3a_statistics_queue.cpp @@ -0,0 +1,256 @@ +/* + * x3a_statistics_queue.c - statistics queue + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "x3a_statistics_queue.h" +#include <linux/videodev2.h> +#include <linux/atomisp.h> +#include <math.h> + +namespace XCam { + +X3aIspStatsData::X3aIspStatsData (struct atomisp_3a_statistics *isp_data, XCam3AStats *data) + : X3aStatsData (data) + , _isp_data (isp_data) +{ + XCAM_ASSERT (_isp_data); +} + +X3aIspStatsData::~X3aIspStatsData () +{ + if (_isp_data) { + if (_isp_data->data) + xcam_free (_isp_data->data); + if (_isp_data->rgby_data) + xcam_free (_isp_data->rgby_data); + xcam_free (_isp_data); + } +} + +bool +X3aIspStatsData::fill_standard_stats () +{ + XCam3AStats *standard_stats = get_stats (); + + XCAM_ASSERT (_isp_data && _isp_data->data); + XCAM_ASSERT (standard_stats); + XCAM_FAIL_RETURN ( + WARNING, + _isp_data && _isp_data->data && standard_stats, + false, + "X3aIspStatsData fill standard stats failed with null data allocated"); + + const struct atomisp_grid_info &isp_info = _isp_data->grid_info; + const XCam3AStatsInfo &standard_info = standard_stats->info; + const struct atomisp_3a_output *isp_data = _isp_data->data; + XCamGridStat *standard_data = standard_stats->stats; + uint32_t pixel_count = isp_info.bqs_per_grid_cell * isp_info.bqs_per_grid_cell; + uint32_t bit_shift = isp_info.elem_bit_depth - 8; + + XCAM_ASSERT (isp_info.width == standard_info.width); + XCAM_ASSERT (isp_info.height == standard_info.height); + for (uint32_t i = 0; i < isp_info.height; ++i) { + for (uint32_t j = 0; j < isp_info.width; ++j) { + standard_data[i * standard_info.aligned_width + j].avg_y = + ((isp_data[i * isp_info.aligned_width + j].ae_y / pixel_count) >> bit_shift); + standard_data[i * standard_info.aligned_width + j].avg_r = + ((isp_data[i * isp_info.aligned_width + j].awb_r / pixel_count) >> bit_shift); + standard_data[i * standard_info.aligned_width + j].avg_gr = + ((isp_data[i * isp_info.aligned_width + j].awb_gr / pixel_count) >> bit_shift); + standard_data[i * standard_info.aligned_width + j].avg_gb = + ((isp_data[i * isp_info.aligned_width + j].awb_gb / pixel_count) >> bit_shift); + standard_data[i * standard_info.aligned_width + j].avg_b = + ((isp_data[i * isp_info.aligned_width + j].awb_b / pixel_count) >> bit_shift); + standard_data[i * standard_info.aligned_width + j].valid_wb_count = + isp_data[i * isp_info.aligned_width + j].awb_cnt; + standard_data[i * standard_info.aligned_width + j].f_value1 = + ((isp_data[i * isp_info.aligned_width + j].af_hpf1 / pixel_count) >> bit_shift); + standard_data[i * standard_info.aligned_width + j].f_value2 = + ((isp_data[i * isp_info.aligned_width + j].af_hpf2 / pixel_count) >> bit_shift); + } + } + + if (isp_info.has_histogram) { + uint32_t hist_bins = standard_info.histogram_bins; + // TODO: atom isp hard code histogram to 256 bins + XCAM_ASSERT (hist_bins == 256); + + XCamHistogram *hist_rgb = standard_stats->hist_rgb; + uint32_t *hist_y = standard_stats->hist_y; + const struct atomisp_3a_rgby_output *isp_hist = _isp_data->rgby_data; + for (uint32_t i = 0; i < hist_bins; i++) { + hist_rgb[i].r = isp_hist[i].r; + hist_rgb[i].gr = isp_hist[i].g; + hist_rgb[i].gb = isp_hist[i].g; + hist_rgb[i].b = isp_hist[i].b; + hist_y[i] = isp_hist[i].y; + } + } + + return true; +} + +X3aIspStatistics::X3aIspStatistics (const SmartPtr<X3aIspStatsData> &stats_data) + : X3aStats (SmartPtr<X3aStatsData> (stats_data)) +{ +} + +X3aIspStatistics::~X3aIspStatistics () +{ +} + +struct atomisp_3a_statistics * +X3aIspStatistics::get_isp_stats () +{ + SmartPtr<X3aIspStatsData> stats = get_buffer_data ().dynamic_cast_ptr<X3aIspStatsData> (); + + XCAM_FAIL_RETURN( + WARNING, + stats.ptr(), + NULL, + "X3aIspStatistics get_stats failed with NULL"); + + return stats->get_isp_stats (); +} + +bool +X3aIspStatistics::fill_standard_stats () +{ + SmartPtr<X3aIspStatsData> stats = get_buffer_data ().dynamic_cast_ptr<X3aIspStatsData> (); + + XCAM_FAIL_RETURN( + WARNING, + stats.ptr(), + false, + "X3aIspStatistics fill standard stats failed with NULL stats data"); + + return stats->fill_standard_stats (); +} + +X3aStatisticsQueue::X3aStatisticsQueue() +{ + xcam_mem_clear (_grid_info); +} + +X3aStatisticsQueue::~X3aStatisticsQueue() +{ +} + +void +X3aStatisticsQueue::set_grid_info (const struct atomisp_grid_info &info) +{ + XCam3AStatsInfo stats_info; + + xcam_mem_clear (stats_info); + _grid_info = info; + + stats_info.width = info.width; + stats_info.height = info.height; + stats_info.aligned_width = info.aligned_width; + stats_info.aligned_height = info.aligned_height; + stats_info.grid_pixel_size = info.bqs_per_grid_cell * 2; + stats_info.bit_depth = 8; + stats_info.histogram_bins = 256; + + set_stats_info (stats_info); +} + +struct atomisp_3a_statistics * +X3aStatisticsQueue::alloc_isp_statsictics () +{ + XCAM_ASSERT (_grid_info.width && _grid_info.height); + XCAM_ASSERT (_grid_info.aligned_width && _grid_info.aligned_height); + + uint32_t grid_size = _grid_info.aligned_width * _grid_info.aligned_height; + //uint32_t grid_size = _grid_info.width * _grid_info.height; + + struct atomisp_3a_statistics *stats = xcam_malloc0_type (struct atomisp_3a_statistics); + XCAM_ASSERT (stats); + stats->data = (struct atomisp_3a_output*)xcam_malloc0 (grid_size * sizeof(*stats->data)); + XCAM_ASSERT (stats->data); + if (!stats || !stats->data) + return NULL; + + if (_grid_info.has_histogram) { + // TODO: atom isp hard code histogram to 256 bins + stats->rgby_data = + (struct atomisp_3a_rgby_output*)xcam_malloc0 (256 * sizeof(*stats->rgby_data)); + XCAM_ASSERT (stats->rgby_data); + if (!stats->rgby_data) + return NULL; + } + + stats->grid_info = _grid_info; + return stats; +} + +bool +X3aStatisticsQueue::fixate_video_info (VideoBufferInfo &info) +{ + X3aStatsPool::fixate_video_info (info); + + XCam3AStatsInfo &stats_info = get_stats_info (); + + _grid_info.enable = 1; + _grid_info.use_dmem = 0; + _grid_info.has_histogram = 0; + _grid_info.width = stats_info.width; + _grid_info.height = stats_info.height; + _grid_info.aligned_width = stats_info.aligned_width; + _grid_info.aligned_height = stats_info.aligned_height; + _grid_info.bqs_per_grid_cell = stats_info.grid_pixel_size / 2; + _grid_info.deci_factor_log2 = (uint32_t)log2 (_grid_info.bqs_per_grid_cell); + _grid_info.elem_bit_depth = stats_info.bit_depth; + + return X3aStatsPool::fixate_video_info (info); +} + +SmartPtr<BufferData> +X3aStatisticsQueue::allocate_data (const VideoBufferInfo &buffer_info) +{ + XCAM_UNUSED (buffer_info); + + XCam3AStats *stats = NULL; + XCam3AStatsInfo stats_info = get_stats_info (); + struct atomisp_3a_statistics *isp_stats = alloc_isp_statsictics (); + + stats = (XCam3AStats *) xcam_malloc0 ( + sizeof (XCam3AStats) + + sizeof (XCamHistogram) * stats_info.histogram_bins + + sizeof (uint32_t) * stats_info.histogram_bins + + sizeof (XCamGridStat) * stats_info.aligned_width * stats_info.aligned_height); + XCAM_ASSERT (isp_stats && stats); + stats->info = stats_info; + stats->hist_rgb = (XCamHistogram *) (stats->stats + + stats_info.aligned_width * stats_info.aligned_height); + stats->hist_y = (uint32_t *) (stats->hist_rgb + stats_info.histogram_bins); + + return new X3aIspStatsData (isp_stats, stats); +} + +SmartPtr<BufferProxy> +X3aStatisticsQueue::create_buffer_from_data (SmartPtr<BufferData> &data) +{ + SmartPtr<X3aIspStatsData> stats_data = data.dynamic_cast_ptr<X3aIspStatsData> (); + XCAM_ASSERT (stats_data.ptr ()); + + return new X3aIspStatistics (stats_data); +} + +}; diff --git a/modules/isp/x3a_statistics_queue.h b/modules/isp/x3a_statistics_queue.h new file mode 100644 index 0000000..9f94dc7 --- /dev/null +++ b/modules/isp/x3a_statistics_queue.h @@ -0,0 +1,101 @@ +/* + * x3a_statistics_queue.h - statistics queue + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_3A_STATISTIC_QUEUE_H +#define XCAM_3A_STATISTIC_QUEUE_H + +#include <xcam_std.h> +#include <xcam_mutex.h> +#include <x3a_stats_pool.h> +#include <linux/atomisp.h> + +namespace XCam { + +class X3aStatisticsQueue; + +class X3aIspStatsData + : public X3aStatsData +{ +public: + explicit X3aIspStatsData (struct atomisp_3a_statistics *isp_data, XCam3AStats *data); + ~X3aIspStatsData (); + struct atomisp_3a_statistics *get_isp_stats () { + return _isp_data; + } + + virtual uint8_t *map () { + return (uint8_t*)(void*)(_isp_data); + } + virtual bool unmap () { + return true; + } + + bool fill_standard_stats (); + +private: + XCAM_DEAD_COPY (X3aIspStatsData); + +private: + struct atomisp_3a_statistics *_isp_data; +}; + +class X3aIspStatistics + : public X3aStats +{ + friend class X3aStatisticsQueue; +protected: + explicit X3aIspStatistics (const SmartPtr<X3aIspStatsData> &stats_data); + +public: + virtual ~X3aIspStatistics (); + struct atomisp_3a_statistics *get_isp_stats (); + + bool fill_standard_stats (); + +private: + XCAM_DEAD_COPY (X3aIspStatistics); +}; + +class X3aStatisticsQueue + : public X3aStatsPool +{ +public: + explicit X3aStatisticsQueue (); + ~X3aStatisticsQueue(); + + void set_grid_info (const struct atomisp_grid_info &info); + +protected: + virtual bool fixate_video_info (VideoBufferInfo &info); + virtual SmartPtr<BufferData> allocate_data (const VideoBufferInfo &buffer_info); + virtual SmartPtr<BufferProxy> create_buffer_from_data (SmartPtr<BufferData> &data); + + +private: + struct atomisp_3a_statistics *alloc_isp_statsictics (); + XCAM_DEAD_COPY (X3aStatisticsQueue); + +private: + struct atomisp_grid_info _grid_info; +}; + +}; + +#endif //XCAM_3A_STATISTIC_QUEUE_H diff --git a/modules/isp/xcam_cpf_reader.c b/modules/isp/xcam_cpf_reader.c new file mode 100644 index 0000000..048ff6b --- /dev/null +++ b/modules/isp/xcam_cpf_reader.c @@ -0,0 +1,167 @@ +/* + * xcam_thread.h - xcam basic thread + * + * Copyright (c) 2014 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + + +#include "xcam_cpf_reader.h" + +#include <string.h> +#include <stdlib.h> +#include "libtbd.h" + +#undef XCAM_FAIL_RETURN_VAL +#define XCAM_FAIL_RETURN_VAL(exp, ret) \ + if (!(exp)) { \ + XCAM_LOG_WARNING ("XCAM_FAIL_RETURN_VAL %s", #exp); \ + return ret; \ + } + +#undef XCAM_FAIL_RETURN +#define XCAM_FAIL_RETURN(exp) \ + if (!(exp)) { \ + XCAM_LOG_WARNING ("XCAM_FAIL_RETURN %s", #exp); \ + return ; \ + } + +void *xcam_new0(size_t size) +{ + void *buf = malloc (size); + memset (buf, 0, size); + return buf; +} + +XCamCpfBlob * xcam_cpf_blob_new () +{ + return (XCamCpfBlob*) xcam_new0 (sizeof(XCamCpfBlob)); +} + +void xcam_cpf_blob_free (XCamCpfBlob *blob) +{ + XCAM_FAIL_RETURN (blob); + + if (blob->data) + xcam_free (blob->data); + + xcam_free (blob); +} + +static int32_t +read_cpf_file (const char *cpf_file, uint8_t **buf) +{ + int32_t size = 0; + FILE *fp = fopen (cpf_file, "rb"); + XCAM_FAIL_RETURN_VAL (fp, -1); + + *buf = NULL; + + if (fseek (fp, 0, SEEK_END) < 0) + goto read_error; + if ((size = ftell (fp)) <= 0) + goto read_error; + if (fseek( fp, 0, SEEK_SET) < 0) + goto read_error; + + *buf = (uint8_t*) xcam_new0 (size); + XCAM_ASSERT (*buf); + if (fread (*buf, 1, size, fp) != (size_t) size) + goto read_error; + + fclose (fp); + return size; + +read_error: + XCAM_LOG_ERROR ("read cpf(%s) failed", cpf_file); + fclose (fp); + if (*buf) { + xcam_free (*buf); + *buf = NULL; + } + return -1; + +} + +boolean +xcam_cpf_read (const char *cpf_file, XCamCpfBlob *aiq_cpf, XCamCpfBlob *hal_cpf) +{ + uint8_t *cpf_buf; + int32_t cpf_size; + + uint8_t *blob; + uint32_t blob_size; + + XCAM_FAIL_RETURN_VAL (cpf_file, FALSE); + XCAM_FAIL_RETURN_VAL (aiq_cpf, FALSE); + + /* read cpf */ + if ((cpf_size = read_cpf_file(cpf_file, &cpf_buf)) <= 0) { + XCAM_LOG_ERROR ("read cpf_file(%s) failed.", cpf_file); + return FALSE; + } + + /* check sum */ + if (tbd_validate (cpf_buf, cpf_size, tbd_tag_cpff) != tbd_err_none) { + XCAM_LOG_ERROR ("tbd validate cpf file(%s) failed.", cpf_file); + goto free_buf; + } + + /* fetch AIQ */ + if ( (tbd_get_record (cpf_buf, tbd_class_aiq, tbd_format_any, + (void**)&blob, &blob_size) != tbd_err_none) || + !blob || blob_size <= 0) { + XCAM_LOG_ERROR ("CPF parse AIQ record failed."); + goto free_buf; + } + aiq_cpf->data = (uint8_t*) malloc (blob_size); + XCAM_ASSERT (aiq_cpf->data); + aiq_cpf->size = blob_size; + memcpy (aiq_cpf->data, blob, blob_size); + + +#if 0 //DRV not necessary + /* fetch DRV */ + if (tbd_get_record (cpf_buf, tbd_class_drv, tbd_format_any, + &drv_blob.data, &drv_blob.size) != tbd_err_none) { + XCAM_LOG_ERROR ("CPF parse DRV record failed."); + return FALSE; + } +#endif + + + /* fetch HAL */ + if (hal_cpf) { + if (tbd_get_record (cpf_buf, tbd_class_hal, tbd_format_any, + (void**)&blob, &blob_size) != tbd_err_none) { + XCAM_LOG_WARNING ("CPF doesn't have HAL record."); + // ignore HAL, not necessary + } else if (blob && blob_size > 0) { + hal_cpf->data = (uint8_t*) malloc (blob_size); + XCAM_ASSERT (hal_cpf->data); + hal_cpf->size = blob_size; + memcpy (hal_cpf->data, blob, blob_size); + } + } + + xcam_free (cpf_buf); + return TRUE; + +free_buf: + xcam_free (cpf_buf); + return FALSE; + +} diff --git a/modules/isp/xcam_cpf_reader.h b/modules/isp/xcam_cpf_reader.h new file mode 100644 index 0000000..ae7d721 --- /dev/null +++ b/modules/isp/xcam_cpf_reader.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +/* + * \file xcam_cpf_reader.h + * \brief xcam CPF reader +*/ + +#ifndef _XCAM_CPF_READER_H +#define _XCAM_CPF_READER_H + +#include <base/xcam_common.h> +#include <stdint.h> +#include <string.h> +#include <stddef.h> + +XCAM_BEGIN_DECLARE + + +typedef int boolean; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +typedef struct _XCamCpfBlob XCamCpfBlob; + +/*! \brief CPF blob + */ +struct _XCamCpfBlob { + uint8_t *data; /*!< pointer to buffer*/ + uint32_t size; /*!< buffer size*/ +}; + +/*! \brief XCam CPF blob allocation. + * buffer is initialized to zero + * + * \return pointer to XCam CPF Blob + */ +XCamCpfBlob * xcam_cpf_blob_new (); + +/*! \brief XCam CPF blob release. + * release the blob structure as well as the buffer inside it. + * + * \param[in,out] pointer to XCam CPF Blob + */ +void xcam_cpf_blob_free (XCamCpfBlob *blob); + +/*! \brief XCam CPF blob release. + * release the blob structure as well as the buffer inside it. Called in xcam_3a_init(). + * + * \param[in] cpf_file CPF file name + * \param[out] aiq_cpf pointer to XCam CPF Blob which will hold AIQ records + * \param[out] hal_cpf pointer to XCam CPF HAL which will hold HAL records + */ +boolean xcam_cpf_read (const char *cpf_file, XCamCpfBlob *aiq_cpf, XCamCpfBlob *hal_cpf); + +XCAM_END_DECLARE + +#endif //_XCAM_CPF_READER_H diff --git a/modules/ocl/Makefile.am b/modules/ocl/Makefile.am new file mode 100644 index 0000000..dc09d6d --- /dev/null +++ b/modules/ocl/Makefile.am @@ -0,0 +1,175 @@ +lib_LTLIBRARIES = libxcam_ocl.la + +XCAMOCL_CXXFLAGS = $(XCAM_CXXFLAGS) +XCAMOCL_LIBS = -ldl \ + $(NULL) + +XCAMOCL_CXXFLAGS += \ + $(LIBCL_CFLAGS) \ + -I$(top_srcdir)/xcore \ + -I$(top_srcdir)/modules \ + -I$(top_builddir)/clx_kernel \ + $(NULL) + +XCAMOCL_LIBS += \ + $(LIBCL_LIBS) \ + $(NULL) + +if HAVE_LIBDRM +XCAMOCL_CXXFLAGS += $(LIBDRM_CFLAGS) +XCAMOCL_LIBS += \ + -ldrm_intel \ + $(LIBDRM_LIBS) \ + $(NULL) +endif + +if HAVE_OPENCV +XCAMOCL_CXXFLAGS += $(OPENCV_CFLAGS) +XCAMOCL_LIBS += $(OPENCV_LIBS) +endif + +xcam_ocl_sources = \ + cl_argument.cpp \ + cl_context.cpp \ + cl_device.cpp \ + cl_kernel.cpp \ + cl_memory.cpp \ + cl_event.cpp \ + cl_utils.cpp \ + cl_image_handler.cpp \ + cl_image_processor.cpp \ + cl_3a_image_processor.cpp \ + cl_post_image_processor.cpp \ + cl_multi_image_handler.cpp \ + cl_csc_image_processor.cpp \ + cl_3a_stats_context.cpp \ + cl_demo_handler.cpp \ + cl_blender.cpp \ + cl_pyramid_blender.cpp \ + cl_geo_map_handler.cpp \ + cl_csc_handler.cpp \ + cl_tnr_handler.cpp \ + cl_defog_dcp_handler.cpp \ + cl_bayer_pipe_handler.cpp \ + cl_bayer_basic_handler.cpp \ + cl_yuv_pipe_handler.cpp \ + cl_rgb_pipe_handler.cpp \ + cl_tonemapping_handler.cpp \ + cl_newtonemapping_handler.cpp \ + cl_fisheye_handler.cpp \ + cl_image_scaler.cpp \ + cl_image_360_stitch.cpp \ + cl_retinex_handler.cpp \ + cl_gauss_handler.cpp \ + cl_wavelet_denoise_handler.cpp \ + cl_newwavelet_denoise_handler.cpp \ + cl_wire_frame_handler.cpp \ + cl_3d_denoise_handler.cpp \ + cl_image_warp_handler.cpp \ + cl_video_stabilizer.cpp \ + cl_video_buffer.cpp \ + priority_buffer_queue.cpp \ + $(NULL) + +if HAVE_OPENCV +xcam_ocl_sources += cv_context.cpp +xcam_ocl_sources += cv_base_class.cpp +xcam_ocl_sources += cv_image_process_helper.cpp +xcam_ocl_sources += cv_image_sharp.cpp +xcam_ocl_sources += cv_edgetaper.cpp +xcam_ocl_sources += cv_wiener_filter.cpp +xcam_ocl_sources += cv_feature_match.cpp +xcam_ocl_sources += cv_image_deblurring.cpp +endif + +if HAVE_LIBDRM +xcam_ocl_sources += intel/cl_intel_context.cpp +xcam_ocl_sources += intel/cl_va_memory.cpp +xcam_ocl_sources += cl_image_bo_buffer.cpp +endif + +libxcam_ocl_la_SOURCES = \ + $(xcam_ocl_sources) \ + $(NULL) + +libxcam_ocl_la_CXXFLAGS = \ + $(XCAMOCL_CXXFLAGS) \ + $(NULL) + +libxcam_ocl_la_LIBADD = \ + $(top_builddir)/xcore/libxcam_core.la \ + $(XCAMOCL_LIBS) \ + $(NULL) + +libxcam_ocl_la_LDFLAGS = \ + $(XCAM_LT_LDFLAGS) \ + $(PTHREAD_LDFLAGS) \ + $(NULL) + +libxcam_oclincludedir = $(includedir)/xcam/ocl + +nobase_libxcam_oclinclude_HEADERS = \ + cl_argument.h \ + cl_context.h \ + cl_event.h \ + cl_device.h \ + cl_memory.h \ + cl_kernel.h \ + cl_utils.h \ + cl_image_handler.h \ + cl_image_processor.h \ + priority_buffer_queue.h \ + cl_3a_image_processor.h \ + cl_3a_stats_context.h \ + cl_rgb_pipe_handler.h \ + cl_bayer_basic_handler.h \ + cl_bayer_pipe_handler.h \ + cl_demo_handler.h \ + cl_tonemapping_handler.h \ + cl_newtonemapping_handler.h \ + cl_csc_handler.h \ + cl_csc_image_processor.h \ + cl_yuv_pipe_handler.h \ + cl_tnr_handler.h \ + cl_post_image_processor.h \ + cl_multi_image_handler.h \ + cl_3d_denoise_handler.h \ + cl_defog_dcp_handler.h \ + cl_fisheye_handler.h \ + cl_gauss_handler.h \ + cl_geo_map_handler.h \ + cl_image_scaler.h \ + cl_image_warp_handler.h \ + cl_image_360_stitch.h \ + cl_blender.h \ + cl_retinex_handler.h \ + cl_wavelet_denoise_handler.h \ + cl_newwavelet_denoise_handler.h \ + cl_wire_frame_handler.h \ + cl_video_stabilizer.h \ + cl_video_buffer.h \ + $(NULL) + +if HAVE_OPENCV +nobase_libxcam_oclinclude_HEADERS += cv_context.h +nobase_libxcam_oclinclude_HEADERS += cv_base_class.h +nobase_libxcam_oclinclude_HEADERS += cv_image_process_helper.h +nobase_libxcam_oclinclude_HEADERS += cv_image_sharp.h +nobase_libxcam_oclinclude_HEADERS += cv_edgetaper.h +nobase_libxcam_oclinclude_HEADERS += cv_wiener_filter.h +nobase_libxcam_oclinclude_HEADERS += cv_feature_match.h +nobase_libxcam_oclinclude_HEADERS += cv_image_deblurring.h +endif + +if HAVE_LIBDRM +nobase_libxcam_oclinclude_HEADERS += intel/cl_intel_context.h +nobase_libxcam_oclinclude_HEADERS += intel/cl_va_memory.h +nobase_libxcam_oclinclude_HEADERS += cl_image_bo_buffer.h +endif + +noinst_HEADERS = \ + cl_pyramid_blender.h \ + $(NULL) + + +libxcam_ocl_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/modules/ocl/cl_3a_image_processor.cpp b/modules/ocl/cl_3a_image_processor.cpp new file mode 100644 index 0000000..7399c76 --- /dev/null +++ b/modules/ocl/cl_3a_image_processor.cpp @@ -0,0 +1,489 @@ +/* + * cl_3a_image_processor.cpp - CL 3A image processor + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ +#include "cl_3a_image_processor.h" +#include "cl_context.h" +#include "cl_csc_handler.h" +#include "cl_bayer_pipe_handler.h" +#include "cl_yuv_pipe_handler.h" +#if ENABLE_YEENR_HANDLER +#include "cl_ee_handler.h" +#endif +#include "cl_tnr_handler.h" +#include "cl_tonemapping_handler.h" +#include "cl_newtonemapping_handler.h" +#include "cl_bayer_basic_handler.h" + +#define XCAM_CL_3A_IMAGE_MAX_POOL_SIZE 6 + +namespace XCam { + +CL3aImageProcessor::CL3aImageProcessor () + : CLImageProcessor ("CL3aImageProcessor") + , _output_fourcc (V4L2_PIX_FMT_NV12) + , _3a_stats_bits (8) + , _pipeline_profile (BasicPipelineProfile) + , _capture_stage (TonemappingStage) + , _wdr_mode (WDRdisabled) + , _tnr_mode (0) + , _enable_gamma (true) + , _enable_macc (true) + , _snr_mode (0) +{ + keep_attached_buf (true); + XCAM_LOG_DEBUG ("CL3aImageProcessor constructed"); +} + +CL3aImageProcessor::~CL3aImageProcessor () +{ + XCAM_LOG_DEBUG ("CL3aImageProcessor destructed"); +} + +void +CL3aImageProcessor::set_stats_callback (const SmartPtr<StatsCallback> &callback) +{ + XCAM_ASSERT (callback.ptr ()); + _stats_callback = callback; +} + +bool +CL3aImageProcessor::set_output_format (uint32_t fourcc) +{ + XCAM_FAIL_RETURN ( + WARNING, + V4L2_PIX_FMT_NV12 == fourcc, + false, + "cl 3a processor doesn't support output format: %s", + xcam_fourcc_to_string (fourcc)); + + _output_fourcc = fourcc; + return true; +} + +bool +CL3aImageProcessor::set_capture_stage (CaptureStage capture_stage) +{ + _capture_stage = capture_stage; + return true; +} + +bool +CL3aImageProcessor::set_3a_stats_bits (uint32_t bits) +{ + switch (bits) { + case 8: + case 12: + _3a_stats_bits = bits; + break; + default: + XCAM_LOG_WARNING ("cl image processor 3a stats doesn't support %d-bits", bits); + return false; + } + return true; +} + +bool +CL3aImageProcessor::can_process_result (SmartPtr<X3aResult> &result) +{ + if (result.ptr() == NULL) + return false; + switch (result->get_type ()) { + case XCAM_3A_RESULT_WHITE_BALANCE: + case XCAM_3A_RESULT_BLACK_LEVEL: + case XCAM_3A_RESULT_R_GAMMA: + case XCAM_3A_RESULT_G_GAMMA: + case XCAM_3A_RESULT_B_GAMMA: + case XCAM_3A_RESULT_RGB2YUV_MATRIX: + case XCAM_3A_RESULT_DEFECT_PIXEL_CORRECTION: + case XCAM_3A_RESULT_MACC: + case XCAM_3A_RESULT_BAYER_NOISE_REDUCTION: + case XCAM_3A_RESULT_BRIGHTNESS: + case XCAM_3A_RESULT_3D_NOISE_REDUCTION: + case XCAM_3A_RESULT_TEMPORAL_NOISE_REDUCTION_YUV: + case XCAM_3A_RESULT_EDGE_ENHANCEMENT: + return true; + + default: + return false; + } + + return false; +} + +XCamReturn +CL3aImageProcessor::apply_3a_results (X3aResultList &results) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + for (X3aResultList::iterator iter = results.begin (); iter != results.end (); ++iter) + { + SmartPtr<X3aResult> &result = *iter; + ret = apply_3a_result (result); + if (ret != XCAM_RETURN_NO_ERROR) + break; + } + return ret; +} + +XCamReturn +CL3aImageProcessor::apply_3a_result (SmartPtr<X3aResult> &result) +{ + STREAM_LOCK; + + if (result.ptr() == NULL) + return XCAM_RETURN_BYPASS; + + uint32_t res_type = result->get_type (); + + switch (res_type) { + case XCAM_3A_RESULT_WHITE_BALANCE: { + SmartPtr<X3aWhiteBalanceResult> wb_res = result.dynamic_cast_ptr<X3aWhiteBalanceResult> (); + XCAM_ASSERT (wb_res.ptr ()); + if (_bayer_basic_pipe.ptr ()) { + _bayer_basic_pipe->set_wb_config (wb_res->get_standard_result ()); + _bayer_basic_pipe->set_3a_result (result); + } + break; + } + + case XCAM_3A_RESULT_BLACK_LEVEL: { + SmartPtr<X3aBlackLevelResult> bl_res = result.dynamic_cast_ptr<X3aBlackLevelResult> (); + XCAM_ASSERT (bl_res.ptr ()); + if (_bayer_basic_pipe.ptr ()) { + _bayer_basic_pipe->set_blc_config (bl_res->get_standard_result ()); + _bayer_basic_pipe->set_3a_result (result); + } + break; + } + + case XCAM_3A_RESULT_DEFECT_PIXEL_CORRECTION: { + SmartPtr<X3aDefectPixelResult> def_res = result.dynamic_cast_ptr<X3aDefectPixelResult> (); + XCAM_ASSERT (def_res.ptr ()); + XCAM_UNUSED (def_res); + break; + } + + case XCAM_3A_RESULT_RGB2YUV_MATRIX: { + SmartPtr<X3aColorMatrixResult> csc_res = result.dynamic_cast_ptr<X3aColorMatrixResult> (); + XCAM_ASSERT (csc_res.ptr ()); + if (_csc.ptr()) { + _csc->set_matrix (csc_res->get_standard_result ()); + _csc->set_3a_result (result); + } + if (_yuv_pipe.ptr()) { + _yuv_pipe->set_rgbtoyuv_matrix (csc_res->get_standard_result ()); + _yuv_pipe->set_3a_result (result); + } + break; + } + + case XCAM_3A_RESULT_MACC: { + SmartPtr<X3aMaccMatrixResult> macc_res = result.dynamic_cast_ptr<X3aMaccMatrixResult> (); + XCAM_ASSERT (macc_res.ptr ()); + if (_yuv_pipe.ptr()) { + _yuv_pipe->set_macc_table (macc_res->get_standard_result ()); + _yuv_pipe->set_3a_result (result); + } + break; + } + case XCAM_3A_RESULT_R_GAMMA: + case XCAM_3A_RESULT_B_GAMMA: + break; + + case XCAM_3A_RESULT_G_GAMMA: + case XCAM_3A_RESULT_Y_GAMMA: { + SmartPtr<X3aGammaTableResult> gamma_res = result.dynamic_cast_ptr<X3aGammaTableResult> (); + XCAM_ASSERT (gamma_res.ptr ()); + if (_bayer_basic_pipe.ptr ()) { + _bayer_basic_pipe->set_gamma_table (gamma_res->get_standard_result ()); + _bayer_basic_pipe->set_3a_result (result); + } + break; + } + + case XCAM_3A_RESULT_3D_NOISE_REDUCTION: { + SmartPtr<X3aTemporalNoiseReduction> nr_res = result.dynamic_cast_ptr<X3aTemporalNoiseReduction> (); + XCAM_ASSERT (nr_res.ptr ()); + XCAM_UNUSED (nr_res); + + break; + } + + case XCAM_3A_RESULT_TEMPORAL_NOISE_REDUCTION_YUV: { + SmartPtr<X3aTemporalNoiseReduction> tnr_res = result.dynamic_cast_ptr<X3aTemporalNoiseReduction> (); + XCAM_ASSERT (tnr_res.ptr ()); + if (_yuv_pipe.ptr ()) { + _yuv_pipe->set_tnr_yuv_config(tnr_res->get_standard_result ()); + _yuv_pipe->set_3a_result (result); + } + break; + } + + case XCAM_3A_RESULT_EDGE_ENHANCEMENT: { + SmartPtr<X3aEdgeEnhancementResult> ee_ee_res = result.dynamic_cast_ptr<X3aEdgeEnhancementResult> (); + XCAM_ASSERT (ee_ee_res.ptr ()); + if (_bayer_pipe.ptr()) { + _bayer_pipe->set_ee_config (ee_ee_res->get_standard_result ()); + _bayer_pipe->set_3a_result (result); + } +#if ENABLE_YEENR_HANDLER + if (_ee.ptr()) { + _ee->set_ee_config_ee (ee_ee_res->get_standard_result ()); + _ee->set_3a_result (result); + } +#endif + break; + } + + case XCAM_3A_RESULT_BAYER_NOISE_REDUCTION: { + SmartPtr<X3aBayerNoiseReduction> bnr_res = result.dynamic_cast_ptr<X3aBayerNoiseReduction> (); + XCAM_ASSERT (bnr_res.ptr ()); + if (_bayer_pipe.ptr()) { + _bayer_pipe->set_bnr_config (bnr_res->get_standard_result ()); + _bayer_pipe->set_3a_result (result); + } + + break; + } + + case XCAM_3A_RESULT_BRIGHTNESS: { + SmartPtr<X3aBrightnessResult> brightness_res = result.dynamic_cast_ptr<X3aBrightnessResult> (); + XCAM_ASSERT (brightness_res.ptr ()); + float brightness_level = ((XCam3aResultBrightness)brightness_res->get_standard_result()).brightness_level; + XCAM_UNUSED (brightness_level); + break; + } + + default: + XCAM_LOG_WARNING ("CL3aImageProcessor unknown 3a result:%d", res_type); + break; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CL3aImageProcessor::create_handlers () +{ + SmartPtr<CLImageHandler> image_handler; + SmartPtr<CLContext> context = get_cl_context (); + + XCAM_ASSERT (context.ptr ()); + + /* bayer pipeline */ + image_handler = create_cl_bayer_basic_image_handler (context, _enable_gamma, _3a_stats_bits); + _bayer_basic_pipe = image_handler.dynamic_cast_ptr<CLBayerBasicImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _bayer_basic_pipe.ptr (), + XCAM_RETURN_ERROR_CL, + "CL3aImageProcessor create bayer basic pipe handler failed"); + image_handler->set_pool_size (XCAM_CL_3A_IMAGE_MAX_POOL_SIZE); + _bayer_basic_pipe->set_stats_callback (_stats_callback); + add_handler (image_handler); + + /* tone mapping */ + switch(_wdr_mode) { + case Gaussian: { + image_handler = create_cl_tonemapping_image_handler (context); + _tonemapping = image_handler.dynamic_cast_ptr<CLTonemappingImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _tonemapping.ptr (), + XCAM_RETURN_ERROR_CL, + "CL3aImageProcessor create tonemapping handler failed"); + _tonemapping->enable_handler (true); + image_handler->set_pool_size (XCAM_CL_3A_IMAGE_MAX_POOL_SIZE); + add_handler (image_handler); + break; + } + case Haleq: { + image_handler = create_cl_newtonemapping_image_handler (context); + _newtonemapping = image_handler.dynamic_cast_ptr<CLNewTonemappingImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _newtonemapping.ptr (), + XCAM_RETURN_ERROR_CL, + "CL3aImageProcessor create tonemapping handler failed"); + _newtonemapping->enable_handler (true); + image_handler->set_pool_size (XCAM_CL_3A_IMAGE_MAX_POOL_SIZE); + add_handler (image_handler); + break; + } + default: + XCAM_LOG_DEBUG ("WDR disabled"); + break; + } + + /* bayer pipe */ + image_handler = create_cl_bayer_pipe_image_handler (context); + _bayer_pipe = image_handler.dynamic_cast_ptr<CLBayerPipeImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + image_handler.ptr (), + XCAM_RETURN_ERROR_CL, + "CL3aImageProcessor create bayer pipe handler failed"); + + _bayer_pipe->enable_denoise (XCAM_DENOISE_TYPE_BNR & _snr_mode); + image_handler->set_pool_size (XCAM_CL_3A_IMAGE_MAX_POOL_SIZE * 2); + add_handler (image_handler); + if(_capture_stage == BasicbayerStage) + return XCAM_RETURN_NO_ERROR; + + image_handler = create_cl_yuv_pipe_image_handler (context); + _yuv_pipe = image_handler.dynamic_cast_ptr<CLYuvPipeImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _yuv_pipe.ptr (), + XCAM_RETURN_ERROR_CL, + "CL3aImageProcessor create yuv pipe handler failed"); + _yuv_pipe->set_tnr_enable (_tnr_mode & CL_TNR_TYPE_YUV); + image_handler->set_pool_size (XCAM_CL_3A_IMAGE_MAX_POOL_SIZE * 2); + add_handler (image_handler); + +#if ENABLE_YEENR_HANDLER + /* ee */ + image_handler = create_cl_ee_image_handler (context); + _ee = image_handler.dynamic_cast_ptr<CLEeImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _ee.ptr (), + XCAM_RETURN_ERROR_CL, + "CL3aImageProcessor create ee handler failed"); + _ee->enable_handler (XCAM_DENOISE_TYPE_EE & _snr_mode); + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + image_handler->set_pool_size (XCAM_CL_3A_IMAGE_MAX_POOL_SIZE); + add_handler (image_handler); +#endif + + XCAM_FAIL_RETURN ( + WARNING, + post_config (), + XCAM_RETURN_ERROR_CL, + "CL3aImageProcessor post_config failed"); + + return XCAM_RETURN_NO_ERROR; +} + +bool +CL3aImageProcessor::post_config () +{ + CLImageProcessor::ImageHandlerList::iterator i_handler = handlers_begin (); + CLImageProcessor::ImageHandlerList::iterator end = handlers_end (); + uint32_t swap_y_count = 0; + bool start_count = false; + bool ret = true; + + if (!_yuv_pipe.ptr ()) //not necessary to check + return true; + + for (; i_handler != end; ++i_handler) { + if (!start_count) { + SmartPtr<CLYuvPipeImageHandler> convert_yuv = (*i_handler).dynamic_cast_ptr<CLYuvPipeImageHandler> (); + if (convert_yuv.ptr () && convert_yuv.ptr () == _yuv_pipe.ptr ()) + start_count = true; + continue; + } + + SmartPtr<CLCloneImageHandler> clone_y = (*i_handler).dynamic_cast_ptr<CLCloneImageHandler> (); + if (clone_y.ptr () && clone_y->is_handler_enabled () && (clone_y->get_clone_flags () & SwappedBuffer::SwapY)) + swap_y_count++; + } + + if (swap_y_count % 2 == 1) + ret = _yuv_pipe->enable_buf_pool_swap_flags (SwappedBuffer::SwapY | SwappedBuffer::SwapUV, SwappedBuffer::OrderY1Y0 | SwappedBuffer::OrderUV0UV1); + else + ret = _yuv_pipe->enable_buf_pool_swap_flags (SwappedBuffer::SwapY | SwappedBuffer::SwapUV, SwappedBuffer::OrderY0Y1 | SwappedBuffer::OrderUV0UV1); + + return ret; +} + +bool +CL3aImageProcessor::set_profile (const CL3aImageProcessor::PipelineProfile value) +{ + _pipeline_profile = value; + + if (value >= AdvancedPipelineProfile) + _tnr_mode |= CL_TNR_TYPE_YUV; + + if (value >= ExtremePipelineProfile) { + _snr_mode |= XCAM_DENOISE_TYPE_BNR; + } + STREAM_LOCK; + if (_yuv_pipe.ptr ()) + _yuv_pipe->set_tnr_enable (_tnr_mode & CL_TNR_TYPE_YUV); + + return true; +} + +bool +CL3aImageProcessor::set_gamma (bool enable) +{ + _enable_gamma = enable; + + STREAM_LOCK; + + return true; +} + +bool +CL3aImageProcessor::set_denoise (uint32_t mode) +{ + _snr_mode = mode; + + STREAM_LOCK; + if (_bayer_pipe.ptr ()) + _bayer_pipe->enable_denoise (XCAM_DENOISE_TYPE_BNR & _snr_mode); + + return true; +} + +bool +CL3aImageProcessor::set_macc (bool enable) +{ + _enable_macc = enable; + + STREAM_LOCK; + return true; +} + +bool +CL3aImageProcessor::set_tonemapping (CLTonemappingMode wdr_mode) +{ + _wdr_mode = wdr_mode; + + STREAM_LOCK; + + return true; +} + +bool +CL3aImageProcessor::set_tnr (uint32_t mode, uint8_t level) +{ + XCAM_UNUSED (level); + _tnr_mode = mode; + + STREAM_LOCK; + if (_yuv_pipe.ptr ()) + _yuv_pipe->set_tnr_enable (_tnr_mode & CL_TNR_TYPE_YUV); + + return true; +} + +}; diff --git a/modules/ocl/cl_3a_image_processor.h b/modules/ocl/cl_3a_image_processor.h new file mode 100644 index 0000000..a501157 --- /dev/null +++ b/modules/ocl/cl_3a_image_processor.h @@ -0,0 +1,128 @@ +/* + * cl_3a_image_processor.h - CL 3A image processor + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_3A_IMAGE_PROCESSOR_H +#define XCAM_CL_3A_IMAGE_PROCESSOR_H + +#include <xcam_std.h> +#include <base/xcam_3a_types.h> +#include <ocl/cl_image_processor.h> +#include <stats_callback_interface.h> + +namespace XCam { + +class CLCscImageHandler; +class CLEeImageHandler; +class CLBayerBasicImageHandler; +class CLBayerPipeImageHandler; +class CLYuvPipeImageHandler; +class CLTonemappingImageHandler; +class CLNewTonemappingImageHandler; + +#define ENABLE_YEENR_HANDLER 0 + +class CL3aImageProcessor + : public CLImageProcessor +{ +public: + enum OutSampleType { + OutSampleYuv, + OutSampleRGB, + OutSampleBayer, + }; + + enum PipelineProfile { + BasicPipelineProfile = 0, + AdvancedPipelineProfile, + ExtremePipelineProfile, + }; + + enum CaptureStage { + BasicbayerStage, + TonemappingStage, + }; + + enum CLTonemappingMode { + WDRdisabled = 0, + Gaussian, + Haleq, + }; + +public: + explicit CL3aImageProcessor (); + virtual ~CL3aImageProcessor (); + + bool set_profile (PipelineProfile value); + void set_stats_callback (const SmartPtr<StatsCallback> &callback); + + bool set_output_format (uint32_t fourcc); + bool set_capture_stage (CaptureStage capture_stage); + bool set_3a_stats_bits (uint32_t bits); + + virtual bool set_denoise (uint32_t mode); + virtual bool set_gamma (bool enable); + virtual bool set_macc (bool enable); + virtual bool set_tnr (uint32_t mode, uint8_t level); + virtual bool set_tonemapping (CLTonemappingMode wdr_mode); + + PipelineProfile get_profile () const { + return _pipeline_profile; + } + +protected: + + //derive from ImageProcessor + virtual bool can_process_result (SmartPtr<X3aResult> &result); + virtual XCamReturn apply_3a_results (X3aResultList &results); + virtual XCamReturn apply_3a_result (SmartPtr<X3aResult> &result); + +private: + virtual XCamReturn create_handlers (); + + bool post_config (); + XCAM_DEAD_COPY (CL3aImageProcessor); + +private: + uint32_t _output_fourcc; + uint32_t _3a_stats_bits; + PipelineProfile _pipeline_profile; + CaptureStage _capture_stage; + CLTonemappingMode _wdr_mode; + SmartPtr<StatsCallback> _stats_callback; + SmartPtr<CLCscImageHandler> _csc; + SmartPtr<CLTonemappingImageHandler> _tonemapping; + SmartPtr<CLNewTonemappingImageHandler> _newtonemapping; +#if ENABLE_YEENR_HANDLER + SmartPtr<CLEeImageHandler> _ee; +#endif + + // simple 3a bayer pipeline + SmartPtr<CLBayerBasicImageHandler> _bayer_basic_pipe; + SmartPtr<CLBayerPipeImageHandler> _bayer_pipe; + SmartPtr<CLYuvPipeImageHandler> _yuv_pipe; + + uint32_t _tnr_mode; + bool _enable_gamma; + bool _enable_macc; + uint32_t _snr_mode; // spatial nr mode +}; + +}; +#endif //XCAM_CL_3A_IMAGE_PROCESSOR_H diff --git a/modules/ocl/cl_3a_stats_context.cpp b/modules/ocl/cl_3a_stats_context.cpp new file mode 100644 index 0000000..4d43e6a --- /dev/null +++ b/modules/ocl/cl_3a_stats_context.cpp @@ -0,0 +1,285 @@ +/* + * cl_3a_stats_context.cpp - CL 3a stats context + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Jia Meng <jia.meng@intel.com> + */ + +#include <xcam_std.h> +#include "cl_3a_stats_context.h" + +namespace XCam { +CL3AStatsCalculatorContext::CL3AStatsCalculatorContext (const SmartPtr<CLContext> &context) + : _context (context) + , _width_factor (1) + , _height_factor (1) + , _factor_shift (0) + , _data_allocated (false) +{ + _stats_pool = new X3aStatsPool (); +} + +CL3AStatsCalculatorContext::~CL3AStatsCalculatorContext () +{ + clean_up_data (); +} + +void +CL3AStatsCalculatorContext::set_bit_depth (uint32_t bits) +{ + XCAM_ASSERT (_stats_pool.ptr ()); + _stats_pool->set_bit_depth (bits); +} + +bool +CL3AStatsCalculatorContext::allocate_data (const VideoBufferInfo &buffer_info, uint32_t width_factor, uint32_t height_factor) +{ + uint32_t multiply_factor = 0; + + _stats_pool->set_video_info (buffer_info); + + XCAM_FAIL_RETURN ( + WARNING, + _stats_pool->reserve (32), // need reserve more if as attachement + false, + "reserve cl stats buffer failed"); + + _stats_info = _stats_pool->get_stats_info (); + XCAM_ASSERT ((width_factor & (width_factor - 1)) == 0 && + (height_factor & (height_factor - 1)) == 0); + _width_factor = width_factor; + _height_factor = height_factor; + multiply_factor = width_factor * height_factor; + _factor_shift = 0; + while ((multiply_factor >>= 1) != 0) { + ++_factor_shift; + } + + _stats_mem_size = + _stats_info.aligned_width * _width_factor * + _stats_info.aligned_height * _height_factor * sizeof (CL3AStatsStruct); + + for (uint32_t i = 0; i < XCAM_CL_3A_STATS_BUFFER_COUNT; ++i) { + SmartPtr<CLBuffer> buf_new = new CLBuffer ( + _context, _stats_mem_size); + + XCAM_ASSERT (buf_new.ptr ()); + XCAM_FAIL_RETURN ( + WARNING, + buf_new->is_valid (), + false, + "allocate cl stats buffer failed"); + _stats_cl_buffers.push (buf_new); + } + _data_allocated = true; + + return true; +} + +void +CL3AStatsCalculatorContext::pre_stop () +{ + if (_stats_pool.ptr ()) + _stats_pool->stop (); + _stats_cl_buffers.pause_pop (); + _stats_cl_buffers.wakeup (); +} + +void +CL3AStatsCalculatorContext::clean_up_data () +{ + _data_allocated = false; + + _stats_cl_buffers.pause_pop (); + _stats_cl_buffers.wakeup (); + _stats_cl_buffers.clear (); +} + +SmartPtr<CLBuffer> +CL3AStatsCalculatorContext::get_buffer () +{ + SmartPtr<CLBuffer> buf = _stats_cl_buffers.pop (); + return buf; +} + +bool +CL3AStatsCalculatorContext::release_buffer (SmartPtr<CLBuffer> &buf) +{ + XCAM_ASSERT (buf.ptr ()); + if (!buf.ptr ()) + return false; + return _stats_cl_buffers.push (buf); +} + +void debug_print_3a_stats (XCam3AStats *stats_ptr) +{ + static int frames = 0; + frames++; + printf ("********frame(%d) debug 3a stats(%dbits) \n", frames, stats_ptr->info.bit_depth); + for (int y = 30; y < 60; ++y) { + printf ("---- y "); + for (int x = 40; x < 80; ++x) + printf ("%4d ", stats_ptr->stats[y * stats_ptr->info.aligned_width + x].avg_y); + printf ("\n"); + } + +#if 0 +#define DUMP_STATS(ch, w, h, aligned_w, stats) do { \ + printf ("stats " #ch ":"); \ + for (uint32_t y = 0; y < h; ++y) { \ + for (uint32_t x = 0; x < w; ++x) \ + printf ("%3d ", stats[y * aligned_w + x].avg_##ch); \ + } \ + printf ("\n"); \ + } while (0) + DUMP_STATS (r, stats_ptr->info.width, stats_ptr->info.height, + stats_ptr->info.aligned_width, stats_ptr->stats); + DUMP_STATS (gr, stats_ptr->info.width, stats_ptr->info.height, + stats_ptr->info.aligned_width, stats_ptr->stats); + DUMP_STATS (gb, stats_ptr->info.width, stats_ptr->info.height, + stats_ptr->info.aligned_width, stats_ptr->stats); + DUMP_STATS (b, stats_ptr->info.width, stats_ptr->info.height, + stats_ptr->info.aligned_width, stats_ptr->stats); + DUMP_STATS (y, stats_ptr->info.width, stats_ptr->info.height, + stats_ptr->info.aligned_width, stats_ptr->stats); +#endif +} + +void debug_print_histogram (XCam3AStats *stats_ptr) +{ +#define DUMP_HISTOGRAM(ch, bins, hist) do { \ + printf ("histogram " #ch ":"); \ + for (uint32_t i = 0; i < bins; i++) { \ + if (i % 16 == 0) printf ("\n"); \ + printf ("%4d ", hist[i].ch); \ + } \ + printf ("\n"); \ + } while (0) + + DUMP_HISTOGRAM (r, stats_ptr->info.histogram_bins, stats_ptr->hist_rgb); + DUMP_HISTOGRAM (gr, stats_ptr->info.histogram_bins, stats_ptr->hist_rgb); + DUMP_HISTOGRAM (gb, stats_ptr->info.histogram_bins, stats_ptr->hist_rgb); + DUMP_HISTOGRAM (b, stats_ptr->info.histogram_bins, stats_ptr->hist_rgb); + + printf ("histogram y:"); + for (uint32_t i = 0; i < stats_ptr->info.histogram_bins; i++) { + if (i % 16 == 0) printf ("\n"); + printf ("%4d ", stats_ptr->hist_y[i]); + } + printf ("\n"); +} + +SmartPtr<X3aStats> +CL3AStatsCalculatorContext::copy_stats_out (const SmartPtr<CLBuffer> &stats_cl_buf) +{ + SmartPtr<VideoBuffer> buffer; + SmartPtr<X3aStats> stats; + SmartPtr<CLEvent> event = new CLEvent; + XCam3AStats *stats_ptr = NULL; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + void *buf_ptr = NULL; + const CL3AStatsStruct *cl_buf_ptr = NULL; + + XCAM_ASSERT (stats_cl_buf.ptr ()); + + buffer = _stats_pool->get_buffer (_stats_pool); + XCAM_FAIL_RETURN (WARNING, buffer.ptr (), NULL, "3a stats pool stopped."); + + stats = buffer.dynamic_cast_ptr<X3aStats> (); + XCAM_ASSERT (stats.ptr ()); + stats_ptr = stats->get_stats (); + + ret = stats_cl_buf->enqueue_map ( + buf_ptr, + 0, _stats_mem_size, + CL_MAP_READ, + CLEvent::EmptyList, + event); + XCAM_FAIL_RETURN (WARNING, ret == XCAM_RETURN_NO_ERROR, NULL, "3a stats enqueue read buffer failed."); + XCAM_ASSERT (event->get_event_id ()); + ret = event->wait (); + XCAM_FAIL_RETURN (WARNING, ret == XCAM_RETURN_NO_ERROR, NULL, "3a stats buffer enqueue event wait failed"); + + cl_buf_ptr = (const CL3AStatsStruct*)buf_ptr; + + XCAM_ASSERT (stats_ptr); + memset (stats_ptr->stats, 0, sizeof (XCamGridStat) * _stats_info.aligned_width * _stats_info.aligned_height); + //uint32_t avg_factor = _width_factor * _height_factor; + //uint32_t avg_round_pading = avg_factor / 2; + uint32_t cl_stats_width = _stats_info.aligned_width * _width_factor; + + for (uint32_t h = 0; h < _stats_info.height; ++h) { + XCamGridStat *grid_stats_line = &stats_ptr->stats[_stats_info.aligned_width * h]; + uint32_t end_i_h = (h + 1) * _height_factor; + for (uint32_t i_h = h * _height_factor; i_h < end_i_h; ++i_h) { + const CL3AStatsStruct *cl_stats_line = &cl_buf_ptr[cl_stats_width * i_h]; + for (uint32_t w = 0; w < _stats_info.width; ++w) { + uint32_t end_i_w = (w + 1) * _width_factor; + for (uint32_t i_w = w * _width_factor; i_w < end_i_w; ++i_w) { + //grid_stats_line[w].avg_y += (cl_stats_line[i_w].avg_y + avg_round_pading) / avg_factor; + grid_stats_line[w].avg_y += (cl_stats_line[i_w].avg_y >> _factor_shift); + grid_stats_line[w].avg_r += (cl_stats_line[i_w].avg_r >> _factor_shift); + grid_stats_line[w].avg_gr += (cl_stats_line[i_w].avg_gr >> _factor_shift); + grid_stats_line[w].avg_gb += (cl_stats_line[i_w].avg_gb >> _factor_shift); + grid_stats_line[w].avg_b += (cl_stats_line[i_w].avg_b >> _factor_shift); + grid_stats_line[w].valid_wb_count += cl_stats_line[i_w].valid_wb_count; + grid_stats_line[w].f_value1 += cl_stats_line[i_w].f_value1; + grid_stats_line[w].f_value2 += cl_stats_line[i_w].f_value2; + } + } + } + } + + event.release (); + + SmartPtr<CLEvent> unmap_event = new CLEvent; + ret = stats_cl_buf->enqueue_unmap (buf_ptr, CLEvent::EmptyList, unmap_event); + XCAM_FAIL_RETURN (WARNING, ret == XCAM_RETURN_NO_ERROR, NULL, "3a stats buffer enqueue unmap failed"); + ret = unmap_event->wait (); + XCAM_FAIL_RETURN (WARNING, ret == XCAM_RETURN_NO_ERROR, NULL, "3a stats buffer enqueue unmap event wait failed"); + unmap_event.release (); + //debug_print_3a_stats (stats_ptr); + fill_histogram (stats_ptr); + //debug_print_histogram (stats_ptr); + + return stats; +} + +bool +CL3AStatsCalculatorContext::fill_histogram (XCam3AStats * stats) +{ + const XCam3AStatsInfo &stats_info = stats->info; + const XCamGridStat *grid_stat; + XCamHistogram *hist_rgb = stats->hist_rgb; + uint32_t *hist_y = stats->hist_y; + + memset (hist_rgb, 0, sizeof(XCamHistogram) * stats_info.histogram_bins); + memset (hist_y, 0, sizeof(uint32_t) * stats_info.histogram_bins); + for (uint32_t i = 0; i < stats_info.width; i++) { + for (uint32_t j = 0; j < stats_info.height; j++) { + grid_stat = &stats->stats[j * stats_info.aligned_width + i]; + hist_rgb[grid_stat->avg_r].r++; + hist_rgb[grid_stat->avg_gr].gr++; + hist_rgb[grid_stat->avg_gb].gb++; + hist_rgb[grid_stat->avg_b].b++; + hist_y[grid_stat->avg_y]++; + } + } + return true; +} + +} diff --git a/modules/ocl/cl_3a_stats_context.h b/modules/ocl/cl_3a_stats_context.h new file mode 100644 index 0000000..e0f5110 --- /dev/null +++ b/modules/ocl/cl_3a_stats_context.h @@ -0,0 +1,81 @@ +/* + * cl_3a_stats_context.h - CL 3a stats context + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_3A_STATS_CONTEXT_H +#define XCAM_CL_3A_STATS_CONTEXT_H + +#include <xcam_std.h> +#include <x3a_stats_pool.h> +#include <ocl/cl_memory.h> +#include <ocl/cl_context.h> + +#define XCAM_CL_3A_STATS_BUFFER_COUNT 6 + +namespace XCam { + +class CL3AStatsCalculatorContext +{ +public: + struct CL3AStatsStruct { + uint16_t avg_y; + uint16_t avg_r; + uint16_t avg_gr; + uint16_t avg_gb; + uint16_t avg_b; + uint16_t valid_wb_count; + uint16_t f_value1; + uint16_t f_value2; + }; + +public: + CL3AStatsCalculatorContext (const SmartPtr<CLContext> &context); + ~CL3AStatsCalculatorContext (); + void set_bit_depth (uint32_t bits); + + bool is_ready () const { + return _data_allocated; + } + bool allocate_data (const VideoBufferInfo &buffer_info, uint32_t width_factor, uint32_t height_factor); + void pre_stop (); + void clean_up_data (); + + SmartPtr<CLBuffer> get_buffer (); + bool release_buffer (SmartPtr<CLBuffer> &buf); + SmartPtr<X3aStats> copy_stats_out (const SmartPtr<CLBuffer> &stats_cl_buf); + +private: + XCAM_DEAD_COPY (CL3AStatsCalculatorContext); + + bool fill_histogram (XCam3AStats *stats); + +private: + SmartPtr<CLContext> _context; + SmartPtr<X3aStatsPool> _stats_pool; + SafeList<CLBuffer> _stats_cl_buffers; + uint32_t _stats_mem_size; + uint32_t _width_factor; + uint32_t _height_factor; + uint32_t _factor_shift; + XCam3AStatsInfo _stats_info; + bool _data_allocated; +}; + +} +#endif //XCAM_CL_3A_STATS_CONTEXT_H diff --git a/modules/ocl/cl_3d_denoise_handler.cpp b/modules/ocl/cl_3d_denoise_handler.cpp new file mode 100644 index 0000000..956ed98 --- /dev/null +++ b/modules/ocl/cl_3d_denoise_handler.cpp @@ -0,0 +1,269 @@ +/* + * cl_3d_denoise_handler.cpp - CL 3D noise reduction handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wei Zong <wei.zong@intel.com> + */ + +#include "cl_utils.h" +#include "cl_3d_denoise_handler.h" + +namespace XCam { + +#define CL_3D_DENOISE_MAX_REFERENCE_FRAME_COUNT 3 +#define CL_3D_DENOISE_REFERENCE_FRAME_COUNT 3 +#define CL_3D_DENOISE_WG_WIDTH 4 +#define CL_3D_DENOISE_WG_HEIGHT 16 + +#define CL_3D_DENOISE_ENABLE_SUBGROUP 1 +#define CL_3D_DENOISE_IIR_FILTERING 1 + +#if CL_3D_DENOISE_ENABLE_SUBGROUP +#define KERNEL_3D_DENOISE_NAME "kernel_3d_denoise" +#else +#define KERNEL_3D_DENOISE_NAME "kernel_3d_denoise_slm" +#endif + +enum { + Kernel3DDenoise, + Kernel3DDenoiseSLM, +}; + +const XCamKernelInfo kernel_3d_denoise_info[] = { + { + "kernel_3d_denoise", +#include "kernel_3d_denoise.clx" + , 0, + }, + + { + "kernel_3d_denoise_slm", +#include "kernel_3d_denoise_slm.clx" + , 0, + }, +}; + +CL3DDenoiseImageKernel::CL3DDenoiseImageKernel ( + const SmartPtr<CLContext> &context, + const char *name, + uint32_t channel, + SmartPtr<CL3DDenoiseImageHandler> &handler) + : CLImageKernel (context, name) + , _channel (channel) + , _ref_count (CL_3D_DENOISE_REFERENCE_FRAME_COUNT) + , _handler (handler) +{ +} + +XCamReturn +CL3DDenoiseImageKernel::prepare_arguments ( + CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + + SmartPtr<VideoBuffer> input = _handler->get_input_buf (); + SmartPtr<VideoBuffer> output = _handler->get_output_buf (); + + const VideoBufferInfo & video_info_in = input->get_video_info (); + const VideoBufferInfo & video_info_out = output->get_video_info (); + + uint32_t info_index = 0; + if (_channel == CL_IMAGE_CHANNEL_Y) { + info_index = 0; + } else if (_channel == CL_IMAGE_CHANNEL_UV) { + info_index = 1; + } + + CLImageDesc cl_desc_in, cl_desc_out; + cl_desc_in.format.image_channel_order = CL_RGBA; +#if CL_3D_DENOISE_ENABLE_SUBGROUP + cl_desc_in.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_desc_in.width = XCAM_ALIGN_UP (video_info_in.width, 8) / 8; +#else + cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc_in.width = XCAM_ALIGN_UP (video_info_in.width, 4) / 4; +#endif + cl_desc_in.height = video_info_in.height >> info_index; + cl_desc_in.row_pitch = video_info_in.strides[info_index]; + + cl_desc_out.format.image_channel_order = CL_RGBA; +#if CL_3D_DENOISE_ENABLE_SUBGROUP + cl_desc_out.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_desc_out.width = XCAM_ALIGN_UP (video_info_out.width, 8) / 8; +#else + cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc_out.width = XCAM_ALIGN_UP (video_info_out.width, 4) / 4; +#endif + cl_desc_out.height = video_info_out.height >> info_index; + cl_desc_out.row_pitch = video_info_out.strides[info_index]; + + _ref_count = _handler->get_ref_framecount (); + float gain = 5.0f / (_handler->get_denoise_config ().gain + 0.0001f); + float threshold = 2.0f * _handler->get_denoise_config ().threshold[info_index]; + + SmartPtr<CLImage> image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[info_index]); + SmartPtr<CLImage> image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[info_index]); + XCAM_ASSERT (image_in->is_valid () && image_out->is_valid ()); + XCAM_FAIL_RETURN ( + WARNING, + image_in->is_valid () && image_out->is_valid (), + XCAM_RETURN_ERROR_MEM, + "cl image kernel(%s) in/out memory not available", get_kernel_name ()); + + if (_image_in_list.size () < _ref_count) { + while (_image_in_list.size () < _ref_count) { + _image_in_list.push_back (image_in); + } + } else { + _image_in_list.pop_back (); + _image_in_list.push_front (image_in); + } + + if (!_image_out_prev.ptr ()) { + _image_out_prev = image_in; + } + + //set args; + args.push_back (new CLArgumentT<float> (gain)); + args.push_back (new CLArgumentT<float> (threshold)); + args.push_back (new CLMemArgument (_image_out_prev)); + args.push_back (new CLMemArgument (image_out)); + + uint8_t image_list_count = _image_in_list.size (); + for (std::list<SmartPtr<CLImage>>::iterator it = _image_in_list.begin (); it != _image_in_list.end (); it++) { + args.push_back (new CLMemArgument (*it)); + } + + //backup enough buffers for kernel + for (; image_list_count < CL_3D_DENOISE_MAX_REFERENCE_FRAME_COUNT; ++image_list_count) { + args.push_back (new CLMemArgument (image_in)); + } + + //set worksize + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; +#if CL_3D_DENOISE_ENABLE_SUBGROUP + work_size.local[0] = CL_3D_DENOISE_WG_WIDTH; + work_size.local[1] = CL_3D_DENOISE_WG_HEIGHT; + work_size.global[0] = XCAM_ALIGN_UP (cl_desc_in.width, work_size.local[0]); + work_size.global[1] = (cl_desc_in.height + work_size.local[1] - 1) / work_size.local[1] * work_size.local[1]; +#else + work_size.local[0] = 8; + work_size.local[1] = 1; + work_size.global[0] = XCAM_ALIGN_UP (cl_desc_in.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP(cl_desc_in.height / 8, 8 * work_size.local[1]); +#endif + + _image_out_prev = image_out; + + return XCAM_RETURN_NO_ERROR; +} + +CL3DDenoiseImageHandler::CL3DDenoiseImageHandler (const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) + , _ref_count (CL_3D_DENOISE_REFERENCE_FRAME_COUNT - 2) +{ + _config.gain = 1.0f; + _config.threshold[0] = 0.05f; + _config.threshold[1] = 0.05f; +} + +bool +CL3DDenoiseImageHandler::set_ref_framecount (const uint8_t count) +{ + _ref_count = count; + + return true; +} + +bool +CL3DDenoiseImageHandler::set_denoise_config (const XCam3aResultTemporalNoiseReduction& config) +{ + _config = config; + + return true; +} + +XCamReturn +CL3DDenoiseImageHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + _input_buf = input; + _output_buf = output; + return XCAM_RETURN_NO_ERROR; +} + +static SmartPtr<CLImageKernel> +create_3d_denoise_kernel ( + const SmartPtr<CLContext> &context, SmartPtr<CL3DDenoiseImageHandler> handler, + uint32_t channel, uint8_t ref_count) +{ + char build_options[1024]; + xcam_mem_clear (build_options); + + snprintf (build_options, sizeof (build_options), + " -DREFERENCE_FRAME_COUNT=%d" + " -DWORKGROUP_WIDTH=%d" + " -DWORKGROUP_HEIGHT=%d" + " -DENABLE_IIR_FILERING=%d", + ref_count, + CL_3D_DENOISE_WG_WIDTH, + CL_3D_DENOISE_WG_HEIGHT, + CL_3D_DENOISE_IIR_FILTERING); + +#if CL_3D_DENOISE_ENABLE_SUBGROUP + int kernel_index = Kernel3DDenoise; +#else + int kernel_index = Kernel3DDenoiseSLM; +#endif + + SmartPtr<CLImageKernel> kernel = + new CL3DDenoiseImageKernel (context, KERNEL_3D_DENOISE_NAME, channel, handler); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, kernel->build_kernel (kernel_3d_denoise_info[kernel_index], build_options) == XCAM_RETURN_NO_ERROR, + NULL, "build 3d denoise kernel failed"); + return kernel; +} + +SmartPtr<CLImageHandler> +create_cl_3d_denoise_image_handler ( + const SmartPtr<CLContext> &context, uint32_t channel, uint8_t ref_count) +{ + SmartPtr<CL3DDenoiseImageHandler> denoise_handler; + SmartPtr<CLImageKernel> denoise_kernel; + + denoise_handler = new CL3DDenoiseImageHandler (context, "cl_3d_denoise_handler"); + XCAM_ASSERT (denoise_handler.ptr ()); + denoise_handler->set_ref_framecount (ref_count); + + if (channel & CL_IMAGE_CHANNEL_Y) { + denoise_kernel = create_3d_denoise_kernel (context, denoise_handler, CL_IMAGE_CHANNEL_Y, ref_count); + XCAM_FAIL_RETURN ( + ERROR, denoise_kernel.ptr (), NULL, "3D denoise handler create Y channel kernel failed."); + + denoise_handler->add_kernel (denoise_kernel); + } + + if (channel & CL_IMAGE_CHANNEL_UV) { + denoise_kernel = create_3d_denoise_kernel (context, denoise_handler, CL_IMAGE_CHANNEL_UV, ref_count); + XCAM_FAIL_RETURN ( + ERROR, denoise_kernel.ptr (), NULL, "3D denoise handler create UV channel kernel failed."); + + denoise_handler->add_kernel (denoise_kernel); + } + + return denoise_handler; +} +}; diff --git a/modules/ocl/cl_3d_denoise_handler.h b/modules/ocl/cl_3d_denoise_handler.h new file mode 100644 index 0000000..f1fa712 --- /dev/null +++ b/modules/ocl/cl_3d_denoise_handler.h @@ -0,0 +1,108 @@ +/* + * cl_3d_denoise_handler.h - CL 3D noise reduction handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wei Zong <wei.zong@intel.com> + */ + +#ifndef XCAM_CL_3D_DENOISE_HANLDER_H +#define XCAM_CL_3D_DENOISE_HANLDER_H + +#include <xcam_std.h> +#include <base/xcam_3a_result.h> +#include <x3a_stats_pool.h> +#include <ocl/cl_image_handler.h> + +namespace XCam { + +class CL3DDenoiseImageHandler; + +class CL3DDenoiseImageKernel + : public CLImageKernel +{ + typedef std::list<SmartPtr<CLImage>> CLImagePtrList; + +private: + +public: + explicit CL3DDenoiseImageKernel ( + const SmartPtr<CLContext> &context, + const char *name, + uint32_t channel, + SmartPtr<CL3DDenoiseImageHandler> &handler); + + virtual ~CL3DDenoiseImageKernel () { + _image_in_list.clear (); + } + +protected: + virtual XCamReturn prepare_arguments ( + CLArgList &args, CLWorkSize &work_size); + +private: + XCAM_DEAD_COPY (CL3DDenoiseImageKernel); + + uint32_t _channel; + uint8_t _ref_count; + SmartPtr<CL3DDenoiseImageHandler> _handler; + + CLImagePtrList _image_in_list; + SmartPtr<CLImage> _image_out_prev; +}; + +class CL3DDenoiseImageHandler + : public CLImageHandler +{ +public: + explicit CL3DDenoiseImageHandler ( + const SmartPtr<CLContext> &context, const char *name); + + bool set_ref_framecount (const uint8_t count); + uint8_t get_ref_framecount () const { + return _ref_count; + }; + + bool set_denoise_config (const XCam3aResultTemporalNoiseReduction& config); + XCam3aResultTemporalNoiseReduction& get_denoise_config () { + return _config; + }; + SmartPtr<VideoBuffer> get_input_buf () { + return _input_buf; + } + SmartPtr<VideoBuffer> get_output_buf () { + return _output_buf; + } + +protected: + virtual XCamReturn prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + XCAM_DEAD_COPY (CL3DDenoiseImageHandler); + +private: + uint8_t _ref_count; + XCam3aResultTemporalNoiseReduction _config; + SmartPtr<VideoBuffer> _input_buf; + SmartPtr<VideoBuffer> _output_buf; +}; + +SmartPtr<CLImageHandler> +create_cl_3d_denoise_image_handler ( + const SmartPtr<CLContext> &context, uint32_t channel, uint8_t ref_count); + +}; + +#endif //XCAM_CL_3D_DENOISE_HANLDER_H diff --git a/modules/ocl/cl_argument.cpp b/modules/ocl/cl_argument.cpp new file mode 100644 index 0000000..4650aec --- /dev/null +++ b/modules/ocl/cl_argument.cpp @@ -0,0 +1,51 @@ +/* + * cl_argument.cpp - CL kernel Argument + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_argument.h" + +namespace XCam { + + +CLWorkSize::CLWorkSize () + : dim (XCAM_DEFAULT_IMAGE_DIM) +{ + xcam_mem_clear (global); + xcam_mem_clear (local); +} + +CLArgument::CLArgument (uint32_t size) + : _arg_adress (NULL) + , _arg_size (size) +{ +} + +CLArgument::~CLArgument () +{ +} + +void +CLArgument::get_value (void *&adress, uint32_t &size) +{ + adress = _arg_adress; + size = _arg_size; +} + + +} diff --git a/modules/ocl/cl_argument.h b/modules/ocl/cl_argument.h new file mode 100644 index 0000000..09eafbb --- /dev/null +++ b/modules/ocl/cl_argument.h @@ -0,0 +1,117 @@ +/* + * cl_argument.h - CL kernel Argument + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_KERNEL_ARGUMENT_H +#define XCAM_CL_KERNEL_ARGUMENT_H + +#include <xcam_std.h> +#include <ocl/cl_memory.h> + +namespace XCam { + +#define XCAM_DEFAULT_IMAGE_DIM 2 +#define XCAM_CL_KERNEL_MAX_WORK_DIM 3 + +struct CLWorkSize +{ + uint32_t dim; + size_t global[XCAM_CL_KERNEL_MAX_WORK_DIM]; + size_t local[XCAM_CL_KERNEL_MAX_WORK_DIM]; + CLWorkSize(); +}; + +class CLArgument +{ +public: + virtual ~CLArgument (); + void get_value (void *&adress, uint32_t &size); + +protected: + CLArgument (uint32_t size); + +private: + XCAM_DEAD_COPY (CLArgument); + +protected: + void *_arg_adress; + uint32_t _arg_size; +}; + +typedef std::list<SmartPtr<CLArgument> > CLArgList; + + +template<typename DataType> +class CLArgumentT + : public CLArgument +{ +public: + + CLArgumentT (const DataType &value) + : CLArgument (sizeof (DataType)) + , _value (value) + { + _arg_adress = (void *) &_value; + } + ~CLArgumentT () {} + +private: + DataType _value; +}; + +template<typename DataType, int count> +class CLArgumentTArray + : public CLArgument +{ +public: + + CLArgumentTArray (const DataType *value) + : CLArgument (sizeof (DataType) * count) + { + memcpy (&_value[0], value, sizeof (DataType) * count); + _arg_adress = (void *) &_value; + } + ~CLArgumentTArray () {} + +private: + DataType _value[count]; +}; + +class CLMemArgument + : public CLArgument +{ +public: + + CLMemArgument (const SmartPtr<CLMemory> &mem) + : CLArgument (sizeof (cl_mem)) + , _mem (mem) + { + XCAM_ASSERT (mem.ptr ()); + _arg_adress = &mem->get_mem_id (); + } + ~CLMemArgument () {} + +private: + SmartPtr<CLMemory> _mem; +}; + + +} + +#endif //XCAM_CL_KERNEL_ARGUMENT_H diff --git a/modules/ocl/cl_bayer_basic_handler.cpp b/modules/ocl/cl_bayer_basic_handler.cpp new file mode 100644 index 0000000..efc2536 --- /dev/null +++ b/modules/ocl/cl_bayer_basic_handler.cpp @@ -0,0 +1,444 @@ +/* + * cl_bayer_basic_handler.cpp - CL bayer basic handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_utils.h" +#include "cl_bayer_basic_handler.h" +#include "xcam_thread.h" + +#define GROUP_CELL_X_SIZE 64 +#define GROUP_CELL_Y_SIZE 4 + +#define STATS_3A_CELL_X_SIZE 8 +#define STATS_3A_CELL_Y_SIZE GROUP_CELL_Y_SIZE + +#define STANDARD_3A_STATS_SIZE 8 + +#define ENABLE_IMAGE_2D_INPUT 0 + +namespace XCam { + +static const XCamKernelInfo kernel_bayer_basic_info = { + "kernel_bayer_basic", +#include "kernel_bayer_basic.clx" + , 0, +}; + +struct BayerPostData { + SmartPtr<VideoBuffer> image_buffer; + SmartPtr<CLBuffer> stats_cl_buf; +}; + +class CLBayer3AStatsThread + : public Thread +{ +public: + CLBayer3AStatsThread (CLBayerBasicImageHandler *handler) + : Thread ("CLBayer3AStatsThread") + , _handler (handler) + {} + ~CLBayer3AStatsThread () {} + + virtual bool emit_stop (); + bool queue_stats (SmartPtr<VideoBuffer> &buf, SmartPtr<CLBuffer> &stats); + SmartPtr<VideoBuffer> pop_buf (); +protected: + virtual bool loop (); + virtual void stopped (); + +private: + CLBayerBasicImageHandler *_handler; + SafeList<BayerPostData> _stats_process_list; + SafeList<VideoBuffer> _buffer_done_list; +}; + +bool +CLBayer3AStatsThread::emit_stop () +{ + _stats_process_list.pause_pop (); + _buffer_done_list.pause_pop (); + + _stats_process_list.wakeup (); + _buffer_done_list.wakeup (); + + return Thread::emit_stop (); +} + +bool +CLBayer3AStatsThread::queue_stats (SmartPtr<VideoBuffer> &buf, SmartPtr<CLBuffer> &stats) +{ + XCAM_FAIL_RETURN ( + WARNING, + buf.ptr () && stats.ptr (), + false, + "cl bayer 3a-stats thread has error buffer/stats to queue"); + + SmartPtr<BayerPostData> data = new BayerPostData; + XCAM_ASSERT (data.ptr ()); + data->image_buffer = buf; + data->stats_cl_buf = stats; + + return _stats_process_list.push (data); +} + +SmartPtr<VideoBuffer> +CLBayer3AStatsThread::pop_buf () +{ + return _buffer_done_list.pop (); +} + +void +CLBayer3AStatsThread::stopped () +{ + _stats_process_list.clear (); + _buffer_done_list.clear (); +} + +bool +CLBayer3AStatsThread::loop () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<BayerPostData> data; + data = _stats_process_list.pop (); + if (!data.ptr ()) { + XCAM_LOG_INFO ("cl bayer 3a-stats thread is going to stop, processing data empty"); + return false; + } + + XCAM_ASSERT (data->image_buffer.ptr ()); + XCAM_ASSERT (data->stats_cl_buf.ptr ()); + XCAM_ASSERT (_handler); + + ret = _handler->process_stats_buffer (data->image_buffer, data->stats_cl_buf); + XCAM_FAIL_RETURN ( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + false, + "cl bayer 3a-stats thread has error buffer on kernel post processing"); + + XCAM_FAIL_RETURN ( + ERROR, + _buffer_done_list.push (data->image_buffer), + false, + "cl bayer 3a-stats thread failed to queue done-buffers"); + return true; +} + +CLBayerBasicImageKernel::CLBayerBasicImageKernel (const SmartPtr<CLContext> &context) + : CLImageKernel (context, "kernel_bayer_basic") +{ +} + +XCamReturn +CLBayerBasicImageHandler::process_stats_buffer (SmartPtr<VideoBuffer> &buffer, SmartPtr<CLBuffer> &cl_stats) +{ + SmartPtr<X3aStats> stats_3a; + SmartPtr<CLContext> context = get_context (); + + XCAM_OBJ_PROFILING_START; + + context->finish (); + stats_3a = _3a_stats_context->copy_stats_out (cl_stats); + if (!stats_3a.ptr ()) { + XCAM_LOG_DEBUG ("copy 3a stats failed, maybe handler stopped"); + return XCAM_RETURN_ERROR_CL; + } + + stats_3a->set_timestamp (buffer->get_timestamp ()); + buffer->attach_buffer (stats_3a); + + if (cl_stats.ptr ()) + _3a_stats_context->release_buffer (cl_stats); + + XCAM_OBJ_PROFILING_END ("3a_stats_cpu_copy(async)", XCAM_OBJ_DUR_FRAME_NUM); + + return post_stats (stats_3a); +} + +CLBayerBasicImageHandler::CLBayerBasicImageHandler ( + const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) + , _is_first_buf (true) +{ + _blc_config.level_gr = XCAM_CL_BLC_DEFAULT_LEVEL; + _blc_config.level_r = XCAM_CL_BLC_DEFAULT_LEVEL; + _blc_config.level_b = XCAM_CL_BLC_DEFAULT_LEVEL; + _blc_config.level_gb = XCAM_CL_BLC_DEFAULT_LEVEL; + _blc_config.color_bits = 10; + + _wb_config.r_gain = 1.0; + _wb_config.gr_gain = 1.0; + _wb_config.gb_gain = 1.0; + _wb_config.b_gain = 1.0; + + for(int i = 0; i < XCAM_GAMMA_TABLE_SIZE; i++) + _gamma_table[i] = (float)i / 256.0f; + _gamma_table[XCAM_GAMMA_TABLE_SIZE] = 0.9999f; + + _3a_stats_context = new CL3AStatsCalculatorContext (context); + XCAM_ASSERT (_3a_stats_context.ptr ()); + _3a_stats_thread = new CLBayer3AStatsThread (this); + XCAM_ASSERT (_3a_stats_thread.ptr ()); + + XCAM_OBJ_PROFILING_INIT; +} + +CLBayerBasicImageHandler::~CLBayerBasicImageHandler () +{ + _3a_stats_thread->stop (); + _3a_stats_context->clean_up_data (); +} + +void +CLBayerBasicImageHandler::set_stats_bits (uint32_t stats_bits) +{ + XCAM_ASSERT (_3a_stats_context.ptr ()); + _3a_stats_context->set_bit_depth (stats_bits); +} + +bool +CLBayerBasicImageHandler::set_bayer_kernel (SmartPtr<CLBayerBasicImageKernel> &kernel) +{ + SmartPtr<CLImageKernel> image_kernel = kernel; + add_kernel (image_kernel); + _bayer_kernel = kernel; + return true; +} + +bool +CLBayerBasicImageHandler::set_blc_config (const XCam3aResultBlackLevel &blc) +{ + _blc_config.level_r = (float)blc.r_level; + _blc_config.level_gr = (float)blc.gr_level; + _blc_config.level_gb = (float)blc.gb_level; + _blc_config.level_b = (float)blc.b_level; + //_blc_config.color_bits = 0; + return true; +} + +bool +CLBayerBasicImageHandler::set_wb_config (const XCam3aResultWhiteBalance &wb) +{ + _wb_config.r_gain = (float)wb.r_gain; + _wb_config.gr_gain = (float)wb.gr_gain; + _wb_config.gb_gain = (float)wb.gb_gain; + _wb_config.b_gain = (float)wb.b_gain; + return true; +} + +bool +CLBayerBasicImageHandler::set_gamma_table (const XCam3aResultGammaTable &gamma) +{ + for(int i = 0; i < XCAM_GAMMA_TABLE_SIZE; i++) + _gamma_table[i] = (float)gamma.table[i] / 256.0f; + + return true; +} + +void +CLBayerBasicImageHandler::emit_stop () +{ + _3a_stats_context->pre_stop (); + _3a_stats_thread->emit_stop (); +} + +XCamReturn +CLBayerBasicImageHandler::prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, + VideoBufferInfo &output) +{ + uint32_t format = XCAM_PIX_FMT_SGRBG16_planar; + bool format_inited = output.init (format, input.width / 2 , input.height / 2); + + XCAM_FAIL_RETURN ( + WARNING, + format_inited, + XCAM_RETURN_ERROR_PARAM, + "CL image handler(%s) output format(%s) unsupported", + get_name (), xcam_fourcc_to_string (format)); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLBayerBasicImageHandler::prepare_parameters ( + SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + SmartPtr<CLContext> context = get_context (); + const VideoBufferInfo & in_video_info = input->get_video_info (); + const VideoBufferInfo & out_video_info = output->get_video_info (); + CLImageDesc in_image_info; + CLImageDesc out_image_info; + CLArgList args; + CLWorkSize work_size; + + XCAM_ASSERT (_bayer_kernel.ptr ()); + + if (!_3a_stats_context->is_ready () && + !_3a_stats_context->allocate_data ( + in_video_info, + STANDARD_3A_STATS_SIZE / STATS_3A_CELL_X_SIZE, + STANDARD_3A_STATS_SIZE / STATS_3A_CELL_Y_SIZE)) { + XCAM_LOG_WARNING ("CL3AStatsCalculatorContext allocate data failed"); + return XCAM_RETURN_ERROR_MEM; + } + + if (_is_first_buf) { + XCAM_FAIL_RETURN ( + WARNING, _3a_stats_thread->start (), XCAM_RETURN_ERROR_THREAD, + "cl bayer basic handler start 3a stats thread failed"); + } + + in_image_info.format.image_channel_order = CL_RGBA; + in_image_info.format.image_channel_data_type = CL_UNSIGNED_INT32; //CL_UNORM_INT16; + in_image_info.width = in_video_info.aligned_width / 8; + in_image_info.height = in_video_info.height; + in_image_info.row_pitch = in_video_info.strides[0]; + + out_image_info.format.image_channel_order = CL_RGBA; + out_image_info.format.image_channel_data_type = CL_UNSIGNED_INT32; //CL_UNORM_INT16; + out_image_info.width = out_video_info.width / 8; + out_image_info.height = out_video_info.aligned_height * 4; + out_image_info.row_pitch = out_video_info.strides[0]; + +#if ENABLE_IMAGE_2D_INPUT + SmartPtr<CLImage> image_in = convert_to_climage (context, input, in_image_info); +#else + SmartPtr<CLBuffer> buffer_in = convert_to_clbuffer (context, input); +#endif + uint32_t input_aligned_width = in_video_info.strides[0] / (2 * 8); // ushort8 + SmartPtr<CLImage> image_out = convert_to_climage (context, output, out_image_info); + + uint32_t out_aligned_height = out_video_info.aligned_height; + _blc_config.color_bits = in_video_info.color_bits; + + SmartPtr<CLBuffer> gamma_table_buffer = new CLBuffer( + context, sizeof(float) * (XCAM_GAMMA_TABLE_SIZE + 1), + CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, &_gamma_table); + + _stats_cl_buffer = _3a_stats_context->get_buffer (); + XCAM_FAIL_RETURN ( + WARNING, + _stats_cl_buffer.ptr () && _stats_cl_buffer->is_valid (), + XCAM_RETURN_ERROR_PARAM, + "CLBayerBasic handler get 3a stats buffer failed"); + + XCAM_FAIL_RETURN ( + WARNING, + image_out->is_valid (), + XCAM_RETURN_ERROR_MEM, + "cl image handler(%s) out memory not available", XCAM_STR(get_name ())); + + //set args; +#if ENABLE_IMAGE_2D_INPUT + args.push_back (new CLMemArgument (image_in)); +#else + args.push_back (new CLMemArgument (buffer_in)); +#endif + args.push_back (new CLArgumentT<uint32_t> (input_aligned_width)); + args.push_back (new CLMemArgument (image_out)); + args.push_back (new CLArgumentT<uint32_t> (out_aligned_height)); + args.push_back (new CLArgumentT<CLBLCConfig> (_blc_config)); + args.push_back (new CLArgumentT<CLWBConfig> (_wb_config)); + args.push_back (new CLMemArgument (gamma_table_buffer)); + args.push_back (new CLMemArgument (_stats_cl_buffer)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 16; + work_size.local[1] = 2; + work_size.global[0] = XCAM_ALIGN_UP(out_video_info.width, GROUP_CELL_X_SIZE) / GROUP_CELL_X_SIZE * work_size.local[0]; + work_size.global[1] = XCAM_ALIGN_UP(out_video_info.aligned_height, GROUP_CELL_Y_SIZE) / GROUP_CELL_Y_SIZE * work_size.local[1]; + + //printf ("work_size:g(%d, %d), l(%d, %d)\n", work_size.global[0], work_size.global[1], work_size.local[0], work_size.local[1]); + XCAM_ASSERT (_bayer_kernel.ptr ()); + XCamReturn ret = _bayer_kernel->set_arguments (args, work_size); + XCAM_FAIL_RETURN ( + WARNING, ret == XCAM_RETURN_NO_ERROR, ret, + "bayer basic kernel set arguments failed."); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLBayerBasicImageHandler::execute_done (SmartPtr<VideoBuffer> &output) +{ + XCAM_FAIL_RETURN ( + ERROR, _3a_stats_thread->queue_stats (output, _stats_cl_buffer), XCAM_RETURN_ERROR_UNKNOWN, + "cl bayer basic handler(%s) process 3a stats failed", XCAM_STR (get_name ())); + + _stats_cl_buffer.release (); + + if (_is_first_buf) { + _is_first_buf = false; + return XCAM_RETURN_BYPASS; + } + + SmartPtr<VideoBuffer> done_buf = _3a_stats_thread->pop_buf (); + XCAM_FAIL_RETURN ( + WARNING, + done_buf.ptr (), + XCAM_RETURN_ERROR_MEM, + "cl bayer handler(%s) failed to get done buffer", get_name ()); + output = done_buf; + + return XCAM_RETURN_NO_ERROR; +} + + +XCamReturn +CLBayerBasicImageHandler::post_stats (const SmartPtr<X3aStats> &stats) +{ + if (_stats_callback.ptr ()) + return _stats_callback->x3a_stats_ready (stats); + + return XCAM_RETURN_NO_ERROR; +} + + +SmartPtr<CLImageHandler> +create_cl_bayer_basic_image_handler (const SmartPtr<CLContext> &context, bool enable_gamma, uint32_t stats_bits) +{ + SmartPtr<CLBayerBasicImageHandler> bayer_planar_handler; + SmartPtr<CLBayerBasicImageKernel> basic_kernel; + char build_options[1024]; + + bayer_planar_handler = new CLBayerBasicImageHandler (context, "cl_handler_bayer_basic"); + bayer_planar_handler->set_stats_bits (stats_bits); + basic_kernel = new CLBayerBasicImageKernel (context); + XCAM_ASSERT (basic_kernel.ptr ()); + + xcam_mem_clear (build_options); + snprintf (build_options, sizeof (build_options), + " -DENABLE_GAMMA=%d " + " -DENABLE_IMAGE_2D_INPUT=%d " + " -DSTATS_BITS=%d ", + (enable_gamma ? 1 : 0), + ENABLE_IMAGE_2D_INPUT, + stats_bits); + XCAM_FAIL_RETURN ( + ERROR, basic_kernel->build_kernel (kernel_bayer_basic_info, build_options) == XCAM_RETURN_NO_ERROR, NULL, + "build bayer-basic kernel(%s) failed", kernel_bayer_basic_info.kernel_name); + + XCAM_ASSERT (basic_kernel->is_valid ()); + bayer_planar_handler->set_bayer_kernel (basic_kernel); + + return bayer_planar_handler; +} + +}; diff --git a/modules/ocl/cl_bayer_basic_handler.h b/modules/ocl/cl_bayer_basic_handler.h new file mode 100644 index 0000000..61a31f5 --- /dev/null +++ b/modules/ocl/cl_bayer_basic_handler.h @@ -0,0 +1,113 @@ +/* + * cl_bayer_basic_handler.h - CL bayer copy handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_BAYER_BASIC_HANLDER_H +#define XCAM_CL_BAYER_BASIC_HANLDER_H + +#include <xcam_std.h> +#include <ocl/cl_image_handler.h> +#include <ocl/cl_memory.h> +#include <ocl/cl_3a_stats_context.h> +#include <stats_callback_interface.h> + +namespace XCam { + +class CLBayerBasicImageHandler; +class CLBayer3AStatsThread; + +#define XCAM_CL_BLC_DEFAULT_LEVEL 0.06 + +/* Black level correction configuration */ +typedef struct { + float level_gr; /* Black level for GR pixels */ + float level_r; /* Black level for R pixels */ + float level_b; /* Black level for B pixels */ + float level_gb; /* Black level for GB pixels */ + uint32_t color_bits; +} CLBLCConfig; + +typedef struct { + float r_gain; + float gr_gain; + float gb_gain; + float b_gain; +} CLWBConfig; + +class CLBayerBasicImageKernel + : public CLImageKernel +{ +public: + explicit CLBayerBasicImageKernel (const SmartPtr<CLContext> &context); +}; + +class CLBayerBasicImageHandler + : public CLImageHandler +{ + friend class CLBayer3AStatsThread; +public: + explicit CLBayerBasicImageHandler (const SmartPtr<CLContext> &context, const char *name); + ~CLBayerBasicImageHandler (); + + void set_stats_callback (SmartPtr<StatsCallback> &callback) { + _stats_callback = callback; + } + bool set_bayer_kernel (SmartPtr<CLBayerBasicImageKernel> &kernel); + + bool set_blc_config (const XCam3aResultBlackLevel &blc); + bool set_wb_config (const XCam3aResultWhiteBalance &wb); + bool set_gamma_table (const XCam3aResultGammaTable &gamma); + void set_stats_bits (uint32_t stats_bits); + + virtual void emit_stop (); + XCamReturn post_stats (const SmartPtr<X3aStats> &stats); + XCamReturn process_stats_buffer (SmartPtr<VideoBuffer> &buffer, SmartPtr<CLBuffer> &cl_stats); + +protected: + virtual XCamReturn prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, VideoBufferInfo &output); + virtual XCamReturn prepare_parameters ( + SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + virtual XCamReturn execute_done (SmartPtr<VideoBuffer> &output); + +private: + SmartPtr<CLBayerBasicImageKernel> _bayer_kernel; + bool _is_first_buf; + CLBLCConfig _blc_config; + CLWBConfig _wb_config; + float _gamma_table[XCAM_GAMMA_TABLE_SIZE + 1]; + + SmartPtr<CL3AStatsCalculatorContext> _3a_stats_context; + SmartPtr<CLBayer3AStatsThread> _3a_stats_thread; + SmartPtr<CLBuffer> _stats_cl_buffer; + + SmartPtr<StatsCallback> _stats_callback; + + XCAM_OBJ_PROFILING_DEFINES; +}; + +SmartPtr<CLImageHandler> +create_cl_bayer_basic_image_handler ( + const SmartPtr<CLContext> &context, + bool enable_gamma = true, + uint32_t stats_bits = 8); + +}; + +#endif //XCAM_CL_BAYER_BASIC_HANLDER_H diff --git a/modules/ocl/cl_bayer_pipe_handler.cpp b/modules/ocl/cl_bayer_pipe_handler.cpp new file mode 100644 index 0000000..a7a8f91 --- /dev/null +++ b/modules/ocl/cl_bayer_pipe_handler.cpp @@ -0,0 +1,236 @@ +/* + * cl_bayer_pipe_handler.cpp - CL bayer pipe handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: wangfei <feix.w.wang@intel.com> + * Author: Shincy Tu <shincy.tu@intel.com> + */ + +#include "cl_utils.h" +#include "cl_bayer_pipe_handler.h" + +#define WORKGROUP_PIXEL_WIDTH 128 +#define WORKGROUP_PIXEL_HEIGHT 8 + +#define BAYER_LOCAL_X_SIZE 64 +#define BAYER_LOCAL_Y_SIZE 2 + +namespace XCam { + +static const float table [XCAM_BNR_TABLE_SIZE] = { + 63.661991f, 60.628166f, 52.366924f, 41.023067f, 29.146584f, 18.781729f, 10.976704f, + 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, + 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, + 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, + 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, + 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, + 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, + 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, 6.000000f, + 6.000000f, +}; + +static const XCamKernelInfo kernel_bayer_pipe_info = { + "kernel_bayer_pipe", +#include "kernel_bayer_pipe.clx" + , 0, +}; + +CLBayerPipeImageKernel::CLBayerPipeImageKernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLBayerPipeImageHandler> &handler) + : CLImageKernel (context, "kernel_bayer_pipe") + , _handler (handler) +{ + +} + +CLBayerPipeImageHandler::CLBayerPipeImageHandler (const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) + , _output_format (XCAM_PIX_FMT_RGB48_planar) + , _enable_denoise (0) +{ + memcpy(_bnr_table, table, sizeof(float)*XCAM_BNR_TABLE_SIZE); + _ee_config.ee_gain = 0.8; + _ee_config.ee_threshold = 0.025; +} + +bool +CLBayerPipeImageHandler::set_output_format (uint32_t fourcc) +{ + XCAM_FAIL_RETURN ( + WARNING, + XCAM_PIX_FMT_RGB48_planar == fourcc || XCAM_PIX_FMT_RGB24_planar == fourcc, + false, + "CL image handler(%s) doesn't support format(%s) settings", + get_name (), xcam_fourcc_to_string (fourcc)); + + _output_format = fourcc; + return true; +} + +bool +CLBayerPipeImageHandler::set_bayer_kernel (SmartPtr<CLBayerPipeImageKernel> &kernel) +{ + SmartPtr<CLImageKernel> image_kernel = kernel; + add_kernel (image_kernel); + _bayer_kernel = kernel; + return true; +} + +bool +CLBayerPipeImageHandler::enable_denoise (bool enable) +{ + _enable_denoise = (enable ? 1 : 0); + return true; + +} + +bool +CLBayerPipeImageHandler::set_ee_config (const XCam3aResultEdgeEnhancement &ee) +{ + _ee_config.ee_gain = (float)ee.gain; + _ee_config.ee_threshold = (float)ee.threshold; + return true; +} +bool +CLBayerPipeImageHandler::set_bnr_config (const XCam3aResultBayerNoiseReduction &bnr) +{ + for(int i = 0; i < XCAM_BNR_TABLE_SIZE; i++) + _bnr_table[i] = (float)bnr.table[i]; + return true; +} + +XCamReturn +CLBayerPipeImageHandler::prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, + VideoBufferInfo &output) +{ + uint32_t format = _output_format; + uint32_t width = input.width; + uint32_t height = input.height; + if (input.format == XCAM_PIX_FMT_SGRBG16_planar) { + width *= 2; + height *= 2; + } + bool format_inited = output.init (format, width, height); + + XCAM_FAIL_RETURN ( + WARNING, + format_inited, + XCAM_RETURN_ERROR_PARAM, + "CL image handler(%s) output format(%s) unsupported", + get_name (), xcam_fourcc_to_string (format)); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLBayerPipeImageHandler::prepare_parameters ( + SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + SmartPtr<CLContext> context = get_context (); + const VideoBufferInfo & in_video_info = input->get_video_info (); + const VideoBufferInfo & out_video_info = output->get_video_info (); + CLArgList args; + CLWorkSize work_size; + + XCAM_ASSERT (_bayer_kernel.ptr ()); + + CLImageDesc in_desc; + in_desc.format.image_channel_order = CL_RGBA; + in_desc.format.image_channel_data_type = CL_UNORM_INT16; //CL_UNSIGNED_INT32; + in_desc.width = in_video_info.width / 4; // 960/4 + in_desc.height = in_video_info.aligned_height * 4; //540 + in_desc.row_pitch = in_video_info.strides[0]; + + SmartPtr<CLImage> image_in = convert_to_climage (context, input, in_desc); + + CLImageDesc out_desc; + out_desc.format.image_channel_order = CL_RGBA; + if (XCAM_PIX_FMT_RGB48_planar == out_video_info.format) + out_desc.format.image_channel_data_type = CL_UNORM_INT16; + else + out_desc.format.image_channel_data_type = CL_UNORM_INT8; + out_desc.width = out_video_info.aligned_width / 4; + out_desc.height = out_video_info.aligned_height * 3; + out_desc.row_pitch = out_video_info.strides[0]; + out_desc.array_size = 3; + out_desc.slice_pitch = out_video_info.strides [0] * out_video_info.aligned_height; + + SmartPtr<CLImage> image_out = convert_to_climage (context, output, out_desc); + + uint input_height = in_video_info.aligned_height; + uint output_height = out_video_info.aligned_height; + + XCAM_ASSERT (image_in.ptr () && image_out.ptr ()); + XCAM_FAIL_RETURN ( + WARNING, + image_in->is_valid () && image_out->is_valid (), + XCAM_RETURN_ERROR_MEM, + "cl image kernel(%s) in/out memory not available", _bayer_kernel->get_kernel_name ()); + + SmartPtr<CLBuffer> bnr_table_buffer = new CLBuffer( + context, sizeof(float) * XCAM_BNR_TABLE_SIZE, + CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, &_bnr_table); + + //set args; + args.push_back (new CLMemArgument (image_in)); + args.push_back (new CLArgumentT<uint> (input_height)); + args.push_back (new CLMemArgument (image_out)); + args.push_back (new CLArgumentT<uint> (output_height)); + args.push_back (new CLMemArgument (bnr_table_buffer)); + args.push_back (new CLArgumentT<uint32_t> (_enable_denoise)); + args.push_back (new CLArgumentT<CLEeConfig> (_ee_config)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = BAYER_LOCAL_X_SIZE; + work_size.local[1] = BAYER_LOCAL_Y_SIZE; + work_size.global[0] = (XCAM_ALIGN_UP(out_video_info.width, WORKGROUP_PIXEL_WIDTH) / WORKGROUP_PIXEL_WIDTH) * + work_size.local[0]; + work_size.global[1] = (XCAM_ALIGN_UP(out_video_info.height, WORKGROUP_PIXEL_HEIGHT) / WORKGROUP_PIXEL_HEIGHT) * + work_size.local[1]; + + XCAM_ASSERT (_bayer_kernel.ptr ()); + XCamReturn ret = _bayer_kernel->set_arguments (args, work_size); + XCAM_FAIL_RETURN ( + WARNING, ret == XCAM_RETURN_NO_ERROR, ret, + "bayer pipe kernel set arguments failed."); + + return XCAM_RETURN_NO_ERROR; +} + + +SmartPtr<CLImageHandler> +create_cl_bayer_pipe_image_handler (const SmartPtr<CLContext> &context) +{ + SmartPtr<CLBayerPipeImageHandler> bayer_pipe_handler; + SmartPtr<CLBayerPipeImageKernel> bayer_pipe_kernel; + + bayer_pipe_handler = new CLBayerPipeImageHandler (context, "cl_handler_bayer_pipe"); + bayer_pipe_kernel = new CLBayerPipeImageKernel (context, bayer_pipe_handler); + XCAM_ASSERT (bayer_pipe_kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, bayer_pipe_kernel->build_kernel (kernel_bayer_pipe_info, NULL) == XCAM_RETURN_NO_ERROR, NULL, + "build bayer-pipe kernel(%s) failed", kernel_bayer_pipe_info.kernel_name); + + XCAM_ASSERT (bayer_pipe_kernel->is_valid ()); + bayer_pipe_handler->set_bayer_kernel (bayer_pipe_kernel); + + return bayer_pipe_handler; +} + +}; diff --git a/modules/ocl/cl_bayer_pipe_handler.h b/modules/ocl/cl_bayer_pipe_handler.h new file mode 100644 index 0000000..8549e30 --- /dev/null +++ b/modules/ocl/cl_bayer_pipe_handler.h @@ -0,0 +1,94 @@ +/* + * cl_bayer_pipe_handler.h - CL bayer pipe handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: wangfei <feix.w.wang@intel.com> + * Author: Shincy Tu <shincy.tu@intel.com> + */ + +#ifndef XCAM_CL_BAYER_PIPE_HANDLER_H +#define XCAM_CL_BAYER_PIPE_HANDLER_H + +#include <xcam_std.h> +#include <stats_callback_interface.h> +#include <x3a_stats_pool.h> +#include <ocl/cl_context.h> +#include <ocl/cl_image_handler.h> +#include <ocl/cl_3a_stats_context.h> + +#define XCAM_BNR_TABLE_SIZE 64 + +namespace XCam { + +class CLBayerPipeImageHandler; + +typedef struct +{ + float ee_gain; + float ee_threshold; + float nr_gain; +} CLEeConfig; + +class CLBayerPipeImageKernel + : public CLImageKernel +{ +public: + explicit CLBayerPipeImageKernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLBayerPipeImageHandler> &handler); + +private: + SmartPtr<CLBayerPipeImageHandler> _handler; +}; + +class CLBayerPipeImageHandler + : public CLImageHandler +{ + friend class CLBayerPipeImageKernel; + +public: + explicit CLBayerPipeImageHandler (const SmartPtr<CLContext> &context, const char *name); + bool set_bayer_kernel (SmartPtr<CLBayerPipeImageKernel> &kernel); + bool set_ee_config (const XCam3aResultEdgeEnhancement &ee); + bool set_bnr_config (const XCam3aResultBayerNoiseReduction &bnr); + bool set_output_format (uint32_t fourcc); + bool enable_denoise (bool enable); + +protected: + virtual XCamReturn prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, VideoBufferInfo &output); + virtual XCamReturn prepare_parameters ( + SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + XCAM_DEAD_COPY (CLBayerPipeImageHandler); + +private: + SmartPtr<CLBayerPipeImageKernel> _bayer_kernel; + uint32_t _output_format; + + uint32_t _enable_denoise; + float _bnr_table[XCAM_BNR_TABLE_SIZE]; + CLEeConfig _ee_config; +}; + +SmartPtr<CLImageHandler> +create_cl_bayer_pipe_image_handler (const SmartPtr<CLContext> &context); + +}; + +#endif //XCAM_CL_BAYER_PIPE_HANDLER_H diff --git a/modules/ocl/cl_blender.cpp b/modules/ocl/cl_blender.cpp new file mode 100644 index 0000000..a1292bf --- /dev/null +++ b/modules/ocl/cl_blender.cpp @@ -0,0 +1,185 @@ +/* + * cl_blender.cpp - CL blender + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_blender.h" +#include "cl_device.h" + +namespace XCam { + +CLBlenderScaleKernel::CLBlenderScaleKernel (const SmartPtr<CLContext> &context, bool is_uv) + : CLImageKernel (context) + , _is_uv (is_uv) +{ +} + +XCamReturn +CLBlenderScaleKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + + SmartPtr<CLImage> image_in = get_input_image (); + SmartPtr<CLImage> image_out = get_output_image (); + XCAM_ASSERT (image_in.ptr () && image_out.ptr ()); + int output_offset_x; + uint32_t output_width, output_height; + get_output_info (output_width, output_height, output_offset_x); + + args.push_back (new CLMemArgument (image_in)); + args.push_back (new CLMemArgument (image_out)); + args.push_back (new CLArgumentT<int> (output_offset_x)); + args.push_back (new CLArgumentT<uint32_t> (output_width)); + args.push_back (new CLArgumentT<uint32_t> (output_height)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 8; + work_size.local[1] = 4; + work_size.global[0] = XCAM_ALIGN_UP (output_width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (output_height, work_size.local[1]); + + return XCAM_RETURN_NO_ERROR; +} + +CLBlender::CLBlender ( + const SmartPtr<CLContext> &context, const char *name, + bool need_uv, CLBlenderScaleMode scale_mode) + : CLImageHandler (context, name) + , Blender (XCAM_CL_BLENDER_ALIGNMENT_X, XCAM_CL_BLENDER_ALIGNMENT_Y) + , _need_uv (need_uv) + , _swap_input_index (false) + , _scale_mode (scale_mode) +{ + XCAM_ASSERT (get_alignment_x () == XCAM_CL_BLENDER_ALIGNMENT_X); + XCAM_ASSERT (get_alignment_y () == XCAM_CL_BLENDER_ALIGNMENT_Y); +} + +bool +CLBlender::set_input_merge_area (const Rect &area, uint32_t index) +{ + Rect tmp_area = area; + if (_scale_mode == CLBlenderScaleGlobal) + tmp_area.width = get_merge_window ().width; + + bool ret = Blender::set_input_merge_area (tmp_area, index); + + if (ret && _scale_mode == CLBlenderScaleGlobal) { + XCAM_ASSERT (fabs((int32_t)(area.width - get_merge_window ().width)) < XCAM_CL_BLENDER_ALIGNMENT_X); + } + + return ret; +} + +XCamReturn +CLBlender::prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, + VideoBufferInfo &output) +{ + uint32_t output_width, output_height; + get_output_size (output_width, output_height); + XCAM_ASSERT (output_height == input.height); + + // aligned at least XCAM_BLENDER_ALIGNED_WIDTH + uint32_t aligned_width = XCAM_MAX (16, XCAM_CL_BLENDER_ALIGNMENT_X); + output.init ( + input.format, output_width, output_height, + XCAM_ALIGN_UP(output_width, aligned_width), XCAM_ALIGN_UP(output_height, 16)); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLBlender::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + XCAM_ASSERT (input.ptr () && output.ptr ()); + SmartPtr<VideoBuffer> input0, input1; + + SmartPtr<VideoBuffer> next = input->find_typed_attach<VideoBuffer> (); + XCAM_FAIL_RETURN( + WARNING, + next.ptr (), + XCAM_RETURN_ERROR_PARAM, + "CLBlender(%s) does NOT find second buffer in attachment", get_name()); + + if (_swap_input_index) { + input0 = next; + input1 = input; + } else { + input0 = input; + input1 = next; + } + + SmartPtr<CLContext> context = get_context (); + const VideoBufferInfo &in0_info = input0->get_video_info (); + const VideoBufferInfo &in1_info = input1->get_video_info (); + const VideoBufferInfo &out_info = output->get_video_info (); + + if (!get_input_valid_area (0).width) { + Rect area; + area.width = in0_info.width; + area.height = in0_info.height; + set_input_valid_area (area, 0); + } + if (!get_input_valid_area (1).width) { + Rect area; + area.width = in1_info.width; + area.height = in1_info.height; + set_input_valid_area (area, 1); + } + + if (!is_merge_window_set ()) { + Rect merge_window; + XCAM_FAIL_RETURN ( + WARNING, + auto_calc_merge_window (get_input_valid_area(0).width, get_input_valid_area(1).width, out_info.width, merge_window), + XCAM_RETURN_ERROR_PARAM, + "CLBlender(%s) auto calculate merge window failed", get_name ()); + + merge_window.pos_y = 0; + merge_window.height = out_info.height; + set_merge_window (merge_window); + + Rect area; + area.width = merge_window.width; + area.height = merge_window.height; + area.pos_x = merge_window.pos_x; + set_input_merge_area (area, 0); + area.pos_x = 0; + set_input_merge_area (area, 1); + } + + ret = allocate_cl_buffers (context, input0, input1, output); + return ret; +} + +SmartPtr<Blender> +create_ocl_blender () +{ + SmartPtr<CLContext> context = CLDevice::instance ()->get_context (); + XCAM_FAIL_RETURN ( + ERROR, context.ptr (), NULL, + "create ocl blender failed to get cl context"); + SmartPtr<CLBlender> blender = create_pyramid_blender (context, 2, true, false).dynamic_cast_ptr<CLBlender> (); + XCAM_FAIL_RETURN ( + ERROR, blender.ptr (), NULL, + "create ocl blender failed to get pyramid blender"); + return blender; +} + +}; + diff --git a/modules/ocl/cl_blender.h b/modules/ocl/cl_blender.h new file mode 100644 index 0000000..c31bc44 --- /dev/null +++ b/modules/ocl/cl_blender.h @@ -0,0 +1,121 @@ +/* + * cl_blender.h - CL blender + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_BLENDER_H +#define XCAM_CL_BLENDER_H + +#include <xcam_std.h> +#include <interface/data_types.h> +#include <interface/blender.h> +#include <ocl/cl_image_handler.h> + +#define XCAM_CL_BLENDER_ALIGNMENT_X 8 +#define XCAM_CL_BLENDER_ALIGNMENT_Y 1 + +namespace XCam { + +enum CLBlenderScaleMode { + CLBlenderScaleLocal = 0, + CLBlenderScaleGlobal, + CLBlenderScaleMax +}; + +enum { + CLBlenderPlaneY = 0, + CLBlenderPlaneUV, + CLBlenderPlaneMax, +}; + +class CLBlenderScaleKernel + : public CLImageKernel +{ +public: + explicit CLBlenderScaleKernel (const SmartPtr<CLContext> &context, bool is_uv); + +protected: + virtual XCamReturn prepare_arguments ( + CLArgList &args, CLWorkSize &work_size); + + virtual SmartPtr<CLImage> get_input_image () = 0; + virtual SmartPtr<CLImage> get_output_image () = 0; + + virtual bool get_output_info (uint32_t &out_width, uint32_t &out_height, int &out_offset_x) = 0; + +private: + XCAM_DEAD_COPY (CLBlenderScaleKernel); + +protected: + bool _is_uv; +}; + +class CLBlender + : public CLImageHandler, public Blender +{ +public: + explicit CLBlender ( + const SmartPtr<CLContext> &context, const char *name, + bool need_uv, CLBlenderScaleMode scale_mode); + + //derived from Blender + virtual bool set_input_merge_area (const Rect &area, uint32_t index); + + bool need_uv () const { + return _need_uv; + } + + CLBlenderScaleMode get_scale_mode () const { + return _scale_mode; + } + + void swap_input_idx (bool flag) { + _swap_input_index = flag; + } + +protected: + virtual XCamReturn prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + virtual XCamReturn prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, + VideoBufferInfo &output); + + //abstract virtual functions + virtual XCamReturn allocate_cl_buffers ( + SmartPtr<CLContext> context, SmartPtr<VideoBuffer> &input0, + SmartPtr<VideoBuffer> &input1, SmartPtr<VideoBuffer> &output) = 0; + +private: + XCAM_DEAD_COPY (CLBlender); + +private: + bool _need_uv; + bool _swap_input_index; + CLBlenderScaleMode _scale_mode; +}; + +SmartPtr<CLImageHandler> +create_linear_blender (const SmartPtr<CLContext> &context, bool need_uv = true); + +SmartPtr<CLImageHandler> +create_pyramid_blender ( + const SmartPtr<CLContext> &context, int layer = 1, bool need_uv = true, + bool need_seam = true, CLBlenderScaleMode scale_mode = CLBlenderScaleLocal); + +}; + +#endif //XCAM_CL_BLENDER_H diff --git a/modules/ocl/cl_context.cpp b/modules/ocl/cl_context.cpp new file mode 100644 index 0000000..e8d179f --- /dev/null +++ b/modules/ocl/cl_context.cpp @@ -0,0 +1,727 @@ +/* + * cl_context.cpp - CL context + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + + +#include "cl_context.h" +#include "cl_kernel.h" +#include "cl_device.h" +#include <utility> + +#undef XCAM_CL_MAX_EVENT_SIZE +#define XCAM_CL_MAX_EVENT_SIZE 256 + +#define OCL_EXT_NAME_CREATE_BUFFER_FROM_LIBVA_INTEL "clCreateBufferFromLibvaIntel" +#define OCL_EXT_NAME_CREATE_BUFFER_FROM_FD_INTEL "clCreateBufferFromFdINTEL" +#define OCL_EXT_NAME_CREATE_IMAGE_FROM_LIBVA_INTEL "clCreateImageFromLibvaIntel" +#define OCL_EXT_NAME_CREATE_IMAGE_FROM_FD_INTEL "clCreateImageFromFdINTEL" +#define OCL_EXT_NAME_GET_MEM_OBJECT_FD_INTEL "clGetMemObjectFdIntel" + +namespace XCam { + +class CLKernel; + +void +CLContext::context_pfn_notify ( + const char* erro_info, + const void *private_info, + size_t cb, + void *user_data +) +{ + CLContext *context = (CLContext*) user_data; + XCAM_UNUSED (context); + XCAM_UNUSED (erro_info); + XCAM_UNUSED (private_info); + XCAM_UNUSED (cb); + XCAM_LOG_DEBUG ("cl context pfn error:%s", XCAM_STR (erro_info)); +} + +void CLContext::program_pfn_notify ( + cl_program program, void *user_data) +{ + CLContext *context = (CLContext*) user_data; + char kernel_names [XCAM_CL_MAX_STR_SIZE]; + + XCAM_UNUSED (context); + XCAM_UNUSED (program); + xcam_mem_clear (kernel_names); + //clGetProgramInfo (program, CL_PROGRAM_KERNEL_NAMES, sizeof (kernel_names) - 1, kernel_names, NULL); + //XCAM_LOG_DEBUG ("cl program report error on kernels: %s", kernel_names); +} + +uint32_t +CLContext::event_list_2_id_array ( + CLEventList &events_wait, + cl_event *cl_events, uint32_t max_count) +{ + uint32_t num_of_events_wait = 0; + + for (CLEventList::iterator iter = events_wait.begin (); + iter != events_wait.end (); ++iter) { + SmartPtr<CLEvent> &event = *iter; + + if (num_of_events_wait >= max_count) { + XCAM_LOG_WARNING ("CLEventList(%d) larger than id_array(max_count:%d)", (uint32_t)events_wait.size(), max_count); + break; + } + XCAM_ASSERT (event->get_event_id ()); + cl_events[num_of_events_wait++] = event->get_event_id (); + } + + return num_of_events_wait; +} + + +CLContext::CLContext (SmartPtr<CLDevice> &device) + : _context_id (NULL) + , _device (device) +{ + if (!init_context ()) { + XCAM_LOG_ERROR ("CL init context failed"); + } + + XCAM_LOG_DEBUG ("CLContext constructed"); +} + +CLContext::~CLContext () +{ + destroy_context (); + XCAM_LOG_DEBUG ("CLContext destructed"); +} + +void +CLContext::terminate () +{ + //_kernel_map.clear (); + _cmd_queue_list.clear (); +} + +XCamReturn +CLContext::flush () +{ + cl_int error_code = CL_SUCCESS; + cl_command_queue cmd_queue_id = NULL; + SmartPtr<CLCommandQueue> cmd_queue = get_default_cmd_queue (); + + XCAM_ASSERT (cmd_queue.ptr ()); + cmd_queue_id = cmd_queue->get_cmd_queue_id (); + error_code = clFlush (cmd_queue_id); + + XCAM_FAIL_RETURN ( + WARNING, + error_code == CL_SUCCESS, + XCAM_RETURN_ERROR_CL, + "CL flush cmdqueue failed with error_code:%d", error_code); + + return XCAM_RETURN_NO_ERROR; +} + + +XCamReturn +CLContext::finish () +{ + cl_int error_code = CL_SUCCESS; + cl_command_queue cmd_queue_id = NULL; + SmartPtr<CLCommandQueue> cmd_queue = get_default_cmd_queue (); + + XCAM_ASSERT (cmd_queue.ptr ()); + cmd_queue_id = cmd_queue->get_cmd_queue_id (); + error_code = clFinish (cmd_queue_id); + + XCAM_FAIL_RETURN ( + WARNING, + error_code == CL_SUCCESS, + XCAM_RETURN_ERROR_CL, + "CL finish cmdqueue failed with error_code:%d", error_code); + + return XCAM_RETURN_NO_ERROR; +} + +bool +CLContext::init_context () +{ + cl_context context_id = NULL; + cl_int err_code = 0; + cl_device_id device_id = _device->get_device_id (); + + XCAM_ASSERT (_context_id == NULL); + + if (!_device->is_inited()) { + XCAM_LOG_ERROR ("create cl context failed since device is not initialized"); + return false; + } + + context_id = + clCreateContext (NULL, 1, &device_id, + CLContext::context_pfn_notify, this, + &err_code); + if (err_code != CL_SUCCESS) + { + XCAM_LOG_WARNING ("create cl context failed, error:%d", err_code); + return false; + } + _context_id = context_id; + return true; +} + +bool +CLContext::init_cmd_queue (SmartPtr<CLContext> &self) +{ + XCAM_ASSERT (_cmd_queue_list.empty ()); + XCAM_ASSERT (self.ptr() == this); + SmartPtr<CLCommandQueue> cmd_queue = create_cmd_queue (self); + if (!cmd_queue.ptr ()) + return false; + + _cmd_queue_list.push_back (cmd_queue); + return true; +} + +SmartPtr<CLCommandQueue> +CLContext::get_default_cmd_queue () +{ + CLCmdQueueList::iterator iter; + + XCAM_ASSERT (!_cmd_queue_list.empty ()); + if (_cmd_queue_list.empty ()) + return NULL; + iter = _cmd_queue_list.begin (); + return *iter; +} + +void +CLContext::destroy_context () +{ + if (!is_valid ()) + return; + clReleaseContext (_context_id); + _context_id = NULL; +} + +XCamReturn +CLContext::execute_kernel ( + const SmartPtr<CLKernel> kernel, + const SmartPtr<CLCommandQueue> queue, + CLEventList &events_wait, + SmartPtr<CLEvent> &event_out) +{ + XCAM_ASSERT (kernel.ptr ()); + + cl_int error_code = CL_SUCCESS; + cl_command_queue cmd_queue_id = NULL; + cl_event *event_out_id = NULL; + cl_event events_id_wait[XCAM_CL_MAX_EVENT_SIZE]; + uint32_t num_of_events_wait = 0; + uint32_t work_group_size = 1; + const size_t *local_sizes = NULL; + cl_kernel kernel_id = kernel->get_kernel_id (); + CLWorkSize work_size = kernel->get_work_size (); + SmartPtr<CLCommandQueue> cmd_queue = queue; + + if (!cmd_queue.ptr ()) { + cmd_queue = get_default_cmd_queue (); + } + XCAM_ASSERT (cmd_queue.ptr ()); + + cmd_queue_id = cmd_queue->get_cmd_queue_id (); + num_of_events_wait = event_list_2_id_array (events_wait, events_id_wait, XCAM_CL_MAX_EVENT_SIZE); + if (event_out.ptr ()) + event_out_id = &event_out->get_event_id (); + + for (uint32_t i = 0; i < work_size.dim; ++i) { + work_group_size *= work_size.local[i]; + } + if (work_group_size) + local_sizes = work_size.local; + else + local_sizes = NULL; + + error_code = + clEnqueueNDRangeKernel ( + cmd_queue_id, kernel_id, + work_size.dim, NULL, work_size.global, local_sizes, + num_of_events_wait, (num_of_events_wait ? events_id_wait : NULL), + event_out_id); + + XCAM_FAIL_RETURN( + WARNING, + error_code == CL_SUCCESS, + XCAM_RETURN_ERROR_CL, + "execute kernel(%s) failed with error_code:%d", + kernel->get_kernel_name (), error_code); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLContext::set_event_callback ( + SmartPtr<CLEvent> &event, cl_int status, + void (*callback) (cl_event, cl_int, void*), + void *user_data) +{ + XCAM_ASSERT (event.ptr () && event->get_event_id ()); + cl_int error_code = clSetEventCallback (event->get_event_id (), status, callback, user_data); + return (error_code == CL_SUCCESS ? XCAM_RETURN_NO_ERROR : XCAM_RETURN_ERROR_CL); +} + +SmartPtr<CLCommandQueue> +CLContext::create_cmd_queue (SmartPtr<CLContext> &self) +{ + cl_device_id device_id = _device->get_device_id (); + cl_command_queue cmd_queue_id = NULL; + cl_int err_code = 0; + SmartPtr<CLCommandQueue> result; + + XCAM_ASSERT (self.ptr() == this); + +#if defined (CL_VERSION_2_0) && (CL_VERSION_2_0 == 1) + cmd_queue_id = clCreateCommandQueueWithProperties (_context_id, device_id, 0, &err_code); +#else + cmd_queue_id = clCreateCommandQueue (_context_id, device_id, 0, &err_code); +#endif + if (err_code != CL_SUCCESS) { + XCAM_LOG_WARNING ("create CL command queue failed, errcode:%d", err_code); + return NULL; + } + + result = new CLCommandQueue (self, cmd_queue_id); + return result; +} + +cl_kernel +CLContext::generate_kernel_id ( + CLKernel *kernel, + const uint8_t *source, size_t length, + CLContext::KernelBuildType type, + uint8_t **gen_binary, size_t *binary_size, + const char *build_option) +{ + struct CLProgram { + cl_program id; + + CLProgram () + : id (NULL) + {} + ~CLProgram () { + if (id) + clReleaseProgram (id); + } + }; + + CLProgram program; + cl_kernel kernel_id = NULL; + cl_int error_code = CL_SUCCESS; + cl_device_id device_id = _device->get_device_id (); + const char * name = kernel->get_kernel_name (); + + XCAM_ASSERT (source && length); + XCAM_ASSERT (name); + + switch (type) { + case KERNEL_BUILD_SOURCE: + program.id = + clCreateProgramWithSource ( + _context_id, 1, + (const char**)(&source), (const size_t *)&length, + &error_code); + break; + case KERNEL_BUILD_BINARY: + program.id = + clCreateProgramWithBinary ( + _context_id, 1, &device_id, + (const size_t *)&length, (const uint8_t**)(&source), + NULL, &error_code); + break; + } + + XCAM_FAIL_RETURN ( + WARNING, + error_code == CL_SUCCESS, + NULL, + "cl create program failed with error_cod:%d", error_code); + XCAM_ASSERT (program.id); + + error_code = clBuildProgram (program.id, 1, &device_id, build_option, CLContext::program_pfn_notify, this); + if (error_code != CL_SUCCESS) { + //char error_log [XCAM_CL_MAX_STR_SIZE]; + char error_log [1024 * 1024 + 32]; + xcam_mem_clear (error_log); + clGetProgramBuildInfo (program.id, device_id, CL_PROGRAM_BUILD_LOG, sizeof (error_log) - 1, error_log, NULL); + XCAM_LOG_WARNING ("CL build program failed on %s, build log:%s", name, error_log); + return NULL; + } + + if (gen_binary != NULL && binary_size != NULL) { + error_code = clGetProgramInfo (program.id, CL_PROGRAM_BINARY_SIZES, sizeof (size_t) * 1, binary_size, NULL); + if (error_code != CL_SUCCESS) { + XCAM_LOG_WARNING ("CL query binary sizes failed on %s, errcode:%d", name, error_code); + } + + *gen_binary = (uint8_t *) xcam_malloc0 (sizeof (uint8_t) * (*binary_size)); + + error_code = clGetProgramInfo (program.id, CL_PROGRAM_BINARIES, sizeof (uint8_t *) * 1, gen_binary, NULL); + if (error_code != CL_SUCCESS) { + XCAM_LOG_WARNING ("CL query program binaries failed on %s, errcode:%d", name, error_code); + } + } + + kernel_id = clCreateKernel (program.id, name, &error_code); + XCAM_FAIL_RETURN ( + WARNING, + error_code == CL_SUCCESS, + NULL, + "cl create kernel(%s) failed with error_cod:%d", name, error_code); + + return kernel_id; +} + +void +CLContext::destroy_kernel_id (cl_kernel &kernel_id) +{ + if (kernel_id) { + clReleaseKernel (kernel_id); + kernel_id = NULL; + } +} + +#if 0 +bool +CLContext::insert_kernel (SmartPtr<CLKernel> &kernel) +{ + std::string kernel_name = kernel->get_kernel_name (); + CLKernelMap::iterator i_pos = _kernel_map.lower_bound (kernel_name); + + XCAM_ASSERT (!kernel_name.empty()); + if (i_pos != _kernel_map.end () && !_kernel_map.key_comp ()(kernel_name, i_pos->first)) { + // need update + i_pos->second = kernel; + XCAM_LOG_DEBUG ("kernel:%s already exist in context, now update to new one", kernel_name.c_str()); + return true; + } + + _kernel_map.insert (i_pos, std::make_pair (kernel_name, kernel)); + return true; +} +#endif + +cl_mem +CLContext::create_image ( + cl_mem_flags flags, const cl_image_format& format, + const cl_image_desc &image_info, void *host_ptr) +{ + cl_mem mem_id = NULL; + cl_int errcode = CL_SUCCESS; + + mem_id = clCreateImage ( + _context_id, flags, + &format, &image_info, + host_ptr, &errcode); + + XCAM_FAIL_RETURN ( + WARNING, + errcode == CL_SUCCESS, + NULL, + "create cl image failed, errcode:%d", errcode); + return mem_id; +} + +void +CLContext::destroy_mem (cl_mem mem_id) +{ + if (mem_id) + clReleaseMemObject (mem_id); +} + +cl_mem +CLContext::create_buffer (uint32_t size, cl_mem_flags flags, void *host_ptr) +{ + cl_mem mem_id = NULL; + cl_int errcode = CL_SUCCESS; + + XCAM_ASSERT (_context_id); + + mem_id = clCreateBuffer ( + _context_id, flags, + size, host_ptr, + &errcode); + + XCAM_FAIL_RETURN ( + WARNING, + errcode == CL_SUCCESS, + NULL, + "create cl buffer failed, errcode:%d", errcode); + return mem_id; +} + +cl_mem +CLContext::create_sub_buffer ( + cl_mem main_mem, + cl_buffer_region region, + cl_mem_flags flags) +{ + cl_mem sub_mem = NULL; + cl_int errcode = CL_SUCCESS; + + sub_mem = clCreateSubBuffer (main_mem, flags, CL_BUFFER_CREATE_TYPE_REGION, ®ion, &errcode); + XCAM_FAIL_RETURN ( + WARNING, + errcode == CL_SUCCESS, + NULL, + "create sub buffer failed, errcode:%d", errcode); + + return sub_mem; +} + +XCamReturn +CLContext::enqueue_read_buffer ( + cl_mem buf_id, void *ptr, + uint32_t offset, uint32_t size, + bool block, + CLEventList &events_wait, + SmartPtr<CLEvent> &event_out) +{ + SmartPtr<CLCommandQueue> cmd_queue; + cl_command_queue cmd_queue_id = NULL; + cl_event *event_out_id = NULL; + cl_event events_id_wait[XCAM_CL_MAX_EVENT_SIZE]; + uint32_t num_of_events_wait = 0; + cl_int errcode = CL_SUCCESS; + + cmd_queue = get_default_cmd_queue (); + cmd_queue_id = cmd_queue->get_cmd_queue_id (); + num_of_events_wait = event_list_2_id_array (events_wait, events_id_wait, XCAM_CL_MAX_EVENT_SIZE); + if (event_out.ptr ()) + event_out_id = &event_out->get_event_id (); + + XCAM_ASSERT (_context_id); + XCAM_ASSERT (cmd_queue_id); + errcode = clEnqueueReadBuffer ( + cmd_queue_id, buf_id, + (block ? CL_BLOCKING : CL_NON_BLOCKING), + offset, size, ptr, + num_of_events_wait, (num_of_events_wait ? events_id_wait : NULL), + event_out_id); + + XCAM_FAIL_RETURN ( + WARNING, + errcode == CL_SUCCESS, + XCAM_RETURN_ERROR_CL, + "cl enqueue read buffer failed with error_code:%d", errcode); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLContext::enqueue_write_buffer ( + cl_mem buf_id, void *ptr, + uint32_t offset, uint32_t size, + bool block, + CLEventList &events_wait, + SmartPtr<CLEvent> &event_out) +{ + SmartPtr<CLCommandQueue> cmd_queue; + cl_command_queue cmd_queue_id = NULL; + cl_event *event_out_id = NULL; + cl_event events_id_wait[XCAM_CL_MAX_EVENT_SIZE]; + uint32_t num_of_events_wait = 0; + cl_int errcode = CL_SUCCESS; + + cmd_queue = get_default_cmd_queue (); + cmd_queue_id = cmd_queue->get_cmd_queue_id (); + num_of_events_wait = event_list_2_id_array (events_wait, events_id_wait, XCAM_CL_MAX_EVENT_SIZE); + if (event_out.ptr ()) + event_out_id = &event_out->get_event_id (); + + XCAM_ASSERT (_context_id); + XCAM_ASSERT (cmd_queue_id); + errcode = clEnqueueWriteBuffer ( + cmd_queue_id, buf_id, + (block ? CL_BLOCKING : CL_NON_BLOCKING), + offset, size, ptr, + num_of_events_wait, (num_of_events_wait ? events_id_wait : NULL), + event_out_id); + + XCAM_FAIL_RETURN ( + WARNING, + errcode == CL_SUCCESS, + XCAM_RETURN_ERROR_CL, + "cl enqueue write buffer failed with error_code:%d", errcode); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLContext::enqueue_map_buffer ( + cl_mem buf_id, void *&ptr, + uint32_t offset, uint32_t size, + bool block, + cl_map_flags map_flags, + CLEventList &events_wait, + SmartPtr<CLEvent> &event_out) +{ + SmartPtr<CLCommandQueue> cmd_queue; + cl_command_queue cmd_queue_id = NULL; + cl_event *event_out_id = NULL; + cl_event events_id_wait[XCAM_CL_MAX_EVENT_SIZE]; + uint32_t num_of_events_wait = 0; + cl_int errcode = CL_SUCCESS; + void *out_ptr = NULL; + + cmd_queue = get_default_cmd_queue (); + cmd_queue_id = cmd_queue->get_cmd_queue_id (); + num_of_events_wait = event_list_2_id_array (events_wait, events_id_wait, XCAM_CL_MAX_EVENT_SIZE); + if (event_out.ptr ()) + event_out_id = &event_out->get_event_id (); + + XCAM_ASSERT (_context_id); + XCAM_ASSERT (cmd_queue_id); + out_ptr = clEnqueueMapBuffer ( + cmd_queue_id, buf_id, + (block ? CL_BLOCKING : CL_NON_BLOCKING), + map_flags, + offset, size, + num_of_events_wait, (num_of_events_wait ? events_id_wait : NULL), + event_out_id, + &errcode); + + XCAM_FAIL_RETURN ( + WARNING, + out_ptr && errcode == CL_SUCCESS, + XCAM_RETURN_ERROR_CL, + "cl enqueue map buffer failed with error_code:%d", errcode); + + ptr = out_ptr; + return XCAM_RETURN_NO_ERROR; +} + + +XCamReturn +CLContext::enqueue_map_image ( + cl_mem buf_id, void *&ptr, + const size_t *origin, + const size_t *region, + size_t *image_row_pitch, + size_t *image_slice_pitch, + bool block, + cl_map_flags map_flags, + CLEventList &events_wait, + SmartPtr<CLEvent> &event_out) +{ + SmartPtr<CLCommandQueue> cmd_queue; + cl_command_queue cmd_queue_id = NULL; + cl_event *event_out_id = NULL; + cl_event events_id_wait[XCAM_CL_MAX_EVENT_SIZE]; + uint32_t num_of_events_wait = 0; + cl_int errcode = CL_SUCCESS; + void *out_ptr = NULL; + + cmd_queue = get_default_cmd_queue (); + cmd_queue_id = cmd_queue->get_cmd_queue_id (); + num_of_events_wait = event_list_2_id_array (events_wait, events_id_wait, XCAM_CL_MAX_EVENT_SIZE); + if (event_out.ptr ()) + event_out_id = &event_out->get_event_id (); + + XCAM_ASSERT (_context_id); + XCAM_ASSERT (cmd_queue_id); + + out_ptr = clEnqueueMapImage ( + cmd_queue_id, buf_id, + (block ? CL_BLOCKING : CL_NON_BLOCKING), + map_flags, + origin, + region, + image_row_pitch, + image_slice_pitch, + num_of_events_wait, (num_of_events_wait ? events_id_wait : NULL), + event_out_id, + &errcode); + + XCAM_FAIL_RETURN ( + WARNING, + out_ptr && errcode == CL_SUCCESS, + XCAM_RETURN_ERROR_CL, + "cl enqueue map buffer failed with error_code:%d", errcode); + + ptr = out_ptr; + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLContext::enqueue_unmap ( + cl_mem mem_id, + void *ptr, + CLEventList &events_wait, + SmartPtr<CLEvent> &event_out) +{ + SmartPtr<CLCommandQueue> cmd_queue; + cl_command_queue cmd_queue_id = NULL; + cl_event *event_out_id = NULL; + cl_event events_id_wait[XCAM_CL_MAX_EVENT_SIZE]; + uint32_t num_of_events_wait = 0; + cl_int errcode = CL_SUCCESS; + + cmd_queue = get_default_cmd_queue (); + cmd_queue_id = cmd_queue->get_cmd_queue_id (); + num_of_events_wait = event_list_2_id_array (events_wait, events_id_wait, XCAM_CL_MAX_EVENT_SIZE); + if (event_out.ptr ()) + event_out_id = &event_out->get_event_id (); + + XCAM_ASSERT (_context_id); + XCAM_ASSERT (cmd_queue_id); + errcode = clEnqueueUnmapMemObject ( + cmd_queue_id, mem_id, ptr, + num_of_events_wait, (num_of_events_wait ? events_id_wait : NULL), + event_out_id); + + XCAM_FAIL_RETURN ( + WARNING, + errcode == CL_SUCCESS, + XCAM_RETURN_ERROR_CL, + "cl enqueue unmap buffer failed with error_code:%d", errcode); + + return XCAM_RETURN_NO_ERROR; +} + +CLCommandQueue::CLCommandQueue (SmartPtr<CLContext> &context, cl_command_queue id) + : _context (context) + , _cmd_queue_id (id) +{ + XCAM_ASSERT (context.ptr ()); + XCAM_ASSERT (id); + XCAM_LOG_DEBUG ("CLCommandQueue constructed"); +} + +CLCommandQueue::~CLCommandQueue () +{ + destroy (); + XCAM_LOG_DEBUG ("CLCommandQueue desstructed"); +} + +void +CLCommandQueue::destroy () +{ + if (_cmd_queue_id == NULL) + return; + + clReleaseCommandQueue (_cmd_queue_id); + _cmd_queue_id = NULL; +} + +}; diff --git a/modules/ocl/cl_context.h b/modules/ocl/cl_context.h new file mode 100644 index 0000000..61c3771 --- /dev/null +++ b/modules/ocl/cl_context.h @@ -0,0 +1,204 @@ +/* + * cl_context.h - CL context + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_CONTEXT_H +#define XCAM_CL_CONTEXT_H + +#include <xcam_std.h> +#include <map> +#include <list> +#include <CL/cl.h> +#include <ocl/cl_event.h> + +namespace XCam { + +class CLKernel; +class CLDevice; +class CLCommandQueue; + +class CLVaBuffer; +class CLVaImage; +class CLIntelContext; + +/* default context: + * SmartPtr<CLContext> context = CLDevice::instance()->get_context(); + */ + +class CLContext { + //typedef std::map<std::string, SmartPtr<CLKernel>> CLKernelMap; + typedef std::list<SmartPtr<CLCommandQueue>> CLCmdQueueList; + + friend class CLDevice; + friend class CLKernel; + friend class CLMemory; + friend class CLBuffer; + friend class CLSubBuffer; + friend class CLImage; + friend class CLImage2D; + friend class CLImage2DArray; + + friend class CLVaBuffer; + friend class CLVaImage; + friend class CLIntelContext; + +public: + enum KernelBuildType { + KERNEL_BUILD_BINARY = 0, + KERNEL_BUILD_SOURCE, + }; + + virtual ~CLContext (); + cl_context get_context_id () { + return _context_id; + } + + XCamReturn flush (); + XCamReturn finish (); + + void terminate (); + +private: + static void context_pfn_notify ( + const char* erro_info, const void *private_info, + size_t cb, void *user_data); + static void program_pfn_notify ( + cl_program program, void *user_data); + + explicit CLContext (SmartPtr<CLDevice> &device); + SmartPtr<CLCommandQueue> create_cmd_queue (SmartPtr<CLContext> &self); + cl_kernel generate_kernel_id ( + CLKernel *kernel, + const uint8_t *source, + size_t length, + KernelBuildType type, + uint8_t **gen_binary, + size_t *binary_size, + const char *build_option); + void destroy_kernel_id (cl_kernel &kernel_id); + XCamReturn execute_kernel ( + const SmartPtr<CLKernel> kernel, + const SmartPtr<CLCommandQueue> queue, + CLEventList &events_wait = CLEvent::EmptyList, + SmartPtr<CLEvent> &event_out = CLEvent::NullEvent); + + XCamReturn set_event_callback ( + SmartPtr<CLEvent> &event, cl_int status, + void (*callback) (cl_event, cl_int, void*), + void *user_data); + //bool insert_kernel (SmartPtr<CLKernel> &kernel); + + bool init_context (); + void destroy_context (); + bool is_valid () const { + return (_context_id != NULL); + } + + bool init_cmd_queue (SmartPtr<CLContext> &self); + SmartPtr<CLCommandQueue> get_default_cmd_queue (); + + //Memory, Image + cl_mem create_image ( + cl_mem_flags flags, const cl_image_format& format, + const cl_image_desc &image_info, void *host_ptr = NULL); + void destroy_mem (cl_mem mem_id); + + // Buffer + cl_mem create_buffer (uint32_t size, cl_mem_flags flags, void *host_ptr); + + cl_mem create_sub_buffer ( + cl_mem main_mem, + cl_buffer_region region, + cl_mem_flags flags = CL_MEM_READ_WRITE); + + XCamReturn enqueue_read_buffer ( + cl_mem buf_id, void *ptr, + uint32_t offset, uint32_t size, + bool block = true, + CLEventList &events_wait = CLEvent::EmptyList, + SmartPtr<CLEvent> &event_out = CLEvent::NullEvent); + + XCamReturn enqueue_write_buffer ( + cl_mem buf_id, void *ptr, + uint32_t offset, uint32_t size, + bool block = true, + CLEventList &events_wait = CLEvent::EmptyList, + SmartPtr<CLEvent> &event_out = CLEvent::NullEvent); + + XCamReturn enqueue_map_buffer ( + cl_mem buf_id, void *&ptr, + uint32_t offset, uint32_t size, + bool block = true, + cl_map_flags map_flags = CL_MAP_READ | CL_MAP_WRITE, + CLEventList &events_wait = CLEvent::EmptyList, + SmartPtr<CLEvent> &event_out = CLEvent::NullEvent); + + XCamReturn enqueue_map_image ( + cl_mem buf_id, void *&ptr, + const size_t *origin, + const size_t *region, + size_t *image_row_pitch, + size_t *image_slice_pitch, + bool block = true, + cl_map_flags map_flags = CL_MAP_READ | CL_MAP_WRITE, + CLEventList &events_wait = CLEvent::EmptyList, + SmartPtr<CLEvent> &event_out = CLEvent::NullEvent); + + XCamReturn enqueue_unmap ( + cl_mem mem_id, + void *ptr, + CLEventList &events_wait = CLEvent::EmptyList, + SmartPtr<CLEvent> &event_out = CLEvent::NullEvent); + + // return valid event count + static uint32_t event_list_2_id_array ( + CLEventList &events_wait, + cl_event *cl_events, uint32_t max_count); + + XCAM_DEAD_COPY (CLContext); + +private: + cl_context _context_id; + SmartPtr<CLDevice> _device; + //CLKernelMap _kernel_map; + CLCmdQueueList _cmd_queue_list; +}; + +class CLCommandQueue { + friend class CLContext; + +public: + virtual ~CLCommandQueue (); + cl_command_queue get_cmd_queue_id () { + return _cmd_queue_id; + } + +private: + explicit CLCommandQueue (SmartPtr<CLContext> &context, cl_command_queue id); + void destroy (); + XCAM_DEAD_COPY (CLCommandQueue); + +private: + SmartPtr<CLContext> _context; + cl_command_queue _cmd_queue_id; +}; + +}; + +#endif //XCAM_CL_CONTEXT_H diff --git a/modules/ocl/cl_csc_handler.cpp b/modules/ocl/cl_csc_handler.cpp new file mode 100644 index 0000000..26a1c2b --- /dev/null +++ b/modules/ocl/cl_csc_handler.cpp @@ -0,0 +1,253 @@ +/* + * cl_csc_handler.cpp - CL csc handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: wangfei <feix.w.wang@intel.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ +#include "cl_utils.h" +#include "cl_csc_handler.h" +#include "cl_device.h" +#include "cl_kernel.h" + +static const XCamKernelInfo kernel_csc_info[] = { + { + "kernel_csc_rgbatonv12", +#include "kernel_csc.clx" + , 0, + }, + { + "kernel_csc_rgbatolab", +#include "kernel_csc.clx" + , 0, + }, + { + "kernel_csc_rgba64torgba", +#include "kernel_csc.clx" + , 0, + }, + { + "kernel_csc_yuyvtorgba", +#include "kernel_csc.clx" + , 0, + }, + { + "kernel_csc_nv12torgba", +#include "kernel_csc.clx" + , 0, + }, +}; + + +float default_rgbtoyuv_matrix[XCAM_COLOR_MATRIX_SIZE] = { + 0.299f, 0.587f, 0.114f, + -0.14713f, -0.28886f, 0.436f, + 0.615f, -0.51499f, -0.10001f +}; + +namespace XCam { + +CLCscImageKernel::CLCscImageKernel (const SmartPtr<CLContext> &context, CLCscType type) + : CLImageKernel (context) + , _kernel_csc_type (type) +{ +} + +CLCscImageHandler::CLCscImageHandler ( + const SmartPtr<CLContext> &context, const char *name, CLCscType type) + : CLImageHandler (context, name) + , _output_format (V4L2_PIX_FMT_NV12) + , _csc_type (type) +{ + memcpy (_rgbtoyuv_matrix, default_rgbtoyuv_matrix, sizeof (_rgbtoyuv_matrix)); + + switch (type) { + case CL_CSC_TYPE_RGBATONV12: + _output_format = V4L2_PIX_FMT_NV12; + break; + case CL_CSC_TYPE_RGBATOLAB: + _output_format = XCAM_PIX_FMT_LAB; + break; + case CL_CSC_TYPE_RGBA64TORGBA: + case CL_CSC_TYPE_YUYVTORGBA: + case CL_CSC_TYPE_NV12TORGBA: + _output_format = V4L2_PIX_FMT_RGBA32; + break; + default: + break; + } +} + +bool +CLCscImageHandler::set_csc_kernel (SmartPtr<CLCscImageKernel> &kernel) +{ + SmartPtr<CLImageKernel> image_kernel = kernel; + add_kernel (image_kernel); + _csc_kernel = kernel; + return true; +} + +bool +CLCscImageHandler::set_matrix (const XCam3aResultColorMatrix &matrix) +{ + for (int i = 0; i < XCAM_COLOR_MATRIX_SIZE; i++) + _rgbtoyuv_matrix[i] = (float)matrix.matrix[i]; + return true; +} + +bool +CLCscImageHandler::set_output_format (uint32_t fourcc) +{ + XCAM_FAIL_RETURN ( + WARNING, + V4L2_PIX_FMT_XBGR32 == fourcc || V4L2_PIX_FMT_NV12 == fourcc, + false, + "CL csc handler doesn't support format: (%s)", + xcam_fourcc_to_string (fourcc)); + + _output_format = fourcc; + return true; +} + +XCamReturn +CLCscImageHandler::prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, + VideoBufferInfo &output) +{ + bool format_inited = output.init (_output_format, input.width, input.height); + + XCAM_FAIL_RETURN ( + WARNING, + format_inited, + XCAM_RETURN_ERROR_PARAM, + "CL image handler(%s) output format(%s) unsupported", + get_name (), xcam_fourcc_to_string (_output_format)); + + return XCAM_RETURN_NO_ERROR; +} + +static bool +ensure_image_desc (const VideoBufferInfo &info, CLImageDesc &desc) +{ + desc.array_size = 0; + desc.slice_pitch = 0; + if (info.format == XCAM_PIX_FMT_RGB48_planar || info.format == XCAM_PIX_FMT_RGB24_planar) + desc.height = info.aligned_height * 3; + + return true; +} + +XCamReturn +CLCscImageHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + SmartPtr<CLContext> context = get_context (); + + const VideoBufferInfo &in_video_info = input->get_video_info (); + const VideoBufferInfo &out_video_info = output->get_video_info (); + CLArgList args; + CLWorkSize work_size; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (_csc_kernel.ptr ()); + + CLImageDesc in_desc, out_desc; + CLImage::video_info_2_cl_image_desc (in_video_info, in_desc); + CLImage::video_info_2_cl_image_desc (out_video_info, out_desc); + ensure_image_desc (in_video_info, in_desc); + ensure_image_desc (out_video_info, out_desc); + + SmartPtr<CLImage> image_in = convert_to_climage (context, input, in_desc, in_video_info.offsets[0]); + SmartPtr<CLImage> image_out = convert_to_climage (context, output, out_desc, out_video_info.offsets[0]); + SmartPtr<CLBuffer> matrix_buffer = new CLBuffer ( + context, sizeof(float)*XCAM_COLOR_MATRIX_SIZE, + CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR , &_rgbtoyuv_matrix); + + XCAM_FAIL_RETURN ( + WARNING, + image_in->is_valid () && image_out->is_valid () && matrix_buffer->is_valid(), + XCAM_RETURN_ERROR_MEM, + "cl image kernel(%s) in/out memory not available", _csc_kernel->get_kernel_name ()); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 4; + work_size.local[1] = 4; + + args.push_back (new CLMemArgument (image_in)); + args.push_back (new CLMemArgument (image_out)); + + do { + if ((_csc_type == CL_CSC_TYPE_RGBATOLAB) + || (_csc_type == CL_CSC_TYPE_RGBA64TORGBA) + || (_csc_type == CL_CSC_TYPE_YUYVTORGBA)) { + work_size.global[0] = out_video_info.width; + work_size.global[1] = out_video_info.height; + break; + } + + SmartPtr<CLImage> image_uv; + if(_csc_type == CL_CSC_TYPE_NV12TORGBA) { + in_desc.height /= 2; + image_uv = convert_to_climage (context, input, in_desc, in_video_info.offsets[1]); + args.push_back (new CLMemArgument (image_uv)); + + work_size.global[0] = out_video_info.width / 2; + work_size.global[1] = out_video_info.height / 2; + break; + } + + if (_csc_type == CL_CSC_TYPE_RGBATONV12) { + out_desc.height /= 2; + image_uv = convert_to_climage (context, output, out_desc, out_video_info.offsets[1]); + args.push_back (new CLMemArgument (image_uv)); + args.push_back (new CLMemArgument (matrix_buffer)); + + work_size.global[0] = out_video_info.width / 2; + work_size.global[1] = out_video_info.height / 2; + break; + } + } while (0); + + XCAM_ASSERT (_csc_kernel.ptr ()); + ret = _csc_kernel->set_arguments (args, work_size); + XCAM_FAIL_RETURN ( + WARNING, ret == XCAM_RETURN_NO_ERROR, ret, + "csc kernel set arguments failed."); + + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<CLImageHandler> +create_cl_csc_image_handler (const SmartPtr<CLContext> &context, CLCscType type) +{ + SmartPtr<CLCscImageHandler> csc_handler; + SmartPtr<CLCscImageKernel> csc_kernel; + + XCAM_ASSERT (type < CL_CSC_TYPE_MAX); + csc_kernel = new CLCscImageKernel (context, type); + XCAM_ASSERT (csc_kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, csc_kernel->build_kernel (kernel_csc_info[type], NULL) == XCAM_RETURN_NO_ERROR, NULL, + "build csc kernel(%s) failed", kernel_csc_info[type].kernel_name); + + XCAM_ASSERT (csc_kernel->is_valid ()); + + csc_handler = new CLCscImageHandler (context, "cl_handler_csc", type); + csc_handler->set_csc_kernel (csc_kernel); + + return csc_handler; +} + +}; diff --git a/modules/ocl/cl_csc_handler.h b/modules/ocl/cl_csc_handler.h new file mode 100644 index 0000000..e812eed --- /dev/null +++ b/modules/ocl/cl_csc_handler.h @@ -0,0 +1,79 @@ +/* + * cl_csc_handler.h - CL csc handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: wangfei <feix.w.wang@intel.com> + */ + +#ifndef XCAM_CL_CSC_HANLDER_H +#define XCAM_CL_CSC_HANLDER_H + +#include <xcam_std.h> +#include <base/xcam_3a_result.h> +#include <ocl/cl_image_handler.h> + +namespace XCam { + +enum CLCscType { + CL_CSC_TYPE_RGBATONV12, + CL_CSC_TYPE_RGBATOLAB, + CL_CSC_TYPE_RGBA64TORGBA, + CL_CSC_TYPE_YUYVTORGBA, + CL_CSC_TYPE_NV12TORGBA, + CL_CSC_TYPE_MAX, +}; + +class CLCscImageKernel + : public CLImageKernel +{ +public: + explicit CLCscImageKernel (const SmartPtr<CLContext> &context, CLCscType type); + +private: + CLCscType _kernel_csc_type; +}; + +class CLCscImageHandler + : public CLImageHandler +{ +public: + explicit CLCscImageHandler (const SmartPtr<CLContext> &context, const char *name, CLCscType type); + bool set_csc_kernel (SmartPtr<CLCscImageKernel> &kernel); + bool set_matrix (const XCam3aResultColorMatrix &matrix); + bool set_output_format (uint32_t fourcc); + +protected: + virtual XCamReturn prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, + VideoBufferInfo &output); + virtual XCamReturn prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + XCAM_DEAD_COPY (CLCscImageHandler); + +private: + float _rgbtoyuv_matrix[XCAM_COLOR_MATRIX_SIZE]; + uint32_t _output_format; + CLCscType _csc_type; + SmartPtr<CLCscImageKernel> _csc_kernel; +}; + +SmartPtr<CLImageHandler> +create_cl_csc_image_handler (const SmartPtr<CLContext> &context, CLCscType type); + +}; + +#endif //XCAM_CL_CSC_HANLDER_H diff --git a/modules/ocl/cl_csc_image_processor.cpp b/modules/ocl/cl_csc_image_processor.cpp new file mode 100644 index 0000000..beaf821 --- /dev/null +++ b/modules/ocl/cl_csc_image_processor.cpp @@ -0,0 +1,61 @@ +/* + * cl_3a_image_processor.cpp - CL 3A image processor + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: wangfei <feix.w.wang@intel.com> + */ +#include "cl_csc_image_processor.h" +#include "cl_context.h" +#include "cl_csc_handler.h" + + +namespace XCam { + +CLCscImageProcessor::CLCscImageProcessor () + : CLImageProcessor ("CLCscImageProcessor") +{ + XCAM_LOG_DEBUG ("CLCscImageProcessor constructed"); +} + +CLCscImageProcessor::~CLCscImageProcessor () +{ + XCAM_LOG_DEBUG ("CLCscImageProcessor destructed"); +} + +XCamReturn +CLCscImageProcessor::create_handlers () +{ + SmartPtr<CLImageHandler> image_handler; + SmartPtr<CLContext> context = get_cl_context (); + + XCAM_ASSERT (context.ptr ()); + + /* color space conversion */ + image_handler = create_cl_csc_image_handler (context, CL_CSC_TYPE_YUYVTORGBA); + _csc = image_handler.dynamic_cast_ptr<CLCscImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _csc .ptr (), + XCAM_RETURN_ERROR_CL, + "CLCscImageProcessor create csc handler failed"); + + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + add_handler (image_handler); + + return XCAM_RETURN_NO_ERROR; +} + +}; diff --git a/modules/ocl/cl_csc_image_processor.h b/modules/ocl/cl_csc_image_processor.h new file mode 100644 index 0000000..76639d3 --- /dev/null +++ b/modules/ocl/cl_csc_image_processor.h @@ -0,0 +1,49 @@ +/* + * cl_3a_image_processor.h - CL 3A image processor + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: wangfei <feix.w.wang@intel.com> + */ + +#ifndef XCAM_CL_CSC_IMAGE_PROCESSOR_H +#define XCAM_CL_CSC_IMAGE_PROCESSOR_H + +#include <xcam_std.h> +#include <stats_callback_interface.h> +#include <ocl/cl_image_processor.h> + +namespace XCam { + +class CLCscImageHandler; + +class CLCscImageProcessor + : public CLImageProcessor +{ + +public: + explicit CLCscImageProcessor (); + virtual ~CLCscImageProcessor (); + +private: + virtual XCamReturn create_handlers (); + XCAM_DEAD_COPY (CLCscImageProcessor); + +private: + SmartPtr<CLCscImageHandler> _csc; +}; + +}; +#endif //XCAM_CL_CSC_IMAGE_PROCESSOR_H diff --git a/modules/ocl/cl_defog_dcp_handler.cpp b/modules/ocl/cl_defog_dcp_handler.cpp new file mode 100644 index 0000000..7300485 --- /dev/null +++ b/modules/ocl/cl_defog_dcp_handler.cpp @@ -0,0 +1,477 @@ +/* + * cl_defog_dcp_handler.cpp - CL defog dark channel prior handler + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_utils.h" +#include "cl_defog_dcp_handler.h" +#include <algorithm> +#include "cl_device.h" + +enum { + KernelDarkChannel = 0, + KernelMinFilter, + KernelBiFilter, + KernelDefogRecover, +}; + +const static XCamKernelInfo kernels_info [] = { + { + "kernel_dark_channel", +#include "kernel_defog_dcp.clx" + , 0, + }, + { + "kernel_min_filter", +#include "kernel_min_filter.clx" + , 0, + }, + { + "kernel_bi_filter", +#include "kernel_bi_filter.clx" + , 0, + }, + { + "kernel_defog_recover", +#include "kernel_defog_dcp.clx" + , 0, + }, +}; + +namespace XCam { + +CLDarkChannelKernel::CLDarkChannelKernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLDefogDcpImageHandler> &defog_handler) + : CLImageKernel (context) + , _defog_handler (defog_handler) +{ +} + +XCamReturn +CLDarkChannelKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + SmartPtr<VideoBuffer> &input = _defog_handler->get_input_buf (); + + const VideoBufferInfo & video_info_in = input->get_video_info (); + + CLImageDesc cl_desc_in; + + cl_desc_in.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_desc_in.format.image_channel_order = CL_RGBA; + cl_desc_in.width = video_info_in.width / 8; + cl_desc_in.height = video_info_in.height; + cl_desc_in.row_pitch = video_info_in.strides[0]; + SmartPtr<CLImage> image_in_y = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]); + + cl_desc_in.height = video_info_in.height / 2; + cl_desc_in.row_pitch = video_info_in.strides[1]; + SmartPtr<CLImage> image_in_uv = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[1]); + + args.push_back (new CLMemArgument (image_in_y)); + args.push_back (new CLMemArgument (image_in_uv)); + + SmartPtr<CLImage> &dark_channel = _defog_handler->get_dark_map (XCAM_DEFOG_DC_ORIGINAL); + args.push_back (new CLMemArgument (dark_channel)); + + // R, G, B channel + for (uint32_t i = 0; i < XCAM_DEFOG_MAX_CHANNELS; ++i) { + SmartPtr<CLImage> &rgb_image = _defog_handler->get_rgb_channel (i); + args.push_back (new CLMemArgument (rgb_image)); + } + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 16; + work_size.local[1] = 2; + work_size.global[0] = XCAM_ALIGN_UP (cl_desc_in.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (cl_desc_in.height, work_size.local[1]); + + return XCAM_RETURN_NO_ERROR; +} + +CLMinFilterKernel::CLMinFilterKernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLDefogDcpImageHandler> &defog_handler, + int index) + : CLImageKernel (context) + , _defog_handler (defog_handler) + , _buf_index (index) +{ + XCAM_ASSERT (XCAM_DEFOG_DC_MIN_FILTER_V == _buf_index || XCAM_DEFOG_DC_MIN_FILTER_H == _buf_index); +} + +XCamReturn +CLMinFilterKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLImage> &dark_channel_in = _defog_handler->get_dark_map (_buf_index - 1); + SmartPtr<CLImage> &dark_channel_out = _defog_handler->get_dark_map (_buf_index); + + args.push_back (new CLMemArgument (dark_channel_in)); + args.push_back (new CLMemArgument (dark_channel_out)); + + const CLImageDesc &cl_desc = dark_channel_in->get_image_desc (); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + if (XCAM_DEFOG_DC_MIN_FILTER_V == _buf_index) { + work_size.local[0] = 16; + work_size.local[1] = 4; + work_size.global[0] = XCAM_ALIGN_UP (cl_desc.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (cl_desc.height / 2, work_size.local[1]); + } else { + work_size.local[0] = 16; + work_size.local[1] = 4; + work_size.global[0] = XCAM_ALIGN_UP (cl_desc.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (cl_desc.height, work_size.local[1]); + } + + return XCAM_RETURN_NO_ERROR; +} + +CLBiFilterKernel::CLBiFilterKernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLDefogDcpImageHandler> &defog_handler) + : CLImageKernel (context) + , _defog_handler (defog_handler) +{ +} + +XCamReturn +CLBiFilterKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + SmartPtr<VideoBuffer> &input = _defog_handler->get_input_buf (); + const VideoBufferInfo & video_info_in = input->get_video_info (); + + CLImageDesc cl_desc_in; + cl_desc_in.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_desc_in.format.image_channel_order = CL_RGBA; + cl_desc_in.width = video_info_in.width / 8; + cl_desc_in.height = video_info_in.height; + cl_desc_in.row_pitch = video_info_in.strides[0]; + SmartPtr<CLImage> image_in_y = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]); + + SmartPtr<CLImage> &dark_channel_in = _defog_handler->get_dark_map (XCAM_DEFOG_DC_ORIGINAL); + SmartPtr<CLImage> &dark_channel_out = _defog_handler->get_dark_map (XCAM_DEFOG_DC_BI_FILTER); + + args.push_back (new CLMemArgument (image_in_y)); + args.push_back (new CLMemArgument (dark_channel_in)); + args.push_back (new CLMemArgument (dark_channel_out)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 16; + work_size.local[1] = 2; + work_size.global[0] = XCAM_ALIGN_UP (cl_desc_in.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (cl_desc_in.height, work_size.local[1]); + + return XCAM_RETURN_NO_ERROR; +} + +CLDefogRecoverKernel::CLDefogRecoverKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLDefogDcpImageHandler> &defog_handler) + : CLImageKernel (context) + , _defog_handler (defog_handler) + , _max_r (255.0f) + , _max_g (255.0f) + , _max_b (255.0f) + , _max_i (255.0f) +{ +} + +float +CLDefogRecoverKernel::get_max_value (SmartPtr<VideoBuffer> &buf) +{ + float ret = 255.0f; + const float max_percent = 1.0f; + + SmartPtr<X3aStats> stats; + SmartPtr<CLVideoBuffer> cl_buf = buf.dynamic_cast_ptr<CLVideoBuffer> (); + if (cl_buf.ptr ()) { + stats = cl_buf->find_3a_stats (); + } +#if HAVE_LIBDRM + else { + SmartPtr<DrmBoBuffer> bo_buf = buf.dynamic_cast_ptr<DrmBoBuffer> (); + stats = bo_buf->find_3a_stats (); + } +#endif + + _max_r = 230.0f; + _max_g = 230.0f; + _max_b = 230.0f; + _max_i = XCAM_MAX (_max_r, _max_g); + _max_i = XCAM_MAX (_max_i, _max_b); + if (!stats.ptr ()) + return ret; + + XCam3AStats *stats_ptr = stats->get_stats (); + if (!stats_ptr || !stats_ptr->hist_y) + return ret; + + uint32_t his_bins = stats_ptr->info.histogram_bins; + uint32_t pixel_count = stats_ptr->info.width * stats_ptr->info.height; + uint32_t max_expect_count = (uint32_t)(max_percent * pixel_count / 100.0f); + uint32_t sum_count = 0; + int32_t i = (int32_t)(his_bins - 1); + + for (; i >= 0; --i) { + sum_count += stats_ptr->hist_y[i]; + if (sum_count >= max_expect_count) + break; + } + ret = (float)i * 256.0f / (1 << stats_ptr->info.bit_depth); + ret = XCAM_MAX (ret, 1.0f); + return ret; +} + +XCamReturn +CLDefogRecoverKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + SmartPtr<VideoBuffer> &input = _defog_handler->get_input_buf (); + SmartPtr<VideoBuffer> &output = _defog_handler->get_output_buf (); + SmartPtr<CLImage> &dark_map = _defog_handler->get_dark_map (XCAM_DEFOG_DC_BI_FILTER); + get_max_value (input); + + args.push_back (new CLMemArgument (dark_map)); + args.push_back (new CLArgumentT<float> (_max_i)); + args.push_back (new CLArgumentT<float> (_max_r)); + args.push_back (new CLArgumentT<float> (_max_g)); + args.push_back (new CLArgumentT<float> (_max_b)); + + for (int i = 0; i < XCAM_DEFOG_MAX_CHANNELS; ++i) { + SmartPtr<CLImage> &input_color = _defog_handler->get_rgb_channel (i); + args.push_back (new CLMemArgument (input_color)); + } + + const VideoBufferInfo & video_info_out = output->get_video_info (); + + CLImageDesc cl_desc_out; + cl_desc_out.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_desc_out.format.image_channel_order = CL_RGBA; + cl_desc_out.width = video_info_out.width / 8; + cl_desc_out.height = video_info_out.height; + cl_desc_out.row_pitch = video_info_out.strides[0]; + SmartPtr<CLImage> image_out_y = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[0]); + + cl_desc_out.height = video_info_out.height / 2; + cl_desc_out.row_pitch = video_info_out.strides[1]; + SmartPtr<CLImage> image_out_uv = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[1]); + + args.push_back (new CLMemArgument (image_out_y)); + args.push_back (new CLMemArgument (image_out_uv)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 16; + work_size.local[1] = 8; + + work_size.global[0] = XCAM_ALIGN_UP (cl_desc_out.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (cl_desc_out.height, work_size.local[1]); // uv height + + return XCAM_RETURN_NO_ERROR; +} + +CLDefogDcpImageHandler::CLDefogDcpImageHandler ( + const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) +{ +} + +XCamReturn +CLDefogDcpImageHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + XCAM_UNUSED (output); + XCamReturn ret = allocate_transmit_bufs (input->get_video_info ()); + XCAM_FAIL_RETURN( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "CLDefogDcpImageHandler allocate transmit buffers failed"); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLDefogDcpImageHandler::execute_done (SmartPtr<VideoBuffer> &output) +{ + XCAM_UNUSED (output); +#if 0 + dump_buffer (); +#endif + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLDefogDcpImageHandler::allocate_transmit_bufs (const VideoBufferInfo &video_info) +{ + int i; + CLImageDesc cl_rgb_desc, cl_dark_desc; + SmartPtr<CLContext> context = get_context (); + + cl_rgb_desc.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_rgb_desc.format.image_channel_order = CL_RGBA; + cl_rgb_desc.width = video_info.width / 8; + cl_rgb_desc.height = video_info.height; + + for (i = 0; i < XCAM_DEFOG_MAX_CHANNELS; ++i) { + _rgb_buf[i] = new CLImage2D (context, cl_rgb_desc); + XCAM_FAIL_RETURN( + WARNING, + _rgb_buf[i]->is_valid (), + XCAM_RETURN_ERROR_MEM, + "CLDefogDcpImageHandler allocate RGB buffers failed"); + } + + cl_dark_desc.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_dark_desc.format.image_channel_order = CL_RGBA; + cl_dark_desc.width = video_info.width / 8; + cl_dark_desc.height = video_info.height; + + for (i = 0; i < XCAM_DEFOG_DC_MAX_BUF; ++i) { + _dark_channel_buf[i] = new CLImage2D (context, cl_dark_desc); + XCAM_FAIL_RETURN( + WARNING, + _dark_channel_buf[i]->is_valid (), + XCAM_RETURN_ERROR_MEM, + "CLDefogDcpImageHandler allocate dark channel buffers failed"); + } + + return XCAM_RETURN_NO_ERROR; +} + +void +CLDefogDcpImageHandler::dump_buffer () +{ + SmartPtr<CLImage> image; + CLImageDesc desc; + uint32_t width, height; + char file_name[1024]; + + // dump dark channel bi-filtered map + image = _dark_channel_buf[XCAM_DEFOG_DC_BI_FILTER]; + desc = image->get_image_desc (); + width = image->get_pixel_bytes () * desc.width; + height = desc.height; + + snprintf (file_name, 1024, "dark-channel-map_%dx%d.y", width, height); + dump_image (image, file_name); +} + +static SmartPtr<CLDarkChannelKernel> +create_kernel_dark_channel (const SmartPtr<CLContext> &context, SmartPtr<CLDefogDcpImageHandler> handler) +{ + SmartPtr<CLDarkChannelKernel> kernel; + + kernel = new CLDarkChannelKernel (context, handler); + XCAM_FAIL_RETURN ( + WARNING, + kernel->build_kernel (kernels_info[KernelDarkChannel], NULL) == XCAM_RETURN_NO_ERROR, + NULL, + "Defog build kernel(%s) failed", kernels_info[KernelDarkChannel].kernel_name); + return kernel; +} + +static SmartPtr<CLMinFilterKernel> +create_kernel_min_filter ( + const SmartPtr<CLContext> &context, + SmartPtr<CLDefogDcpImageHandler> handler, + int index) +{ + SmartPtr<CLMinFilterKernel> kernel; + + char build_options[1024]; + xcam_mem_clear (build_options); + snprintf ( + build_options, sizeof (build_options), + " -DVERTICAL_MIN_KERNEL=%d ", (XCAM_DEFOG_DC_MIN_FILTER_V == index ? 1 : 0)); + + kernel = new CLMinFilterKernel (context, handler, index); + XCAM_FAIL_RETURN ( + WARNING, + kernel->build_kernel (kernels_info[KernelMinFilter], build_options) == XCAM_RETURN_NO_ERROR, + NULL, + "Defog build kernel(%s) failed", kernels_info[KernelMinFilter].kernel_name); + + return kernel; +} + +static SmartPtr<CLBiFilterKernel> +create_kernel_bi_filter ( + const SmartPtr<CLContext> &context, SmartPtr<CLDefogDcpImageHandler> handler) +{ + SmartPtr<CLBiFilterKernel> kernel; + + kernel = new CLBiFilterKernel (context, handler); + XCAM_FAIL_RETURN ( + WARNING, + kernel->build_kernel (kernels_info[KernelBiFilter], NULL) == XCAM_RETURN_NO_ERROR, + NULL, + "Defog build kernel(%s) failed", kernels_info[KernelBiFilter].kernel_name); + + return kernel; +} + +static SmartPtr<CLDefogRecoverKernel> +create_kernel_defog_recover ( + const SmartPtr<CLContext> &context, SmartPtr<CLDefogDcpImageHandler> handler) +{ + SmartPtr<CLDefogRecoverKernel> kernel; + + kernel = new CLDefogRecoverKernel (context, handler); + XCAM_FAIL_RETURN ( + WARNING, + kernel->build_kernel (kernels_info[KernelDefogRecover], NULL) == XCAM_RETURN_NO_ERROR, + NULL, + "Defog build kernel(%s) failed", kernels_info[KernelDefogRecover].kernel_name); + return kernel; +} + +SmartPtr<CLImageHandler> +create_cl_defog_dcp_image_handler (const SmartPtr<CLContext> &context) +{ + SmartPtr<CLDefogDcpImageHandler> defog_handler; + + SmartPtr<CLImageKernel> kernel; + + defog_handler = new CLDefogDcpImageHandler (context, "cl_handler_defog_dcp"); + kernel = create_kernel_dark_channel (context, defog_handler); + XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "defog handler create dark channel kernel failed"); + defog_handler->add_kernel (kernel); + +#if 0 + for (int i = XCAM_DEFOG_DC_MIN_FILTER_V; i <= XCAM_DEFOG_DC_MIN_FILTER_H; ++i) { + SmartPtr<CLImageKernel> min_kernel; + min_kernel = create_kernel_min_filter (context, defog_handler, i); + XCAM_FAIL_RETURN (ERROR, min_kernel.ptr (), NULL, "defog handler create min filter kernel failed"); + defog_handler->add_kernel (min_kernel); + } +#endif + + kernel = create_kernel_bi_filter (context, defog_handler); + XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "defog handler create bilateral filter kernel failed"); + defog_handler->add_kernel (kernel); + + kernel = create_kernel_defog_recover (context, defog_handler); + XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "defog handler create defog recover kernel failed"); + defog_handler->add_kernel (kernel); + + return defog_handler; +} + +} diff --git a/modules/ocl/cl_defog_dcp_handler.h b/modules/ocl/cl_defog_dcp_handler.h new file mode 100644 index 0000000..1560bf5 --- /dev/null +++ b/modules/ocl/cl_defog_dcp_handler.h @@ -0,0 +1,150 @@ +/* + * cl_defog_dcp_handler.h - CL defog dark channel prior handler + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_DEFOG_DCP_HANLDER_H +#define XCAM_CL_DEFOG_DCP_HANLDER_H + +#include <xcam_std.h> +#include <base/xcam_3a_result.h> +#include <x3a_stats_pool.h> +#include <ocl/cl_image_handler.h> + +#define XCAM_DEFOG_DC_ORIGINAL 0 +#define XCAM_DEFOG_DC_MIN_FILTER_V 1 +#define XCAM_DEFOG_DC_MIN_FILTER_H 2 +#define XCAM_DEFOG_DC_BI_FILTER 3 +#define XCAM_DEFOG_DC_REFINED 4 +#define XCAM_DEFOG_DC_MAX_BUF 5 + + +#define XCAM_DEFOG_R_CHANNEL 0 +#define XCAM_DEFOG_G_CHANNEL 1 +#define XCAM_DEFOG_B_CHANNEL 2 +#define XCAM_DEFOG_MAX_CHANNELS 3 + +namespace XCam { + +class CLDefogDcpImageHandler; + +class CLDarkChannelKernel + : public CLImageKernel +{ +public: + explicit CLDarkChannelKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLDefogDcpImageHandler> &defog_handler); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + +private: + SmartPtr<CLDefogDcpImageHandler> _defog_handler; +}; + +class CLMinFilterKernel + : public CLImageKernel +{ +public: + explicit CLMinFilterKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLDefogDcpImageHandler> &defog_handler, int index); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + + SmartPtr<CLDefogDcpImageHandler> _defog_handler; + uint32_t _buf_index; +}; + +class CLBiFilterKernel + : public CLImageKernel +{ +public: + explicit CLBiFilterKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLDefogDcpImageHandler> &defog_handler); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + +private: + XCAM_DEAD_COPY (CLBiFilterKernel); + +private: + SmartPtr<CLDefogDcpImageHandler> _defog_handler; +}; + +class CLDefogRecoverKernel + : public CLImageKernel +{ +public: + explicit CLDefogRecoverKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLDefogDcpImageHandler> &defog_handler); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + +private: + float get_max_value (SmartPtr<VideoBuffer> &buf); + + XCAM_DEAD_COPY (CLDefogRecoverKernel); + +private: + SmartPtr<CLDefogDcpImageHandler> _defog_handler; + float _max_r; + float _max_g; + float _max_b; + float _max_i; +}; + +class CLDefogDcpImageHandler + : public CLImageHandler +{ +public: + explicit CLDefogDcpImageHandler ( + const SmartPtr<CLContext> &context, const char *name); + + SmartPtr<CLImage> &get_dark_map (uint index) { + XCAM_ASSERT (index < XCAM_DEFOG_DC_MAX_BUF); + return _dark_channel_buf[index]; + }; + SmartPtr<CLImage> &get_rgb_channel (uint index) { + XCAM_ASSERT (index < XCAM_DEFOG_MAX_CHANNELS); + return _rgb_buf[index]; + }; + +protected: + virtual XCamReturn prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + virtual XCamReturn execute_done (SmartPtr<VideoBuffer> &output); + +private: + XCamReturn allocate_transmit_bufs (const VideoBufferInfo &video_info); + void dump_buffer(); + + XCAM_DEAD_COPY (CLDefogDcpImageHandler); + +private: + SmartPtr<CLImage> _dark_channel_buf[XCAM_DEFOG_DC_MAX_BUF]; + SmartPtr<CLImage> _rgb_buf[XCAM_DEFOG_MAX_CHANNELS]; +}; + +SmartPtr<CLImageHandler> +create_cl_defog_dcp_image_handler (const SmartPtr<CLContext> &context); + +}; + +#endif //XCAM_CL_DEFOG_DCP_HANLDER_H diff --git a/modules/ocl/cl_demo_handler.cpp b/modules/ocl/cl_demo_handler.cpp new file mode 100644 index 0000000..ad09698 --- /dev/null +++ b/modules/ocl/cl_demo_handler.cpp @@ -0,0 +1,136 @@ +/* + * cl_demo_handler.cpp - CL demo handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ +#include "cl_utils.h" +#include "cl_demo_handler.h" +#include "cl_device.h" +#include "cl_kernel.h" + +namespace XCam { + +static const XCamKernelInfo kernel_demo_info = { + "kernel_demo", +#include "kernel_demo.clx" + , 0, +}; + +CLDemoImageHandler::CLDemoImageHandler (const SmartPtr<CLContext> &context) + : CLImageHandler (context, "cl_demo_handler") +{ +} + +XCamReturn +CLDemoImageHandler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + const VideoBufferInfo &info = input->get_video_info (); + XCAM_FAIL_RETURN ( + ERROR, + info.format == V4L2_PIX_FMT_RGBA32, + XCAM_RETURN_ERROR_PARAM, + "CLDemoImageHandler support only RGBA format"); + + return CLImageHandler::prepare_output_buf (input, output); +} + +XCamReturn +CLDemoImageHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + SmartPtr<CLContext> context = CLDevice::instance ()->get_context (); + const VideoBufferInfo &info = input->get_video_info (); + CLArgList args; + CLWorkSize work_size; + + CLImageDesc desc; + desc.format.image_channel_order = CL_RGBA; + desc.format.image_channel_data_type = CL_UNORM_INT8; + desc.width = info.aligned_width; + desc.height = info.height; + desc.row_pitch = info.strides[0]; + desc.array_size = 0; + desc.slice_pitch = 0; + + SmartPtr<CLImage> input_image = convert_to_climage (context, input, desc); + SmartPtr<CLImage> output_image = convert_to_climage (context, output, desc); + + XCAM_ASSERT (input_image.ptr () && output_image.ptr ()); + XCAM_ASSERT (input_image->is_valid () && output_image->is_valid ()); + args.push_back (new CLMemArgument (input_image)); + args.push_back (new CLMemArgument (output_image)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.global[0] = desc.width; + work_size.global[1] = desc.height; + work_size.local[0] = 8; + work_size.local[1] = 4; + + _copy_kernel->set_arguments (args, work_size); + + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<CLImageHandler> +create_cl_demo_image_handler (const SmartPtr<CLContext> &context) +{ + SmartPtr<CLDemoImageHandler> demo_handler; + SmartPtr<CLImageKernel> demo_kernel; + + demo_kernel = new CLImageKernel (context); + XCAM_ASSERT (demo_kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, demo_kernel->build_kernel (kernel_demo_info, NULL) == XCAM_RETURN_NO_ERROR, + NULL, "build demo kernel failed"); + + XCAM_ASSERT (demo_kernel->is_valid ()); + demo_handler = new CLDemoImageHandler (context); + XCAM_ASSERT (demo_handler.ptr ()); + demo_handler->set_copy_kernel (demo_kernel); + + return demo_handler; +} + +SmartPtr<CLImageHandler> +create_cl_binary_demo_image_handler (const SmartPtr<CLContext> &context, const uint8_t *binary, size_t size) +{ + SmartPtr<CLDemoImageHandler> demo_handler; + SmartPtr<CLImageKernel> demo_kernel; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + demo_kernel = new CLImageKernel (context, "kernel_demo"); + { +#if 0 + XCAM_CL_KERNEL_FUNC_BINARY_BEGIN(kernel_demo) +#include "kernel_demo.clx.bin" + XCAM_CL_KERNEL_FUNC_END; + ret = demo_kernel->load_from_binary (kernel_demo_body, sizeof (kernel_demo_body)); +#endif + ret = demo_kernel->load_from_binary (binary, size); + XCAM_FAIL_RETURN ( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + NULL, + "CL image handler(%s) load binary failed", demo_kernel->get_kernel_name()); + } + XCAM_ASSERT (demo_kernel->is_valid ()); + demo_handler = new CLDemoImageHandler (context); + demo_handler->set_copy_kernel (demo_kernel); + + return demo_handler; +} + +}; diff --git a/modules/ocl/cl_demo_handler.h b/modules/ocl/cl_demo_handler.h new file mode 100644 index 0000000..c5f3203 --- /dev/null +++ b/modules/ocl/cl_demo_handler.h @@ -0,0 +1,55 @@ +/* + * cl_demo_handler.h - CL demo handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_DEMO_HANLDER_H +#define XCAM_CL_DEMO_HANLDER_H + +#include <xcam_std.h> +#include <ocl/cl_image_handler.h> + +namespace XCam { + +class CLDemoImageHandler + : public CLImageHandler +{ +public: + explicit CLDemoImageHandler (const SmartPtr<CLContext> &context); + void set_copy_kernel (SmartPtr<CLImageKernel> &kernel) { + _copy_kernel = kernel; + add_kernel (kernel); + } + +protected: + virtual XCamReturn prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + virtual XCamReturn prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + SmartPtr<CLImageKernel> _copy_kernel; +}; + +SmartPtr<CLImageHandler> +create_cl_demo_image_handler (const SmartPtr<CLContext> &context); + +SmartPtr<CLImageHandler> +create_cl_binary_demo_image_handler (const SmartPtr<CLContext> &context, const uint8_t *binary, size_t size); + +}; + +#endif //XCAM_CL_DEMO_HANLDER_H diff --git a/modules/ocl/cl_device.cpp b/modules/ocl/cl_device.cpp new file mode 100644 index 0000000..c3f2a41 --- /dev/null +++ b/modules/ocl/cl_device.cpp @@ -0,0 +1,212 @@ +/* + * cl_device.cpp - CL device + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_device.h" +#include "cl_context.h" +#if HAVE_LIBDRM +#include "intel/cl_intel_context.h" +#endif + +namespace XCam { + +SmartPtr<CLDevice> CLDevice::_instance; +Mutex CLDevice::_instance_mutex; + +SmartPtr<CLDevice> +CLDevice::instance () +{ + SmartLock locker(_instance_mutex); + if (_instance.ptr()) + return _instance; + + _instance = new CLDevice (); + // create default context + if (_instance->is_inited() && + !_instance->create_default_context ()) { + XCAM_LOG_WARNING ("CL device create default context failed"); + } + + return _instance; +} + +CLDevice::CLDevice() + : _platform_id (NULL) + , _device_id (NULL) + , _inited (false) +{ + if (!init()) { + XCAM_LOG_WARNING ("CL device init failed"); + } + XCAM_LOG_DEBUG ("CL device constructed"); +} + +CLDevice::~CLDevice () +{ + XCAM_LOG_DEBUG ("CL device destructed"); +} + +SmartPtr<CLContext> +CLDevice::get_context () +{ + //created in CLDevice construction + return _default_context; +} + +void * +CLDevice::get_extension_function (const char *func_name) +{ + XCAM_ASSERT (func_name); + void *ext_func = NULL; + +#if defined (CL_VERSION_1_2) && (CL_VERSION_1_2 == 1) + ext_func = (void *) clGetExtensionFunctionAddressForPlatform (_platform_id, func_name); +#else + ext_func = (void *) clGetExtensionFunctionAddress (func_name); +#endif + if (!ext_func) + XCAM_LOG_ERROR ("ocl driver get extension function (%s) failed", func_name); + + return ext_func; +} + +void +CLDevice::terminate () +{ + if (_default_context.ptr ()) { + _default_context->terminate (); + _default_context.release (); + } +} + +bool +CLDevice::init () +{ + cl_platform_id platform_id = NULL; + cl_device_id device_id = NULL; + cl_uint num_platform = 0; + cl_uint num_device = 0; + CLDevieInfo device_info; + + if (clGetPlatformIDs (1, &platform_id, &num_platform) != CL_SUCCESS) + { + XCAM_LOG_WARNING ("get cl platform ID failed"); + return false; + } + XCAM_ASSERT (num_platform >= 1); + + if (clGetDeviceIDs (platform_id, CL_DEVICE_TYPE_GPU, 1, &device_id, &num_device) != CL_SUCCESS) + { + XCAM_LOG_WARNING ("get cl device ID failed"); + return false; + } + XCAM_ASSERT (num_device >= 1); + + // only query first device info + if (!query_device_info (device_id, device_info)) { + //continue + XCAM_LOG_WARNING ("cl get device info failed but continue"); + } else { + XCAM_LOG_INFO ( + "cl get device info,\n" + "\tmax_compute_unit:%" PRIu32 + "\tmax_work_item_dims:%" PRIu32 + "\tmax_work_item_sizes:{%" PRIuS ", %" PRIuS ", %" PRIuS "}" + "\tmax_work_group_size:%" PRIuS + "\timage_pitch_alignment:%" PRIu32, + device_info.max_compute_unit, + device_info.max_work_item_dims, + device_info.max_work_item_sizes[0], device_info.max_work_item_sizes[1], device_info.max_work_item_sizes[2], + device_info.max_work_group_size, + device_info.image_pitch_alignment); + } + + // get platform name string length + size_t sz = 0; + if (clGetPlatformInfo(platform_id, CL_PLATFORM_NAME, 0, 0, &sz) != CL_SUCCESS) + { + XCAM_LOG_WARNING ("get cl platform name failed"); + return false; + } + + // get platform name string + if (sz >= XCAM_CL_MAX_STR_SIZE) { + sz = XCAM_CL_MAX_STR_SIZE - 1; + } + if (clGetPlatformInfo(platform_id, CL_PLATFORM_NAME, sz, _platform_name, 0) != CL_SUCCESS) + { + XCAM_LOG_WARNING ("get cl platform name failed"); + return false; + } + + _platform_id = platform_id; + _device_id = device_id; + _device_info = device_info; + _platform_name[sz] = 0; + _inited = true; + return true; +} + +bool +CLDevice::query_device_info (cl_device_id device_id, CLDevieInfo &info) +{ +#undef XCAM_CL_GET_DEVICE_INFO +#define XCAM_CL_GET_DEVICE_INFO(name, val) \ + do { \ + if (clGetDeviceInfo (device_id, name, sizeof (val), &(val), NULL) != CL_SUCCESS) { \ + XCAM_LOG_WARNING ("cl get device info(%s) failed", #name); \ + } } while (0) + + XCAM_CL_GET_DEVICE_INFO (CL_DEVICE_MAX_COMPUTE_UNITS, info.max_compute_unit); + XCAM_CL_GET_DEVICE_INFO (CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, info.max_work_item_dims); + XCAM_CL_GET_DEVICE_INFO (CL_DEVICE_MAX_WORK_ITEM_SIZES, info.max_work_item_sizes); + XCAM_CL_GET_DEVICE_INFO (CL_DEVICE_MAX_WORK_GROUP_SIZE, info.max_work_group_size); + XCAM_CL_GET_DEVICE_INFO (CL_DEVICE_MAX_WORK_GROUP_SIZE, info.max_work_group_size); + + cl_uint alignment = 0; + XCAM_CL_GET_DEVICE_INFO (CL_DEVICE_IMAGE_PITCH_ALIGNMENT, alignment); + if (alignment) + info.image_pitch_alignment = alignment; + else + info.image_pitch_alignment = 4; + return true; +} + +bool +CLDevice::create_default_context () +{ + SmartPtr<CLContext> context; + +#if HAVE_LIBDRM + context = new CLIntelContext (_instance); +#else + context = new CLContext (_instance); +#endif + if (!context->is_valid()) + return false; + + // init first cmdqueue + if (context->is_valid () && !context->init_cmd_queue (context)) { + XCAM_LOG_ERROR ("CL context init cmd queue failed"); + } + _default_context = context; + return true; +} + +}; diff --git a/modules/ocl/cl_device.h b/modules/ocl/cl_device.h new file mode 100644 index 0000000..f688e53 --- /dev/null +++ b/modules/ocl/cl_device.h @@ -0,0 +1,99 @@ +/* + * cl_device.h - CL device + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_DEVICE_H +#define XCAM_CL_DEVICE_H + +#include <xcam_std.h> +#include <xcam_mutex.h> +#include <CL/cl.h> + +namespace XCam { + +class CLContext; + +struct CLDevieInfo { + uint32_t max_compute_unit; + uint32_t max_work_item_dims; + size_t max_work_item_sizes [3]; + size_t max_work_group_size; + uint32_t image_pitch_alignment; + + CLDevieInfo () + : max_compute_unit (0) + , max_work_item_dims (0) + , max_work_group_size (0) + , image_pitch_alignment (4) + { + xcam_mem_clear (max_work_item_sizes); + } +}; + +// terminate () must called before program exit + +class CLDevice { +public: + ~CLDevice (); + static SmartPtr<CLDevice> instance (); + + bool is_inited () const { + return _inited; + } + const CLDevieInfo &get_device_info () { + return _device_info; + } + cl_device_id get_device_id () { + return _device_id; + } + cl_platform_id get_platform_id () { + return _platform_id; + } + char* get_platform_name () { + return _platform_name; + } + + SmartPtr<CLContext> get_context (); + void *get_extension_function (const char *func_name); + void terminate (); + +private: + CLDevice (); + bool init (); + bool query_device_info (cl_device_id device_id, CLDevieInfo &info); + bool create_default_context (); + + XCAM_DEAD_COPY (CLDevice); + +private: + static SmartPtr<CLDevice> _instance; + static Mutex _instance_mutex; + char _platform_name[XCAM_CL_MAX_STR_SIZE]; + cl_platform_id _platform_id; + cl_device_id _device_id; + CLDevieInfo _device_info; + bool _inited; + + //Mutex _context_mutex; + SmartPtr<CLContext> _default_context; +}; + +}; + +#endif //XCAM_CL_DEVICE_H diff --git a/modules/ocl/cl_event.cpp b/modules/ocl/cl_event.cpp new file mode 100644 index 0000000..aa7600d --- /dev/null +++ b/modules/ocl/cl_event.cpp @@ -0,0 +1,120 @@ +/* + * cl_event.cpp - CL event + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_event.h" + +namespace XCam { + +SmartPtr<CLEvent> CLEvent::NullEvent; +CLEventList CLEvent::EmptyList; + +CLEvent::CLEvent (cl_event event_id) + : _event_id (event_id) +{ +} + +CLEvent::~CLEvent () +{ + if (_event_id) { + clReleaseEvent (_event_id); + } +} + +XCamReturn +CLEvent::wait () +{ + cl_int error_code = CL_SUCCESS; + + XCAM_FAIL_RETURN ( + DEBUG, + _event_id, + XCAM_RETURN_ERROR_PARAM, + "cl event wait failed, there's no event id"); + + error_code = clWaitForEvents (1, &_event_id); + + XCAM_FAIL_RETURN ( + WARNING, + error_code == CL_SUCCESS, + XCAM_RETURN_ERROR_CL, + "cl event wait failed with error cod:%d", error_code); + + return XCAM_RETURN_NO_ERROR; +} + +bool +CLEvent::get_cl_event_info ( + cl_event_info param_name, size_t param_size, + void *param, size_t *param_size_ret) +{ + cl_int error_code = CL_SUCCESS; + + XCAM_FAIL_RETURN ( + DEBUG, + _event_id, + false, + "cl event wait failed, there's no event id"); + + clGetEventInfo (_event_id, param_name, param_size, param, param_size_ret); + + XCAM_FAIL_RETURN( + WARNING, + error_code == CL_SUCCESS, + false, + "clGetEventInfo failed on param:%d, errno:%d", param_name, error_code); + return true; +} + +XCamReturn +cl_events_wait (CLEventList &event_list) +{ +#define XCAM_MAX_CL_EVENT_COUNT 256 + + cl_event event_ids [XCAM_MAX_CL_EVENT_COUNT]; + uint32_t event_count = 0; + cl_int error_code = CL_SUCCESS; + + if (event_list.empty ()) + return XCAM_RETURN_NO_ERROR; + + xcam_mem_clear (event_ids); + for (CLEventList::iterator iter = event_list.begin (); + iter != event_list.end (); ++iter) { + SmartPtr<CLEvent> &event = *iter; + XCAM_ASSERT (event->get_event_id ()); + event_ids[event_count++] = event->get_event_id (); + if (event_count >= XCAM_MAX_CL_EVENT_COUNT) + break; + } + + XCAM_ASSERT (event_count > 0); + + error_code = clWaitForEvents (event_count, event_ids); + + XCAM_FAIL_RETURN ( + WARNING, + error_code == CL_SUCCESS, + XCAM_RETURN_ERROR_CL, + "cl events wait failed with error cod:%d", error_code); + + return XCAM_RETURN_NO_ERROR; +} + +}; diff --git a/modules/ocl/cl_event.h b/modules/ocl/cl_event.h new file mode 100644 index 0000000..226aca0 --- /dev/null +++ b/modules/ocl/cl_event.h @@ -0,0 +1,67 @@ +/* + * cl_event.h - CL event + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_EVENT_H +#define XCAM_CL_EVENT_H + +#include <xcam_std.h> +#include <list> +#include <CL/cl.h> + +namespace XCam { + +class CLEvent; + +typedef std::list<SmartPtr<CLEvent>> CLEventList; + +class CLEvent { +public: + explicit CLEvent (cl_event event_id = NULL); + ~CLEvent (); + void set_event_id (cl_event event_id) { + _event_id = event_id; + } + cl_event &get_event_id () { + return _event_id; + } + + XCamReturn wait (); + + bool get_cl_event_info ( + cl_event_info param_name, size_t param_size, + void *param, size_t *param_size_ret = NULL); + +private: + + XCAM_DEAD_COPY (CLEvent); + +public: + static SmartPtr<CLEvent> NullEvent; + static CLEventList EmptyList; + +private: + cl_event _event_id; +}; + +XCamReturn +cl_events_wait (CLEventList &event_list); +}; + +#endif //XCAM_CL_EVENT_H
\ No newline at end of file diff --git a/modules/ocl/cl_fisheye_handler.cpp b/modules/ocl/cl_fisheye_handler.cpp new file mode 100644 index 0000000..a7866c5 --- /dev/null +++ b/modules/ocl/cl_fisheye_handler.cpp @@ -0,0 +1,609 @@ +/* + * cl_fisheye_handler.cpp - CL fisheye handler + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_utils.h" +#include "cl_fisheye_handler.h" +#include "cl_device.h" + +#define XCAM_LSC_ARRAY_SIZE 64 + +static const float max_gray_threshold = 220.0f; +static const float min_gray_threshold = 80.0f; + +static const float lsc_array[XCAM_LSC_ARRAY_SIZE] = { + 1.000000f, 1.000150f, 1.000334f, 1.000523f, 1.000761f, 1.001317f, 1.002109f, 1.003472f, + 1.004502f, 1.008459f, 1.011816f, 1.014686f, 1.016767f, 1.018425f, 1.020455f, 1.022125f, + 1.023080f, 1.025468f, 1.029810f, 1.035422f, 1.041943f, 1.047689f, 1.054206f, 1.059395f, + 1.063541f, 1.068729f, 1.074158f, 1.082766f, 1.088606f, 1.095224f, 1.102773f, 1.112865f, + 1.117108f, 1.132849f, 1.140659f, 1.147847f, 1.157544f, 1.165002f, 1.175248f, 1.181730f, + 1.196203f, 1.205452f, 1.216974f, 1.236338f, 1.251963f, 1.269212f, 1.293479f, 1.311051f, + 1.336007f, 1.357711f, 1.385124f, 1.409937f, 1.448611f, 1.473716f, 1.501837f, 1.525721f, + 1.555186f, 1.602372f, 1.632105f, 1.698443f, 1.759641f, 1.836303f, 1.939085f, 2.066358f +}; + +namespace XCam { + +#define DEFAULT_FISHEYE_TABLE_SCALE 8.0f + +enum { + KernelFisheye2GPS, + KernelFisheyeTable, + KernelLSCTable +}; + +const XCamKernelInfo kernel_fisheye_info[] = { + { + "kernel_fisheye_2_gps", +#include "kernel_fisheye.clx" + , 0, + }, + { + "kernel_fisheye_table", +#include "kernel_fisheye.clx" + , 0, + }, + { + "kernel_lsc_table", +#include "kernel_fisheye.clx" + , 0, + }, +}; + +CLFisheye2GPSKernel::CLFisheye2GPSKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLFisheyeHandler> &handler) + : CLImageKernel (context) + , _handler (handler) +{ + XCAM_ASSERT (handler.ptr ()); +} + +XCamReturn +CLFisheye2GPSKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLImage> input_y = _handler->get_input_image (NV12PlaneYIdx); + SmartPtr<CLImage> input_uv = _handler->get_input_image (NV12PlaneUVIdx); + SmartPtr<CLImage> output_y = _handler->get_output_image (NV12PlaneYIdx); + SmartPtr<CLImage> output_uv = _handler->get_output_image (NV12PlaneUVIdx); + const CLImageDesc &input_y_desc = input_y->get_image_desc (); + const CLImageDesc &outuv_desc = output_uv->get_image_desc (); + FisheyeInfo fisheye_info; + float input_y_size[2]; + float out_center[2]; //width/height + float radian_per_pixel[2]; + + input_y_size[0] = input_y_desc.width; + input_y_size[1] = input_y_desc.height; + + uint32_t dst_w, dst_h; + float dst_range_x, dst_range_y; + _handler->get_output_size (dst_w, dst_h); + out_center[0] = (float)dst_w / 2.0f; + out_center[1] = (float)dst_h / 2.0f; + + _handler->get_dst_range (dst_range_x, dst_range_y); + radian_per_pixel[0] = degree2radian (dst_range_x) / (float)dst_w; + radian_per_pixel[1] = degree2radian (dst_range_y) / (float)dst_h; + + fisheye_info = _handler->get_fisheye_info (); + fisheye_info.wide_angle = degree2radian (fisheye_info.wide_angle); + fisheye_info.rotate_angle = degree2radian (fisheye_info.rotate_angle); + + XCAM_LOG_DEBUG ("@CLFisheye2GPSKernel input size(%d, %d), out_center:(%d, %d), range:(%d,%d)", + (int)input_y_size[0], (int)input_y_size[1], + (int)out_center[0], (int)out_center[1], + (int)dst_range_x, (int)dst_range_y); + + args.push_back (new CLMemArgument (input_y)); + args.push_back (new CLMemArgument (input_uv)); + args.push_back (new CLArgumentTArray<float, 2> (input_y_size)); + args.push_back (new CLArgumentT<FisheyeInfo> (fisheye_info)); + args.push_back (new CLMemArgument (output_y)); + args.push_back (new CLMemArgument (output_uv)); + args.push_back (new CLArgumentTArray<float, 2> (out_center)); + args.push_back (new CLArgumentTArray<float, 2> (radian_per_pixel)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 16; + work_size.local[1] = 4; + work_size.global[0] = XCAM_ALIGN_UP (outuv_desc.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (outuv_desc.height, work_size.local[1]); + + return XCAM_RETURN_NO_ERROR; +} + +CLFisheyeHandler::CLFisheyeHandler (const SmartPtr<CLContext> &context, SurroundMode surround_mode, bool use_map, bool need_lsc) + : CLImageHandler (context, "CLFisheyeHandler") + , _output_width (0) + , _output_height (0) + , _range_longitude (180.0f) + , _range_latitude (180.0f) + , _map_factor (DEFAULT_FISHEYE_TABLE_SCALE) + , _use_map (use_map) + , _need_lsc (need_lsc ? 1 : 0) + , _lsc_array_size (0) + , _lsc_array (NULL) + , _surround_mode (surround_mode) +{ + xcam_mem_clear (_gray_threshold); +} + +CLFisheyeHandler::~CLFisheyeHandler() +{ + if (_lsc_array) + xcam_free (_lsc_array); +} + +void +CLFisheyeHandler::set_output_size (uint32_t width, uint32_t height) +{ + _output_width = width; + _output_height = height; +} + +void +CLFisheyeHandler::get_output_size (uint32_t &width, uint32_t &height) const +{ + width = _output_width; + height = _output_height; +} + +void +CLFisheyeHandler::set_dst_range (float longitude, float latitude) +{ + _range_longitude = longitude; + _range_latitude = latitude; +} + +void +CLFisheyeHandler::get_dst_range (float &longitude, float &latitude) const +{ + longitude = _range_longitude; + latitude = _range_latitude; +} + +void +CLFisheyeHandler::set_fisheye_info (const FisheyeInfo &info) +{ + _fisheye_info = info; +} + +void +CLFisheyeHandler::set_lsc_table (float *table, uint32_t table_size) +{ + if (_lsc_array) + xcam_free (_lsc_array); + + _lsc_array_size = table_size; + _lsc_array = (float *) xcam_malloc0 (_lsc_array_size * sizeof (float)); + XCAM_ASSERT (_lsc_array); + memcpy (_lsc_array, table, _lsc_array_size * sizeof (float)); +} + +void +CLFisheyeHandler::set_lsc_gray_threshold (float min_threshold, float max_threshold) +{ + _gray_threshold[0] = min_threshold; + _gray_threshold[1] = max_threshold; +} + +XCamReturn +CLFisheyeHandler::prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, + VideoBufferInfo &output) +{ + XCAM_FAIL_RETURN ( + WARNING, input.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM, + "CLFisheyeHandler(%s) input buffer format(%s) is not supported, try NV12", + get_name (), xcam_fourcc_to_string (input.format)); + + if (!_output_width || !_output_height) { + return XCAM_RETURN_ERROR_PARAM; + } + XCAM_FAIL_RETURN ( + WARNING, _output_width && _output_height, XCAM_RETURN_ERROR_PARAM, + "CLFisheyeHandler output size(%d, %d) should > 0", + _output_width, _output_height); + + output.init ( + input.format, _output_width, _output_height, + XCAM_ALIGN_UP (_output_width, 16), XCAM_ALIGN_UP (_output_height, 16)); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLFisheyeHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + const VideoBufferInfo &in_info = input->get_video_info (); + const VideoBufferInfo &out_info = output->get_video_info (); + SmartPtr<CLContext> context = get_context (); + uint32_t input_image_w = XCAM_ALIGN_DOWN (in_info.width, 2); + uint32_t input_image_h = XCAM_ALIGN_DOWN (in_info.height, 2); + + XCAM_FAIL_RETURN ( + WARNING, _fisheye_info.is_valid (), XCAM_RETURN_ERROR_PARAM, + "CLFisheyeHandler fisheye info is not valid, please check"); + + CLImageDesc cl_desc; + cl_desc.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc.format.image_channel_order = CL_R; + cl_desc.width = input_image_w; + cl_desc.height = input_image_h; + cl_desc.row_pitch = in_info.strides[NV12PlaneYIdx]; + _input[NV12PlaneYIdx] = convert_to_climage (context, input, cl_desc, in_info.offsets[NV12PlaneYIdx]); + + cl_desc.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc.format.image_channel_order = CL_RG; + cl_desc.width = input_image_w / 2; + cl_desc.height = input_image_h / 2; + cl_desc.row_pitch = in_info.strides[NV12PlaneUVIdx]; + _input[NV12PlaneUVIdx] = convert_to_climage (context, input, cl_desc, in_info.offsets[NV12PlaneUVIdx]); + + if (_use_map) { + cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_desc.format.image_channel_order = CL_RGBA; + cl_desc.width = XCAM_ALIGN_DOWN (out_info.width, 8) / 8; //CL_RGBA * CL_UNSIGNED_INT16 = 8 + cl_desc.height = XCAM_ALIGN_DOWN (out_info.height, 2); + cl_desc.row_pitch = out_info.strides[NV12PlaneYIdx]; + _output[NV12PlaneYIdx] = convert_to_climage (context, output, cl_desc, out_info.offsets[NV12PlaneYIdx]); + cl_desc.height /= 2; + cl_desc.row_pitch = out_info.strides[NV12PlaneUVIdx]; + _output[NV12PlaneUVIdx] = convert_to_climage (context, output, cl_desc, out_info.offsets[NV12PlaneUVIdx]); + } else { + cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT8; + cl_desc.format.image_channel_order = CL_RGBA; + cl_desc.width = XCAM_ALIGN_DOWN (out_info.width, 4) / 4; //CL_RGBA * CL_UNSIGNED_INT8 = 4 + cl_desc.height = XCAM_ALIGN_DOWN (out_info.height, 2); + cl_desc.row_pitch = out_info.strides[NV12PlaneYIdx]; + _output[NV12PlaneYIdx] = convert_to_climage (context, output, cl_desc, out_info.offsets[NV12PlaneYIdx]); + cl_desc.height /= 2; + cl_desc.row_pitch = out_info.strides[NV12PlaneUVIdx]; + _output[NV12PlaneUVIdx] = convert_to_climage (context, output, cl_desc, out_info.offsets[NV12PlaneUVIdx]); + } + + XCAM_ASSERT ( + _input[NV12PlaneYIdx].ptr () && _input[NV12PlaneYIdx]->is_valid () && + _input[NV12PlaneUVIdx].ptr () && _input[NV12PlaneUVIdx]->is_valid () && + _output[NV12PlaneYIdx].ptr () && _output[NV12PlaneYIdx]->is_valid () && + _output[NV12PlaneUVIdx].ptr () && _output[NV12PlaneUVIdx]->is_valid ()); + + if (_use_map && !_geo_table.ptr ()) { + generate_fisheye_table (input_image_w, input_image_h, _fisheye_info); + } + + if (!_lsc_table.ptr () && _need_lsc) + generate_lsc_table (input_image_w, input_image_h, _fisheye_info); + + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<CLImage> +CLFisheyeHandler::create_cl_image ( + uint32_t width, uint32_t height, cl_channel_order order, cl_channel_type type) +{ + CLImageDesc cl_desc; + cl_desc.format.image_channel_data_type = type; + cl_desc.format.image_channel_order = order; + cl_desc.width = width; + cl_desc.height = height; + + SmartPtr<CLContext> context = get_context (); + XCAM_ASSERT (context.ptr ()); + SmartPtr<CLImage> image = new CLImage2D (context, cl_desc); + XCAM_FAIL_RETURN ( + ERROR, image.ptr () && image->is_valid (), + NULL, "[%s] create cl image failed", get_name ()); + return image; +} + +#if 0 +static void +dump_geo_table (SmartPtr<CLImage> table) +{ + const CLImageDesc &desc = table->get_image_desc (); + void *ptr = NULL; + size_t origin[3] = {0, 0, 0}; + size_t region[3] = {desc.width, desc.height, 1}; + size_t row_pitch; + size_t slice_pitch; + + char name[1024]; + snprintf (name, 1024, "geo_table_x_%dx%d.x", desc.width, desc.height); + FILE *fp = fopen (name, "wb"); + XCamReturn ret = table->enqueue_map (ptr, origin, region, &row_pitch, &slice_pitch, CL_MAP_READ); + XCAM_ASSERT (ret == XCAM_RETURN_NO_ERROR); + + for (uint32_t i = 0; i < desc.height; ++i) { + float * line = (float*)((uint8_t*)ptr + row_pitch * i); + for (uint32_t j = 0; j < desc.width; ++j) { + float *buf = line + j * 4; + if (i == 120) + printf ("%.02f,", *buf); + uint8_t val = *buf * 255; + fwrite (&val, sizeof (val), 1, fp); + } + } + printf ("\n"); + fclose (fp); + table->enqueue_unmap (ptr); +} +#endif + +XCamReturn +CLFisheyeHandler::generate_fisheye_table ( + uint32_t fisheye_width, uint32_t fisheye_height, const FisheyeInfo &fisheye_info) +{ + SmartPtr<CLContext> context = get_context (); + XCAM_ASSERT (context.ptr ()); + SmartPtr<CLKernel> table_kernel = new CLKernel (context, "fisheye_table_temp"); + XCAM_FAIL_RETURN ( + ERROR, table_kernel->build_kernel (kernel_fisheye_info[KernelFisheyeTable], NULL) == XCAM_RETURN_NO_ERROR, + XCAM_RETURN_ERROR_CL, "[%s] build fisheye table kernel failed", get_name ()); + + float longitude, latitude; + get_dst_range (longitude, latitude); + XCAM_FAIL_RETURN ( + ERROR, longitude > 0.0f && latitude > 0.0f, + XCAM_RETURN_ERROR_PARAM, "[%s] dest latitude and longitude were not set", get_name ()); + + uint32_t output_width, output_height; + get_output_size (output_width, output_height); + + uint32_t table_width, table_height; + table_width = output_width / _map_factor; + table_width = XCAM_ALIGN_UP (table_width, 4); + table_height = output_height / _map_factor; + table_height = XCAM_ALIGN_UP (table_height, 2); + _geo_table = create_cl_image (table_width, table_height, CL_RGBA, CL_FLOAT); + XCAM_FAIL_RETURN ( + ERROR, _geo_table.ptr () && _geo_table->is_valid (), + XCAM_RETURN_ERROR_MEM, "[%s] check geo map buffer failed", get_name ()); + + if(_surround_mode == BowlView) { + BowlDataConfig bowl_data_config = get_bowl_config(); + IntrinsicParameter intrinsic_param = get_intrinsic_param(); + ExtrinsicParameter extrinsic_param = get_extrinsic_param(); + + SurViewFisheyeDewarp::MapTable map_table(table_width * table_height * 2); + PolyFisheyeDewarp fd; + fd.set_intrinsic_param(intrinsic_param); + fd.set_extrinsic_param(extrinsic_param); + + fd.fisheye_dewarp(map_table, table_width, table_height, output_width, output_height, bowl_data_config); + + float *map_ptr = NULL; + size_t origin[3] = {0, 0, 0}; + size_t region[3] = {table_width, table_height, 1}; + size_t row_pitch; + size_t slice_pitch; + XCamReturn ret = _geo_table->enqueue_map ((void *&)map_ptr, origin, region, &row_pitch, &slice_pitch, CL_MAP_WRITE); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "CLFisheyeHandler mesh table failed in enqueue_map"); + + for (uint32_t row = 0; row < table_height; row++) { + for(uint32_t col = 0; col < table_width; col++) { + map_ptr[row * row_pitch / 4 + col * 4] = map_table[row * table_width + col].x / fisheye_width; + map_ptr[row * row_pitch / 4 + col * 4 + 1] = map_table[row * table_width + col].y / fisheye_height; + } + } + _geo_table->enqueue_unmap ((void *&)map_ptr); + } else { + CLArgList args; + CLWorkSize work_size; + + FisheyeInfo fisheye_arg1 = fisheye_info; + fisheye_arg1.wide_angle = degree2radian (fisheye_info.wide_angle); + fisheye_arg1.rotate_angle = degree2radian (fisheye_info.rotate_angle); + args.push_back (new CLArgumentT<FisheyeInfo> (fisheye_arg1)); + + float fisheye_image_size[2]; + fisheye_image_size[0] = fisheye_width; + fisheye_image_size[1] = fisheye_height; + args.push_back (new CLArgumentTArray<float, 2> (fisheye_image_size)); + args.push_back (new CLMemArgument (_geo_table)); + + float radian_per_pixel[2]; + radian_per_pixel[0] = degree2radian (longitude / table_width); + radian_per_pixel[1] = degree2radian (latitude / table_height); + args.push_back (new CLArgumentTArray<float, 2> (radian_per_pixel)); + + float table_center[2]; + table_center[0] = table_width / 2.0f; + table_center[1] = table_height / 2.0f; + args.push_back (new CLArgumentTArray<float, 2> (table_center)); + + work_size.dim = 2; + work_size.local[0] = 8; + work_size.local[1] = 4; + work_size.global[0] = XCAM_ALIGN_UP (table_width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (table_height, work_size.local[1]); + + XCAM_FAIL_RETURN ( + ERROR, table_kernel->set_arguments (args, work_size) == XCAM_RETURN_NO_ERROR, + XCAM_RETURN_ERROR_CL, "kernel_fisheye_table set arguments failed"); + + XCAM_FAIL_RETURN ( + ERROR, table_kernel->execute (table_kernel, true) == XCAM_RETURN_NO_ERROR, + XCAM_RETURN_ERROR_CL, "[%s] execute kernel_fisheye_table failed", get_name ()); + } + //dump_geo_table (_geo_table); + + return XCAM_RETURN_NO_ERROR; +} + +void +CLFisheyeHandler::ensure_lsc_params () +{ + if (_lsc_array) + return; + + _lsc_array_size = XCAM_LSC_ARRAY_SIZE; + _lsc_array = (float *) xcam_malloc0 (_lsc_array_size * sizeof (float)); + XCAM_ASSERT (_lsc_array); + memcpy (_lsc_array, lsc_array, _lsc_array_size * sizeof (float)); + + _gray_threshold[1] = max_gray_threshold; + _gray_threshold[0] = min_gray_threshold; +} + +XCamReturn +CLFisheyeHandler::generate_lsc_table ( + uint32_t fisheye_width, uint32_t fisheye_height, FisheyeInfo &fisheye_info) +{ + if (!_need_lsc) { + XCAM_LOG_WARNING ("lsc is not needed, don't generate lsc table"); + return XCAM_RETURN_NO_ERROR; + } + + if (!_geo_table.ptr ()) { + XCAM_LOG_ERROR ("generate lsc table failed, need generate fisheye table first"); + return XCAM_RETURN_ERROR_MEM; + } + + ensure_lsc_params (); + + SmartPtr<CLContext> context = get_context (); + XCAM_ASSERT (context.ptr ()); + SmartPtr<CLKernel> table_kernel = new CLKernel (context, "lsc_table"); + XCAM_FAIL_RETURN ( + ERROR, table_kernel->build_kernel (kernel_fisheye_info[KernelLSCTable], NULL) == XCAM_RETURN_NO_ERROR, + XCAM_RETURN_ERROR_CL, "[%s] build lsc table kernel failed", get_name ()); + + SmartPtr<CLBuffer> array_buf = new CLBuffer ( + context, _lsc_array_size * sizeof (float), + CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, _lsc_array); + xcam_free (_lsc_array); + + CLImageDesc desc = _geo_table->get_image_desc (); + _lsc_table = create_cl_image (desc.width, desc.height, CL_R, CL_FLOAT); + XCAM_FAIL_RETURN ( + ERROR, _lsc_table.ptr () && _lsc_table->is_valid (), + XCAM_RETURN_ERROR_MEM, "[%s] create lsc image failed", get_name ()); + + CLArgList args; + args.push_back (new CLMemArgument (_geo_table)); + args.push_back (new CLMemArgument (_lsc_table)); + args.push_back (new CLMemArgument (array_buf)); + args.push_back (new CLArgumentT<uint32_t> (_lsc_array_size)); + args.push_back (new CLArgumentT<FisheyeInfo> (fisheye_info)); + + float fisheye_image_size[2]; + fisheye_image_size[0] = fisheye_width; + fisheye_image_size[1] = fisheye_height; + args.push_back (new CLArgumentTArray<float, 2> (fisheye_image_size)); + + CLWorkSize work_size; + work_size.dim = 2; + work_size.local[0] = 8; + work_size.local[1] = 4; + work_size.global[0] = XCAM_ALIGN_UP (desc.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (desc.height, work_size.local[1]); + + XCAM_FAIL_RETURN ( + ERROR, table_kernel->set_arguments (args, work_size) == XCAM_RETURN_NO_ERROR, + XCAM_RETURN_ERROR_CL, "kernel_lsc_table set arguments failed"); + + XCAM_FAIL_RETURN ( + ERROR, table_kernel->execute (table_kernel, true) == XCAM_RETURN_NO_ERROR, + XCAM_RETURN_ERROR_CL, "[%s] execute kernel_lsc_table failed", get_name ()); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLFisheyeHandler::execute_done (SmartPtr<VideoBuffer> &output) +{ + XCAM_UNUSED (output); + + for (int i = 0; i < NV12PlaneMax; ++i) { + _input[i].release (); + _output[i].release (); + } + + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<CLImage> +CLFisheyeHandler::get_geo_input_image (NV12PlaneIdx index) { + return get_input_image(index); +} + +SmartPtr<CLImage> +CLFisheyeHandler::get_geo_output_image (NV12PlaneIdx index) { + return get_output_image (index); +} + +void +CLFisheyeHandler::get_geo_equivalent_out_size (float &width, float &height) +{ + width = _output_width; + height = _output_height; +} + +void +CLFisheyeHandler::get_geo_pixel_out_size (float &width, float &height) +{ + width = _output_width; + height = _output_height; +} + +SmartPtr<CLImage> +CLFisheyeHandler::get_lsc_table () { + XCAM_ASSERT (_lsc_table.ptr ()); + return _lsc_table; +} + +float* +CLFisheyeHandler::get_lsc_gray_threshold () { + return _gray_threshold; +} + +static SmartPtr<CLImageKernel> +create_fishey_gps_kernel (const SmartPtr<CLContext> &context, SmartPtr<CLFisheyeHandler> handler) +{ + SmartPtr<CLImageKernel> kernel = new CLFisheye2GPSKernel (context, handler); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, kernel->build_kernel (kernel_fisheye_info[KernelFisheye2GPS], NULL) == XCAM_RETURN_NO_ERROR, + NULL, "build fisheye kernel failed"); + return kernel; +} + +SmartPtr<CLImageHandler> +create_fisheye_handler (const SmartPtr<CLContext> &context, SurroundMode surround_mode, bool use_map, bool need_lsc) +{ + SmartPtr<CLFisheyeHandler> handler; + SmartPtr<CLImageKernel> kernel; + + handler = new CLFisheyeHandler (context, surround_mode, use_map, need_lsc); + XCAM_ASSERT (handler.ptr ()); + + if (use_map) { + kernel = create_geo_map_kernel (context, handler, need_lsc); + } else { + kernel = create_fishey_gps_kernel (context, handler); + } + XCAM_FAIL_RETURN ( + ERROR, kernel.ptr (), NULL, "Fisheye handler create kernel failed."); + + handler->add_kernel (kernel); + return handler; +} + + +} diff --git a/modules/ocl/cl_fisheye_handler.h b/modules/ocl/cl_fisheye_handler.h new file mode 100644 index 0000000..be7452f --- /dev/null +++ b/modules/ocl/cl_fisheye_handler.h @@ -0,0 +1,163 @@ +/* + * cl_fisheye_handler.h - CL fisheye handler + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_FISHEYE_HANDLER_H +#define XCAM_CL_FISHEYE_HANDLER_H + +#include <xcam_std.h> +#include <interface/data_types.h> +#include <ocl/cl_image_handler.h> +#include <ocl/cl_geo_map_handler.h> +#include <surview_fisheye_dewarp.h> + +namespace XCam { + +class CLFisheyeHandler; +class CLFisheye2GPSKernel + : public CLImageKernel +{ +public: + explicit CLFisheye2GPSKernel (const SmartPtr<CLContext> &context, SmartPtr<CLFisheyeHandler> &handler); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + +private: + SmartPtr<CLFisheyeHandler> _handler; +}; + +class CLFisheyeHandler + : public CLImageHandler + , public GeoKernelParamCallback +{ + friend class CLFisheye2GPSKernel; +public: + explicit CLFisheyeHandler (const SmartPtr<CLContext> &context, SurroundMode surround_mode, bool use_map, bool need_lsc); + virtual ~CLFisheyeHandler(); + + void set_output_size (uint32_t width, uint32_t height); + void get_output_size (uint32_t &width, uint32_t &height) const; + + void set_dst_range (float longitude, float latitude); + void get_dst_range (float &longitude, float &latitude) const; + void set_fisheye_info (const FisheyeInfo &info); + const FisheyeInfo &get_fisheye_info () const { + return _fisheye_info; + } + + void set_lsc_table (float *table, uint32_t table_size); + void set_lsc_gray_threshold (float min_threshold, float max_threshold); + + void set_bowl_config(const BowlDataConfig bowl_data_config) { + _bowl_data_config = bowl_data_config; + } + const BowlDataConfig &get_bowl_config() { + return _bowl_data_config; + } + + void set_intrinsic_param(const IntrinsicParameter intrinsic_param) { + _intrinsic_param = intrinsic_param; + } + const IntrinsicParameter &get_intrinsic_param() { + return _intrinsic_param; + } + + void set_extrinsic_param(const ExtrinsicParameter extrinsic_param) { + _extrinsic_param = extrinsic_param; + } + const ExtrinsicParameter &get_extrinsic_param() { + return _extrinsic_param; + } + + +protected: + // derived from CLImageHandler + virtual XCamReturn prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, VideoBufferInfo &output); + virtual XCamReturn prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + virtual XCamReturn execute_done (SmartPtr<VideoBuffer> &output); + + // derived from GeoKernelParamCallback + virtual SmartPtr<CLImage> get_geo_input_image (NV12PlaneIdx index); + virtual SmartPtr<CLImage> get_geo_output_image (NV12PlaneIdx index); + virtual SmartPtr<CLImage> get_geo_map_table () { + return _geo_table; + } + virtual void get_geo_equivalent_out_size (float &width, float &height); + virtual void get_geo_pixel_out_size (float &width, float &height); + + virtual SmartPtr<CLImage> get_lsc_table (); + virtual float* get_lsc_gray_threshold (); + +private: + SmartPtr<CLImage> &get_input_image (NV12PlaneIdx index) { + XCAM_ASSERT (index < NV12PlaneMax); + return _input [index]; + } + SmartPtr<CLImage> &get_output_image (NV12PlaneIdx index) { + XCAM_ASSERT (index < NV12PlaneMax); + return _output [index]; + } + + SmartPtr<CLImage> create_cl_image ( + uint32_t width, uint32_t height, cl_channel_order order, cl_channel_type type); + XCamReturn generate_fisheye_table ( + uint32_t fisheye_width, uint32_t fisheye_height, const FisheyeInfo &fisheye_info); + + void ensure_lsc_params (); + XCamReturn generate_lsc_table ( + uint32_t fisheye_width, uint32_t fisheye_height, FisheyeInfo &fisheye_info); + + + XCAM_DEAD_COPY (CLFisheyeHandler); + +private: + uint32_t _output_width; + uint32_t _output_height; + float _range_longitude; + float _range_latitude; + FisheyeInfo _fisheye_info; + float _map_factor; + bool _use_map; + uint32_t _need_lsc; + uint32_t _lsc_array_size; + float _gray_threshold[2]; // [min_gray_threshold, max_gray_threshold] + float *_lsc_array; + + BowlDataConfig _bowl_data_config; + + IntrinsicParameter _intrinsic_param; + ExtrinsicParameter _extrinsic_param; + + SurroundMode _surround_mode; + + SmartPtr<CLImage> _geo_table; + SmartPtr<CLImage> _lsc_table; + SmartPtr<CLImage> _input[NV12PlaneMax]; + SmartPtr<CLImage> _output[NV12PlaneMax]; +}; + +SmartPtr<CLImageHandler> +create_fisheye_handler (const SmartPtr<CLContext> &context, SurroundMode surround_mode = SphereView, bool use_map = false, bool need_lsc = false); + +} + +#endif //XCAM_CL_FISHEYE_HANDLER_H + diff --git a/modules/ocl/cl_gauss_handler.cpp b/modules/ocl/cl_gauss_handler.cpp new file mode 100644 index 0000000..e29df9e --- /dev/null +++ b/modules/ocl/cl_gauss_handler.cpp @@ -0,0 +1,214 @@ +/* + * cl_gauss_handler.cpp - CL gauss handler + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: wangfei <feix.w.wang@intel.com> + * Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_utils.h" +#include "cl_gauss_handler.h" +#include <algorithm> + +#define XCAM_GAUSS_SCALE(radius) ((radius) * 2 + 1) + +namespace XCam { + +const static XCamKernelInfo kernel_gauss_info = { + "kernel_gauss", +#include "kernel_gauss.clx" + , 0, +}; + +class CLGaussImageKernelImpl + : public CLGaussImageKernel +{ +public: + CLGaussImageKernelImpl ( + SmartPtr<CLGaussImageHandler> &handler, + const SmartPtr<CLContext> &context, uint32_t radius, float sigma); + + virtual SmartPtr<VideoBuffer> get_input_buf (); + virtual SmartPtr<VideoBuffer> get_output_buf (); +private: + SmartPtr<CLGaussImageHandler> _handler; +}; + +CLGaussImageKernelImpl::CLGaussImageKernelImpl ( + SmartPtr<CLGaussImageHandler> &handler, + const SmartPtr<CLContext> &context, + uint32_t radius, + float sigma +) + : CLGaussImageKernel (context, radius, sigma) + , _handler (handler) +{ +} + +SmartPtr<VideoBuffer> +CLGaussImageKernelImpl::get_input_buf () +{ + return _handler->get_input_buf (); +} +SmartPtr<VideoBuffer> +CLGaussImageKernelImpl::get_output_buf () +{ + return _handler->get_output_buf ();; +} + +CLGaussImageKernel::CLGaussImageKernel ( + const SmartPtr<CLContext> &context, uint32_t radius, float sigma) + : CLImageKernel (context, "kernel_gauss") + , _g_radius (radius) + , _g_table (NULL) +{ + set_gaussian(radius, sigma); +} + +CLGaussImageKernel::~CLGaussImageKernel () +{ + xcam_free (_g_table); +} + +bool +CLGaussImageKernel::set_gaussian (uint32_t radius, float sigma) +{ + uint32_t i, j; + uint32_t scale = XCAM_GAUSS_SCALE (radius); + float dis = 0.0f, sum = 0.0f; + uint32_t scale_size = scale * scale * sizeof (_g_table[0]); + + xcam_free (_g_table); + _g_table_buffer.release (); + _g_radius = radius; + _g_table = (float*) xcam_malloc0 (scale_size); + XCAM_ASSERT (_g_table); + + for(i = 0; i < scale; i++) { + for(j = 0; j < scale; j++) { + dis = ((float)i - radius) * ((float)i - radius) + ((float)j - radius) * ((float)j - radius); + _g_table[i * scale + j] = exp(-dis / (2.0f * sigma * sigma)); + sum += _g_table[i * scale + j]; + } + } + + for(i = 0; i < scale * scale; i++) { + _g_table[i] = _g_table[i] / sum; + } + + _g_table_buffer = new CLBuffer( + get_context (), scale_size, + CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR , _g_table); + + return true; +} + +XCamReturn +CLGaussImageKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + SmartPtr<VideoBuffer> input = get_input_buf (); + SmartPtr<VideoBuffer> output = get_output_buf (); + + XCAM_FAIL_RETURN ( + WARNING, + input.ptr () && output.ptr (), + XCAM_RETURN_ERROR_MEM, + "cl image kernel(%s) get input/output buffer failed", get_kernel_name ()); + + const VideoBufferInfo & video_info_in = input->get_video_info (); + const VideoBufferInfo & video_info_out = output->get_video_info (); + CLImageDesc cl_desc_in, cl_desc_out; + + cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc_in.format.image_channel_order = CL_R; + cl_desc_in.width = video_info_in.width; + cl_desc_in.height = video_info_in.height; + cl_desc_in.row_pitch = video_info_in.strides[0]; + SmartPtr<CLImage> image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]); + + cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc_out.format.image_channel_order = CL_RGBA; + cl_desc_out.width = video_info_out.width / 4; + cl_desc_out.height = video_info_out.height; + cl_desc_out.row_pitch = video_info_out.strides[0]; + SmartPtr<CLImage> image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[0]); + + XCAM_FAIL_RETURN ( + WARNING, + image_in->is_valid () && image_out->is_valid (), + XCAM_RETURN_ERROR_MEM, + "cl image kernel(%s) in/out memory not available", get_kernel_name ()); + + //set args; + args.push_back (new CLMemArgument (image_in)); + args.push_back (new CLMemArgument (image_out)); + args.push_back (new CLMemArgument (_g_table_buffer)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.global[0] = XCAM_ALIGN_UP(cl_desc_out.width, 8); + work_size.global[1] = XCAM_ALIGN_UP (cl_desc_out.height / 2, 4); + work_size.local[0] = 8; + work_size.local[1] = 4; + + return XCAM_RETURN_NO_ERROR; +} + +CLGaussImageHandler::CLGaussImageHandler (const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) +{ +} + +bool +CLGaussImageHandler::set_gaussian_table (int size, float sigma) +{ + _gauss_kernel->set_gaussian (size, sigma); + return true; +} + +bool +CLGaussImageHandler::set_gauss_kernel(SmartPtr<CLGaussImageKernel> &kernel) +{ + SmartPtr<CLImageKernel> image_kernel = kernel; + add_kernel (image_kernel); + _gauss_kernel = kernel; + return true; +} + +SmartPtr<CLImageHandler> +create_cl_gauss_image_handler (const SmartPtr<CLContext> &context, uint32_t radius, float sigma) +{ + SmartPtr<CLGaussImageHandler> gauss_handler; + SmartPtr<CLGaussImageKernel> gauss_kernel; + char build_options[1024]; + + xcam_mem_clear (build_options); + snprintf (build_options, sizeof (build_options), " -DGAUSS_RADIUS=%d ", radius); + + gauss_handler = new CLGaussImageHandler (context, "cl_handler_gauss"); + gauss_kernel = new CLGaussImageKernelImpl (gauss_handler, context, radius, sigma); + XCAM_ASSERT (gauss_kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, gauss_kernel->build_kernel (kernel_gauss_info, build_options) == XCAM_RETURN_NO_ERROR, NULL, + "build gaussian kernel(%s) failed", kernel_gauss_info.kernel_name); + + XCAM_ASSERT (gauss_kernel->is_valid ()); + gauss_handler->set_gauss_kernel (gauss_kernel); + + return gauss_handler; +} + +} diff --git a/modules/ocl/cl_gauss_handler.h b/modules/ocl/cl_gauss_handler.h new file mode 100644 index 0000000..261c89a --- /dev/null +++ b/modules/ocl/cl_gauss_handler.h @@ -0,0 +1,76 @@ +/* + * cl_gauss_handler.h - CL gauss handler. + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: wangfei <feix.w.wang@intel.com> + */ + +#ifndef XCAM_CL_GAUSS_HANLDER_H +#define XCAM_CL_GAUSS_HANLDER_H + +#include <xcam_std.h> +#include <base/xcam_3a_result.h> +#include <x3a_stats_pool.h> +#include <ocl/cl_image_handler.h> + +#define XCAM_GAUSS_DEFAULT_RADIUS 2 +#define XCAM_GAUSS_DEFAULT_SIGMA 2.0f + +namespace XCam { + +class CLGaussImageKernel + : public CLImageKernel +{ +public: + explicit CLGaussImageKernel ( + const SmartPtr<CLContext> &context, uint32_t radius, float sigma); + virtual ~CLGaussImageKernel (); + bool set_gaussian(uint32_t radius, float sigma); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + + // new virtual fucntions + virtual SmartPtr<VideoBuffer> get_input_buf () = 0; + virtual SmartPtr<VideoBuffer> get_output_buf () = 0; + +protected: + SmartPtr<CLBuffer> _g_table_buffer; + uint32_t _g_radius; + float *_g_table; +}; + +class CLGaussImageHandler + : public CLImageHandler +{ +public: + explicit CLGaussImageHandler (const SmartPtr<CLContext> &context, const char *name); + bool set_gauss_kernel(SmartPtr<CLGaussImageKernel> &kernel); + bool set_gaussian_table(int size, float sigma); + +private: + SmartPtr<CLGaussImageKernel> _gauss_kernel; +}; + +SmartPtr<CLImageHandler> +create_cl_gauss_image_handler ( + const SmartPtr<CLContext> &context, + uint32_t radius = XCAM_GAUSS_DEFAULT_RADIUS, + float sigma = XCAM_GAUSS_DEFAULT_SIGMA); + +}; + +#endif //XCAM_CL_GAUSS_HANLDER_H diff --git a/modules/ocl/cl_geo_map_handler.cpp b/modules/ocl/cl_geo_map_handler.cpp new file mode 100644 index 0000000..8151425 --- /dev/null +++ b/modules/ocl/cl_geo_map_handler.cpp @@ -0,0 +1,354 @@ +/* + * cl_geo_map_handler.cpp - CL geometry map handler + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_utils.h" +#include "cl_geo_map_handler.h" +#include "cl_device.h" + +namespace XCam { + +static const XCamKernelInfo kernel_geo_map_info = { + "kernel_geo_map", +#include "kernel_geo_map.clx" + , 0, +}; + +// GEO_MAP_CHANNEL for CL_RGBA channel +#define GEO_MAP_CHANNEL 4 /* only use channel_0, channel_1 */ + +CLGeoMapKernel::CLGeoMapKernel ( + const SmartPtr<CLContext> &context, const SmartPtr<GeoKernelParamCallback> handler, bool need_lsc) + : CLImageKernel (context) + , _handler (handler) + , _need_lsc (need_lsc) +{ + XCAM_ASSERT (handler.ptr ()); +} + +XCamReturn +CLGeoMapKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLImage> input_y = _handler->get_geo_input_image (NV12PlaneYIdx); + SmartPtr<CLImage> input_uv = _handler->get_geo_input_image (NV12PlaneUVIdx); + SmartPtr<CLImage> output_y = _handler->get_geo_output_image (NV12PlaneYIdx); + SmartPtr<CLImage> output_uv = _handler->get_geo_output_image (NV12PlaneUVIdx); + const CLImageDesc &outuv_desc = output_uv->get_image_desc (); + SmartPtr<CLImage> geo_image = _handler->get_geo_map_table (); + + float geo_scale_size[2]; //width/height + float out_size[2]; + _handler->get_geo_equivalent_out_size (geo_scale_size[0], geo_scale_size[1]); + _handler->get_geo_pixel_out_size (out_size[0], out_size[1]); + + args.push_back (new CLMemArgument (input_y)); + args.push_back (new CLMemArgument (input_uv)); + args.push_back (new CLMemArgument (geo_image)); + args.push_back (new CLArgumentTArray<float, 2> (geo_scale_size)); + + if (_need_lsc) { + SmartPtr<CLImage> lsc_image = _handler->get_lsc_table (); + float *gray_threshold = _handler->get_lsc_gray_threshold (); + XCAM_FAIL_RETURN ( + ERROR, + lsc_image.ptr() && lsc_image->is_valid () && gray_threshold, + XCAM_RETURN_ERROR_PARAM, + "CLGeoMapHandler::lsc table or gray threshold was not found"); + args.push_back (new CLMemArgument (lsc_image)); + args.push_back (new CLArgumentTArray<float, 2> (gray_threshold)); + } + args.push_back (new CLMemArgument (output_y)); + args.push_back (new CLMemArgument (output_uv)); + args.push_back (new CLArgumentTArray<float, 2> (out_size)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 16; + work_size.local[1] = 4; + work_size.global[0] = XCAM_ALIGN_UP (outuv_desc.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (outuv_desc.height, work_size.local[1]); + + return XCAM_RETURN_NO_ERROR; +} + +CLGeoMapHandler::CLGeoMapHandler (const SmartPtr<CLContext> &context) + : CLImageHandler (context, "CLGeoMapHandler") + , _output_width (0) + , _output_height (0) + , _map_width (0) + , _map_height (0) + , _map_aligned_width (0) + , _uint_x (0.0f) + , _uint_y (0.0f) + , _geo_map_normalized (false) +{ +} + +void +CLGeoMapHandler::get_geo_equivalent_out_size (float &width, float &height) +{ + width = _map_width * _uint_x; + height = _map_height * _uint_y; +} + +void +CLGeoMapHandler::get_geo_pixel_out_size (float &width, float &height) +{ + width = _output_width; + height = _output_height; +} + +bool +CLGeoMapHandler::set_map_uint (float uint_x, float uint_y) +{ + _uint_x = uint_x; + _uint_y = uint_y; + return true; +} + +bool +CLGeoMapHandler::set_map_data (GeoPos *data, uint32_t width, uint32_t height) +{ + uint32_t size = width * height * GEO_MAP_CHANNEL * sizeof (float); // 4 for CL_RGBA, + float *map_ptr = NULL; + + XCAM_FAIL_RETURN ( + ERROR, check_geo_map_buf (width, height), false, + "CLGeoMapKernel check geo map buffer failed"); + + XCamReturn ret = _geo_map->enqueue_map ((void *&)map_ptr, 0, size); + XCAM_FAIL_RETURN ( + WARNING, ret == XCAM_RETURN_NO_ERROR, false, + "CLGeoMapKernel map buffer failed"); + + uint32_t start, idx; + for (uint32_t h = 0; h < height; ++h) { + for (uint32_t w = 0; w < width; ++w) { + start = (h * _map_aligned_width + w) * GEO_MAP_CHANNEL; + idx = h * width + w; + + map_ptr [start] = data [idx].x; + map_ptr [start + 1] = data [idx].y; + } + } + _geo_map->enqueue_unmap ((void *&)map_ptr); + _geo_map_normalized = false; + return true; +} + +bool +CLGeoMapHandler::check_geo_map_buf (uint32_t width, uint32_t height) +{ + XCAM_ASSERT (width && height); + if (width == _map_width && height == _map_height && _geo_map.ptr ()) { + return true; // geo memory already created + } + + uint32_t aligned_width = XCAM_ALIGN_UP (width, XCAM_CL_IMAGE_ALIGNMENT_X); // 4 channel for CL_RGBA, but only use RG + uint32_t row_pitch = aligned_width * GEO_MAP_CHANNEL * sizeof (float); + uint32_t size = row_pitch * height; + SmartPtr<CLContext> context = get_context (); + XCAM_ASSERT (context.ptr ()); + _geo_map = new CLBuffer (context, size); + + if (!_geo_map.ptr () || !_geo_map->is_valid ()) { + XCAM_LOG_ERROR ("CLGeoMapKernel create geo map buffer failed."); + _geo_map.release (); + return false; + } + + CLImageDesc cl_geo_desc; + cl_geo_desc.format.image_channel_data_type = CL_FLOAT; + cl_geo_desc.format.image_channel_order = CL_RGBA; // CL_FLOAT need co-work with CL_RGBA + cl_geo_desc.width = width; + cl_geo_desc.height = height; + cl_geo_desc.row_pitch = row_pitch; + _geo_image = new CLImage2D (context, cl_geo_desc, 0, _geo_map); + if (!_geo_image.ptr () || !_geo_image->is_valid ()) { + XCAM_LOG_ERROR ("CLGeoMapKernel convert geo map buffer to image2d failed."); + _geo_map.release (); + _geo_image.release (); + return false; + } + + _map_width = width; + _map_height = height; + _map_aligned_width = aligned_width; + return true; +} + + +bool +CLGeoMapHandler::normalize_geo_map (uint32_t image_w, uint32_t image_h) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + uint32_t row_pitch = _map_aligned_width * GEO_MAP_CHANNEL * sizeof (float); // 4 channel for CL_RGBA, but only use RG + uint32_t size = row_pitch * _map_height; + float *map_ptr = NULL; + + XCAM_ASSERT (image_w && image_h); + XCAM_FAIL_RETURN ( + ERROR, _geo_map.ptr () && _geo_map->is_valid (), + false, "CLGeoMapKernel geo_map was not initialized"); + + ret = _geo_map->enqueue_map ((void *&)map_ptr, 0, size); + XCAM_FAIL_RETURN (WARNING, ret == XCAM_RETURN_NO_ERROR, false, "CLGeoMapKernel map buffer failed"); + uint32_t idx = 0; + for (uint32_t h = 0; h < _map_height; ++h) { + for (uint32_t w = 0; w < _map_width; ++w) { + idx = (h * _map_aligned_width + w) * GEO_MAP_CHANNEL; + + map_ptr [idx] /= image_w; + map_ptr [idx + 1] /= image_h; + } + } + _geo_map->enqueue_unmap ((void *&)map_ptr); + + return true; +} + +XCamReturn +CLGeoMapHandler::prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, VideoBufferInfo &output) +{ + XCAM_FAIL_RETURN ( + WARNING, input.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM, + "CLGeoMapHandler(%s) input buffer format(%s) not NV12", get_name (), xcam_fourcc_to_string (input.format)); + + if (!_output_width || !_output_height) { + _output_width = input.width; + _output_height = input.height; + } + output.init ( + input.format, _output_width, _output_height, + XCAM_ALIGN_UP (_output_width, 16), XCAM_ALIGN_UP (_output_height, 16)); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLGeoMapHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + const VideoBufferInfo &in_info = input->get_video_info (); + const VideoBufferInfo &out_info = output->get_video_info (); + SmartPtr<CLContext> context = get_context (); + uint32_t input_image_w = XCAM_ALIGN_DOWN (in_info.width, 2); + uint32_t input_image_h = XCAM_ALIGN_DOWN (in_info.height, 2); + + CLImageDesc cl_desc; + cl_desc.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc.format.image_channel_order = CL_R; + cl_desc.width = input_image_w; + cl_desc.height = input_image_h; + cl_desc.row_pitch = in_info.strides[NV12PlaneYIdx]; + _input[NV12PlaneYIdx] = convert_to_climage (context, input, cl_desc, in_info.offsets[NV12PlaneYIdx]); + + cl_desc.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc.format.image_channel_order = CL_RG; + cl_desc.width = input_image_w / 2; + cl_desc.height = input_image_h / 2; + cl_desc.row_pitch = in_info.strides[NV12PlaneUVIdx]; + _input[NV12PlaneUVIdx] = convert_to_climage (context, input, cl_desc, in_info.offsets[NV12PlaneUVIdx]); + + cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_desc.format.image_channel_order = CL_RGBA; + cl_desc.width = XCAM_ALIGN_DOWN (out_info.width, 4) / 8; //CL_RGBA * CL_UNSIGNED_INT16 = 8 + cl_desc.height = XCAM_ALIGN_DOWN (out_info.height, 2); + cl_desc.row_pitch = out_info.strides[NV12PlaneYIdx]; + _output[NV12PlaneYIdx] = convert_to_climage (context, output, cl_desc, out_info.offsets[NV12PlaneYIdx]); + cl_desc.height /= 2; + cl_desc.row_pitch = out_info.strides[NV12PlaneUVIdx]; + _output[NV12PlaneUVIdx] = convert_to_climage (context, output, cl_desc, out_info.offsets[NV12PlaneUVIdx]); + + XCAM_ASSERT ( + _input[NV12PlaneYIdx].ptr () && _input[NV12PlaneYIdx]->is_valid () && + _input[NV12PlaneUVIdx].ptr () && _input[NV12PlaneUVIdx]->is_valid () && + _output[NV12PlaneYIdx].ptr () && _output[NV12PlaneYIdx]->is_valid () && + _output[NV12PlaneUVIdx].ptr () && _output[NV12PlaneUVIdx]->is_valid ()); + + XCAM_FAIL_RETURN ( + ERROR, _geo_map.ptr () && _geo_map->is_valid (), + XCAM_RETURN_ERROR_PARAM, "CLGeoMapHandler map data was not set"); + + //calculate kernel map unit_x, unit_y. + float uint_x, uint_y; + get_map_uint (uint_x, uint_y); + if (uint_x < 1.0f && uint_y < 1.0f) { + uint_x = out_info.width / (float)_map_width; + uint_y = out_info.height / (float)_map_height; + set_map_uint (uint_x, uint_y); + } + + if (!_geo_map_normalized) { + XCAM_FAIL_RETURN ( + ERROR, normalize_geo_map (input_image_w, input_image_h), + XCAM_RETURN_ERROR_PARAM, "CLGeoMapHandler normalized geo map failed"); + _geo_map_normalized = true; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLGeoMapHandler::execute_done (SmartPtr<VideoBuffer> &output) +{ + XCAM_UNUSED (output); + + for (int i = 0; i < NV12PlaneMax; ++i) { + _input[i].release (); + _output[i].release (); + } + + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<CLImageKernel> +create_geo_map_kernel ( + const SmartPtr<CLContext> &context, SmartPtr<GeoKernelParamCallback> param_cb, bool need_lsc) +{ + SmartPtr<CLImageKernel> kernel; + kernel = new CLGeoMapKernel (context, param_cb, need_lsc); + XCAM_ASSERT (kernel.ptr ()); + + char build_options[1024]; + snprintf (build_options, sizeof(build_options), "-DENABLE_LSC=%d", need_lsc ? 1 : 0); + XCAM_FAIL_RETURN ( + ERROR, kernel->build_kernel (kernel_geo_map_info, build_options) == XCAM_RETURN_NO_ERROR, + NULL, "build geo map kernel failed"); + + return kernel; +} + +SmartPtr<CLImageHandler> +create_geo_map_handler (const SmartPtr<CLContext> &context, bool need_lsc) +{ + SmartPtr<CLGeoMapHandler> handler; + SmartPtr<CLImageKernel> kernel; + + handler = new CLGeoMapHandler (context); + XCAM_ASSERT (handler.ptr ()); + + kernel = create_geo_map_kernel (context, handler, need_lsc); + XCAM_FAIL_RETURN ( + ERROR, kernel.ptr (), NULL, "CLMapHandler build geo map kernel failed"); + handler->add_kernel (kernel); + + return handler; +} + +} diff --git a/modules/ocl/cl_geo_map_handler.h b/modules/ocl/cl_geo_map_handler.h new file mode 100644 index 0000000..a41ad27 --- /dev/null +++ b/modules/ocl/cl_geo_map_handler.h @@ -0,0 +1,160 @@ +/* + * cl_geo_map_handler.h - CL geometry map handler + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_GEO_MAP_HANDLER_H +#define XCAM_CL_GEO_MAP_HANDLER_H + +#include <xcam_std.h> +#include <ocl/cl_image_handler.h> + +namespace XCam { + +struct GeoPos { + double x; + double y; + + GeoPos () : x(0), y(0) {} +}; + +class CLGeoMapKernel; +class GeoKernelParamCallback +{ + friend class CLGeoMapKernel; + +public: + GeoKernelParamCallback () {} + virtual ~GeoKernelParamCallback () {} + +protected: + virtual SmartPtr<CLImage> get_geo_input_image (NV12PlaneIdx index) = 0; + virtual SmartPtr<CLImage> get_geo_output_image (NV12PlaneIdx index) = 0; + virtual SmartPtr<CLImage> get_geo_map_table () = 0; + virtual void get_geo_equivalent_out_size (float &width, float &height) = 0; + virtual void get_geo_pixel_out_size (float &width, float &height) = 0; + + virtual SmartPtr<CLImage> get_lsc_table () = 0; + virtual float* get_lsc_gray_threshold() = 0; + +private: + XCAM_DEAD_COPY (GeoKernelParamCallback); +}; + +class CLGeoMapHandler; +class CLGeoMapKernel + : public CLImageKernel +{ +public: + explicit CLGeoMapKernel ( + const SmartPtr<CLContext> &context, + const SmartPtr<GeoKernelParamCallback> handler, + bool need_lsc); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + +private: + SmartPtr<GeoKernelParamCallback> _handler; + bool _need_lsc; +}; + +class CLGeoMapHandler + : public CLImageHandler + , public GeoKernelParamCallback +{ +public: + explicit CLGeoMapHandler (const SmartPtr<CLContext> &context); + void set_output_size (uint32_t width, uint32_t height) { + _output_width = width; + _output_height = height; + } + void get_output_size (uint32_t &width, uint32_t &height) const { + width = _output_width; + height = _output_height; + } + + bool set_map_data (GeoPos *data, uint32_t width, uint32_t height); + bool set_map_uint (float uint_x, float uint_y); + void get_map_uint (float &uint_x, float &uint_y) { + uint_x = _uint_x; + uint_y = _uint_y; + } + +protected: + // derived from GeoKernelParamCallback + virtual SmartPtr<CLImage> get_geo_input_image (NV12PlaneIdx index) { + XCAM_ASSERT (index < NV12PlaneMax); + return _input [index]; + } + virtual SmartPtr<CLImage> get_geo_output_image (NV12PlaneIdx index) { + XCAM_ASSERT (index < NV12PlaneMax); + return _output [index]; + } + virtual SmartPtr<CLImage> get_geo_map_table () { + XCAM_ASSERT (_geo_image.ptr ()); + return _geo_image; + } + virtual void get_geo_equivalent_out_size (float &width, float &height); + virtual void get_geo_pixel_out_size (float &width, float &height); + + virtual SmartPtr<CLImage> get_lsc_table () { + XCAM_ASSERT (false && "CLGeoMapHandler::lsc table is not supported"); + return NULL; + } + virtual float* get_lsc_gray_threshold () { + XCAM_ASSERT (false && "CLGeoMapHandler::lsc gray threshold is not supported"); + return NULL; + } + +protected: + virtual XCamReturn prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, + VideoBufferInfo &output); + virtual XCamReturn prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + virtual XCamReturn execute_done (SmartPtr<VideoBuffer> &output); + +private: + bool normalize_geo_map (uint32_t image_w, uint32_t image_h); + bool check_geo_map_buf (uint32_t width, uint32_t height); + + XCAM_DEAD_COPY (CLGeoMapHandler); + +private: + uint32_t _output_width; + uint32_t _output_height; + uint32_t _map_width, _map_height; + uint32_t _map_aligned_width; + float _uint_x, _uint_y; + SmartPtr<CLImage> _input[NV12PlaneMax]; + SmartPtr<CLImage> _output[NV12PlaneMax]; + SmartPtr<CLBuffer> _geo_map; + SmartPtr<CLImage> _geo_image; + bool _geo_map_normalized; +}; + +SmartPtr<CLImageKernel> +create_geo_map_kernel ( + const SmartPtr<CLContext> &context, SmartPtr<GeoKernelParamCallback> param_cb, bool need_lsc); + +SmartPtr<CLImageHandler> +create_geo_map_handler (const SmartPtr<CLContext> &context, bool need_lsc = false); + +} + +#endif //XCAM_CL_GEO_MAP_HANDLER_H
\ No newline at end of file diff --git a/modules/ocl/cl_image_360_stitch.cpp b/modules/ocl/cl_image_360_stitch.cpp new file mode 100644 index 0000000..ae19b27 --- /dev/null +++ b/modules/ocl/cl_image_360_stitch.cpp @@ -0,0 +1,902 @@ +/* + * cl_image_360_stitch.cpp - CL Image 360 stitch + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_utils.h" +#include "cl_image_360_stitch.h" +#if HAVE_OPENCV +#include "cv_feature_match.h" +#endif + +#define XCAM_BLENDER_GLOBAL_SCALE_EXT_WIDTH 64 + +#define STITCH_CHECK(ret, msg, ...) \ + if ((ret) != XCAM_RETURN_NO_ERROR) { \ + XCAM_LOG_WARNING (msg, ## __VA_ARGS__); \ + return ret; \ + } + +namespace XCam { + +CLBlenderGlobalScaleKernel::CLBlenderGlobalScaleKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLImage360Stitch> &stitch, bool is_uv) + : CLBlenderScaleKernel (context, is_uv) + , _stitch (stitch) +{ +} + +SmartPtr<CLImage> +CLBlenderGlobalScaleKernel::get_input_image () { + SmartPtr<CLContext> context = get_context (); + SmartPtr<VideoBuffer> input = _stitch->get_global_scale_input (); + + CLImageDesc cl_desc; + SmartPtr<CLImage> cl_image; + const VideoBufferInfo &buf_info = input->get_video_info (); + + cl_desc.format.image_channel_data_type = CL_UNORM_INT8; + if (_is_uv) { + cl_desc.format.image_channel_order = CL_RG; + cl_desc.width = buf_info.width / 2; + cl_desc.height = buf_info.height / 2; + cl_desc.row_pitch = buf_info.strides[1]; + cl_image = convert_to_climage (context, input, cl_desc, buf_info.offsets[1]); + } else { + cl_desc.format.image_channel_order = CL_R; + cl_desc.width = buf_info.width; + cl_desc.height = buf_info.height; + cl_desc.row_pitch = buf_info.strides[0]; + cl_image = convert_to_climage (context, input, cl_desc, buf_info.offsets[0]); + } + + return cl_image; +} + +SmartPtr<CLImage> +CLBlenderGlobalScaleKernel::get_output_image () { + SmartPtr<CLContext> context = get_context (); + SmartPtr<VideoBuffer> output = _stitch->get_global_scale_output (); + + CLImageDesc cl_desc; + SmartPtr<CLImage> cl_image; + const VideoBufferInfo &buf_info = output->get_video_info (); + + cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_desc.format.image_channel_order = CL_RGBA; + if (_is_uv) { + cl_desc.width = buf_info.width / 8; + cl_desc.height = buf_info.height / 2; + cl_desc.row_pitch = buf_info.strides[1]; + cl_image = convert_to_climage (context, output, cl_desc, buf_info.offsets[1]); + } else { + cl_desc.width = buf_info.width / 8; + cl_desc.height = buf_info.height; + cl_desc.row_pitch = buf_info.strides[0]; + cl_image = convert_to_climage (context, output, cl_desc, buf_info.offsets[0]); + } + + return cl_image; +} + +bool +CLBlenderGlobalScaleKernel::get_output_info ( + uint32_t &out_width, uint32_t &out_height, int &out_offset_x) +{ + SmartPtr<VideoBuffer> output = _stitch->get_global_scale_output (); + const VideoBufferInfo &output_info = output->get_video_info (); + + out_width = output_info.width / 8; + out_height = _is_uv ? output_info.height / 2 : output_info.height; + out_offset_x = 0; + + return true; +} + +#if HAVE_OPENCV +static CVFMConfig +get_fm_default_config (StitchResMode res_mode) +{ + CVFMConfig config; + + switch (res_mode) { + case StitchRes1080P: { + config.sitch_min_width = 56; + config.min_corners = 8; + config.offset_factor = 0.8f; + config.delta_mean_offset = 5.0f; + config.recur_offset_error = 8.0f; + config.max_adjusted_offset = 12.0f; + config.max_valid_offset_y = 8.0f; + config.max_track_error = 24.0f; + + break; + } + case StitchRes1080P4: { + config.sitch_min_width = 128; + config.min_corners = 4; + config.offset_factor = 0.8f; + config.delta_mean_offset = 24.0f; + config.recur_offset_error = 12.0f; + config.max_adjusted_offset = 24.0f; + config.max_valid_offset_y = 64.0f; + config.max_track_error = 32.0f; + + break; + } + case StitchRes4K: { + config.sitch_min_width = 160; + config.min_corners = 8; + config.offset_factor = 0.8f; + config.delta_mean_offset = 5.0f; + config.recur_offset_error = 8.0f; + config.max_adjusted_offset = 12.0f; + config.max_valid_offset_y = 8.0f; + config.max_track_error = 24.0f; + + break; + } + default: + XCAM_LOG_DEBUG ("unknown reslution mode (%d)", res_mode); + break; + } + + return config; +} +#endif + +static StitchInfo +get_default_stitch_info (StitchResMode res_mode) +{ + StitchInfo stitch_info; + + switch (res_mode) { + case StitchRes1080P: { + stitch_info.merge_width[0] = 56; + stitch_info.merge_width[1] = 56; + + stitch_info.crop[0].left = 96; + stitch_info.crop[0].right = 96; + stitch_info.crop[0].top = 0; + stitch_info.crop[0].bottom = 0; + stitch_info.crop[1].left = 96; + stitch_info.crop[1].right = 96; + stitch_info.crop[1].top = 0; + stitch_info.crop[1].bottom = 0; + + stitch_info.fisheye_info[0].center_x = 480.0f; + stitch_info.fisheye_info[0].center_y = 480.0f; + stitch_info.fisheye_info[0].wide_angle = 202.8f; + stitch_info.fisheye_info[0].radius = 480.0f; + stitch_info.fisheye_info[0].rotate_angle = -90.0f; + stitch_info.fisheye_info[1].center_x = 1440.0f; + stitch_info.fisheye_info[1].center_y = 480.0f; + stitch_info.fisheye_info[1].wide_angle = 202.8f; + stitch_info.fisheye_info[1].radius = 480.0f; + stitch_info.fisheye_info[1].rotate_angle = 89.4f; + break; + } + case StitchRes1080P4: { + stitch_info.merge_width[0] = 288; + stitch_info.merge_width[1] = 288; + stitch_info.merge_width[2] = 288; + stitch_info.merge_width[3] = 288; + + stitch_info.crop[0].left = 0; + stitch_info.crop[0].right = 0; + stitch_info.crop[0].top = 0; + stitch_info.crop[0].bottom = 0; + stitch_info.crop[1].left = 0; + stitch_info.crop[1].right = 0; + stitch_info.crop[1].top = 0; + stitch_info.crop[1].bottom = 0; + stitch_info.crop[2].left = 0; + stitch_info.crop[2].right = 0; + stitch_info.crop[2].top = 0; + stitch_info.crop[2].bottom = 0; + stitch_info.crop[3].left = 0; + stitch_info.crop[3].right = 0; + stitch_info.crop[3].top = 0; + stitch_info.crop[3].bottom = 0; + + stitch_info.fisheye_info[0].center_x = 640.0f; + stitch_info.fisheye_info[0].center_y = 400.0f; + stitch_info.fisheye_info[0].wide_angle = 120.0f; + stitch_info.fisheye_info[0].radius = 640.0f; + stitch_info.fisheye_info[0].rotate_angle = 0.0f; + stitch_info.fisheye_info[1].center_x = 640.0f; + stitch_info.fisheye_info[1].center_y = 400.0f; + stitch_info.fisheye_info[1].wide_angle = 120.0f; + stitch_info.fisheye_info[1].radius = 640.0f; + stitch_info.fisheye_info[1].rotate_angle = 0.0f; + stitch_info.fisheye_info[2].center_x = 640.0f; + stitch_info.fisheye_info[2].center_y = 400.0f; + stitch_info.fisheye_info[2].wide_angle = 120.0f; + stitch_info.fisheye_info[2].radius = 640.0f; + stitch_info.fisheye_info[2].rotate_angle = 0.0f; + stitch_info.fisheye_info[3].center_x = 640.0f; + stitch_info.fisheye_info[3].center_y = 400.0f; + stitch_info.fisheye_info[3].wide_angle = 120.0f; + stitch_info.fisheye_info[3].radius = 640.0f; + stitch_info.fisheye_info[3].rotate_angle = 0.0f; + break; + } + case StitchRes4K: { + stitch_info.merge_width[0] = 160; + stitch_info.merge_width[1] = 160; + + stitch_info.crop[0].left = 64; + stitch_info.crop[0].right = 64; + stitch_info.crop[0].top = 0; + stitch_info.crop[0].bottom = 0; + stitch_info.crop[1].left = 64; + stitch_info.crop[1].right = 64; + stitch_info.crop[1].top = 0; + stitch_info.crop[1].bottom = 0; + + stitch_info.fisheye_info[0].center_x = 1024.0f; + stitch_info.fisheye_info[0].center_y = 1024.0f; + stitch_info.fisheye_info[0].wide_angle = 195.0f; + stitch_info.fisheye_info[0].radius = 1040.0f; + stitch_info.fisheye_info[0].rotate_angle = 0.0f; + + stitch_info.fisheye_info[1].center_x = 3072.0f; + stitch_info.fisheye_info[1].center_y = 1016.0f; + stitch_info.fisheye_info[1].wide_angle = 192.0f; + stitch_info.fisheye_info[1].radius = 1040.0f; + stitch_info.fisheye_info[1].rotate_angle = 0.4f; + break; + } + default: + XCAM_LOG_DEBUG ("unknown reslution mode (%d)", res_mode); + break; + } + + return stitch_info; +} + +CLImage360Stitch::CLImage360Stitch ( + const SmartPtr<CLContext> &context, CLBlenderScaleMode scale_mode, SurroundMode surround_mode, + StitchResMode res_mode, int fisheye_num, bool all_in_one_img) + : CLMultiImageHandler (context, "CLImage360Stitch") + , _context (context) + , _output_width (0) + , _output_height (0) + , _scale_mode (scale_mode) + , _surround_mode (surround_mode) + , _res_mode (res_mode) + , _is_stitch_inited (false) + , _fisheye_num (fisheye_num) + , _all_in_one_img (all_in_one_img) +{ +#if HAVE_OPENCV + for (int i = 0; i < fisheye_num; i++) { + _feature_match[i] = new CVFeatureMatch (); + XCAM_ASSERT (_feature_match[i].ptr ()); + _feature_match[i]->set_config (get_fm_default_config (res_mode)); + _feature_match[i]->set_fm_index (i); + } +#endif +} + +bool +CLImage360Stitch::set_stitch_info (StitchInfo stitch_info) +{ + if (_is_stitch_inited) { + XCAM_LOG_WARNING ("stitching info was initialized and can't be set twice"); + return false; + } + + for (int index = 0; index < _fisheye_num; ++index) { + _fisheye[index].handler->set_fisheye_info (stitch_info.fisheye_info[index]); + } + + _stitch_info = stitch_info; + _is_stitch_inited = true; + + return true; +} + +StitchInfo +CLImage360Stitch::get_stitch_info () +{ + if (!_is_stitch_inited) { + XCAM_LOG_WARNING ("stitch-info was not initialized, return default parameters"); + return get_default_stitch_info (_res_mode); + } + + return _stitch_info; +} + +bool +CLImage360Stitch::set_fisheye_handler (SmartPtr<CLFisheyeHandler> fisheye, int index) +{ + XCAM_ASSERT (index < _fisheye_num); + + _fisheye[index].handler = fisheye; + SmartPtr<CLImageHandler> handler = fisheye; + return add_image_handler (handler); +} + +bool +CLImage360Stitch::set_blender (SmartPtr<CLBlender> blender, int idx) +{ + _blender[idx] = blender; + + SmartPtr<CLImageHandler> handler = blender; + return add_image_handler (handler); +} + +void +CLImage360Stitch::set_fisheye_intrinsic (IntrinsicParameter intrinsic_param, int index) +{ + _fisheye[index].handler->set_intrinsic_param(intrinsic_param); +} + +void +CLImage360Stitch::set_fisheye_extrinsic (ExtrinsicParameter extrinsic_param, int index) +{ + _fisheye[index].handler->set_extrinsic_param(extrinsic_param); +} + +const BowlDataConfig & +CLImage360Stitch::get_fisheye_bowl_config (int index) +{ + XCAM_ASSERT (index < _fisheye_num); + return _fisheye[index].handler->get_bowl_config (); +} + +bool +CLImage360Stitch::set_image_overlap (const int idx, const Rect &overlap0, const Rect &overlap1) +{ + XCAM_ASSERT (idx < _fisheye_num); + _overlaps[idx][0] = overlap0; + _overlaps[idx][1] = overlap1; + return true; +} + +void +CLImage360Stitch::set_feature_match_ocl (bool fm_ocl) +{ +#if HAVE_OPENCV + for (int i = 0; i < _fisheye_num; i++) { + _feature_match[i]->set_ocl (fm_ocl); + } +#else + XCAM_UNUSED (fm_ocl); + XCAM_LOG_WARNING ("non-OpenCV mode, failed to set ocl for feature match"); +#endif +} + +#if HAVE_OPENCV +void +CLImage360Stitch::set_feature_match_config (const int idx, CVFMConfig config) +{ + _feature_match[idx]->set_config (config); +} + +CVFMConfig +CLImage360Stitch::get_feature_match_config (const int idx) +{ + return _feature_match[idx]->get_config (); +} +#endif + +void +CLImage360Stitch::calc_fisheye_initial_info (SmartPtr<VideoBuffer> &output) +{ + const VideoBufferInfo &out_info = output->get_video_info (); + + if(_surround_mode == SphereView) { + uint32_t fisheye_width_sum = out_info.width; + for (int i = 0; i < _fisheye_num; i++) { + fisheye_width_sum += _stitch_info.merge_width[i] + _stitch_info.crop[i].left + _stitch_info.crop[i].right; + } + _fisheye[0].width = fisheye_width_sum / _fisheye_num; + _fisheye[0].width = XCAM_ALIGN_UP (_fisheye[0].width, 16); + _fisheye[0].height = out_info.height + _stitch_info.crop[0].top + _stitch_info.crop[0].bottom; + XCAM_LOG_INFO ( + "fisheye correction output size width:%d height:%d", + _fisheye[0].width, _fisheye[0].height); + + for (int i = 1; i < _fisheye_num; i++) { + _fisheye[i].width = _fisheye[0].width; + _fisheye[i].height = _fisheye[0].height; + } + + float max_dst_longitude, max_dst_latitude; + for (int i = 0; i < _fisheye_num; ++i) { + max_dst_latitude = (_stitch_info.fisheye_info[i].wide_angle > 180.0f) ? + 180.0f : _stitch_info.fisheye_info[i].wide_angle; + max_dst_longitude = max_dst_latitude * _fisheye[i].width / _fisheye[i].height; + + _fisheye[i].handler->set_dst_range (max_dst_longitude, max_dst_latitude); + _fisheye[i].handler->set_output_size (_fisheye[i].width, _fisheye[i].height); + } + } else { + _fisheye[0].height = out_info.height + _stitch_info.crop[0].top + _stitch_info.crop[0].bottom; + + float view_angle[XCAM_STITCH_FISHEYE_MAX_NUM]; + + view_angle[0] = 68.0f; + _fisheye[0].width = view_angle[0] / 360.0f * out_info.width; + _fisheye[0].width = XCAM_ALIGN_UP (_fisheye[0].width, 32); + + view_angle[1] = 152.0f; + _fisheye[1].width = view_angle[1] / 360.0f * out_info.width; + _fisheye[1].width = XCAM_ALIGN_UP (_fisheye[1].width, 32); + + view_angle[2] = 68.0f; + _fisheye[2].width = view_angle[2] / 360.0f * out_info.width; + _fisheye[2].width = XCAM_ALIGN_UP (_fisheye[2].width, 32); + + view_angle[3] = 152.0f; + _fisheye[3].width = view_angle[3] / 360.0f * out_info.width; + _fisheye[3].width = XCAM_ALIGN_UP (_fisheye[3].width, 32); + + XCAM_LOG_INFO ( + "fisheye correction output size width:%d height:%d", + _fisheye[0].width, _fisheye[0].height); + + BowlDataConfig bowl_data_config[XCAM_STITCH_FISHEYE_MAX_NUM]; + + bowl_data_config[0].angle_start = -view_angle[0] / 2; + bowl_data_config[0].angle_end = view_angle[0] / 2; + + for (int i = 1; i < _fisheye_num; i++) { + _fisheye[i].height = _fisheye[0].height; + float angle_center = 360.0f / _fisheye_num * i; + bowl_data_config[i].angle_start = angle_center - view_angle[i] / 2; + bowl_data_config[i].angle_end = angle_center + view_angle[i] / 2; + } + + for(int i = 0; i < _fisheye_num; i++) { + _fisheye[i].handler->set_bowl_config(bowl_data_config[i]); + _fisheye[i].handler->set_output_size (_fisheye[i].width, _fisheye[i].height); + } + + for(int i = 0; i < _fisheye_num; i++) { + _stitch_info.merge_width[i] = XCAM_ALIGN_UP((uint32_t)(20.0f / 360.0f * out_info.width), 32); + } + } +} + +void +CLImage360Stitch::update_image_overlap () +{ + static bool is_merge_info_inited = false; + if (!is_merge_info_inited) { + int idx_next = 1; + for (int i = 0; i < _fisheye_num; i++) { + idx_next = (i == (_fisheye_num - 1)) ? 0 : (i + 1); + + _img_merge_info[i].left.pos_x = _stitch_info.crop[i].left; + _img_merge_info[i].left.pos_y = _stitch_info.crop[i].top; + _img_merge_info[i].left.width = _stitch_info.merge_width[i]; + _img_merge_info[i].left.height = _fisheye[i].height - _stitch_info.crop[i].top + - _stitch_info.crop[i].bottom; + + _img_merge_info[i].right.pos_x = _fisheye[i].width - _stitch_info.crop[i].right + - _stitch_info.merge_width[idx_next]; + _img_merge_info[i].right.pos_y = _stitch_info.crop[i].top; + _img_merge_info[i].right.width = _stitch_info.merge_width[idx_next]; + _img_merge_info[i].right.height = _fisheye[i].height - _stitch_info.crop[i].top + - _stitch_info.crop[i].bottom; + } + + is_merge_info_inited = true; + } + + for (int i = 0; i < _fisheye_num; i++) { + set_image_overlap (i, _img_merge_info[i].left, _img_merge_info[i].right); + } +} + +XCamReturn +CLImage360Stitch::prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, VideoBufferInfo &output) +{ + if (_output_width == 0 || _output_height == 0) { + XCAM_LOG_ERROR ("incorrect output size: width:%d height:%d", _output_width, _output_height); + return XCAM_RETURN_ERROR_PARAM; + } + + // aligned at least XCAM_CL_BLENDER_ALIGNMENT_X + uint32_t aligned_width = XCAM_MAX (16, XCAM_CL_BLENDER_ALIGNMENT_X); + output.init ( + input.format, _output_width, _output_height, + XCAM_ALIGN_UP(_output_width, aligned_width), XCAM_ALIGN_UP(_output_height, 16)); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLImage360Stitch::ensure_fisheye_parameters ( + SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + static bool is_fisheye_inited = false; + + if (!is_fisheye_inited) { + calc_fisheye_initial_info (output); + is_fisheye_inited = true; + } + + SmartPtr<VideoBuffer> pre_buf; + SmartPtr<VideoBuffer> cur_buf = input; + for (int i = 0; i < _fisheye_num; i++) { + if (!_fisheye[i].pool.ptr ()) + create_buffer_pool (_fisheye[i].pool, _fisheye[i].width, _fisheye[i].height); + + _fisheye[i].buf = _fisheye[i].pool->get_buffer (_fisheye[i].pool); + XCAM_ASSERT (_fisheye[i].buf.ptr ()); + + XCamReturn ret = ensure_handler_parameters (_fisheye[i].handler, cur_buf, _fisheye[i].buf); + STITCH_CHECK (ret, "execute fisheye prepare_parameters failed"); + + if (!_all_in_one_img) { + pre_buf = cur_buf; + cur_buf = cur_buf->find_typed_attach<VideoBuffer> (); + if (!cur_buf.ptr () && (i != (_fisheye_num - 1))) { + XCAM_LOG_ERROR ("conflicting attached buffers and fisheye number"); + return XCAM_RETURN_ERROR_PARAM; + } + pre_buf->detach_buffer (cur_buf); + } + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLImage360Stitch::prepare_global_scale_blender_parameters ( + SmartPtr<VideoBuffer> &input0, SmartPtr<VideoBuffer> &input1, SmartPtr<VideoBuffer> &output, + int idx, int idx_next, int &cur_start_pos) +{ + const VideoBufferInfo &in0_info = input0->get_video_info (); + const VideoBufferInfo &in1_info = input1->get_video_info (); + const VideoBufferInfo &out_info = output->get_video_info (); + + XCAM_ASSERT (in0_info.height == in1_info.height); + XCAM_ASSERT (in0_info.width <= out_info.width && in1_info.width <= out_info.width); + + Rect left_lap = get_image_overlap (idx, 1); + Rect right_lap = get_image_overlap (idx_next, 0); + + int left_img_mid = XCAM_ALIGN_DOWN (in0_info.width / 2, XCAM_CL_BLENDER_ALIGNMENT_X); + int right_img_mid = XCAM_ALIGN_DOWN (in1_info.width / 2, XCAM_CL_BLENDER_ALIGNMENT_X); + + int32_t prev_pos; + prev_pos = left_lap.pos_x; + left_lap.pos_x = XCAM_ALIGN_AROUND (left_lap.pos_x, XCAM_CL_BLENDER_ALIGNMENT_X); + left_lap.width = XCAM_ALIGN_UP (left_lap.width, XCAM_CL_BLENDER_ALIGNMENT_X); + right_lap.pos_x += left_lap.pos_x - prev_pos; + right_lap.pos_x = XCAM_ALIGN_AROUND (right_lap.pos_x, XCAM_CL_BLENDER_ALIGNMENT_X); + right_lap.width = left_lap.width; + + Rect area; + area.pos_y = left_lap.pos_y; + area.height = left_lap.height; + area.pos_x = left_img_mid; + area.width = left_lap.pos_x + left_lap.width - left_img_mid; + _blender[idx]->set_input_valid_area (area, 0); + + area.pos_y = right_lap.pos_y; + area.height = right_lap.height; + area.pos_x = right_lap.pos_x; + area.width = right_img_mid - right_lap.pos_x; + _blender[idx]->set_input_valid_area (area, 1); + + Rect out_merge_window; + out_merge_window.width = left_lap.width; + out_merge_window.pos_x = cur_start_pos + (left_lap.pos_x - left_img_mid); + out_merge_window.pos_y = 0; + out_merge_window.height = out_info.height; + _blender[idx]->set_merge_window (out_merge_window); + + _blender[idx]->set_input_merge_area (left_lap, 0); + _blender[idx]->set_input_merge_area (right_lap, 1); + + cur_start_pos += left_lap.pos_x - left_img_mid + right_img_mid - right_lap.pos_x; + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLImage360Stitch::prepare_local_scale_blender_parameters ( + SmartPtr<VideoBuffer> &input0, SmartPtr<VideoBuffer> &input1, SmartPtr<VideoBuffer> &output, int idx, int idx_next) +{ + const VideoBufferInfo &in0_info = input0->get_video_info (); + const VideoBufferInfo &in1_info = input1->get_video_info (); + const VideoBufferInfo &out_info = output->get_video_info (); + + XCAM_ASSERT (in0_info.height == in1_info.height); + XCAM_ASSERT (in0_info.width <= out_info.width && in1_info.width <= out_info.width); + + Rect left_lap = get_image_overlap (idx, 1); + Rect right_lap = get_image_overlap (idx_next, 0); + + int left_img_mid = XCAM_ALIGN_DOWN (in0_info.width / 2, XCAM_CL_BLENDER_ALIGNMENT_X); + int right_img_mid = XCAM_ALIGN_DOWN (in1_info.width / 2, XCAM_CL_BLENDER_ALIGNMENT_X); + int cur_start_pos = XCAM_ALIGN_DOWN (out_info.width / _fisheye_num * idx, XCAM_CL_BLENDER_ALIGNMENT_X); + int merge_std_width = XCAM_ALIGN_DOWN (out_info.width / _fisheye_num, XCAM_CL_BLENDER_ALIGNMENT_X); + + int32_t prev_pos; + prev_pos = left_lap.pos_x; + left_lap.pos_x = XCAM_ALIGN_AROUND (left_lap.pos_x, XCAM_CL_BLENDER_ALIGNMENT_X); + left_lap.width = XCAM_ALIGN_UP (left_lap.width, XCAM_CL_BLENDER_ALIGNMENT_X); + right_lap.pos_x += left_lap.pos_x - prev_pos; + right_lap.pos_x = XCAM_ALIGN_AROUND (right_lap.pos_x, XCAM_CL_BLENDER_ALIGNMENT_X); + right_lap.width = left_lap.width; + + Rect area; + area.pos_y = left_lap.pos_y; + area.height = left_lap.height; + area.pos_x = left_img_mid; + area.width = left_lap.pos_x + left_lap.width - left_img_mid; + _blender[idx]->set_input_valid_area (area, 0); + + area.pos_y = right_lap.pos_y; + area.height = right_lap.height; + area.pos_x = right_lap.pos_x; + area.width = right_img_mid - right_lap.pos_x; + _blender[idx]->set_input_valid_area (area, 1); + + Rect out_merge_window; + int delta_width = merge_std_width - (right_img_mid - right_lap.pos_x) - (left_lap.pos_x - left_img_mid); + out_merge_window.width = left_lap.width + delta_width; + out_merge_window.pos_x = cur_start_pos + (left_lap.pos_x - left_img_mid); + out_merge_window.pos_y = 0; + out_merge_window.height = out_info.height; + _blender[idx]->set_merge_window (out_merge_window); + + _blender[idx]->set_input_merge_area (left_lap, 0); + _blender[idx]->set_input_merge_area (right_lap, 1); + + return XCAM_RETURN_NO_ERROR; +} + +bool +CLImage360Stitch::create_buffer_pool (SmartPtr<BufferPool> &buf_pool, uint32_t width, uint32_t height) +{ + VideoBufferInfo buf_info; + width = XCAM_ALIGN_UP (width, 16); + buf_info.init (V4L2_PIX_FMT_NV12, width, height, + XCAM_ALIGN_UP (width, 16), XCAM_ALIGN_UP (height, 16)); + + buf_pool = new CLVideoBufferPool (); + XCAM_ASSERT (buf_pool.ptr ()); + buf_pool->set_video_info (buf_info); + if (!buf_pool->reserve (6)) { + XCAM_LOG_ERROR ("CLImage360Stitch init buffer pool failed"); + return false; + } + + return true; +} + +XCamReturn +CLImage360Stitch::reset_buffer_info (SmartPtr<VideoBuffer> &input) +{ + VideoBufferInfo reset_info; + const VideoBufferInfo &buf_info = input->get_video_info (); + + uint32_t reset_width = 0; + for (int i = 0; i < _fisheye_num; i++) { + Rect img_left = get_image_overlap (i, 0); + Rect img_right = get_image_overlap (i, 1); + + reset_width += img_right.pos_x - img_left.pos_x; + } + + reset_width = XCAM_ALIGN_UP (reset_width, XCAM_CL_BLENDER_ALIGNMENT_X); + reset_info.init (buf_info.format, reset_width, buf_info.height, + buf_info.aligned_width, buf_info.aligned_height); + + input->set_video_info (reset_info); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLImage360Stitch::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + if (!_is_stitch_inited) + set_stitch_info (get_default_stitch_info (_res_mode)); + + ret = ensure_fisheye_parameters (input, output); + STITCH_CHECK (ret, "ensure fisheye parameters failed"); + + update_image_overlap (); + if (_scale_mode == CLBlenderScaleLocal) { + int idx_next = 1; + for (int i = 0; i < _fisheye_num; i++) { + idx_next = (i == (_fisheye_num - 1)) ? 0 : (i + 1); + + ret = prepare_local_scale_blender_parameters ( + _fisheye[i].buf, _fisheye[idx_next].buf, output, i, idx_next); + STITCH_CHECK (ret, "prepare local scale blender parameters failed"); + + _fisheye[i].buf->attach_buffer (_fisheye[idx_next].buf); + ret = ensure_handler_parameters (_blender[i], _fisheye[i].buf, output); + STITCH_CHECK (ret, "blender: execute ensure_parameters failed"); + _fisheye[i].buf->detach_buffer (_fisheye[idx_next].buf); + } + } else { //global scale + const VideoBufferInfo &buf_info = output->get_video_info (); + if (!_scale_buf_pool.ptr ()) + create_buffer_pool (_scale_buf_pool, buf_info.width + XCAM_BLENDER_GLOBAL_SCALE_EXT_WIDTH, buf_info.height); + SmartPtr<VideoBuffer> scale_input = _scale_buf_pool->get_buffer (_scale_buf_pool); + XCAM_ASSERT (scale_input.ptr ()); + + int idx_next = 1; + int cur_start_pos = 0; + for (int i = 0; i < _fisheye_num; i++) { + idx_next = (i == (_fisheye_num - 1)) ? 0 : (i + 1); + + ret = prepare_global_scale_blender_parameters ( + _fisheye[i].buf, _fisheye[idx_next].buf, scale_input, i, idx_next, cur_start_pos); + STITCH_CHECK (ret, "prepare global scale blender parameters failed"); + + _fisheye[i].buf->attach_buffer (_fisheye[idx_next].buf); + ret = ensure_handler_parameters (_blender[i], _fisheye[i].buf, scale_input); + STITCH_CHECK (ret, "blender: execute ensure_parameters failed"); + _fisheye[i].buf->detach_buffer (_fisheye[idx_next].buf); + } + + reset_buffer_info (scale_input); + _scale_global_input = scale_input; + _scale_global_output = output; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLImage360Stitch::execute_done (SmartPtr<VideoBuffer> &output) +{ +#if HAVE_OPENCV + for (int i = 0; i < _fisheye_num; i++) { + if (!_feature_match[i]->is_ocl_path ()) { + get_context ()->finish (); + break; + } + } +#endif + + _scale_global_input.release (); + _scale_global_output.release (); + + return CLMultiImageHandler::execute_done (output); +} + +static void +convert_to_stitch_rect (Rect xcam_rect, Rect &stitch_rect) +{ + stitch_rect.pos_x = xcam_rect.pos_x; + stitch_rect.pos_y = xcam_rect.pos_y + xcam_rect.height / 3; + stitch_rect.width = xcam_rect.width; + stitch_rect.height = xcam_rect.height / 3; +} + +static void +convert_to_xcam_rect (Rect stitch_rect, Rect &xcam_rect) +{ + xcam_rect.pos_x = stitch_rect.pos_x; + xcam_rect.width = stitch_rect.width; +} + + +XCamReturn +CLImage360Stitch::sub_handler_execute_done (SmartPtr<CLImageHandler> &handler) +{ +#if HAVE_OPENCV + XCAM_ASSERT (handler.ptr ()); + + if (handler.ptr () == _fisheye[_fisheye_num - 1].handler.ptr ()) { + int idx_next = 1; + Rect crop_left, crop_right; + + for (int i = 0; i < _fisheye_num; i++) { + idx_next = (i == (_fisheye_num - 1)) ? 0 : (i + 1); + + convert_to_stitch_rect (_img_merge_info[i].right, crop_left); + convert_to_stitch_rect (_img_merge_info[idx_next].left, crop_right); + + _feature_match[i]->optical_flow_feature_match ( + _fisheye[i].buf, _fisheye[idx_next].buf, crop_left, crop_right, _fisheye[i].width); + + convert_to_xcam_rect (crop_left, _img_merge_info[i].right); + convert_to_xcam_rect (crop_right, _img_merge_info[idx_next].left); + } + } +#else + XCAM_UNUSED (handler); +#endif + + return XCAM_RETURN_NO_ERROR; +} + +static SmartPtr<CLImageKernel> +create_blender_global_scale_kernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLImage360Stitch> &stitch, + bool is_uv) +{ + char transform_option[1024]; + snprintf (transform_option, sizeof(transform_option), "-DPYRAMID_UV=%d", is_uv ? 1 : 0); + + static const XCamKernelInfo &kernel_info = { + "kernel_pyramid_scale", +#include "kernel_gauss_lap_pyramid.clx" + , 0 + }; + + SmartPtr<CLImageKernel> kernel; + kernel = new CLBlenderGlobalScaleKernel (context, stitch, is_uv); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, + kernel->build_kernel (kernel_info, transform_option) == XCAM_RETURN_NO_ERROR, + NULL, + "load blender global scaling kernel(%s) failed", is_uv ? "UV" : "Y"); + + return kernel; +} + +SmartPtr<CLImageHandler> +create_image_360_stitch ( + const SmartPtr<CLContext> &context, bool need_seam, + CLBlenderScaleMode scale_mode, bool fisheye_map, bool need_lsc, SurroundMode surround_mode, + StitchResMode res_mode, int fisheye_num, bool all_in_one_img) +{ + const int layer = 2; + const bool need_uv = true; + SmartPtr<CLFisheyeHandler> fisheye; + SmartPtr<CLBlender> blender; + SmartPtr<CLImage360Stitch> stitch = new CLImage360Stitch ( + context, scale_mode, surround_mode, res_mode, fisheye_num, all_in_one_img); + XCAM_ASSERT (stitch.ptr ()); + + for (int index = 0; index < fisheye_num; ++index) { + fisheye = create_fisheye_handler (context, surround_mode, fisheye_map, need_lsc).dynamic_cast_ptr<CLFisheyeHandler> (); + XCAM_FAIL_RETURN (ERROR, fisheye.ptr (), NULL, "image_360_stitch create fisheye handler failed"); + fisheye->disable_buf_pool (true); + stitch->set_fisheye_handler (fisheye, index); + } + + for (int index = 0; index < fisheye_num; ++index) { + blender = create_pyramid_blender (context, layer, need_uv, need_seam, scale_mode).dynamic_cast_ptr<CLBlender> (); + XCAM_FAIL_RETURN (ERROR, blender.ptr (), NULL, "image_360_stitch create blender failed"); + blender->disable_buf_pool (true); + stitch->set_blender (blender, index); + } + + if (scale_mode == CLBlenderScaleGlobal) { + int max_plane = need_uv ? 2 : 1; + bool uv_status[2] = {false, true}; + for (int plane = 0; plane < max_plane; ++plane) { + SmartPtr<CLImageKernel> kernel = create_blender_global_scale_kernel (context, stitch, uv_status[plane]); + XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create blender global scaling kernel failed"); + stitch->add_kernel (kernel); + } + } + + return stitch; +} + +} + diff --git a/modules/ocl/cl_image_360_stitch.h b/modules/ocl/cl_image_360_stitch.h new file mode 100644 index 0000000..2c6babf --- /dev/null +++ b/modules/ocl/cl_image_360_stitch.h @@ -0,0 +1,165 @@ +/* + * cl_image_360_stitch.h - CL Image 360 stitch + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_IMAGE_360_STITCH_H +#define XCAM_CL_IMAGE_360_STITCH_H + +#include <xcam_std.h> +#include <interface/stitcher.h> +#include <interface/feature_match.h> +#include <ocl/cl_multi_image_handler.h> +#include <ocl/cl_fisheye_handler.h> +#include <ocl/cl_blender.h> + +namespace XCam { + +struct CLFisheyeParams { + SmartPtr<CLFisheyeHandler> handler; + SmartPtr<BufferPool> pool; + SmartPtr<VideoBuffer> buf; + + uint32_t width; + uint32_t height; + + CLFisheyeParams () : width (0), height (0) {} +}; + +class CLImage360Stitch; +class CLBlenderGlobalScaleKernel + : public CLBlenderScaleKernel +{ +public: + explicit CLBlenderGlobalScaleKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLImage360Stitch> &stitch, bool is_uv); + +protected: + virtual SmartPtr<CLImage> get_input_image (); + virtual SmartPtr<CLImage> get_output_image (); + virtual bool get_output_info (uint32_t &out_width, uint32_t &out_height, int &out_offset_x); + +private: + SmartPtr<CLImage360Stitch> _stitch; +}; + +class CLImage360Stitch + : public CLMultiImageHandler +{ +public: + explicit CLImage360Stitch ( + const SmartPtr<CLContext> &context, CLBlenderScaleMode scale_mode, SurroundMode surround_mode, + StitchResMode res_mode, int fisheye_num, bool all_in_one_img); + + bool set_stitch_info (StitchInfo stitch_info); + StitchInfo get_stitch_info (); + void set_output_size (uint32_t width, uint32_t height) { + _output_width = width; //XCAM_ALIGN_UP (width, XCAM_BLENDER_ALIGNED_WIDTH); + _output_height = height; + } + + bool set_fisheye_handler (SmartPtr<CLFisheyeHandler> fisheye, int index); + bool set_blender (SmartPtr<CLBlender> blender, int idx); + + void set_fisheye_intrinsic (IntrinsicParameter intrinsic_param, int index); + void set_fisheye_extrinsic (ExtrinsicParameter extrinsic_param, int index); + + const BowlDataConfig &get_fisheye_bowl_config (int index = 0); + + bool set_image_overlap (const int idx, const Rect &overlap0, const Rect &overlap1); + const Rect &get_image_overlap (int img_idx, int num) { + XCAM_ASSERT (img_idx < _fisheye_num && num < 2); + return _overlaps[img_idx][num]; + } + + SmartPtr<VideoBuffer> &get_global_scale_input () { + return _scale_global_input; + } + SmartPtr<VideoBuffer> &get_global_scale_output () { + return _scale_global_output; + } + + void set_feature_match_ocl (bool use_ocl); +#if HAVE_OPENCV + void set_feature_match_config (const int idx, CVFMConfig config); + CVFMConfig get_feature_match_config (const int idx); +#endif + +protected: + virtual XCamReturn prepare_buffer_pool_video_info (const VideoBufferInfo &input, VideoBufferInfo &output); + virtual XCamReturn prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + virtual XCamReturn execute_done (SmartPtr<VideoBuffer> &output); + + XCamReturn ensure_fisheye_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + XCamReturn prepare_local_scale_blender_parameters ( + SmartPtr<VideoBuffer> &input0, SmartPtr<VideoBuffer> &input1, SmartPtr<VideoBuffer> &output, int idx, int idx_next); + XCamReturn prepare_global_scale_blender_parameters ( + SmartPtr<VideoBuffer> &input0, SmartPtr<VideoBuffer> &input1, SmartPtr<VideoBuffer> &output, + int idx, int idx_next, int &cur_start_pos); + + bool create_buffer_pool (SmartPtr<BufferPool> &buf_pool, uint32_t width, uint32_t height); + XCamReturn reset_buffer_info (SmartPtr<VideoBuffer> &input); + + virtual XCamReturn sub_handler_execute_done (SmartPtr<CLImageHandler> &handler); + + void calc_fisheye_initial_info (SmartPtr<VideoBuffer> &output); + void update_image_overlap (); + +private: + XCAM_DEAD_COPY (CLImage360Stitch); + +private: + SmartPtr<CLContext> _context; + CLFisheyeParams _fisheye[XCAM_STITCH_FISHEYE_MAX_NUM]; + SmartPtr<CLBlender> _blender[XCAM_STITCH_FISHEYE_MAX_NUM]; + SmartPtr<FeatureMatch> _feature_match[XCAM_STITCH_FISHEYE_MAX_NUM]; + + uint32_t _output_width; + uint32_t _output_height; + ImageMergeInfo _img_merge_info[XCAM_STITCH_FISHEYE_MAX_NUM]; + Rect _overlaps[XCAM_STITCH_FISHEYE_MAX_NUM][2]; // 2=>Overlap0 and overlap1 + + CLBlenderScaleMode _scale_mode; + SmartPtr<BufferPool> _scale_buf_pool; + SmartPtr<VideoBuffer> _scale_global_input; + SmartPtr<VideoBuffer> _scale_global_output; + + SurroundMode _surround_mode; + StitchResMode _res_mode; + + bool _is_stitch_inited; + int _fisheye_num; + bool _all_in_one_img; + StitchInfo _stitch_info; +}; + +SmartPtr<CLImageHandler> +create_image_360_stitch ( + const SmartPtr<CLContext> &context, + bool need_seam = false, + CLBlenderScaleMode scale_mode = CLBlenderScaleLocal, + bool fisheye_map = false, + bool need_lsc = false, + SurroundMode surround_mode = SphereView, + StitchResMode res_mode = StitchRes1080P, + int fisheye_num = 2, + bool all_in_one_img = true); + +} + +#endif //XCAM_CL_IMAGE_360_STITCH_H diff --git a/modules/ocl/cl_image_bo_buffer.cpp b/modules/ocl/cl_image_bo_buffer.cpp new file mode 100644 index 0000000..f3b208b --- /dev/null +++ b/modules/ocl/cl_image_bo_buffer.cpp @@ -0,0 +1,225 @@ +/* + * cl_image_bo_buffer.cpp - cl image bo buffer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_image_bo_buffer.h" +#include "cl_memory.h" +#include "swapped_buffer.h" + + +namespace XCam { + +CLImageBoData::CLImageBoData (SmartPtr<DrmDisplay> &display, SmartPtr<CLImage> &image, drm_intel_bo *bo) + : DrmBoData (display, bo) + , _image (image) +{ + XCAM_ASSERT (image->get_mem_id ()); +} + +int +CLImageBoData::get_fd () +{ + if (!_image.ptr()) + return -1; + return _image->export_fd (); +} + +CLImageBoBuffer::CLImageBoBuffer (const VideoBufferInfo &info, const SmartPtr<CLImageBoData> &data) + : BufferProxy (info, data) + , DrmBoBuffer (info, data) +{ +} + +SmartPtr<CLImage> +CLImageBoBuffer::get_cl_image () +{ + SmartPtr<BufferData> data = get_buffer_data (); + SmartPtr<CLImageBoData> image = data.dynamic_cast_ptr<CLImageBoData> (); + + XCAM_FAIL_RETURN( + WARNING, + image.ptr(), + NULL, + "CLImageBoBuffer get_buffer_data failed with NULL"); + return image->get_image (); +} + +SmartPtr<SwappedBuffer> +CLImageBoBuffer::create_new_swap_buffer ( + const VideoBufferInfo &info, SmartPtr<BufferData> &data) +{ + XCAM_ASSERT (get_buffer_data ().ptr () == data.ptr ()); + + SmartPtr<CLImageBoData> bo = data.dynamic_cast_ptr<CLImageBoData> (); + + XCAM_FAIL_RETURN( + WARNING, + bo.ptr(), + NULL, + "CLImageBoBuffer create_new_swap_buffer failed with NULL buffer data"); + + return new CLImageBoBuffer (info, bo); +} + +CLBoBufferPool::CLBoBufferPool (SmartPtr<DrmDisplay> &display, SmartPtr<CLContext> &context) + : DrmBoBufferPool (display) + , _context (context) +{ + XCAM_ASSERT (context.ptr ()); + XCAM_LOG_DEBUG ("CLBoBufferPool constructed"); +} + +CLBoBufferPool::~CLBoBufferPool () +{ + XCAM_LOG_DEBUG ("CLBoBufferPool destructed"); +} + +SmartPtr<CLImageBoData> +CLBoBufferPool::create_image_bo (const VideoBufferInfo &info) +{ + int32_t mem_fd = -1; + SmartPtr<DrmDisplay> display = get_drm_display (); + drm_intel_bo *bo = NULL; + CLImageDesc desc; + SmartPtr<CLImageBoData> data; + SmartPtr<CLImage> image; + uint32_t swap_flags = get_swap_flags (); + uint32_t extra_array_size = 0; + if (swap_flags & (uint32_t)(SwappedBuffer::SwapY)) + ++extra_array_size; + if (swap_flags & (uint32_t)(SwappedBuffer::SwapUV)) + ++extra_array_size; + + if (info.components == 1) + image = new CLImage2D (_context, info, CL_MEM_READ_WRITE); + else + image = new CLImage2DArray (_context, info, CL_MEM_READ_WRITE, extra_array_size); + XCAM_FAIL_RETURN ( + WARNING, + image.ptr () && image->get_mem_id (), + NULL, + "CLBoBufferPool create image failed"); + + desc = image->get_image_desc (); + mem_fd = image->export_fd (); + XCAM_FAIL_RETURN ( + WARNING, + mem_fd >= 0, + NULL, + "CLBoBufferPool export image fd failed"); + + bo = display->create_drm_bo_from_fd (mem_fd, desc.size); + XCAM_FAIL_RETURN ( + WARNING, + bo, + NULL, + "CLBoBufferPool bind fd to bo failed"); + + data = new CLImageBoData (display, image, bo); + XCAM_FAIL_RETURN ( + WARNING, + data.ptr (), + NULL, + "CLBoBufferPool bind CLImage to CLImageBoData failed"); + return data; +} + +bool +CLBoBufferPool::fixate_video_info (VideoBufferInfo &info) +{ + bool need_reset_info = false; + uint32_t i = 0; + SmartPtr<CLImage> image; + uint32_t swap_flags = get_swap_flags (); + SmartPtr<CLImageBoData> image_data = create_image_bo (info); + XCAM_FAIL_RETURN ( + WARNING, + image_data.ptr (), + NULL, + "CLBoBufferPool fixate_video_info failed"); + + image = image_data->get_image (); + XCAM_ASSERT (image.ptr ()); + + CLImageDesc desc = image->get_image_desc (); + if (desc.row_pitch != info.strides [0] || desc.size != info.size) + need_reset_info = true; + + for (i = 1; i < info.components && !need_reset_info; ++i) { + XCAM_ASSERT (desc.slice_pitch && desc.array_size >= info.components); + if (desc.row_pitch != info.strides [i] || + info.offsets [i] != desc.slice_pitch * i) + need_reset_info = true; + } + if (need_reset_info) { + VideoBufferPlanarInfo plane_info; + info.get_planar_info (plane_info, 0); + uint32_t aligned_width = desc.row_pitch / plane_info.pixel_bytes; + uint32_t aligned_height = info.aligned_height; + if (info.components > 0) + aligned_height = desc.slice_pitch / desc.row_pitch; + info.init (info.format, info.width, info.height, aligned_width, aligned_height, desc.size); + for (i = 1; i < info.components; ++i) { + info.offsets[i] = desc.slice_pitch * i; + info.strides[i] = desc.row_pitch; + } + } + + if (swap_flags && desc.array_size >= 2) { + if (swap_flags & (uint32_t)(SwappedBuffer::SwapY)) { + _swap_offsets[SwappedBuffer::SwapYOffset0] = info.offsets[0]; + _swap_offsets[SwappedBuffer::SwapYOffset1] = desc.slice_pitch * 2; + } + if (swap_flags & (uint32_t)(SwappedBuffer::SwapUV)) { + _swap_offsets[SwappedBuffer::SwapUVOffset0] = info.offsets[1]; + _swap_offsets[SwappedBuffer::SwapUVOffset1] = desc.slice_pitch * (desc.array_size - 1); + } + } + + if(!init_swap_order (info)) { + XCAM_LOG_ERROR ("CLBoBufferPool: fix video info faield to init swap order"); + return false; + } + + add_data_unsafe (image_data); + + return true; +} + +SmartPtr<BufferData> +CLBoBufferPool::allocate_data (const VideoBufferInfo &buffer_info) +{ + SmartPtr<CLImageBoData> image_data = create_image_bo (buffer_info); + return image_data; +} + +SmartPtr<BufferProxy> +CLBoBufferPool::create_buffer_from_data (SmartPtr<BufferData> &data) +{ + const VideoBufferInfo & info = get_video_info (); + SmartPtr<CLImageBoData> image_data = data.dynamic_cast_ptr<CLImageBoData> (); + XCAM_ASSERT (image_data.ptr ()); + + SmartPtr<CLImageBoBuffer> out_buf = new CLImageBoBuffer (info, image_data); + XCAM_ASSERT (out_buf.ptr ()); + out_buf->set_swap_info (_swap_flags, _swap_offsets); + return out_buf; +} + +}; diff --git a/modules/ocl/cl_image_bo_buffer.h b/modules/ocl/cl_image_bo_buffer.h new file mode 100644 index 0000000..42a32ed --- /dev/null +++ b/modules/ocl/cl_image_bo_buffer.h @@ -0,0 +1,92 @@ +/* + * cl_image_bo_buffer.h - cl image bo buffer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_IMAGE_BO_BUFFER_H +#define XCAM_CL_IMAGE_BO_BUFFER_H + +#include <xcam_std.h> +#include <drm_bo_buffer.h> +#include <ocl/cl_memory.h> +#include <ocl/cl_context.h> + +namespace XCam { + +class CLImageBoBuffer; +class CLBoBufferPool; + +class CLImageBoData + : public DrmBoData +{ + friend class CLBoBufferPool; + friend class CLImageBoBuffer; +public: + virtual int get_fd (); + +private: + explicit CLImageBoData (SmartPtr<DrmDisplay> &display, SmartPtr<CLImage> &image, drm_intel_bo *bo); + XCAM_DEAD_COPY (CLImageBoData); + + SmartPtr<CLImage> &get_image () { + return _image; + } + +private: + SmartPtr<CLImage> _image; +}; + +class CLImageBoBuffer + : public DrmBoBuffer +{ + friend class CLBoBufferPool; +public: + SmartPtr<CLImage> get_cl_image (); + +protected: + CLImageBoBuffer (const VideoBufferInfo &info, const SmartPtr<CLImageBoData> &data); + + //derived from SwappedBuffer + virtual SmartPtr<SwappedBuffer> create_new_swap_buffer ( + const VideoBufferInfo &info, SmartPtr<BufferData> &data); +}; + +class CLBoBufferPool + : public DrmBoBufferPool +{ +public: + explicit CLBoBufferPool (SmartPtr<DrmDisplay> &display, SmartPtr<CLContext> &context); + ~CLBoBufferPool (); + +protected: + // derived from BufferPool + virtual bool fixate_video_info (VideoBufferInfo &info); + virtual SmartPtr<BufferData> allocate_data (const VideoBufferInfo &buffer_info); + virtual SmartPtr<BufferProxy> create_buffer_from_data (SmartPtr<BufferData> &data); + +private: + SmartPtr<CLImageBoData> create_image_bo (const VideoBufferInfo &buffer_info); + XCAM_DEAD_COPY (CLBoBufferPool); + +private: + SmartPtr<CLContext> _context; +}; + + +}; +#endif // XCAM_CL_IMAGE_BO_BUFFER_H diff --git a/modules/ocl/cl_image_handler.cpp b/modules/ocl/cl_image_handler.cpp new file mode 100644 index 0000000..f9fc56c --- /dev/null +++ b/modules/ocl/cl_image_handler.cpp @@ -0,0 +1,526 @@ +/* + * cl_image_handler.cpp - CL image handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_image_handler.h" +#if HAVE_LIBDRM +#include "drm_display.h" +#include "cl_image_bo_buffer.h" +#include "drm_bo_buffer.h" +#endif +#include "cl_device.h" +#include "swapped_buffer.h" + +namespace XCam { + +#define XCAM_CL_IMAGE_HANDLER_DEFAULT_BUF_NUM 4 + +CLImageKernel::CLImageKernel (const SmartPtr<CLContext> &context, const char *name, bool enable) + : CLKernel (context, name) + , _enable (enable) +{ +} + +CLImageKernel::~CLImageKernel () +{ +} + +/* + * Default kernel arguments + * arg0: + * input, __read_only image2d_t + * arg1: + * output, __write_only image2d_t + * suppose cl can get width/height pixels from + * get_image_width/get_image_height + */ +XCamReturn +CLImageKernel::pre_execute () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + CLArgList args; + CLWorkSize work_size; + + XCAM_FAIL_RETURN ( + ERROR, !is_arguments_set (), XCAM_RETURN_ERROR_PARAM, + "cl image kernel(%s) pre_execute failed since arguments was set somewhere", get_kernel_name ()); + + ret = prepare_arguments (args, work_size); + XCAM_FAIL_RETURN ( + WARNING, + ret == XCAM_RETURN_NO_ERROR, ret, + "cl image kernel(%s) prepare arguments failed", get_kernel_name ()); + + ret = set_arguments (args, work_size); + XCAM_FAIL_RETURN ( + WARNING, + ret == XCAM_RETURN_NO_ERROR, ret, + "cl image kernel(%s) set_arguments failed", get_kernel_name ()); + + return ret; +} + +XCamReturn +CLImageKernel::prepare_arguments ( + CLArgList &args, CLWorkSize &work_size) +{ + XCAM_UNUSED (args); + XCAM_UNUSED (work_size); + + XCAM_LOG_ERROR ( + "cl image kernel(%s) prepare_arguments error." + "Did you forget to set_arguments or prepare_arguments was not derived", get_kernel_name ()); + return XCAM_RETURN_ERROR_CL; +} + +CLImageHandler::CLImageHandler (const SmartPtr<CLContext> &context, const char *name) + : _name (NULL) + , _enable (true) + , _context (context) + , _buf_pool_type (CLImageHandler::CLVideoPoolType) + , _disable_buf_pool (false) + , _buf_pool_size (XCAM_CL_IMAGE_HANDLER_DEFAULT_BUF_NUM) + , _buf_swap_flags ((uint32_t)(SwappedBuffer::OrderY0Y1) | (uint32_t)(SwappedBuffer::OrderUV0UV1)) + , _buf_swap_init_order (SwappedBuffer::OrderY0Y1) + , _result_timestamp (XCam::InvalidTimestamp) +{ + XCAM_ASSERT (name); + if (name) + _name = strndup (name, XCAM_MAX_STR_SIZE); + + XCAM_OBJ_PROFILING_INIT; +} + +CLImageHandler::~CLImageHandler () +{ + if (_name) + xcam_free (_name); +} + +bool +CLImageHandler::enable_buf_pool_swap_flags ( + uint32_t flags, + uint32_t init_order) +{ +#if HAVE_LIBDRM + _buf_swap_flags = flags; + _buf_swap_init_order = init_order; + + SmartPtr<DrmBoBufferPool> pool = _buf_pool.dynamic_cast_ptr<DrmBoBufferPool> (); + + if (pool.ptr () && !pool->update_swap_init_order (init_order)) { + XCAM_LOG_ERROR ( + "Handler(%s) update swap order(0x%04x) to buffer pool failed", + XCAM_STR (get_name ()), + init_order); + return false; + } + return true; +#else + XCAM_LOG_ERROR ("CLImageHandler doesn't support swapping flags"); + + XCAM_UNUSED (flags); + XCAM_UNUSED (init_order); + return false; +#endif +} + +bool +CLImageHandler::add_kernel (const SmartPtr<CLImageKernel> &kernel) +{ + _kernels.push_back (kernel); + return true; +} + +bool +CLImageHandler::enable_handler (bool enable) +{ + _enable = enable; + return true; +} + +bool +CLImageHandler::is_handler_enabled () const +{ + return _enable; +} + +XCamReturn +CLImageHandler::create_buffer_pool (const VideoBufferInfo &video_info) +{ + if (_buf_pool.ptr ()) + return XCAM_RETURN_ERROR_PARAM; + + SmartPtr<BufferPool> buffer_pool; + if (_buf_pool_type == CLImageHandler::CLVideoPoolType) { + buffer_pool = new CLVideoBufferPool (); + } +#if HAVE_LIBDRM + else { + SmartPtr<DrmDisplay> display = DrmDisplay::instance (); + XCAM_FAIL_RETURN( + WARNING, + display.ptr (), + XCAM_RETURN_ERROR_CL, + "CLImageHandler(%s) failed to get drm dispay", XCAM_STR (_name)); + + if (_buf_pool_type == CLImageHandler::DrmBoPoolType) { + buffer_pool = new DrmBoBufferPool (display); + } else if (_buf_pool_type == CLImageHandler::CLBoPoolType) { + buffer_pool = new CLBoBufferPool (display, get_context ()); + } + } +#endif + XCAM_FAIL_RETURN( + WARNING, + buffer_pool.ptr (), + XCAM_RETURN_ERROR_CL, + "CLImageHandler(%s) create buffer pool failed, pool_type:%d", + XCAM_STR (_name), (int32_t)_buf_pool_type); + + XCAM_ASSERT (buffer_pool.ptr ()); + // buffer_pool->set_swap_flags (_buf_swap_flags, _buf_swap_init_order); + buffer_pool->set_video_info (video_info); + + XCAM_FAIL_RETURN( + WARNING, + buffer_pool->reserve (_buf_pool_size), + XCAM_RETURN_ERROR_CL, + "CLImageHandler(%s) failed to init drm buffer pool", XCAM_STR (_name)); + + _buf_pool = buffer_pool; + return XCAM_RETURN_NO_ERROR; +} + +bool CLImageHandler::is_ready () +{ + if (_disable_buf_pool) + return true; + if (!_buf_pool.ptr ()) //execute not triggered + return true; + if (_buf_pool->has_free_buffers ()) + return true; + return false; +} + +XCamReturn CLImageHandler::prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, + VideoBufferInfo &output) +{ + output = input; + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLImageHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + XCAM_UNUSED (input); + XCAM_UNUSED (output); + XCAM_ASSERT (input.ptr () && output.ptr ()); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLImageHandler::ensure_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + XCamReturn ret = prepare_parameters (input, output); + XCAM_FAIL_RETURN( + WARNING, ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS, ret, + "CLImageHandler(%s) failed to prepare_parameters", XCAM_STR (_name)); + + reset_buf_cache (input, output); + return ret; +} + +void +CLImageHandler::reset_buf_cache (const SmartPtr<VideoBuffer>& input, const SmartPtr<VideoBuffer>& output) +{ + _input_buf_cache = input; + _output_buf_cache = output; +} + +XCamReturn +CLImageHandler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + if (_disable_buf_pool) + return XCAM_RETURN_NO_ERROR; + + if (!_buf_pool.ptr ()) { + VideoBufferInfo output_video_info; + + ret = prepare_buffer_pool_video_info (input->get_video_info (), output_video_info); + XCAM_FAIL_RETURN( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "CLImageHandler(%s) prepare output video info failed", XCAM_STR (_name)); + + ret = create_buffer_pool (output_video_info); + XCAM_FAIL_RETURN( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "CLImageHandler(%s) ensure drm buffer pool failed", XCAM_STR (_name)); + } + + output = _buf_pool->get_buffer (_buf_pool); + XCAM_FAIL_RETURN( + WARNING, + output.ptr(), + XCAM_RETURN_ERROR_UNKNOWN, + "CLImageHandler(%s) failed to get drm buffer from pool", XCAM_STR (_name)); + + // TODO, need consider output is not sync up with input buffer + output->set_timestamp (input->get_timestamp ()); + output->copy_attaches (input); + + return XCAM_RETURN_NO_ERROR; +} + +void +CLImageHandler::emit_stop () +{ + for (KernelList::iterator i_kernel = _kernels.begin (); + i_kernel != _kernels.end (); ++i_kernel) { + (*i_kernel)->pre_stop (); + } + + if (_buf_pool.ptr ()) + _buf_pool->stop (); +} + +SmartPtr<VideoBuffer> & +CLImageHandler::get_input_buf () +{ + XCAM_ASSERT (_input_buf_cache.ptr ()); + return _input_buf_cache; +} + +SmartPtr<VideoBuffer> & +CLImageHandler::get_output_buf () +{ + XCAM_ASSERT (_output_buf_cache.ptr ()); + return _output_buf_cache; +} + +XCamReturn +CLImageHandler::execute_kernel (SmartPtr<CLImageKernel> &kernel) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + if (!kernel->is_enabled ()) + return XCAM_RETURN_NO_ERROR; + + if (!kernel->is_arguments_set ()) { + XCAM_FAIL_RETURN ( + WARNING, + (ret = kernel->pre_execute ()) == XCAM_RETURN_NO_ERROR, ret, + "cl_image_handler(%s) pre_execute kernel(%s) failed", + XCAM_STR (_name), kernel->get_kernel_name ()); + } + + CLArgList args = kernel->get_args (); + ret = kernel->execute (kernel, false); + XCAM_FAIL_RETURN ( + WARNING, ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS, ret, + "cl_image_handler(%s) execute kernel(%s) failed", + XCAM_STR (_name), kernel->get_kernel_name ()); + +#if 0 + ret = kernel->post_execute (args); + XCAM_FAIL_RETURN ( + WARNING, + (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS), + ret, + "cl_image_handler(%s) post_execute kernel(%s) failed", + XCAM_STR (_name), kernel->get_kernel_name ()); +#endif + + return ret; +} + +XCamReturn +CLImageHandler::execute_kernels () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + for (KernelList::iterator i_kernel = _kernels.begin (); + i_kernel != _kernels.end (); ++i_kernel) { + SmartPtr<CLImageKernel> &kernel = *i_kernel; + + XCAM_FAIL_RETURN ( + WARNING, kernel.ptr(), XCAM_RETURN_ERROR_PARAM, + "kernel empty"); + + ret = execute_kernel (kernel); + + if (ret != XCAM_RETURN_NO_ERROR) + break; + } + + return ret; +} + +XCamReturn +CLImageHandler::execute (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_FAIL_RETURN ( + WARNING, + !_kernels.empty (), + XCAM_RETURN_ERROR_PARAM, + "cl_image_handler(%s) no image kernel set", XCAM_STR (_name)); + + if (!is_handler_enabled ()) { + output = input; + return XCAM_RETURN_NO_ERROR; + } + + XCAM_FAIL_RETURN ( + WARNING, + (ret = prepare_output_buf (input, output)) == XCAM_RETURN_NO_ERROR, + ret, + "cl_image_handler (%s) prepare output buf failed", XCAM_STR (_name)); + XCAM_ASSERT (output.ptr ()); + + ret = ensure_parameters (input, output); + XCAM_FAIL_RETURN ( + WARNING, (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS), ret, + "cl_image_handler (%s) ensure parameters failed", XCAM_STR (_name)); + + if (ret == XCAM_RETURN_BYPASS) + return ret; + + XCAM_OBJ_PROFILING_START; + ret = execute_kernels (); + + reset_buf_cache (NULL, NULL); + +#if ENABLE_PROFILING + get_context ()->finish (); +#endif + XCAM_OBJ_PROFILING_END (XCAM_STR (_name), XCAM_OBJ_DUR_FRAME_NUM); + + XCAM_FAIL_RETURN ( + WARNING, (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS), ret, + "cl_image_handler (%s) execute kernels failed", XCAM_STR (_name)); + + if (ret != XCAM_RETURN_NO_ERROR) + return ret; + + ret = execute_done (output); + return ret; +} + +XCamReturn +CLImageHandler::execute_done (SmartPtr<VideoBuffer> &output) +{ + XCAM_UNUSED (output); + return XCAM_RETURN_NO_ERROR; +} + +void +CLImageHandler::set_3a_result (SmartPtr<X3aResult> &result) +{ + if (!result.ptr ()) + return; + + int64_t ts = result->get_timestamp (); + _result_timestamp = (ts != XCam::InvalidTimestamp) ? ts : _result_timestamp; + + X3aResultList::iterator i_res = _3a_results.begin (); + for (; i_res != _3a_results.end(); ++i_res) { + if (result->get_type () == (*i_res)->get_type ()) { + (*i_res) = result; + break; + } + } + + if (i_res == _3a_results.end ()) { + _3a_results.push_back (result); + } +} + +SmartPtr<X3aResult> +CLImageHandler::get_3a_result (XCam3aResultType type) +{ + X3aResultList::iterator i_res = _3a_results.begin (); + SmartPtr<X3aResult> res; + + for ( ; i_res != _3a_results.end(); ++i_res) { + if (type == (*i_res)->get_type ()) { + res = (*i_res); + break; + } + } + return res; +} + +bool +CLImageHandler::append_kernels (SmartPtr<CLImageHandler> handler) +{ + XCAM_ASSERT (!handler->_kernels.empty ()); + _kernels.insert (_kernels.end (), handler->_kernels.begin (), handler->_kernels.end ()); + return true; +} + +CLCloneImageHandler::CLCloneImageHandler (const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) + , _clone_flags (SwappedBuffer::SwapNone) +{ +} + +XCamReturn +CLCloneImageHandler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ +#if HAVE_LIBDRM + XCAM_FAIL_RETURN ( + ERROR, + _clone_flags != (uint32_t)(SwappedBuffer::SwapNone), + XCAM_RETURN_ERROR_PARAM, + "CLCloneImageHandler(%s) clone output buffer failed since clone_flags none", + XCAM_STR (get_name ())); + + XCAM_ASSERT (input.ptr ()); + SmartPtr<SwappedBuffer> swap_input = input.dynamic_cast_ptr<DrmBoBuffer> (); + XCAM_ASSERT (swap_input.ptr ()); + SmartPtr<SwappedBuffer> swap_output = swap_input->swap_clone (swap_input, _clone_flags); + SmartPtr<DrmBoBuffer> swapped_buf = swap_output.dynamic_cast_ptr<DrmBoBuffer> (); + XCAM_FAIL_RETURN ( + ERROR, + swapped_buf.ptr (), + XCAM_RETURN_ERROR_UNKNOWN, + "CLCloneImageHandler(%s) clone output buffer failed(clone_flags:%d)", + XCAM_STR (get_name ()), _clone_flags); + + output = swapped_buf; + return XCAM_RETURN_NO_ERROR; +#else + XCAM_LOG_ERROR ("CLCloneImageHandler doesn't support DrmBoBuffer"); + + XCAM_UNUSED (input); + XCAM_UNUSED (output); + return XCAM_RETURN_ERROR_PARAM; +#endif +} + +}; diff --git a/modules/ocl/cl_image_handler.h b/modules/ocl/cl_image_handler.h new file mode 100644 index 0000000..45c1b31 --- /dev/null +++ b/modules/ocl/cl_image_handler.h @@ -0,0 +1,200 @@ +/* + * cl_image_handler.h - CL image handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_IMAGE_HANDLER_H +#define XCAM_CL_IMAGE_HANDLER_H + +#include <xcam_std.h> +#include <swapped_buffer.h> +#include <x3a_result.h> +#include <ocl/cl_kernel.h> +#include <ocl/cl_argument.h> +#include <ocl/cl_memory.h> +#include <ocl/cl_video_buffer.h> + +namespace XCam { + +class CLImageHandler; + +class CLImageKernel + : public CLKernel +{ + friend class CLImageHandler; + +public: + explicit CLImageKernel (const SmartPtr<CLContext> &context, const char *name = NULL, bool enable = true); + virtual ~CLImageKernel (); + + void set_enable (bool enable) { + _enable = enable; + } + + bool is_enabled () const { + return _enable; + } + virtual void pre_stop () {} + +protected: + XCamReturn pre_execute (); + virtual XCamReturn prepare_arguments ( + CLArgList &args, CLWorkSize &work_size); + +private: + XCAM_DEAD_COPY (CLImageKernel); + +private: + bool _enable; +}; + +class CLMultiImageHandler; +class CLImageHandler +{ + friend class CLMultiImageHandler; + +public: + typedef std::list<SmartPtr<CLImageKernel>> KernelList; + enum BufferPoolType { + CLVideoPoolType = 0x0000, + CLBoPoolType = 0x0001, + DrmBoPoolType = 0x0002 + }; + +public: + explicit CLImageHandler (const SmartPtr<CLContext> &context, const char *name); + virtual ~CLImageHandler (); + const char *get_name () const { + return _name; + } + SmartPtr<CLContext> &get_context () { + return _context; + } + + void set_3a_result (SmartPtr<X3aResult> &result); + SmartPtr<X3aResult> get_3a_result (XCam3aResultType type); + + int64_t get_result_timestamp () const { + return _result_timestamp; + }; + + void set_pool_type (BufferPoolType type) { + _buf_pool_type = type; + } + void set_pool_size (uint32_t size) { + XCAM_ASSERT (size); + _buf_pool_size = size; + } + void disable_buf_pool (bool flag) { + _disable_buf_pool = flag; + } + + bool is_buf_pool_disabled () const { + return _disable_buf_pool; + } + + bool enable_buf_pool_swap_flags ( + uint32_t flags, + uint32_t init_order = (uint32_t)(SwappedBuffer::OrderY0Y1)); + + bool add_kernel (const SmartPtr<CLImageKernel> &kernel); + bool enable_handler (bool enable); + bool is_handler_enabled () const; + + virtual bool is_ready (); + XCamReturn execute (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + virtual void emit_stop (); + + SmartPtr<VideoBuffer> &get_input_buf (); + SmartPtr<VideoBuffer> &get_output_buf (); + +private: + virtual XCamReturn prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, + VideoBufferInfo &output); + + // if derive prepare_output_buf, then prepare_buffer_pool_video_info is not involked + virtual XCamReturn prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + virtual XCamReturn execute_done (SmartPtr<VideoBuffer> &output); + +protected: + virtual XCamReturn prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + + //only for multi-handler + virtual XCamReturn execute_kernels (); + + XCamReturn ensure_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + XCamReturn execute_kernel (SmartPtr<CLImageKernel> &kernel); + XCamReturn create_buffer_pool (const VideoBufferInfo &video_info); + SmartPtr<BufferPool> &get_buffer_pool () { + return _buf_pool; + } + void reset_buf_cache (const SmartPtr<VideoBuffer>& input, const SmartPtr<VideoBuffer>& output); + + bool append_kernels (SmartPtr<CLImageHandler> handler); + +private: + XCAM_DEAD_COPY (CLImageHandler); + +private: + char *_name; + bool _enable; + KernelList _kernels; + SmartPtr<CLContext> _context; + SmartPtr<BufferPool> _buf_pool; + BufferPoolType _buf_pool_type; + bool _disable_buf_pool; + uint32_t _buf_pool_size; + uint32_t _buf_swap_flags; + uint32_t _buf_swap_init_order; + X3aResultList _3a_results; + int64_t _result_timestamp; + + SmartPtr<VideoBuffer> _input_buf_cache; + SmartPtr<VideoBuffer> _output_buf_cache; + + XCAM_OBJ_PROFILING_DEFINES; +}; + +// never allocate buffer, only swap output from input +class CLCloneImageHandler + : public CLImageHandler +{ +public: + explicit CLCloneImageHandler (const SmartPtr<CLContext> &context, const char *name); + void set_clone_flags (uint32_t flags) { + _clone_flags = flags; + } + uint32_t get_clone_flags () const { + return _clone_flags; + } + +protected: + //derived from CLImageHandler + virtual XCamReturn prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + XCAM_DEAD_COPY (CLCloneImageHandler); + + uint32_t _clone_flags; +}; + + +}; + +#endif // XCAM_CL_IMAGE_HANDLER_H diff --git a/modules/ocl/cl_image_processor.cpp b/modules/ocl/cl_image_processor.cpp new file mode 100644 index 0000000..c0cbd98 --- /dev/null +++ b/modules/ocl/cl_image_processor.cpp @@ -0,0 +1,372 @@ +/* + * cl_image_processor.cpp - CL image processor + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ +#include "cl_image_processor.h" +#include "cl_context.h" +#include "cl_device.h" +#include "cl_image_handler.h" +#include "cl_demo_handler.h" +#include "xcam_thread.h" + +namespace XCam { + +class CLHandlerThread + : public Thread +{ +public: + CLHandlerThread (CLImageProcessor *processor) + : Thread ("CLHandlerThread") + , _processor (processor) + {} + ~CLHandlerThread () {} + + virtual bool loop (); + +private: + CLImageProcessor *_processor; +}; + +bool CLHandlerThread::loop () +{ + XCAM_ASSERT (_processor); + XCamReturn ret = _processor->process_cl_buffer_queue (); + if (ret != XCAM_RETURN_NO_ERROR && ret != XCAM_RETURN_BYPASS) + return false; + return true; +} + +class CLBufferNotifyThread + : public Thread +{ +public: + CLBufferNotifyThread (CLImageProcessor *processor) + : Thread ("CLBufNtfThrd") + , _processor (processor) + {} + ~CLBufferNotifyThread () {} + + virtual bool loop (); + +private: + CLImageProcessor *_processor; +}; + +bool CLBufferNotifyThread::loop () +{ + XCAM_ASSERT (_processor); + XCamReturn ret = _processor->process_done_buffer (); + if (ret < XCAM_RETURN_NO_ERROR) + return false; + return true; +} +CLImageProcessor::CLImageProcessor (const char* name) + : ImageProcessor (name ? name : "CLImageProcessor") + , _seq_num (0) + , _keep_attached_buffer (false) +{ + _context = CLDevice::instance ()->get_context (); + XCAM_ASSERT (_context.ptr()); + + _handler_thread = new CLHandlerThread (this); + XCAM_ASSERT (_handler_thread.ptr ()); + + _done_buf_thread = new CLBufferNotifyThread (this); + XCAM_ASSERT (_done_buf_thread.ptr ()); + + XCAM_LOG_DEBUG ("CLImageProcessor constructed"); + XCAM_OBJ_PROFILING_INIT; +} + +CLImageProcessor::~CLImageProcessor () +{ + XCAM_LOG_DEBUG ("CLImageProcessor destructed"); +} + +void +CLImageProcessor::keep_attached_buf(bool flag) +{ + _keep_attached_buffer = flag; +} + +bool +CLImageProcessor::add_handler (SmartPtr<CLImageHandler> &handler) +{ + XCAM_ASSERT (handler.ptr ()); + _handlers.push_back (handler); + return true; +} + +CLImageProcessor::ImageHandlerList::iterator +CLImageProcessor::handlers_begin () +{ + return _handlers.begin (); +} + +CLImageProcessor::ImageHandlerList::iterator +CLImageProcessor::handlers_end () +{ + return _handlers.end (); +} + +SmartPtr<CLContext> +CLImageProcessor::get_cl_context () +{ + return _context; +} + +bool +CLImageProcessor::can_process_result (SmartPtr<X3aResult> &result) +{ + XCAM_UNUSED (result); + return false; +} + +XCamReturn +CLImageProcessor::apply_3a_results (X3aResultList &results) +{ + XCAM_UNUSED (results); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLImageProcessor::apply_3a_result (SmartPtr<X3aResult> &result) +{ + XCAM_UNUSED (result); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLImageProcessor::process_buffer (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + XCAM_ASSERT (input.ptr ()); + + // Always set to NULL, output buf should be handled in CLBufferNotifyThread + output = NULL; + + STREAM_LOCK; + + if (_handlers.empty()) { + ret = create_handlers (); + } + + XCAM_FAIL_RETURN ( + WARNING, + !_handlers.empty () && ret == XCAM_RETURN_NO_ERROR, + XCAM_RETURN_ERROR_CL, + "CL image processor create handlers failed"); + + SmartPtr<PriorityBuffer> p_buf = new PriorityBuffer; + p_buf->set_seq_num (_seq_num++); + p_buf->data = input; + p_buf->handler = *(_handlers.begin ()); + + XCAM_FAIL_RETURN ( + WARNING, + _process_buffer_queue.push_priority_buf (p_buf), + XCAM_RETURN_ERROR_UNKNOWN, + "CLImageProcessor push priority buffer failed"); + + return XCAM_RETURN_BYPASS; +} + +XCamReturn +CLImageProcessor::process_done_buffer () +{ + SmartPtr<VideoBuffer> done_buf = _done_buffer_queue.pop (-1); + if (!done_buf.ptr ()) + return XCAM_RETURN_ERROR_THREAD; + + //notify buffer done, only in this thread + notify_process_buffer_done (done_buf); + return XCAM_RETURN_NO_ERROR; +} + +uint32_t +CLImageProcessor::check_ready_buffers () +{ + uint32_t ready_count = 0; + bool is_ready_or_disabled = false; + UnsafePriorityBufferList::iterator i = _not_ready_buffers.begin (); + + while (i != _not_ready_buffers.end()) { + SmartPtr<PriorityBuffer> buf = *i; + XCAM_ASSERT (buf.ptr () && buf->handler.ptr ()); + { + is_ready_or_disabled = (!buf->handler->is_handler_enabled () || buf->handler->is_ready ()); + } + if (is_ready_or_disabled) { + ready_count ++; + _process_buffer_queue.push_priority_buf (buf); + _not_ready_buffers.erase (i++); + } else + ++i; + } + return ready_count; +} + +XCamReturn +CLImageProcessor::process_cl_buffer_queue () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<PriorityBuffer> p_buf; + const int32_t timeout = 5000; // 5ms + uint32_t ready_count = 0; + + { + STREAM_LOCK; // make sure handler APIs are protected + check_ready_buffers (); + } + + p_buf = _process_buffer_queue.pop (timeout); + + if (!p_buf.ptr ()) { + //XCAM_LOG_DEBUG ("cl buffer queue stopped"); + return XCAM_RETURN_BYPASS; + } + + SmartPtr<VideoBuffer> data = p_buf->data; + SmartPtr<CLImageHandler> handler = p_buf->handler; + SmartPtr <VideoBuffer> out_data; + + XCAM_ASSERT (data.ptr () && handler.ptr ()); + + XCAM_LOG_DEBUG ("buf:%d, rank:%d\n", p_buf->seq_num, p_buf->rank); + + { + STREAM_LOCK; + if (handler->is_handler_enabled () && !handler->is_ready ()) { + _not_ready_buffers.push_back (p_buf); + return XCAM_RETURN_NO_ERROR; + } + + ready_count = check_ready_buffers (); + if (ready_count) { + _process_buffer_queue.push_priority_buf (p_buf); + return XCAM_RETURN_BYPASS; + } + + ret = handler->execute (data, out_data); + XCAM_FAIL_RETURN ( + WARNING, + (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS), + ret, + "CLImageProcessor execute image handler failed"); + XCAM_ASSERT (out_data.ptr ()); + if (ret == XCAM_RETURN_BYPASS) + return ret; + + // for loop in handler, find next handler + ImageHandlerList::iterator i_handler = _handlers.begin (); + while (i_handler != _handlers.end ()) + { + if (handler.ptr () == (*i_handler).ptr ()) { + ++i_handler; + break; + } + ++i_handler; + } + + //skip all disabled handlers + while (i_handler != _handlers.end () && !(*i_handler)->is_handler_enabled ()) + ++i_handler; + + if (i_handler != _handlers.end ()) + p_buf->handler = *i_handler; + else + p_buf->handler = NULL; + } + + // buffer processed by all handlers, done + if (!p_buf->handler.ptr ()) { + if (!_keep_attached_buffer && out_data.ptr ()) + out_data->clear_attached_buffers (); + + XCAM_OBJ_PROFILING_START; + CLDevice::instance()->get_context ()->finish (); + XCAM_OBJ_PROFILING_END (get_name (), XCAM_OBJ_DUR_FRAME_NUM); + + // buffer done, push back + _done_buffer_queue.push (out_data); + return XCAM_RETURN_NO_ERROR; + } + + p_buf->data = out_data; + p_buf->down_rank (); + + XCAM_FAIL_RETURN ( + WARNING, + _process_buffer_queue.push_priority_buf (p_buf), + XCAM_RETURN_ERROR_UNKNOWN, + "CLImageProcessor push priority buffer failed"); + + return ret; +} + +XCamReturn +CLImageProcessor::emit_start () +{ + _done_buffer_queue.resume_pop (); + _process_buffer_queue.resume_pop (); + + if (!_done_buf_thread->start ()) + return XCAM_RETURN_ERROR_THREAD; + + if (!_handler_thread->start ()) + return XCAM_RETURN_ERROR_THREAD; + + return XCAM_RETURN_NO_ERROR; +} + +void +CLImageProcessor::emit_stop () +{ + _process_buffer_queue.pause_pop(); + _done_buffer_queue.pause_pop (); + + + for (ImageHandlerList::iterator i_handler = _handlers.begin (); + i_handler != _handlers.end (); ++i_handler) { + (*i_handler)->emit_stop (); + } + + _handler_thread->stop (); + _done_buf_thread->stop (); + _not_ready_buffers.clear (); + _process_buffer_queue.clear (); + _done_buffer_queue.clear (); +} + +XCamReturn +CLImageProcessor::create_handlers () +{ + SmartPtr<CLImageHandler> demo_handler; + demo_handler = create_cl_demo_image_handler (_context); + // demo_handler = create_cl_binary_demo_image_handler (_context); + XCAM_FAIL_RETURN ( + WARNING, + demo_handler.ptr (), + XCAM_RETURN_ERROR_CL, + "CLImageProcessor create demo handler failed"); + add_handler (demo_handler); + + return XCAM_RETURN_NO_ERROR; +} + +}; diff --git a/modules/ocl/cl_image_processor.h b/modules/ocl/cl_image_processor.h new file mode 100644 index 0000000..b955b1a --- /dev/null +++ b/modules/ocl/cl_image_processor.h @@ -0,0 +1,97 @@ +/* + * cl_image_processor.h - CL image processor + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_IMAGE_PROCESSOR_H +#define XCAM_CL_IMAGE_PROCESSOR_H + +#include <xcam_std.h> +#include <image_processor.h> +#include <ocl/priority_buffer_queue.h> +#include <list> + +namespace XCam { + +class CLImageHandler; +class CLContext; +class CLHandlerThread; +class CLBufferNotifyThread; + +class CLImageProcessor + : public ImageProcessor +{ +public: + typedef std::list<SmartPtr<CLImageHandler>> ImageHandlerList; + typedef std::list<SmartPtr<PriorityBuffer>> UnsafePriorityBufferList; + friend class CLHandlerThread; + friend class CLBufferNotifyThread; + +public: + explicit CLImageProcessor (const char* name = NULL); + virtual ~CLImageProcessor (); + + void keep_attached_buf (bool flag); + + bool add_handler (SmartPtr<CLImageHandler> &handler); + ImageHandlerList::iterator handlers_begin (); + ImageHandlerList::iterator handlers_end (); + +protected: + + //derive from ImageProcessor + virtual bool can_process_result (SmartPtr<X3aResult> &result); + virtual XCamReturn apply_3a_results (X3aResultList &results); + virtual XCamReturn apply_3a_result (SmartPtr<X3aResult> &result); + virtual XCamReturn process_buffer (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + virtual XCamReturn emit_start (); + virtual void emit_stop (); + + SmartPtr<CLContext> get_cl_context (); + +private: + virtual XCamReturn create_handlers (); + + XCamReturn process_cl_buffer_queue (); + XCamReturn process_done_buffer (); + uint32_t check_ready_buffers (); + + XCAM_DEAD_COPY (CLImageProcessor); + +protected: + +// STREAM_LOCK only used in class derived from CLImageProcessor +#define STREAM_LOCK SmartLock stream_lock (this->_stream_mutex) + // stream lock + Mutex _stream_mutex; + +private: + SmartPtr<CLContext> _context; + ImageHandlerList _handlers; + SmartPtr<CLHandlerThread> _handler_thread; + PriorityBufferQueue _process_buffer_queue; + UnsafePriorityBufferList _not_ready_buffers; + SmartPtr<CLBufferNotifyThread> _done_buf_thread; + SafeList<VideoBuffer> _done_buffer_queue; + uint32_t _seq_num; + bool _keep_attached_buffer; //default false + XCAM_OBJ_PROFILING_DEFINES; +}; + +}; +#endif //XCAM_CL_IMAGE_PROCESSOR_H diff --git a/modules/ocl/cl_image_scaler.cpp b/modules/ocl/cl_image_scaler.cpp new file mode 100644 index 0000000..c888b36 --- /dev/null +++ b/modules/ocl/cl_image_scaler.cpp @@ -0,0 +1,287 @@ +/* + * cl_image_scaler.cpp - CL image scaler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include "cl_utils.h" +#include "cl_image_scaler.h" + +namespace XCam { + +static const XCamKernelInfo kernel_scale_info = { + "kernel_image_scaler", +#include "kernel_image_scaler.clx" + , 0, +}; + +CLScalerKernel::CLScalerKernel ( + const SmartPtr<CLContext> &context, + CLImageScalerMemoryLayout mem_layout +) + : CLImageKernel (context, "kernel_image_scaler") + , _mem_layout (mem_layout) +{ +} + +XCamReturn +CLScalerKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<CLContext> context = get_context (); + + SmartPtr<VideoBuffer> input = get_input_buffer (); + SmartPtr<VideoBuffer> output = get_output_buffer (); + SmartPtr<CLImage> image_in, image_out; + + XCAM_FAIL_RETURN ( + WARNING, + input.ptr () && output.ptr (), + XCAM_RETURN_ERROR_MEM, + "cl image kernel(%s) get input/output buffer failed", XCAM_STR(get_kernel_name ())); + + const VideoBufferInfo &input_info = input->get_video_info (); + const VideoBufferInfo &output_info = output->get_video_info (); + + uint32_t output_width = 0, output_height = 0; + CLImageDesc output_imageDesc; + + uint32_t channel_bits = XCAM_ALIGN_UP (output_info.color_bits, 8); + if (channel_bits == 8) + output_imageDesc.format.image_channel_data_type = CL_UNSIGNED_INT8; + else if (channel_bits == 16) + output_imageDesc.format.image_channel_data_type = CL_UNSIGNED_INT16; + + if ((CL_IMAGE_SCALER_NV12_UV == get_mem_layout ()) && (V4L2_PIX_FMT_NV12 == input_info.format)) { + output_imageDesc.format.image_channel_order = CL_RG; + output_imageDesc.width = output_info.width / 2; + output_imageDesc.height = output_info.height / 2; + output_imageDesc.row_pitch = output_info.strides[1]; + + image_out = convert_to_climage (context, output, output_imageDesc, output_info.offsets[1]); + output_width = output_info.width / 2; + output_height = output_info.height / 2; + } else { + output_imageDesc.format.image_channel_order = CL_R; + output_imageDesc.width = output_info.width; + output_imageDesc.height = output_info.height; + output_imageDesc.row_pitch = output_info.strides[0]; + + image_out = convert_to_climage (context, output, output_imageDesc, output_info.offsets[0]); + output_width = output_info.width; + output_height = output_info.height; + } + + CLImageDesc input_imageDesc; + channel_bits = XCAM_ALIGN_UP (input_info.color_bits, 8); + if (channel_bits == 8) + input_imageDesc.format.image_channel_data_type = CL_UNSIGNED_INT8; + else if (channel_bits == 16) + input_imageDesc.format.image_channel_data_type = CL_UNSIGNED_INT16; + + if ((CL_IMAGE_SCALER_NV12_UV == get_mem_layout ()) && (V4L2_PIX_FMT_NV12 == input_info.format)) { + input_imageDesc.format.image_channel_order = CL_RG; + input_imageDesc.width = input_info.width / 2; + input_imageDesc.height = input_info.height / 2; + input_imageDesc.row_pitch = input_info.strides[1]; + + image_in = convert_to_climage (context, input, input_imageDesc, input_info.offsets[1]); + } else { + input_imageDesc.format.image_channel_order = CL_R; + input_imageDesc.width = input_info.width; + input_imageDesc.height = input_info.height; + input_imageDesc.row_pitch = input_info.strides[0]; + + image_in = convert_to_climage (context, input, input_imageDesc, input_info.offsets[0]); + } + + //set args; + args.push_back (new CLMemArgument (image_in)); + args.push_back (new CLMemArgument (image_out)); + args.push_back (new CLArgumentT<uint32_t> (output_width)); + args.push_back (new CLArgumentT<uint32_t> (output_height)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.global[0] = XCAM_ALIGN_UP (output_width, XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE0); + work_size.global[1] = XCAM_ALIGN_UP (output_height, XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE1); + work_size.local[0] = XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE0; + work_size.local[1] = XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE1; + + return ret; +} + +CLImageScalerKernel::CLImageScalerKernel ( + const SmartPtr<CLContext> &context, + CLImageScalerMemoryLayout mem_layout, + SmartPtr<CLImageScaler> &scaler +) + : CLScalerKernel (context, mem_layout) + , _scaler (scaler) +{ +} + +SmartPtr<VideoBuffer> +CLImageScalerKernel::get_input_buffer () +{ + return _scaler->get_input_buf (); +} + +SmartPtr<VideoBuffer> +CLImageScalerKernel::get_output_buffer () +{ + return _scaler->get_scaler_buf (); +} + +CLImageScaler::CLImageScaler (const SmartPtr<CLContext> &context) + : CLImageHandler (context, "CLImageScaler") + , _h_scaler_factor (0.5) + , _v_scaler_factor (0.5) +{ +} + +void +CLImageScaler::emit_stop () +{ + if (_scaler_buf_pool.ptr ()) + _scaler_buf_pool->stop (); +} + +bool +CLImageScaler::set_scaler_factor (const double h_factor, const double v_factor) +{ + _h_scaler_factor = h_factor; + _v_scaler_factor = v_factor; + + return true; +} + +bool +CLImageScaler::get_scaler_factor (double &h_factor, double &v_factor) const +{ + h_factor = _h_scaler_factor; + v_factor = _v_scaler_factor; + + return true; +}; + +XCamReturn +CLImageScaler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + output = input; + + ret = prepare_scaler_buf (input->get_video_info (), _scaler_buf); + XCAM_FAIL_RETURN( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "CLImageScalerKernel prepare scaled video buf failed"); + + _scaler_buf->set_timestamp (input->get_timestamp ()); + + return ret; +} + +XCamReturn +CLImageScaler::execute_done (SmartPtr<VideoBuffer> &output) +{ + XCAM_UNUSED (output); + get_context ()->finish(); + XCAM_ASSERT (_scaler_buf.ptr ()); + + //post buffer out + return post_buffer (_scaler_buf); +} + +XCamReturn +CLImageScaler::prepare_scaler_buf (const VideoBufferInfo &video_info, SmartPtr<VideoBuffer> &output) +{ + if (!_scaler_buf_pool.ptr ()) { + VideoBufferInfo scaler_video_info; + uint32_t new_width = XCAM_ALIGN_UP ((uint32_t)(video_info.width * _h_scaler_factor), + 2 * XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE0); + uint32_t new_height = XCAM_ALIGN_UP ((uint32_t)(video_info.height * _v_scaler_factor), + 2 * XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE1); + + scaler_video_info.init (video_info.format, new_width, new_height); + + _scaler_buf_pool = new CLVideoBufferPool (); + XCAM_ASSERT (_scaler_buf_pool.ptr ()); + _scaler_buf_pool->set_video_info (scaler_video_info); + _scaler_buf_pool->reserve (6); + } + + output = _scaler_buf_pool->get_buffer (_scaler_buf_pool); + XCAM_ASSERT (output.ptr ()); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLImageScaler::post_buffer (const SmartPtr<VideoBuffer> &buffer) +{ + if (_scaler_callback.ptr ()) + return _scaler_callback->scaled_image_ready (buffer); + + return XCAM_RETURN_NO_ERROR; +} + +static SmartPtr<CLImageKernel> +create_scale_kernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLImageScaler> &handler, CLImageScalerMemoryLayout layout) +{ + SmartPtr<CLImageKernel> kernel; + kernel = new CLImageScalerKernel (context, layout, handler); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, kernel->build_kernel (kernel_scale_info, NULL) == XCAM_RETURN_NO_ERROR, NULL, + "build scaler kernel(%s) failed", kernel_scale_info.kernel_name); + XCAM_ASSERT (kernel->is_valid ()); + return kernel; +} + +SmartPtr<CLImageHandler> +create_cl_image_scaler_handler (const SmartPtr<CLContext> &context, const uint32_t format) +{ + SmartPtr<CLImageScaler> scaler_handler; + SmartPtr<CLImageKernel> scaler_kernel; + + scaler_handler = new CLImageScaler (context); + XCAM_ASSERT (scaler_handler.ptr ()); + + if (V4L2_PIX_FMT_NV12 == format) { + //Y + scaler_kernel = create_scale_kernel (context, scaler_handler, CL_IMAGE_SCALER_NV12_Y); + XCAM_FAIL_RETURN (ERROR, scaler_kernel.ptr (), NULL, "build CL_IMAGE_SCALER_NV12_Y kernel failed"); + scaler_handler->add_kernel (scaler_kernel); + //UV + scaler_kernel = create_scale_kernel (context, scaler_handler, CL_IMAGE_SCALER_NV12_UV); + XCAM_FAIL_RETURN (ERROR, scaler_kernel.ptr (), NULL, "build CL_IMAGE_SCALER_NV12_UV kernel failed"); + scaler_handler->add_kernel (scaler_kernel); + } else if (XCAM_PIX_FMT_RGBA64 == format) { + scaler_kernel = create_scale_kernel (context, scaler_handler, CL_IMAGE_SCALER_RGBA); + XCAM_FAIL_RETURN (ERROR, scaler_kernel.ptr (), NULL, "build CL_IMAGE_SCALER_RGBA kernel failed"); + scaler_handler->add_kernel (scaler_kernel); + } else { + XCAM_LOG_ERROR ("create cl image scaler failed, unknown format:0x%08x", format); + return NULL; + } + + return scaler_handler; +} + +}; diff --git a/modules/ocl/cl_image_scaler.h b/modules/ocl/cl_image_scaler.h new file mode 100644 index 0000000..bb4edf6 --- /dev/null +++ b/modules/ocl/cl_image_scaler.h @@ -0,0 +1,122 @@ +/* + * cl_image_scaler.h - CL image scaler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#ifndef XCAM_CL_IMAGE_SCALER_H +#define XCAM_CL_IMAGE_SCALER_H + +#include <xcam_std.h> +#include <ocl/cl_image_handler.h> +#include <ocl/cl_memory.h> +#include <stats_callback_interface.h> + +namespace XCam { + +enum CLImageScalerMemoryLayout { + CL_IMAGE_SCALER_NV12_Y = 0, + CL_IMAGE_SCALER_NV12_UV = 1, + CL_IMAGE_SCALER_RGBA = 2, +}; + +#define XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE0 8 +#define XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE1 4 + +class CLImageScaler; + +class CLScalerKernel + : public CLImageKernel +{ +public: + explicit CLScalerKernel ( + const SmartPtr<CLContext> &context, CLImageScalerMemoryLayout mem_layout); + +public: + CLImageScalerMemoryLayout get_mem_layout () const { + return _mem_layout; + }; + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + + //new virtual functions + virtual SmartPtr<VideoBuffer> get_input_buffer () = 0; + virtual SmartPtr<VideoBuffer> get_output_buffer () = 0; + +protected: + CLImageScalerMemoryLayout _mem_layout; +}; + +class CLImageScalerKernel + : public CLScalerKernel +{ +public: + explicit CLImageScalerKernel ( + const SmartPtr<CLContext> &context, CLImageScalerMemoryLayout mem_layout, SmartPtr<CLImageScaler> &scaler); + +protected: + virtual SmartPtr<VideoBuffer> get_input_buffer (); + virtual SmartPtr<VideoBuffer> get_output_buffer (); + +private: + XCAM_DEAD_COPY (CLImageScalerKernel); + +private: + SmartPtr<CLImageScaler> _scaler; +}; + +class CLImageScaler + : public CLImageHandler +{ + friend class CLImageScalerKernel; +public: + explicit CLImageScaler (const SmartPtr<CLContext> &context); + void set_buffer_callback (SmartPtr<StatsCallback> &callback) { + _scaler_callback = callback; + } + + bool set_scaler_factor (const double h_factor, const double v_factor); + bool get_scaler_factor (double &h_factor, double &v_factor) const; + SmartPtr<VideoBuffer> &get_scaler_buf () { + return _scaler_buf; + }; + + void emit_stop (); + +protected: + virtual XCamReturn prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + virtual XCamReturn execute_done (SmartPtr<VideoBuffer> &output); + +private: + XCamReturn prepare_scaler_buf (const VideoBufferInfo &video_info, SmartPtr<VideoBuffer> &output); + XCamReturn post_buffer (const SmartPtr<VideoBuffer> &buffer); + +private: + double _h_scaler_factor; + double _v_scaler_factor; + SmartPtr<BufferPool> _scaler_buf_pool; + SmartPtr<VideoBuffer> _scaler_buf; + SmartPtr<StatsCallback> _scaler_callback; +}; + +SmartPtr<CLImageHandler> +create_cl_image_scaler_handler (const SmartPtr<CLContext> &context, uint32_t format); + +}; + +#endif // XCAM_CL_IMAGE_SCALER_H diff --git a/modules/ocl/cl_image_warp_handler.cpp b/modules/ocl/cl_image_warp_handler.cpp new file mode 100644 index 0000000..89f659c --- /dev/null +++ b/modules/ocl/cl_image_warp_handler.cpp @@ -0,0 +1,294 @@ +/* + * cl_image_warp_handler.cpp - CL image warping handler + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include "cl_utils.h" +#include "cl_image_warp_handler.h" + +namespace XCam { + +#define CL_IMAGE_WARP_WG_WIDTH 8 +#define CL_IMAGE_WARP_WG_HEIGHT 4 + + +static const XCamKernelInfo kernel_image_warp_info [] = { + { + "kernel_image_warp_8_pixel", +#include "kernel_image_warp.clx" + , 0, + }, + { + "kernel_image_warp_1_pixel", +#include "kernel_image_warp.clx" + , 0, + } +}; + +CLImageWarpKernel::CLImageWarpKernel ( + const SmartPtr<CLContext> &context, + const char *name, + uint32_t channel, + SmartPtr<CLImageHandler> &handler) + : CLImageKernel (context, name) + , _channel (channel) +{ + _handler = handler.dynamic_cast_ptr<CLImageWarpHandler> (); +} + +XCamReturn +CLImageWarpKernel::prepare_arguments ( + CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + SmartPtr<VideoBuffer> input = _handler->get_warp_input_buf (); + SmartPtr<VideoBuffer> output = _handler->get_output_buf (); + + const VideoBufferInfo & video_info_in = input->get_video_info (); + const VideoBufferInfo & video_info_out = output->get_video_info (); + + uint32_t info_index = 0; + if (_channel == CL_IMAGE_CHANNEL_Y) { + info_index = 0; + } else if (_channel == CL_IMAGE_CHANNEL_UV) { + info_index = 1; + } + + CLImageDesc cl_desc_in, cl_desc_out; + cl_desc_in.format.image_channel_order = info_index == 0 ? CL_R : CL_RG; + cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc_in.width = video_info_in.width >> info_index; + cl_desc_in.height = video_info_in.height >> info_index; + cl_desc_in.row_pitch = video_info_in.strides[info_index]; + +#if CL_IMAGE_WARP_WRITE_UINT + cl_desc_out.format.image_channel_data_type = info_index == 0 ? CL_UNSIGNED_INT16 : CL_UNSIGNED_INT32; + cl_desc_out.format.image_channel_order = CL_RGBA; + cl_desc_out.width = XCAM_ALIGN_DOWN (video_info_out.width >> info_index, 8) / 8; + cl_desc_out.height = video_info_out.height >> info_index; +#else + cl_desc_out.format.image_channel_order = info_index == 0 ? CL_R : CL_RG; + cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc_out.width = video_info_out.width >> info_index; + cl_desc_out.height = video_info_out.height >> info_index; +#endif + + cl_desc_out.row_pitch = video_info_out.strides[info_index]; + SmartPtr<CLImage> image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[info_index]); + + CLWarpConfig warp_config = _handler->get_warp_config (); + if ((warp_config.trim_ratio > 0.5f) || (warp_config.trim_ratio < 0.0f)) { + warp_config.trim_ratio = 0.0f; + } + + float sample_rate_x = (float)warp_config.width / (float)video_info_in.width; + float sample_rate_y = (float)warp_config.height / (float)video_info_in.height; + XCAM_LOG_DEBUG ("warp analyze image sample rate(%fx%f)", sample_rate_x, sample_rate_y); + warp_config.proj_mat[2] = warp_config.proj_mat[2] / sample_rate_x; + warp_config.proj_mat[5] = warp_config.proj_mat[5] / sample_rate_y; + warp_config.proj_mat[6] = warp_config.proj_mat[6] * sample_rate_x; + warp_config.proj_mat[7] = warp_config.proj_mat[7] * sample_rate_y; + + /* + For NV12 image (YUV420), UV plane has half horizontal & vertical coordinate size of Y plane, + need to adjust the projection matrix as: + H(uv) = [0.5, 0, 0; 0, 0.5, 0; 0, 0, 1] * H(y) * [2, 0, 0; 0, 2, 0; 0, 0, 1] + */ + if (_channel == CL_IMAGE_CHANNEL_UV) { + warp_config.proj_mat[2] = 0.5 * warp_config.proj_mat[2]; + warp_config.proj_mat[5] = 0.5 * warp_config.proj_mat[5]; + warp_config.proj_mat[6] = 2.0 * warp_config.proj_mat[6]; + warp_config.proj_mat[7] = 2.0 * warp_config.proj_mat[7]; + } + + /* + Trim image: shift toward origin then scale up + Trim Matrix (TMat) + TMat = [ scale_x, 0.0f, shift_x; + 0.0f, scale_y, shift_y; + 1.0f, 1.0f, 1.0f; ] + + Warp Perspective Matrix = TMat * HMat + */ +#if CL_IMAGE_WARP_WRITE_UINT + float shift_x = warp_config.trim_ratio * cl_desc_out.width * 8.0f; +#else + float shift_x = warp_config.trim_ratio * cl_desc_out.width; +#endif + float shift_y = warp_config.trim_ratio * cl_desc_out.height; + float scale_x = 1.0f - 2.0f * warp_config.trim_ratio; + float scale_y = 1.0f - 2.0f * warp_config.trim_ratio; + + warp_config.proj_mat[0] = scale_x * warp_config.proj_mat[0] + shift_x * warp_config.proj_mat[6]; + warp_config.proj_mat[1] = scale_x * warp_config.proj_mat[1] + shift_x * warp_config.proj_mat[7]; + warp_config.proj_mat[2] = scale_x * warp_config.proj_mat[2] + shift_x * warp_config.proj_mat[8]; + warp_config.proj_mat[3] = scale_y * warp_config.proj_mat[3] + shift_y * warp_config.proj_mat[6]; + warp_config.proj_mat[4] = scale_y * warp_config.proj_mat[4] + shift_y * warp_config.proj_mat[7]; + warp_config.proj_mat[5] = scale_y * warp_config.proj_mat[5] + shift_y * warp_config.proj_mat[8]; + + XCAM_LOG_DEBUG ("warp config image size(%dx%d)", warp_config.width, warp_config.height); + XCAM_LOG_DEBUG ("proj_mat[%d]=(%f, %f, %f, %f, %f, %f, %f, %f, %f);", warp_config.frame_id, + warp_config.proj_mat[0], warp_config.proj_mat[1], warp_config.proj_mat[2], + warp_config.proj_mat[3], warp_config.proj_mat[4], warp_config.proj_mat[5], + warp_config.proj_mat[6], warp_config.proj_mat[7], warp_config.proj_mat[8]); + + SmartPtr<CLImage> image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[info_index]); + XCAM_FAIL_RETURN ( + WARNING, + image_in->is_valid () && image_out->is_valid (), + XCAM_RETURN_ERROR_MEM, + "cl image kernel(%s) in/out memory not available", get_kernel_name ()); + + //set args; + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = CL_IMAGE_WARP_WG_WIDTH; + work_size.local[1] = CL_IMAGE_WARP_WG_HEIGHT; + work_size.global[0] = XCAM_ALIGN_UP (cl_desc_out.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP(cl_desc_out.height, work_size.local[1]); + + args.push_back (new CLMemArgument (image_in)); + args.push_back (new CLMemArgument (image_out)); + args.push_back (new CLArgumentT<CLWarpConfig> (warp_config)); + + return XCAM_RETURN_NO_ERROR; +} + +CLImageWarpHandler::CLImageWarpHandler (const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) +{ +} + +bool +CLImageWarpHandler::is_ready () +{ + bool ret = !_warp_config_list.empty (); + return ret && CLImageHandler::is_ready (); +} + +XCamReturn +CLImageWarpHandler::execute_done (SmartPtr<VideoBuffer> &output) +{ + XCAM_UNUSED (output); + if (!_warp_config_list.empty ()) { + _warp_config_list.pop_front (); + } + + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<VideoBuffer> +CLImageWarpHandler::get_warp_input_buf () +{ + return CLImageHandler::get_input_buf (); +} + +bool +CLImageWarpHandler::set_warp_config (const XCamDVSResult& config) +{ + CLWarpConfig warp_config; + warp_config.frame_id = config.frame_id; + warp_config.width = config.frame_width; + warp_config.height = config.frame_height; + for( int i = 0; i < 9; i++ ) { + warp_config.proj_mat[i] = config.proj_mat[i]; + } + XCAM_LOG_DEBUG ("warp_mat{%d}=[%f, %f, %f; %f, %f, %f; %f, %f, %f]", warp_config.frame_id + 1, + warp_config.proj_mat[0], warp_config.proj_mat[1], warp_config.proj_mat[2], + warp_config.proj_mat[3], warp_config.proj_mat[4], warp_config.proj_mat[5], + warp_config.proj_mat[6], warp_config.proj_mat[7], warp_config.proj_mat[8]); +#if 0 + printf ("warp_mat{%d}=[%f, %f, %f; %f, %f, %f; %f, %f, %f]; \n", warp_config.frame_id + 1, + warp_config.proj_mat[0], warp_config.proj_mat[1], warp_config.proj_mat[2], + warp_config.proj_mat[3], warp_config.proj_mat[4], warp_config.proj_mat[5], + warp_config.proj_mat[6], warp_config.proj_mat[7], warp_config.proj_mat[8]); +#endif + _warp_config_list.push_back (warp_config); + + return true; +} + +CLWarpConfig +CLImageWarpHandler::get_warp_config () +{ + CLWarpConfig warp_config; + + if (_warp_config_list.size () > 0) { + warp_config = *(_warp_config_list.begin ()); + } else { + warp_config.frame_id = -1; + warp_config.proj_mat[0] = 1.0f; + warp_config.proj_mat[1] = 0.0f; + warp_config.proj_mat[2] = 0.0f; + warp_config.proj_mat[3] = 0.0f; + warp_config.proj_mat[4] = 1.0f; + warp_config.proj_mat[5] = 0.0f; + warp_config.proj_mat[6] = 0.0f; + warp_config.proj_mat[7] = 0.0f; + warp_config.proj_mat[8] = 1.0f; + } + + return warp_config; +} + +static SmartPtr<CLImageWarpKernel> +create_kernel_image_warp ( + const SmartPtr<CLContext> &context, + uint32_t channel, + SmartPtr<CLImageHandler> handler) +{ + SmartPtr<CLImageWarpKernel> warp_kernel; + + const char *name = (channel == CL_IMAGE_CHANNEL_Y ? "kernel_image_warp_y" : "kernel_image_warp_uv"); + char build_options[1024]; + xcam_mem_clear (build_options); + + snprintf (build_options, sizeof (build_options), + " -DWARP_Y=%d ", + (channel == CL_IMAGE_CHANNEL_Y ? 1 : 0)); + + warp_kernel = new CLImageWarpKernel (context, name, channel, handler); + XCAM_ASSERT (warp_kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, warp_kernel->build_kernel (kernel_image_warp_info[KernelImageWarp], build_options) == XCAM_RETURN_NO_ERROR, + NULL, "build image warp kernel failed"); + XCAM_ASSERT (warp_kernel->is_valid ()); + + return warp_kernel; +} + +SmartPtr<CLImageHandler> +create_cl_image_warp_handler (const SmartPtr<CLContext> &context) +{ + SmartPtr<CLImageWarpHandler> warp_handler; + SmartPtr<CLImageKernel> warp_kernel; + + warp_handler = new CLImageWarpHandler (context); + XCAM_ASSERT (warp_handler.ptr ()); + + warp_kernel = create_kernel_image_warp (context, CL_IMAGE_CHANNEL_Y, warp_handler); + XCAM_ASSERT (warp_kernel.ptr ()); + warp_handler->add_kernel (warp_kernel); + + warp_kernel = create_kernel_image_warp (context, CL_IMAGE_CHANNEL_UV, warp_handler); + XCAM_ASSERT (warp_kernel.ptr ()); + warp_handler->add_kernel (warp_kernel); + + return warp_handler; +} + +}; diff --git a/modules/ocl/cl_image_warp_handler.h b/modules/ocl/cl_image_warp_handler.h new file mode 100644 index 0000000..6354bed --- /dev/null +++ b/modules/ocl/cl_image_warp_handler.h @@ -0,0 +1,123 @@ +/* + * cl_image_warp_handler.h - CL image warping handler + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#ifndef XCAM_CL_IMAGE_WARP_H +#define XCAM_CL_IMAGE_WARP_H + +#include <xcam_std.h> +#include <ocl/cl_image_handler.h> +#include <ocl/cl_memory.h> + +namespace XCam { + +#define CL_IMAGE_WARP_WRITE_UINT 1 + +enum { +#if CL_IMAGE_WARP_WRITE_UINT + KernelImageWarp = 0, +#else + KernelImageWarp = 1, +#endif +}; + +struct CLWarpConfig { + int frame_id; + int width; + int height; + float trim_ratio; + float proj_mat[9]; + + CLWarpConfig () + : frame_id (-1) + , width (-1) + , height (-1) + , trim_ratio (0.05f) + { + proj_mat[0] = 1.0f; + proj_mat[1] = 0.0f; + proj_mat[2] = 0.0f; + proj_mat[3] = 0.0f; + proj_mat[4] = 1.0f; + proj_mat[5] = 0.0f; + proj_mat[6] = 0.0f; + proj_mat[7] = 0.0f; + proj_mat[8] = 1.0f; + }; +}; + +class CLImageWarpHandler; + +class CLImageWarpKernel + : public CLImageKernel +{ +public: + explicit CLImageWarpKernel ( + const SmartPtr<CLContext> &context, + const char *name, + uint32_t channel, + SmartPtr<CLImageHandler> &handler); + + virtual ~CLImageWarpKernel () {}; + +protected: + virtual XCamReturn prepare_arguments ( + CLArgList &args, CLWorkSize &work_size); + +private: + XCAM_DEAD_COPY (CLImageWarpKernel); + + uint32_t _channel; + SmartPtr<CLImageWarpHandler> _handler; +}; + +class CLImageWarpHandler + : public CLImageHandler +{ + typedef std::list<CLWarpConfig> CLWarpConfigList; + +public: + explicit CLImageWarpHandler (const SmartPtr<CLContext> &context, const char *name = "CLImageWarpHandler"); + virtual ~CLImageWarpHandler () { + _warp_config_list.clear (); + } + + virtual SmartPtr<VideoBuffer> get_warp_input_buf (); + + bool set_warp_config (const XCamDVSResult& config); + CLWarpConfig get_warp_config (); + + virtual bool is_ready (); + +protected: + virtual XCamReturn execute_done (SmartPtr<VideoBuffer> &output); + +private: + XCAM_DEAD_COPY (CLImageWarpHandler); + + CLWarpConfigList _warp_config_list; + +}; + +SmartPtr<CLImageHandler> +create_cl_image_warp_handler (const SmartPtr<CLContext> &context); + +}; + +#endif // XCAM_CL_IMAGE_WARP_H diff --git a/modules/ocl/cl_kernel.cpp b/modules/ocl/cl_kernel.cpp new file mode 100644 index 0000000..fdda8ec --- /dev/null +++ b/modules/ocl/cl_kernel.cpp @@ -0,0 +1,493 @@ +/* + * cl_kernel.cpp - CL kernel + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_kernel.h" +#include "cl_context.h" +#include "cl_device.h" +#include "file_handle.h" + +#include <sys/stat.h> + +#define ENABLE_DEBUG_KERNEL 0 + +#define XCAM_CL_KERNEL_DEFAULT_LOCAL_WORK_SIZE 0 + +namespace XCam { + +CLKernel::KernelMap CLKernel::_kernel_map; +Mutex CLKernel::_kernel_map_mutex; + +static char* +default_cache_path () { + static char path[XCAM_MAX_STR_SIZE] = {0}; + snprintf ( + path, XCAM_MAX_STR_SIZE - 1, + "%s/%s", std::getenv ("HOME"), ".xcam/"); + + return path; +} + +const char* CLKernel::_kernel_cache_path = default_cache_path (); + +CLKernel::CLKernel (const SmartPtr<CLContext> &context, const char *name) + : _name (NULL) + , _kernel_id (NULL) + , _context (context) +{ + XCAM_ASSERT (context.ptr ()); + //XCAM_ASSERT (name); + + if (name) + _name = strndup (name, XCAM_MAX_STR_SIZE); + + set_default_work_size (); + + XCAM_OBJ_PROFILING_INIT; +} + +CLKernel::~CLKernel () +{ + destroy (); + if (_name) + xcam_free (_name); +} + +void +CLKernel::destroy () +{ + if (!_parent_kernel.ptr ()) + _context->destroy_kernel_id (_kernel_id); +} + +static void +get_string_key_id (const char *str, uint32_t len, uint8_t key_id[8]) +{ + uint32_t key[2]; + uint32_t *ptr = (uint32_t*)(str); + uint32_t aligned_len = 0; + uint32_t i = 0; + + xcam_mem_clear (key); + if (!len) + len = strlen (str); + aligned_len = XCAM_ALIGN_DOWN (len, 8); + + for (i = 0; i < aligned_len / 8; ++i) { + key[0] ^= ptr[0]; + key[1] ^= ptr[1]; + ptr += 2; + } + memcpy (key_id, key, 8); + len -= aligned_len; + str += aligned_len; + for (i = 0; i < len; ++i) { + key_id[i] ^= (uint8_t)str[i]; + } +} + +XCamReturn +CLKernel::build_kernel (const XCamKernelInfo& info, const char* options) +{ + KernelMap::iterator i_kernel; + SmartPtr<CLKernel> single_kernel; + char key_str[1024]; + uint8_t body_key[8]; + std::string key; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_FAIL_RETURN (ERROR, info.kernel_name, XCAM_RETURN_ERROR_PARAM, "build kernel failed since kernel name null"); + + xcam_mem_clear (body_key); + get_string_key_id (info.kernel_body, info.kernel_body_len, body_key); + snprintf ( + key_str, sizeof(key_str), + "%s#%02x%02x%02x%02x%02x%02x%02x%02x#%s", + info.kernel_name, + body_key[0], body_key[1], body_key[2], body_key[3], body_key[4], body_key[5], body_key[6], body_key[7], + XCAM_STR(options)); + key = key_str; + + char temp_filename[XCAM_MAX_STR_SIZE] = {0}; + char cache_filename[XCAM_MAX_STR_SIZE] = {0}; + FileHandle temp_file; + FileHandle cache_file; + size_t read_cache_size = 0; + size_t write_cache_size = 0; + uint8_t *kernel_cache = NULL; + bool load_cache = false; + struct timeval ts; + + const char* cache_path = std::getenv ("XCAM_CL_KERNEL_CACHE_PATH"); + if (NULL == cache_path) { + cache_path = _kernel_cache_path; + } + + snprintf ( + cache_filename, XCAM_MAX_STR_SIZE - 1, + "%s/%s", + cache_path, key_str); + + { + SmartLock locker (_kernel_map_mutex); + + i_kernel = _kernel_map.find (key); + if (i_kernel == _kernel_map.end ()) { + SmartPtr<CLContext> context = get_context (); + single_kernel = new CLKernel (context, info.kernel_name); + XCAM_ASSERT (single_kernel.ptr ()); + + if (access (cache_path, F_OK) == -1) { + mkdir (cache_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + } + + ret = cache_file.open (cache_filename, "r"); + if (ret == XCAM_RETURN_NO_ERROR) { + cache_file.get_file_size (read_cache_size); + if (read_cache_size > 0) { + kernel_cache = (uint8_t*) xcam_malloc0 (sizeof (uint8_t) * (read_cache_size + 1)); + if (NULL != kernel_cache) { + cache_file.read_file (kernel_cache, read_cache_size); + cache_file.close (); + + ret = single_kernel->load_from_binary (kernel_cache, read_cache_size); + xcam_free (kernel_cache); + kernel_cache = NULL; + + XCAM_FAIL_RETURN ( + ERROR, ret == XCAM_RETURN_NO_ERROR, ret, + "build kernel(%s) from binary failed", key_str); + + load_cache = true; + } + } + } else { + XCAM_LOG_DEBUG ("open kernel cache file to read failed ret(%d)", ret); + } + + if (load_cache == false) { + ret = single_kernel->load_from_source (info.kernel_body, strlen (info.kernel_body), &kernel_cache, &write_cache_size, options); + XCAM_FAIL_RETURN ( + ERROR, ret == XCAM_RETURN_NO_ERROR, ret, + "build kernel(%s) from source failed", key_str); + } + + _kernel_map.insert (std::make_pair (key, single_kernel)); + //_kernel_map[key] = single_kernel; + } else { + single_kernel = i_kernel->second; + } + } + + if (load_cache == false && NULL != kernel_cache) { + gettimeofday (&ts, NULL); + snprintf ( + temp_filename, XCAM_MAX_STR_SIZE - 1, + "%s." XCAM_TIMESTAMP_FORMAT, + cache_filename, XCAM_TIMESTAMP_ARGS (XCAM_TIMEVAL_2_USEC (ts))); + + ret = temp_file.open (temp_filename, "wb"); + if (ret == XCAM_RETURN_NO_ERROR) { + ret = temp_file.write_file (kernel_cache, write_cache_size); + temp_file.close (); + if (ret == XCAM_RETURN_NO_ERROR && write_cache_size > 0) { + rename (temp_filename, cache_filename); + } else { + remove (temp_filename); + } + } else { + XCAM_LOG_ERROR ("open kernel cache file to write failed ret(%d)", ret); + } + xcam_free (kernel_cache); + kernel_cache = NULL; + } + + XCAM_FAIL_RETURN ( + ERROR, (single_kernel.ptr () && single_kernel->is_valid ()), XCAM_RETURN_ERROR_UNKNOWN, + "build kernel(%s) failed, unknown error", key_str); + + ret = this->clone (single_kernel); + XCAM_FAIL_RETURN ( + ERROR, ret == XCAM_RETURN_NO_ERROR, ret, + "load kernel(%s) from kernel failed", key_str); + return ret; +} + +XCamReturn +CLKernel::load_from_source ( + const char *source, size_t length, + uint8_t **gen_binary, size_t *binary_size, + const char *build_option) +{ + cl_kernel new_kernel_id = NULL; + + XCAM_ASSERT (source); + if (!source) { + XCAM_LOG_WARNING ("kernel:%s source empty", XCAM_STR (_name)); + return XCAM_RETURN_ERROR_PARAM; + } + + if (_kernel_id) { + XCAM_LOG_WARNING ("kernel:%s already build yet", XCAM_STR (_name)); + return XCAM_RETURN_ERROR_PARAM; + } + + XCAM_ASSERT (_context.ptr ()); + + if (length == 0) + length = strlen (source); + + new_kernel_id = + _context->generate_kernel_id ( + this, + (const uint8_t *)source, length, + CLContext::KERNEL_BUILD_SOURCE, + gen_binary, binary_size, + build_option); + XCAM_FAIL_RETURN( + WARNING, + new_kernel_id != NULL, + XCAM_RETURN_ERROR_CL, + "cl kernel(%s) load from source failed", XCAM_STR (_name)); + + _kernel_id = new_kernel_id; + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLKernel::load_from_binary (const uint8_t *binary, size_t length) +{ + cl_kernel new_kernel_id = NULL; + + XCAM_ASSERT (binary); + if (!binary || !length) { + XCAM_LOG_WARNING ("kernel:%s binary empty", XCAM_STR (_name)); + return XCAM_RETURN_ERROR_PARAM; + } + + if (_kernel_id) { + XCAM_LOG_WARNING ("kernel:%s already build yet", XCAM_STR (_name)); + return XCAM_RETURN_ERROR_PARAM; + } + + XCAM_ASSERT (_context.ptr ()); + + new_kernel_id = + _context->generate_kernel_id ( + this, + binary, length, + CLContext::KERNEL_BUILD_BINARY, + NULL, NULL, + NULL); + XCAM_FAIL_RETURN( + WARNING, + new_kernel_id != NULL, + XCAM_RETURN_ERROR_CL, + "cl kernel(%s) load from binary failed", XCAM_STR (_name)); + + _kernel_id = new_kernel_id; + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLKernel::clone (SmartPtr<CLKernel> kernel) +{ + XCAM_FAIL_RETURN ( + WARNING, + kernel.ptr () && kernel->is_valid (), + XCAM_RETURN_ERROR_CL, + "cl kernel(%s) load from kernel failed", XCAM_STR (_name)); + _kernel_id = kernel->get_kernel_id (); + _parent_kernel = kernel; + if (!_name && kernel->get_kernel_name ()) { + _name = strndup (kernel->get_kernel_name (), XCAM_MAX_STR_SIZE); + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLKernel::set_arguments (const CLArgList &args, const CLWorkSize &work_size) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + uint32_t i_count = 0; + + XCAM_FAIL_RETURN ( + ERROR, _arg_list.empty (), XCAM_RETURN_ERROR_PARAM, + "cl image kernel(%s) arguments was already set, can NOT be set twice", get_kernel_name ()); + + for (CLArgList::const_iterator iter = args.begin (); iter != args.end (); ++iter, ++i_count) { + const SmartPtr<CLArgument> &arg = *iter; + XCAM_FAIL_RETURN ( + WARNING, arg.ptr (), + XCAM_RETURN_ERROR_PARAM, "cl image kernel(%s) argc(%d) is NULL", get_kernel_name (), i_count); + + void *adress = NULL; + uint32_t size = 0; + arg->get_value (adress, size); + ret = set_argument (i_count, adress, size); + XCAM_FAIL_RETURN ( + WARNING, ret == XCAM_RETURN_NO_ERROR, + ret, "cl image kernel(%s) set argc(%d) failed", get_kernel_name (), i_count); + } + + ret = set_work_size (work_size); + XCAM_FAIL_RETURN ( + WARNING, ret == XCAM_RETURN_NO_ERROR, ret, + "cl image kernel(%s) set worksize(global:%dx%dx%d, local:%dx%dx%d) failed", + XCAM_STR(get_kernel_name ()), + (int)work_size.global[0], (int)work_size.global[1], (int)work_size.global[2], + (int)work_size.local[0], (int)work_size.local[1], (int)work_size.local[2]); + + _arg_list = args; + return ret; +} + +XCamReturn +CLKernel::set_argument (uint32_t arg_i, void *arg_addr, uint32_t arg_size) +{ + cl_int error_code = clSetKernelArg (_kernel_id, arg_i, arg_size, arg_addr); + if (error_code != CL_SUCCESS) { + XCAM_LOG_DEBUG ("kernel(%s) set arg_i(%d) failed", _name, arg_i); + return XCAM_RETURN_ERROR_CL; + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLKernel::set_work_size (const CLWorkSize &work_size) +{ + uint32_t i = 0; + uint32_t work_group_size = 1; + const CLDevieInfo &dev_info = CLDevice::instance ()->get_device_info (); + + XCAM_FAIL_RETURN ( + WARNING, + work_size.dim <= dev_info.max_work_item_dims, + XCAM_RETURN_ERROR_PARAM, + "kernel(%s) work dims(%d) greater than device max dims(%d)", + _name, work_size.dim, dev_info.max_work_item_dims); + + for (i = 0; i < work_size.dim; ++i) { + work_group_size *= work_size.local [i]; + + XCAM_FAIL_RETURN ( + WARNING, + work_size.local [i] <= dev_info.max_work_item_sizes [i], + XCAM_RETURN_ERROR_PARAM, + "kernel(%s) work item(%d) size:%d is greater than device max work item size(%d)", + _name, i, (uint32_t)work_size.local [i], (uint32_t)dev_info.max_work_item_sizes [i]); + } + + XCAM_FAIL_RETURN ( + WARNING, + work_group_size == 0 || work_group_size <= dev_info.max_work_group_size, + XCAM_RETURN_ERROR_PARAM, + "kernel(%s) work-group-size:%d is greater than device max work-group-size(%d)", + _name, work_group_size, (uint32_t)dev_info.max_work_group_size); + + _work_size = work_size; + + return XCAM_RETURN_NO_ERROR; +} + +void +CLKernel::set_default_work_size () +{ + _work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + for (uint32_t i = 0; i < _work_size.dim; ++i) { + //_global_work_size [i] = XCAM_CL_KERNEL_DEFAULT_GLOBAL_WORK_SIZE; + _work_size.local [i] = XCAM_CL_KERNEL_DEFAULT_LOCAL_WORK_SIZE; + } +} + +struct KernelUserData { + SmartPtr<CLKernel> kernel; + SmartPtr<CLEvent> event; + CLArgList arg_list; + + KernelUserData (const SmartPtr<CLKernel> &k, SmartPtr<CLEvent> &e) + : kernel (k) + , event (e) + {} +}; + +void +CLKernel::event_notify (cl_event event, cl_int status, void* data) +{ + KernelUserData *kernel_data = (KernelUserData *)data; + XCAM_ASSERT (event == kernel_data->event->get_event_id ()); + XCAM_UNUSED (status); + XCAM_UNUSED (event); + + delete kernel_data; +} + +XCamReturn +CLKernel::execute ( + const SmartPtr<CLKernel> self, + bool block, + CLEventList &events, + SmartPtr<CLEvent> &event_out) +{ + XCAM_ASSERT (self.ptr () == this); + XCAM_ASSERT (_context.ptr ()); + SmartPtr<CLEvent> kernel_event = event_out; + + if (!block && !kernel_event.ptr ()) { + kernel_event = new CLEvent; + } + +#if ENABLE_DEBUG_KERNEL + XCAM_OBJ_PROFILING_START; +#endif + + XCamReturn ret = _context->execute_kernel (self, NULL, events, kernel_event); + + XCAM_FAIL_RETURN ( + ERROR, + ret == XCAM_RETURN_NO_ERROR, + ret, + "kernel(%s) execute failed", XCAM_STR(_name)); + + + if (block) { + _context->finish (); + } else { + XCAM_ASSERT (kernel_event.ptr () && kernel_event->get_event_id ()); + KernelUserData *user_data = new KernelUserData (self, kernel_event); + user_data->arg_list.swap (_arg_list); + ret = _context->set_event_callback (kernel_event, CL_COMPLETE, event_notify, user_data); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("kernel(%s) set event callback failed", XCAM_STR (_name)); + _context->finish (); + delete user_data; + } + } + _arg_list.clear (); + +#if ENABLE_DEBUG_KERNEL + _context->finish (); + char name[1024]; + snprintf (name, 1024, "%s-%p", XCAM_STR (_name), this); + XCAM_OBJ_PROFILING_END (name, XCAM_OBJ_DUR_FRAME_NUM); +#endif + return ret; +} + +}; diff --git a/modules/ocl/cl_kernel.h b/modules/ocl/cl_kernel.h new file mode 100644 index 0000000..1acc896 --- /dev/null +++ b/modules/ocl/cl_kernel.h @@ -0,0 +1,143 @@ +/* + * cl_kernel.h - CL kernel + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_KERNEL_H +#define XCAM_CL_KERNEL_H + +#include <xcam_std.h> +#include <xcam_mutex.h> +#include <ocl/cl_event.h> +#include <ocl/cl_argument.h> + +#include <CL/cl.h> +#include <string> +#include <unistd.h> + +#define XCAM_CL_KERNEL_FUNC_SOURCE_BEGIN(func) \ + const char func##_body []= +//const char *func##_name = #func; + +#define XCAM_CL_KERNEL_FUNC_BINARY_BEGIN(func) \ + const uint8_t func##_body[] = + +#define XCAM_CL_KERNEL_FUNC_END + +XCAM_BEGIN_DECLARE + +typedef struct _XCamKernelInfo { + const char *kernel_name; + const char *kernel_body; + size_t kernel_body_len; +} XCamKernelInfo; + +XCAM_END_DECLARE + +namespace XCam { + +class CLContext; +class CLKernel; + +/* + * Example to create a kernel + * XCAM_CL_KERNEL_FUNC_SOURCE_BEGIN(kernel_demo) + * #include "kernel_demo.clx" + * XCAM_CL_KERNEL_FUNC_END + * SmartPtr<CLKernel> kernel = new CLKernel (context, kernel_demo); + * kernel->load_from_source (kernel_demo_body, strlen(kernel_demo_body)); + * XCAM_ASSERT (kernel->is_valid()); + */ +class CLKernel { + friend class CLContext; +public: + explicit CLKernel (const SmartPtr<CLContext> &context, const char *name); + virtual ~CLKernel (); + + XCamReturn build_kernel (const XCamKernelInfo& info, const char* options = NULL); + + cl_kernel get_kernel_id () { + return _kernel_id; + } + bool is_valid () const { + return _kernel_id != NULL; + } + const char *get_kernel_name () const { + return _name; + } + SmartPtr<CLContext> &get_context () { + return _context; + } + + XCamReturn set_arguments (const CLArgList &args, const CLWorkSize &work_size); + const CLWorkSize &get_work_size () const { + return _work_size; + } + + bool is_arguments_set () const { + return !_arg_list.empty (); + } + const CLArgList &get_args () const { + return _arg_list; + } + + XCamReturn execute ( + const SmartPtr<CLKernel> self, + bool block = false, + CLEventList &events = CLEvent::EmptyList, + SmartPtr<CLEvent> &event_out = CLEvent::NullEvent); + + XCamReturn load_from_source ( + const char *source, size_t length = 0, + uint8_t **gen_binary = NULL, + size_t *binary_size = NULL, + const char *build_option = NULL); + + XCamReturn load_from_binary (const uint8_t *binary, size_t length); + +private: + XCamReturn set_argument (uint32_t arg_i, void *arg_addr, uint32_t arg_size); + XCamReturn set_work_size (const CLWorkSize &work_size); + void set_default_work_size (); + void destroy (); + XCamReturn clone (SmartPtr<CLKernel> kernel); + + static void event_notify (cl_event event, cl_int status, void* data); + XCAM_DEAD_COPY (CLKernel); + +private: + typedef std::map<std::string, SmartPtr<CLKernel> > KernelMap; + + static KernelMap _kernel_map; + static Mutex _kernel_map_mutex; + static const char *_kernel_cache_path; + +private: + char *_name; + cl_kernel _kernel_id; + SmartPtr<CLContext> _context; + SmartPtr<CLKernel> _parent_kernel; + CLArgList _arg_list; + CLWorkSize _work_size; + + XCAM_OBJ_PROFILING_DEFINES; +}; + +}; + +#endif //XCAM_CL_KERNEL_H diff --git a/modules/ocl/cl_memory.cpp b/modules/ocl/cl_memory.cpp new file mode 100644 index 0000000..90e7d0e --- /dev/null +++ b/modules/ocl/cl_memory.cpp @@ -0,0 +1,663 @@ +/* + * cl_memory.cpp - CL memory + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_utils.h" +#include "cl_memory.h" +#if HAVE_LIBDRM +#include "intel/cl_va_memory.h" +#endif + +namespace XCam { + +CLImageDesc::CLImageDesc () + : format {CL_R, CL_UNORM_INT8} + , width (0) + , height (0) + , row_pitch (0) + , slice_pitch (0) + , array_size (0) + , size (0) +{ +} + +bool +CLImageDesc::operator == (const CLImageDesc& desc) const +{ + if (desc.format.image_channel_data_type == this->format.image_channel_data_type && + desc.format.image_channel_order == this->format.image_channel_order && + desc.width == this->width && + desc.height == this->height && + desc.row_pitch == this->row_pitch && + desc.slice_pitch == this->slice_pitch && + desc.array_size == this->array_size)// && + //desc.size == this->size) + return true; + return false; +} + +CLMemory::CLMemory (const SmartPtr<CLContext> &context) + : _context (context) + , _mem_id (NULL) + , _mem_fd (-1) + , _mem_need_destroy (true) + , _mapped_ptr (NULL) +{ + XCAM_ASSERT (context.ptr () && context->is_valid ()); +} + +CLMemory::~CLMemory () +{ + release_fd (); + + if (_mapped_ptr) + enqueue_unmap (_mapped_ptr); + + if (_mem_id && _mem_need_destroy) { + _context->destroy_mem (_mem_id); + } +} + +int32_t +CLMemory::export_fd () +{ + if (_mem_fd >= 0) + return _mem_fd; + +#if HAVE_LIBDRM + SmartPtr<CLIntelContext> context = _context.dynamic_cast_ptr<CLIntelContext> (); + _mem_fd = context->export_mem_fd (_mem_id); +#endif + if (_mem_fd < 0) + XCAM_LOG_ERROR ("invalid fd:%d", _mem_fd); + + return _mem_fd; +} + +void +CLMemory::release_fd () +{ + if (_mem_fd <= 0) + return; + + close (_mem_fd); + _mem_fd = -1; +} + +XCamReturn +CLMemory::enqueue_unmap ( + void *ptr, + CLEventList &event_waits, + SmartPtr<CLEvent> &event_out) +{ + SmartPtr<CLContext> context = get_context (); + cl_mem mem_id = get_mem_id (); + + XCAM_ASSERT (is_valid ()); + if (!is_valid ()) + return XCAM_RETURN_ERROR_PARAM; + + XCAM_ASSERT (ptr == _mapped_ptr); + if (ptr == _mapped_ptr) + _mapped_ptr = NULL; + + return context->enqueue_unmap (mem_id, ptr, event_waits, event_out); +} + +bool CLMemory::get_cl_mem_info ( + cl_image_info param_name, size_t param_size, + void *param, size_t *param_size_ret) +{ + cl_mem mem_id = get_mem_id (); + cl_int error_code = CL_SUCCESS; + if (!mem_id) + return false; + + error_code = clGetMemObjectInfo (mem_id, param_name, param_size, param, param_size_ret); + XCAM_FAIL_RETURN( + WARNING, + error_code == CL_SUCCESS, + false, + "clGetMemObjectInfo failed on param:%d, errno:%d", param_name, error_code); + return true; +} + +CLBuffer::CLBuffer (const SmartPtr<CLContext> &context) + : CLMemory (context) +{ +} + +CLBuffer::CLBuffer ( + const SmartPtr<CLContext> &context, uint32_t size, + cl_mem_flags flags, void *host_ptr) + : CLMemory (context) + , _flags (flags) + , _size (size) +{ + init_buffer (context, size, flags, host_ptr); +} + +bool +CLBuffer::init_buffer ( + const SmartPtr<CLContext> &context, uint32_t size, + cl_mem_flags flags, void *host_ptr) +{ + cl_mem mem_id = NULL; + + mem_id = context->create_buffer (size, flags, host_ptr); + if (mem_id == NULL) { + XCAM_LOG_WARNING ("CLBuffer create buffer failed"); + return false; + } + + set_mem_id (mem_id); + return true; +} + +CLSubBuffer::CLSubBuffer ( + const SmartPtr<CLContext> &context, SmartPtr<CLBuffer> main_buf, + cl_mem_flags flags, uint32_t offset, uint32_t size) + : CLBuffer (context) + , _main_buf (main_buf) + , _flags (flags) + , _size (size) +{ + init_sub_buffer (context, main_buf, flags, offset, size); +} + +bool +CLSubBuffer::init_sub_buffer ( + const SmartPtr<CLContext> &context, + SmartPtr<CLBuffer> main_buf, + cl_mem_flags flags, + uint32_t offset, + uint32_t size) +{ + cl_mem sub_mem = NULL; + cl_mem main_mem = main_buf->get_mem_id (); + XCAM_FAIL_RETURN (ERROR, main_mem != NULL, false, "get memory from main image failed"); + + cl_buffer_region region; + region.origin = offset; + region.size = size; + + sub_mem = context->create_sub_buffer (main_mem, region, flags); + if (sub_mem == NULL) { + XCAM_LOG_WARNING ("CLBuffer create sub buffer failed"); + return false; + } + + set_mem_id (sub_mem); + return true; +} + +XCamReturn +CLBuffer::enqueue_read ( + void *ptr, uint32_t offset, uint32_t size, + CLEventList &event_waits, + SmartPtr<CLEvent> &event_out) +{ + SmartPtr<CLContext> context = get_context (); + cl_mem mem_id = get_mem_id (); + + XCAM_ASSERT (is_valid ()); + if (!is_valid ()) + return XCAM_RETURN_ERROR_PARAM; + + return context->enqueue_read_buffer (mem_id, ptr, offset, size, true, event_waits, event_out); +} + +XCamReturn +CLBuffer::enqueue_write ( + void *ptr, uint32_t offset, uint32_t size, + CLEventList &event_waits, + SmartPtr<CLEvent> &event_out) +{ + SmartPtr<CLContext> context = get_context (); + cl_mem mem_id = get_mem_id (); + + XCAM_ASSERT (is_valid ()); + if (!is_valid ()) + return XCAM_RETURN_ERROR_PARAM; + + return context->enqueue_write_buffer (mem_id, ptr, offset, size, true, event_waits, event_out); +} + +XCamReturn +CLBuffer::enqueue_map ( + void *&ptr, uint32_t offset, uint32_t size, + cl_map_flags map_flags, + CLEventList &event_waits, + SmartPtr<CLEvent> &event_out) +{ + SmartPtr<CLContext> context = get_context (); + cl_mem mem_id = get_mem_id (); + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (is_valid ()); + if (!is_valid ()) + return XCAM_RETURN_ERROR_PARAM; + + ret = context->enqueue_map_buffer (mem_id, ptr, offset, size, true, map_flags, event_waits, event_out); + XCAM_FAIL_RETURN ( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "enqueue_map failed "); + + set_mapped_ptr (ptr); + return ret; +} + +CLImage::CLImage (const SmartPtr<CLContext> &context) + : CLMemory (context) +{ +} + +uint32_t +CLImage::get_pixel_bytes () const +{ + return calculate_pixel_bytes(_image_desc.format); +} + +bool +CLImage::get_cl_image_info (cl_image_info param_name, size_t param_size, void *param, size_t *param_size_ret) +{ + cl_mem mem_id = get_mem_id (); + cl_int error_code = CL_SUCCESS; + if (!mem_id) + return false; + + error_code = clGetImageInfo (mem_id, param_name, param_size, param, param_size_ret); + XCAM_FAIL_RETURN( + WARNING, + error_code == CL_SUCCESS, + false, + "clGetImageInfo failed on param:%d, errno:%d", param_name, error_code); + return true; +} + +uint32_t +CLImage::calculate_pixel_bytes (const cl_image_format &fmt) +{ + uint32_t a = 0, b = 0; + switch (fmt.image_channel_order) { + case CL_R: + case CL_A: + case CL_Rx: + a = 1; + break; + case CL_RG: + case CL_RA: + case CL_RGx: + a = 2; + break; + case CL_RGB: + case CL_RGBx: + a = 3; + break; + case CL_RGBA: + case CL_BGRA: + case CL_ARGB: + a = 4; + break; + default: + XCAM_LOG_DEBUG ("calculate_pixel_bytes with wrong channel_order:0x%04x", fmt.image_channel_order); + return 0; + } + + switch (fmt.image_channel_data_type) { + case CL_UNORM_INT8: + case CL_SNORM_INT8: + case CL_SIGNED_INT8: + case CL_UNSIGNED_INT8: + b = 1; + break; + case CL_SNORM_INT16: + case CL_UNORM_INT16: + case CL_SIGNED_INT16: + case CL_UNSIGNED_INT16: + case CL_HALF_FLOAT: + b = 2; + break; + case CL_UNORM_INT24: + b = 3; + break; + case CL_SIGNED_INT32: + case CL_UNSIGNED_INT32: + case CL_FLOAT: + b = 4; + break; + default: + XCAM_LOG_DEBUG ("calculate_pixel_bytes with wrong channel_data_type:0x%04x", fmt.image_channel_data_type); + return 0; + } + + return a * b; +} + +bool +CLImage::video_info_2_cl_image_desc ( + const VideoBufferInfo & video_info, + CLImageDesc &image_desc) +{ + image_desc.width = video_info.width; + image_desc.height = video_info.height; + image_desc.array_size = 0; + image_desc.row_pitch = video_info.strides[0]; + XCAM_ASSERT (image_desc.row_pitch >= image_desc.width); + image_desc.slice_pitch = 0; + + switch (video_info.format) { + case XCAM_PIX_FMT_RGB48: + //cl_image_info.fmt.image_channel_order = CL_RGB; + //cl_image_info.fmt.image_channel_data_type = CL_UNORM_INT16; + XCAM_LOG_WARNING ( + "video_info to cl_image_info doesn't support XCAM_PIX_FMT_RGB48, maybe try XCAM_PIX_FMT_RGBA64 instread\n" + " **** XCAM_PIX_FMT_RGB48 need check with cl implementation ****"); + return false; + break; + case V4L2_PIX_FMT_GREY: + image_desc.format.image_channel_order = CL_R; + image_desc.format.image_channel_data_type = CL_UNORM_INT8; + break; + + case XCAM_PIX_FMT_RGBA64: + image_desc.format.image_channel_order = CL_RGBA; + image_desc.format.image_channel_data_type = CL_UNORM_INT16; + break; + + case V4L2_PIX_FMT_RGB24: + image_desc.format.image_channel_order = CL_RGB; + image_desc.format.image_channel_data_type = CL_UNORM_INT8; + break; + + case V4L2_PIX_FMT_RGB565: + image_desc.format.image_channel_order = CL_RGB; + image_desc.format.image_channel_data_type = CL_UNORM_SHORT_565; + break; + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_BGR32: + image_desc.format.image_channel_order = CL_BGRA; + image_desc.format.image_channel_data_type = CL_UNORM_INT8; + break; + // cl doesn'tn support ARGB32 up to now, how about consider V4L2_PIX_FMT_RGBA32 + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_ARGB32: + case V4L2_PIX_FMT_XRGB32: + image_desc.format.image_channel_order = CL_ARGB; + image_desc.format.image_channel_data_type = CL_UNORM_INT8; + break; + + case V4L2_PIX_FMT_RGBA32: + image_desc.format.image_channel_order = CL_RGBA; + image_desc.format.image_channel_data_type = CL_UNORM_INT8; + break; + + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_SBGGR16: + case XCAM_PIX_FMT_SGRBG16: + image_desc.format.image_channel_order = CL_R; + image_desc.format.image_channel_data_type = CL_UNORM_INT16; + break; + + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + image_desc.format.image_channel_order = CL_R; + image_desc.format.image_channel_data_type = CL_UNORM_INT8; + break; + + case V4L2_PIX_FMT_NV12: + image_desc.format.image_channel_order = CL_R; + image_desc.format.image_channel_data_type = CL_UNORM_INT8; + image_desc.array_size = 2; + image_desc.slice_pitch = video_info.strides [0] * video_info.aligned_height; + break; + + case V4L2_PIX_FMT_YUYV: + image_desc.format.image_channel_order = CL_RGBA; + image_desc.format.image_channel_data_type = CL_UNORM_INT8; + image_desc.width /= 2; + break; + + case XCAM_PIX_FMT_LAB: + image_desc.format.image_channel_order = CL_R; + image_desc.format.image_channel_data_type = CL_FLOAT; + break; + + case XCAM_PIX_FMT_RGB48_planar: + case XCAM_PIX_FMT_RGB24_planar: + image_desc.format.image_channel_order = CL_RGBA; + if (XCAM_PIX_FMT_RGB48_planar == video_info.format) + image_desc.format.image_channel_data_type = CL_UNORM_INT16; + else + image_desc.format.image_channel_data_type = CL_UNORM_INT8; + image_desc.width = video_info.aligned_width / 4; + image_desc.array_size = 3; + image_desc.slice_pitch = video_info.strides [0] * video_info.aligned_height; + break; + + case XCAM_PIX_FMT_SGRBG16_planar: + case XCAM_PIX_FMT_SGRBG8_planar: + image_desc.format.image_channel_order = CL_RGBA; + if (XCAM_PIX_FMT_SGRBG16_planar == video_info.format) + image_desc.format.image_channel_data_type = CL_UNORM_INT16; + else + image_desc.format.image_channel_data_type = CL_UNORM_INT8; + image_desc.width = video_info.aligned_width / 4; + image_desc.array_size = 4; + image_desc.slice_pitch = video_info.strides [0] * video_info.aligned_height; + break; + + default: + XCAM_LOG_WARNING ( + "video_info to cl_image_info doesn't support format:%s", + xcam_fourcc_to_string (video_info.format)); + return false; + } + + return true; +} + +void +CLImage::init_desc_by_image () +{ + size_t width = 0, height = 0, row_pitch = 0, slice_pitch = 0, array_size = 0, mem_size = 0; + cl_image_format format = {CL_R, CL_UNORM_INT8}; + + get_cl_image_info (CL_IMAGE_FORMAT, sizeof(format), &format); + get_cl_image_info (CL_IMAGE_WIDTH, sizeof(width), &width); + get_cl_image_info (CL_IMAGE_HEIGHT, sizeof(height), &height); + get_cl_image_info (CL_IMAGE_ROW_PITCH, sizeof(row_pitch), &row_pitch); + get_cl_image_info (CL_IMAGE_SLICE_PITCH, sizeof(slice_pitch), &slice_pitch); + get_cl_image_info (CL_IMAGE_ARRAY_SIZE, sizeof(array_size), &array_size); + get_cl_mem_info (CL_MEM_SIZE, sizeof(mem_size), &mem_size); + + _image_desc.format = format; + _image_desc.width = width; + _image_desc.height = height; + _image_desc.row_pitch = row_pitch; + _image_desc.slice_pitch = slice_pitch; + _image_desc.array_size = array_size; + _image_desc.size = mem_size; +} + +XCamReturn +CLImage::enqueue_map ( + void *&ptr, + size_t *origin, size_t *region, + size_t *row_pitch, size_t *slice_pitch, + cl_map_flags map_flags, + CLEventList &event_waits, + SmartPtr<CLEvent> &event_out) +{ + SmartPtr<CLContext> context = get_context (); + cl_mem mem_id = get_mem_id (); + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (is_valid ()); + if (!is_valid ()) + return XCAM_RETURN_ERROR_PARAM; + + ret = context->enqueue_map_image (mem_id, ptr, origin, region, row_pitch, slice_pitch, true, map_flags, event_waits, event_out); + XCAM_FAIL_RETURN ( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "enqueue_map failed "); + + set_mapped_ptr (ptr); + return ret; +} + +CLImage2D::CLImage2D ( + const SmartPtr<CLContext> &context, + const VideoBufferInfo &video_info, + cl_mem_flags flags) + : CLImage (context) +{ + CLImageDesc cl_desc; + + if (!video_info_2_cl_image_desc (video_info, cl_desc)) { + XCAM_LOG_WARNING ("CLVaImage create va image failed on default videoinfo"); + return; + } + + init_image_2d (context, cl_desc, flags); +} + +CLImage2D::CLImage2D ( + const SmartPtr<CLContext> &context, + const CLImageDesc &cl_desc, + cl_mem_flags flags, + SmartPtr<CLBuffer> bind_buf) + : CLImage (context) +{ + _bind_buf = bind_buf; + init_image_2d (context, cl_desc, flags); +} + +bool CLImage2D::init_image_2d ( + const SmartPtr<CLContext> &context, + const CLImageDesc &desc, + cl_mem_flags flags) +{ + cl_mem mem_id = 0; + cl_image_desc cl_desc; + + xcam_mem_clear (cl_desc); + cl_desc.image_type = CL_MEM_OBJECT_IMAGE2D; + cl_desc.image_width = desc.width; + cl_desc.image_height = desc.height; + cl_desc.image_depth = 1; + cl_desc.image_array_size = 0; + cl_desc.image_row_pitch = 0; + cl_desc.image_slice_pitch = 0; + cl_desc.num_mip_levels = 0; + cl_desc.num_samples = 0; + cl_desc.buffer = NULL; + if (_bind_buf.ptr ()) { + if (desc.row_pitch) + cl_desc.image_row_pitch = desc.row_pitch; + else { + cl_desc.image_row_pitch = calculate_pixel_bytes(desc.format) * desc.width; + } + XCAM_ASSERT (cl_desc.image_row_pitch); + cl_desc.buffer = _bind_buf->get_mem_id (); + XCAM_ASSERT (cl_desc.buffer); + } + + mem_id = context->create_image (flags, desc.format, cl_desc); + if (mem_id == NULL) { + XCAM_LOG_WARNING ("CLImage2D create image 2d failed"); + return false; + } + set_mem_id (mem_id); + init_desc_by_image (); + return true; +} + +CLImage2DArray::CLImage2DArray ( + const SmartPtr<CLContext> &context, + const VideoBufferInfo &video_info, + cl_mem_flags flags, + uint32_t extra_array_size) + : CLImage (context) +{ + CLImageDesc cl_desc; + + XCAM_ASSERT (video_info.components >= 2); + + if (!video_info_2_cl_image_desc (video_info, cl_desc)) { + XCAM_LOG_WARNING ("CLVaImage create va image failed on default videoinfo"); + return; + } + XCAM_ASSERT (cl_desc.array_size >= 2); + + //special process for BYT platform for slice-pitch + //if (video_info.format == V4L2_PIX_FMT_NV12) + cl_desc.height = XCAM_ALIGN_UP (cl_desc.height, 16); + + cl_desc.array_size += extra_array_size; + + init_image_2d_array (context, cl_desc, flags); +} + +bool CLImage2DArray::init_image_2d_array ( + const SmartPtr<CLContext> &context, + const CLImageDesc &desc, + cl_mem_flags flags) +{ + cl_mem mem_id = 0; + cl_image_desc cl_desc; + + xcam_mem_clear (cl_desc); + cl_desc.image_type = CL_MEM_OBJECT_IMAGE2D_ARRAY; + cl_desc.image_width = desc.width; + cl_desc.image_height = desc.height; + cl_desc.image_depth = 1; + cl_desc.image_array_size = desc.array_size; + cl_desc.image_row_pitch = 0; + cl_desc.image_slice_pitch = 0; + cl_desc.num_mip_levels = 0; + cl_desc.num_samples = 0; + cl_desc.buffer = NULL; + + mem_id = context->create_image (flags, desc.format, cl_desc); + if (mem_id == NULL) { + XCAM_LOG_WARNING ("CLImage2D create image 2d failed"); + return false; + } + set_mem_id (mem_id); + init_desc_by_image (); + return true; +} + + +}; diff --git a/modules/ocl/cl_memory.h b/modules/ocl/cl_memory.h new file mode 100644 index 0000000..acc3fc5 --- /dev/null +++ b/modules/ocl/cl_memory.h @@ -0,0 +1,264 @@ +/* + * cl_memory.h - CL memory + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_MEMORY_H +#define XCAM_CL_MEMORY_H + +#include "ocl/cl_context.h" +#include "ocl/cl_event.h" +#include "video_buffer.h" + +#include <unistd.h> + +namespace XCam { + +struct CLImageDesc { + cl_image_format format; + uint32_t width; + uint32_t height; + uint32_t row_pitch; + uint32_t slice_pitch; + uint32_t array_size; + uint32_t size; + + CLImageDesc (); + bool operator == (const CLImageDesc& desc) const; +}; + +class CLMemory { +public: + explicit CLMemory (const SmartPtr<CLContext> &context); + virtual ~CLMemory (); + + cl_mem &get_mem_id () { + return _mem_id; + } + bool is_valid () const { + return _mem_id != NULL; + } + + bool get_cl_mem_info ( + cl_image_info param_name, size_t param_size, + void *param, size_t *param_size_ret = NULL); + + int32_t export_fd (); + void release_fd (); + + XCamReturn enqueue_unmap ( + void *ptr, + CLEventList &events_wait = CLEvent::EmptyList, + SmartPtr<CLEvent> &event_out = CLEvent::NullEvent); + +protected: + void set_mem_id (cl_mem &id, bool need_destroy = true) { + _mem_id = id; + _mem_need_destroy = need_destroy; + } + + void set_mapped_ptr (void *ptr) { + _mapped_ptr = ptr; + } + + SmartPtr<CLContext> &get_context () { + return _context; + } + +private: + XCAM_DEAD_COPY (CLMemory); + +private: + SmartPtr<CLContext> _context; + cl_mem _mem_id; + int32_t _mem_fd; + bool _mem_need_destroy; + void *_mapped_ptr; +}; + +class CLBuffer + : public CLMemory +{ +protected: + explicit CLBuffer (const SmartPtr<CLContext> &context); + +public: + explicit CLBuffer ( + const SmartPtr<CLContext> &context, uint32_t size, + cl_mem_flags flags = CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, + void *host_ptr = NULL); + + XCamReturn enqueue_read ( + void *ptr, uint32_t offset, uint32_t size, + CLEventList &event_waits = CLEvent::EmptyList, + SmartPtr<CLEvent> &event_out = CLEvent::NullEvent); + XCamReturn enqueue_write ( + void *ptr, uint32_t offset, uint32_t size, + CLEventList &event_waits = CLEvent::EmptyList, + SmartPtr<CLEvent> &event_out = CLEvent::NullEvent); + XCamReturn enqueue_map ( + void *&ptr, uint32_t offset, uint32_t size, + cl_map_flags map_flags = CL_MAP_READ | CL_MAP_WRITE, + CLEventList &event_waits = CLEvent::EmptyList, + SmartPtr<CLEvent> &event_out = CLEvent::NullEvent); + + uint32_t get_buf_size () const { + return _size; + } + +protected: + void set_buf_size (uint32_t size) { + _size = size; + } + +private: + bool init_buffer ( + const SmartPtr<CLContext> &context, uint32_t size, + cl_mem_flags flags, void *host_ptr); + + XCAM_DEAD_COPY (CLBuffer); + +private: + cl_mem_flags _flags; + uint32_t _size; +}; + +class CLSubBuffer + : public CLBuffer +{ +protected: + explicit CLSubBuffer (const SmartPtr<CLContext> &context); + +public: + explicit CLSubBuffer ( + const SmartPtr<CLContext> &context, + SmartPtr<CLBuffer> main_buf, + cl_mem_flags flags = CL_MEM_READ_WRITE, + uint32_t offset = 0, + uint32_t size = 0); + +private: + bool init_sub_buffer ( + const SmartPtr<CLContext> &context, + SmartPtr<CLBuffer> main_buf, + cl_mem_flags flags, + uint32_t offset, + uint32_t size); + + XCAM_DEAD_COPY (CLSubBuffer); + +private: + SmartPtr<CLBuffer> _main_buf; + cl_mem_flags _flags; + uint32_t _size; +}; + +class CLImage + : public CLMemory +{ +public: + virtual ~CLImage () {} + + const CLImageDesc &get_image_desc () const { + return _image_desc; + } + uint32_t get_pixel_bytes () const; + + static uint32_t calculate_pixel_bytes (const cl_image_format &fmt); + static bool video_info_2_cl_image_desc ( + const VideoBufferInfo & video_info, + CLImageDesc &cl_desc); + + XCamReturn enqueue_map ( + void *&ptr, + size_t *origin, size_t *region, + size_t *row_pitch, size_t *slice_pitch, + cl_map_flags map_flags = CL_MAP_READ | CL_MAP_WRITE, + CLEventList &event_waits = CLEvent::EmptyList, + SmartPtr<CLEvent> &event_out = CLEvent::NullEvent); + +protected: + explicit CLImage (const SmartPtr<CLContext> &context); + void init_desc_by_image (); + bool get_cl_image_info ( + cl_image_info param_name, size_t param_size, + void *param, size_t *param_size_ret = NULL); + +private: + XCAM_DEAD_COPY (CLImage); + + CLImageDesc _image_desc; +}; + +class CLImage2D + : public CLImage +{ +public: + explicit CLImage2D ( + const SmartPtr<CLContext> &context, + const VideoBufferInfo &video_info, + cl_mem_flags flags = CL_MEM_READ_WRITE); + + explicit CLImage2D ( + const SmartPtr<CLContext> &context, + const CLImageDesc &cl_desc, + cl_mem_flags flags = CL_MEM_READ_WRITE, + SmartPtr<CLBuffer> bind_buf = NULL); + + SmartPtr<CLBuffer> get_bind_buf () { + return _bind_buf; + } + + ~CLImage2D () {} + +private: + bool init_image_2d ( + const SmartPtr<CLContext> &context, + const CLImageDesc &cl_desc, + cl_mem_flags flags); + + XCAM_DEAD_COPY (CLImage2D); + +private: + SmartPtr<CLBuffer> _bind_buf; +}; + +class CLImage2DArray + : public CLImage +{ +public: + explicit CLImage2DArray ( + const SmartPtr<CLContext> &context, + const VideoBufferInfo &video_info, + cl_mem_flags flags = CL_MEM_READ_WRITE, + uint32_t extra_array_size = 0); + + ~CLImage2DArray () {} + +private: + bool init_image_2d_array ( + const SmartPtr<CLContext> &context, + const CLImageDesc &cl_desc, + cl_mem_flags flags); + + XCAM_DEAD_COPY (CLImage2DArray); +}; + + +}; +#endif // diff --git a/modules/ocl/cl_multi_image_handler.cpp b/modules/ocl/cl_multi_image_handler.cpp new file mode 100644 index 0000000..4b8fd38 --- /dev/null +++ b/modules/ocl/cl_multi_image_handler.cpp @@ -0,0 +1,144 @@ +/* + * cl_multi_image_handler.cpp - CL multi-image handler + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_multi_image_handler.h" +#if ENABLE_PROFILING +#include "cl_device.h" +#endif + +namespace XCam { + +CLMultiImageHandler::CLMultiImageHandler (const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) +{ +} + +CLMultiImageHandler::~CLMultiImageHandler () +{ + _handler_list.clear (); +} + +bool +CLMultiImageHandler::add_image_handler (SmartPtr<CLImageHandler> &handler) +{ + _handler_list.push_back (handler); + return append_kernels (handler); +} + +XCamReturn +CLMultiImageHandler::execute_kernels () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + for (KernelList::iterator i_kernel = _kernels.begin (); + i_kernel != _kernels.end (); ++i_kernel) { + SmartPtr<CLImageKernel> &kernel = *i_kernel; + XCAM_FAIL_RETURN (WARNING, kernel.ptr(), ret, "kernel empty"); + + if (!kernel->is_enabled ()) + continue; + + ret = execute_kernel (kernel); + + XCAM_FAIL_RETURN ( + WARNING, + (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS), ret, + "cl_multi_image_handler(%s) execute kernel(%s) failed", + XCAM_STR (_name), kernel->get_kernel_name ()); + + if (ret != XCAM_RETURN_NO_ERROR) + break; + + for (HandlerList::iterator i_handler = _handler_list.begin (); + i_handler != _handler_list.end (); ++i_handler) { + SmartPtr<CLImageHandler> &sub_handler = *i_handler; + XCAM_ASSERT (sub_handler.ptr ()); + + SmartPtr<CLImageKernel> &sub_handler_last_kernel = *(sub_handler->_kernels.rbegin()); + XCAM_ASSERT (sub_handler_last_kernel.ptr ()); + if (sub_handler_last_kernel.ptr () == kernel.ptr ()) { + sub_handler->reset_buf_cache (NULL, NULL); + sub_handler_execute_done (sub_handler); + break; + } + } + } + + return ret; +} + +XCamReturn +CLMultiImageHandler::ensure_handler_parameters ( + const SmartPtr<CLImageHandler> &handler, SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + XCAM_ASSERT (handler.ptr ()); + return handler->ensure_parameters (input, output); +} + +XCamReturn +CLMultiImageHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + for (HandlerList::iterator i_handler = _handler_list.begin (); + i_handler != _handler_list.end (); ++i_handler) { + SmartPtr<CLImageHandler> &handler = *i_handler; + XCAM_ASSERT (handler.ptr ()); + XCamReturn ret = ensure_handler_parameters (handler, input, output); + + XCAM_FAIL_RETURN ( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "CLMultiImageHandler(%s) prepare parameters failed on handler(%s)", + XCAM_STR (get_name ()), XCAM_STR (handler->get_name ())); + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLMultiImageHandler::execute_done (SmartPtr<VideoBuffer> &output) +{ + for (HandlerList::iterator i_handler = _handler_list.begin (); + i_handler != _handler_list.end (); ++i_handler) { + SmartPtr<CLImageHandler> &handler = *i_handler; + XCAM_ASSERT (handler.ptr ()); + + XCamReturn ret = handler->execute_done (output); + if (ret == XCAM_RETURN_BYPASS) + return ret; + + XCAM_FAIL_RETURN ( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "CLMultiImageHandler(%s) execute buffer done failed on handler(%s)", + XCAM_STR (get_name ()), XCAM_STR (handler->get_name ())); + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLMultiImageHandler::sub_handler_execute_done (SmartPtr<CLImageHandler> &handler) +{ + XCAM_UNUSED (handler); + return XCAM_RETURN_NO_ERROR; +} + +} + diff --git a/modules/ocl/cl_multi_image_handler.h b/modules/ocl/cl_multi_image_handler.h new file mode 100644 index 0000000..7b44818 --- /dev/null +++ b/modules/ocl/cl_multi_image_handler.h @@ -0,0 +1,59 @@ +/* + * cl_multi_image_handler.h - CL multi-image handler + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_MULTI_IMAGE_HANDLER_H +#define XCAM_CL_MULTI_IMAGE_HANDLER_H + +#include <xcam_std.h> +#include <ocl/cl_image_handler.h> + +namespace XCam { + +class CLMultiImageHandler + : public CLImageHandler +{ +public: + typedef std::list<SmartPtr<CLImageHandler> > HandlerList; + +public: + explicit CLMultiImageHandler (const SmartPtr<CLContext> &context, const char *name); + virtual ~CLMultiImageHandler (); + bool add_image_handler (SmartPtr<CLImageHandler> &handler); + +protected: + virtual XCamReturn prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + virtual XCamReturn execute_kernels (); + virtual XCamReturn execute_done (SmartPtr<VideoBuffer> &output); + + virtual XCamReturn sub_handler_execute_done (SmartPtr<CLImageHandler> &handler); + + XCamReturn ensure_handler_parameters ( + const SmartPtr<CLImageHandler> &handler, SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + XCAM_DEAD_COPY (CLMultiImageHandler); + +protected: + HandlerList _handler_list; +}; + +}; + +#endif // XCAM_CL_MULTI_IMAGE_HANDLER_H
\ No newline at end of file diff --git a/modules/ocl/cl_newtonemapping_handler.cpp b/modules/ocl/cl_newtonemapping_handler.cpp new file mode 100644 index 0000000..3b3be10 --- /dev/null +++ b/modules/ocl/cl_newtonemapping_handler.cpp @@ -0,0 +1,401 @@ +/* + * cl_newtonemapping_handler.cpp - CL tonemapping handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wu Junkai <junkai.wu@intel.com> + */ + +#include "cl_utils.h" +#include "cl_newtonemapping_handler.h" + +namespace XCam { + +static const XCamKernelInfo kernel_tone_mapping_pipe_info = { + "kernel_newtonemapping", +#include "kernel_newtonemapping.clx" + , 0, +}; + +CLNewTonemappingImageKernel::CLNewTonemappingImageKernel ( + const SmartPtr<CLContext> &context, const char *name) + : CLImageKernel (context, name) +{ +} + +static void +haleq(int *y, int *hist, int *hist_leq, int left, int right, int level, int index_left, int index_right) +{ + int l; + float e, le; + + l = (left + right) / 2; + int num_left = left > 0 ? hist[left - 1] : 0; + int pixel_num = hist[right] - num_left; + e = y[num_left + pixel_num / 2]; + + if(e != 0) + { + le = 0.5f * (e - l) + l; + } + else + { + le = l; + } + + int index = (index_left + index_right) / 2; + hist_leq[index] = (int)(le + 0.5f); + + if(level > 5) return; + + haleq (y, hist, hist_leq, left, (int)(le + 0.5f), level + 1, index_left, index); + haleq (y, hist, hist_leq, (int)(le + 0.5f) + 1, right, level + 1, index + 1, index_right); +} + +static void +block_split_haleq(int* hist, int hist_bin_count, int pixel_num, int block_start_index, float* y_max, float* y_avg, float* map_hist) +{ + int block_id = block_start_index / hist_bin_count; + + for(int i = hist_bin_count - 1; i >= 0; i--) + { + if(hist[i] > 0) + { + y_max[block_id] = i; + break; + } + } + + for(int i = 0; i < hist_bin_count; i++) + { + y_avg[block_id] += i * hist[i]; + } + + y_max[block_id] = y_max[block_id] + 1; + y_avg[block_id] = y_avg[block_id] / pixel_num; + + int *hist_log = (int *) xcam_malloc0 (hist_bin_count * sizeof (int)); + int *sort_y = (int *) xcam_malloc0 ((pixel_num + 1) * sizeof (int)); + int *map_index_leq = (int *) xcam_malloc0 (hist_bin_count * sizeof (int)); + int *map_index_log = (int *) xcam_malloc0 (hist_bin_count * sizeof (int)); + XCAM_ASSERT (hist_log && sort_y && map_index_leq && map_index_log); + + int thres = (int)(1500 * 1500 / (y_avg[block_id] * y_avg[block_id] + 1) * 600); + int y_max0 = (y_max[block_id] > thres) ? thres : y_max[block_id]; + int y_max1 = (y_max[block_id] - thres) > 0 ? (y_max[block_id] - thres) : 0; + + float t0 = 0.01f * y_max0 + 0.001f; + float t1 = 0.001f * y_max1 + 0.001f; + float max0_log = log(y_max0 + t0); + float max1_log = log(y_max1 + t1); + float t0_log = log(t0); + float t1_log = log(t1); + float factor0; + + if(y_max[block_id] < thres) + { + factor0 = (hist_bin_count - 1) / (max0_log - t0_log + 0.001f); + } + else + factor0 = y_max0 / (max0_log - t0_log + 0.001f); + + float factor1 = y_max1 / (max1_log - t1_log + 0.001f); + + if(y_max[block_id] < thres) + { + for(int i = 0; i < y_max[block_id]; i++) + { + int index = (int)((log(i + t0) - t0_log) * factor0 + 0.5f); + hist_log[index] += hist[i]; + map_index_log[i] = index; + } + } + else + { + for(int i = 0; i < y_max0; i++) + { + int index = (int)((log(i + t0) - t0_log) * factor0 + 0.5f); + hist_log[index] += hist[i]; + map_index_log[i] = index; + } + + for(int i = y_max0; i < y_max[block_id]; i++) + { + int r = y_max[block_id] - i; + int index = (int)((log(r + t1) - t1_log) * factor1 + 0.5f); + index = y_max[block_id] - index; + hist_log[index] += hist[i]; + map_index_log[i] = index; + } + } + + for(int i = y_max[block_id]; i < hist_bin_count; i++) + { + hist_log[map_index_log[(int)y_max[block_id] - 1]] += hist[i]; + map_index_log[i] = map_index_log[(int)y_max[block_id] - 1]; + } + + int sort_index = 1; + for(int i = 0; i < hist_bin_count; i++) + { + for(int l = 0; l < hist_log[i]; l++) + { + sort_y[sort_index] = i; + sort_index++; + } + } + sort_y[0] = 0; + + for(int i = 1; i < hist_bin_count; i++) + { + hist_log[i] += hist_log[i - 1]; + } + + int map_leq_index[256]; + + haleq(sort_y, hist_log, map_leq_index, 0, hist_bin_count - 1, 0, 0, 255); + + map_leq_index[255] = hist_bin_count; + map_leq_index[0] = 0; + + for(int i = 1; i < 255; i++) + { + if(i % 2 == 0) map_leq_index[i] = (map_leq_index[i - 1] + map_leq_index[i + 1]) / 2; + if(map_leq_index[i] < map_leq_index[i - 1]) + map_leq_index[i] = map_leq_index[i - 1]; + } + + for(int i = 0; i < 255; i++) + { + for(int k = map_leq_index[i]; k < map_leq_index[i + 1]; k++) + { + map_index_leq[k] = (float)i; + } + } + + for(int i = 0; i < hist_bin_count; i++) + { + map_hist[i + block_start_index] = map_index_leq[map_index_log[i]] / 255.0f; + } + + y_max[block_id] = y_max[block_id] / hist_bin_count; + y_avg[block_id] = y_avg[block_id] / hist_bin_count; + + xcam_free (hist_log); + hist_log = NULL; + xcam_free (map_index_leq); + map_index_leq = NULL; + xcam_free (map_index_log); + map_index_log = NULL; + xcam_free (sort_y); + sort_y = NULL; +} + +CLNewTonemappingImageHandler::CLNewTonemappingImageHandler ( + const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) + , _output_format (XCAM_PIX_FMT_SGRBG16_planar) + , _block_factor (4) +{ + for(int i = 0; i < 65536; i++) + { + _map_hist[i] = i; + } + + for(int i = 0; i < 4 * 4; i++) + { + _y_max[i] = 0.0f; + _y_avg[i] = 0.0f; + } +} + +bool +CLNewTonemappingImageHandler::set_tonemapping_kernel(SmartPtr<CLNewTonemappingImageKernel> &kernel) +{ + SmartPtr<CLImageKernel> image_kernel = kernel; + add_kernel (image_kernel); + _tonemapping_kernel = kernel; + return true; +} + +XCamReturn +CLNewTonemappingImageHandler::prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, + VideoBufferInfo &output) +{ + bool format_inited = output.init (_output_format, input.width, input.height); + + XCAM_FAIL_RETURN ( + WARNING, + format_inited, + XCAM_RETURN_ERROR_PARAM, + "CL image handler(%s) output format(%s) unsupported", + get_name (), xcam_fourcc_to_string (_output_format)); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLNewTonemappingImageHandler::prepare_parameters ( + SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + SmartPtr<CLContext> context = get_context (); + const VideoBufferInfo &video_info = input->get_video_info (); + CLArgList args; + CLWorkSize work_size; + + XCAM_ASSERT (_tonemapping_kernel.ptr ()); + + CLImageDesc desc; + desc.format.image_channel_order = CL_RGBA; + desc.format.image_channel_data_type = CL_UNORM_INT16; + desc.width = video_info.aligned_width / 4; + desc.height = video_info.aligned_height * 4; + desc.row_pitch = video_info.strides[0]; + desc.array_size = 4; + desc.slice_pitch = video_info.strides [0] * video_info.aligned_height; + + SmartPtr<CLImage> image_in = convert_to_climage (context, input, desc); + SmartPtr<CLImage> image_out = convert_to_climage (context, output, desc); + int image_width = video_info.aligned_width; + int image_height = video_info.aligned_height; + + XCAM_FAIL_RETURN ( + WARNING, + image_in->is_valid () && image_out->is_valid (), + XCAM_RETURN_ERROR_MEM, + "cl image handler(%s) in/out memory not available", XCAM_STR (get_name ())); + + SmartPtr<X3aStats> stats; + SmartPtr<CLVideoBuffer> cl_buf = input.dynamic_cast_ptr<CLVideoBuffer> (); + if (cl_buf.ptr ()) { + stats = cl_buf->find_3a_stats (); + } +#if HAVE_LIBDRM + else { + SmartPtr<DrmBoBuffer> bo_buf = input.dynamic_cast_ptr<DrmBoBuffer> (); + stats = bo_buf->find_3a_stats (); + } +#endif + XCAM_FAIL_RETURN ( + ERROR, stats.ptr (), XCAM_RETURN_ERROR_MEM, + "new tonemapping handler prepare_arguments find_3a_stats failed"); + + XCam3AStats *stats_ptr = stats->get_stats (); + XCAM_FAIL_RETURN ( + ERROR, stats_ptr, XCAM_RETURN_ERROR_MEM, + "new tonemapping handler prepare_arguments get_stats failed"); + + int block_factor = 4; + int width_per_block = stats_ptr->info.width / block_factor; + int height_per_block = stats_ptr->info.height / block_factor; + int height_last_block = height_per_block + stats_ptr->info.height % block_factor; + int hist_bin_count = 1 << stats_ptr->info.bit_depth; + + int *hist_per_block = (int *) xcam_malloc0 (hist_bin_count * sizeof (int)); + XCAM_ASSERT (hist_per_block); + + for(int block_row = 0; block_row < block_factor; block_row++) + { + for(int block_col = 0; block_col < block_factor; block_col++) + { + int block_start_index = (block_row * block_factor + block_col) * hist_bin_count; + int start_index = block_row * height_per_block * stats_ptr->info.width + block_col * width_per_block; + + for(int i = 0; i < hist_bin_count; i++) + { + hist_per_block[i] = 0; + } + + if(block_row == block_factor - 1) + { + height_per_block = height_last_block; + } + + int block_totalnum = width_per_block * height_per_block; + for(int i = 0; i < height_per_block; i++) + { + for(int j = 0; j < width_per_block; j++) + { + int y = stats_ptr->stats[start_index + i * stats_ptr->info.width + j].avg_y; + hist_per_block[y]++; + } + } + + block_split_haleq (hist_per_block, hist_bin_count, block_totalnum, block_start_index, _y_max, _y_avg, _map_hist); + } + } + + xcam_free (hist_per_block); + hist_per_block = NULL; + + SmartPtr<CLBuffer> y_max_buffer = new CLBuffer( + context, sizeof(float) * block_factor * block_factor, + CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, &_y_max); + + SmartPtr<CLBuffer> y_avg_buffer = new CLBuffer( + context, sizeof(float) * block_factor * block_factor, + CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, &_y_avg); + + SmartPtr<CLBuffer> map_hist_buffer = new CLBuffer( + context, sizeof(float) * hist_bin_count * block_factor * block_factor, + CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, &_map_hist); + + //set args; + args.push_back (new CLMemArgument (image_in)); + args.push_back (new CLMemArgument (image_out)); + args.push_back (new CLMemArgument (y_max_buffer)); + args.push_back (new CLMemArgument (y_avg_buffer)); + args.push_back (new CLMemArgument (map_hist_buffer)); + args.push_back (new CLArgumentT<int> (image_width)); + args.push_back (new CLArgumentT<int> (image_height)); + + const CLImageDesc out_info = image_out->get_image_desc (); + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.global[0] = out_info.width; + work_size.global[1] = out_info.height / 4; + work_size.local[0] = 8; + work_size.local[1] = 8; + + XCAM_ASSERT (_tonemapping_kernel.ptr ()); + XCamReturn ret = _tonemapping_kernel->set_arguments (args, work_size); + XCAM_FAIL_RETURN ( + WARNING, ret == XCAM_RETURN_NO_ERROR, ret, + "new tone mapping kernel set arguments failed."); + + return XCAM_RETURN_NO_ERROR; +} + + +SmartPtr<CLImageHandler> +create_cl_newtonemapping_image_handler (const SmartPtr<CLContext> &context) +{ + SmartPtr<CLNewTonemappingImageHandler> tonemapping_handler; + SmartPtr<CLNewTonemappingImageKernel> tonemapping_kernel; + + tonemapping_kernel = new CLNewTonemappingImageKernel (context, "kernel_newtonemapping"); + XCAM_ASSERT (tonemapping_kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, tonemapping_kernel->build_kernel (kernel_tone_mapping_pipe_info, NULL) == XCAM_RETURN_NO_ERROR, NULL, + "build new tonemapping kernel(%s) failed", kernel_tone_mapping_pipe_info.kernel_name); + + XCAM_ASSERT (tonemapping_kernel->is_valid ()); + tonemapping_handler = new CLNewTonemappingImageHandler(context, "cl_handler_newtonemapping"); + tonemapping_handler->set_tonemapping_kernel(tonemapping_kernel); + + return tonemapping_handler; +} + +}; diff --git a/modules/ocl/cl_newtonemapping_handler.h b/modules/ocl/cl_newtonemapping_handler.h new file mode 100644 index 0000000..aaf2163 --- /dev/null +++ b/modules/ocl/cl_newtonemapping_handler.h @@ -0,0 +1,70 @@ +/* + * cl_newtonemapping_handler.h - CL tonemapping handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wu Junkai <junkai.wu@intel.com> + */ + +#ifndef XCAM_CL_NEWTONEMAPPING_HANLDER_H +#define XCAM_CL_NEWTONEMAPPING_HANLDER_H + +#include <xcam_std.h> +#include <ocl/cl_image_handler.h> +#include <x3a_stats_pool.h> + +namespace XCam { + +class CLNewTonemappingImageKernel + : public CLImageKernel +{ +public: + explicit CLNewTonemappingImageKernel ( + const SmartPtr<CLContext> &context, const char *name); + +private: + SmartPtr<CLBuffer> _y_max_buffer; + SmartPtr<CLBuffer> _y_avg_buffer; + SmartPtr<CLBuffer> _map_hist_buffer; +}; + +class CLNewTonemappingImageHandler + : public CLImageHandler +{ +public: + explicit CLNewTonemappingImageHandler (const SmartPtr<CLContext> &context, const char *name); + bool set_tonemapping_kernel(SmartPtr<CLNewTonemappingImageKernel> &kernel); + +protected: + virtual XCamReturn prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, VideoBufferInfo &output); + virtual XCamReturn prepare_parameters ( + SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + SmartPtr<CLNewTonemappingImageKernel> _tonemapping_kernel; + int32_t _output_format; + int _block_factor; + float _map_hist[65536]; + float _y_max[16]; + float _y_avg[16]; +}; + +SmartPtr<CLImageHandler> +create_cl_newtonemapping_image_handler (const SmartPtr<CLContext> &context); + +}; + +#endif //XCAM_CL_NEWTONEMAPPING_HANLDER_H diff --git a/modules/ocl/cl_newwavelet_denoise_handler.cpp b/modules/ocl/cl_newwavelet_denoise_handler.cpp new file mode 100644 index 0000000..19ce275 --- /dev/null +++ b/modules/ocl/cl_newwavelet_denoise_handler.cpp @@ -0,0 +1,980 @@ +/* + * cl_newwavelet_denoise_handler.cpp - CL wavelet denoise handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wei Zong <wei.zong@intel.com> + */ + +#include "cl_utils.h" +#include "cl_context.h" +#include "cl_device.h" +#include "cl_newwavelet_denoise_handler.h" + +#define WAVELET_DECOMPOSITION_LEVELS 4 + +namespace XCam { + +enum { + KernelWaveletDecompose = 0, + KernelWaveletReconstruct, + KernelWaveletNoiseEstimate, + KernelWaveletThreshold, +}; + +static const XCamKernelInfo kernel_new_wavelet_info[] = { + { + "kernel_wavelet_haar_decomposition", +#include "kernel_wavelet_haar.clx" + , 0, + }, + { + "kernel_wavelet_haar_reconstruction", +#include "kernel_wavelet_haar.clx" + , 0, + }, + { + "kernel_wavelet_coeff_variance", +#include "kernel_wavelet_coeff.clx" + , 0, + }, + { + "kernel_wavelet_coeff_thresholding", +#include "kernel_wavelet_coeff.clx" + , 0, + }, +}; + + +CLWaveletNoiseEstimateKernel::CLWaveletNoiseEstimateKernel ( + const SmartPtr<CLContext> &context, + const char *name, + SmartPtr<CLNewWaveletDenoiseImageHandler> &handler, + uint32_t channel, + uint32_t subband, + uint32_t layer) + : CLImageKernel (context, name) + , _decomposition_levels (WAVELET_DECOMPOSITION_LEVELS) + , _channel (channel) + , _subband (subband) + , _current_layer (layer) + , _analog_gain (-1.0) + , _handler (handler) +{ +} + +SmartPtr<CLImage> +CLWaveletNoiseEstimateKernel::get_input_buffer () +{ + SmartPtr<VideoBuffer> input = _handler->get_input_buf (); + const VideoBufferInfo & video_info = input->get_video_info (); + + SmartPtr<CLImage> image; + SmartPtr<CLWaveletDecompBuffer> buffer = _handler->get_decomp_buffer (_channel, _current_layer); + XCAM_ASSERT (buffer.ptr ()); + + if (_subband == CL_WAVELET_SUBBAND_HL) { + image = buffer->hl[0]; + } else if (_subband == CL_WAVELET_SUBBAND_LH) { + image = buffer->lh[0]; + } else if (_subband == CL_WAVELET_SUBBAND_HH) { + image = buffer->hh[0]; + } else { + image = buffer->ll; + } + + float current_ag = _handler->get_denoise_config ().analog_gain; + if ((_analog_gain == -1.0f) || + (fabs(_analog_gain - current_ag) > 0.2)) { + + if ((_current_layer == 1) && (_subband == CL_WAVELET_SUBBAND_HH)) { + _analog_gain = current_ag; + estimate_noise_variance (video_info, buffer->hh[0], buffer->noise_variance); + _handler->set_estimated_noise_variation (buffer->noise_variance); + } else { + _handler->get_estimated_noise_variation (buffer->noise_variance); + } + } else { + _handler->get_estimated_noise_variation (buffer->noise_variance); + } + return image; +} + +SmartPtr<CLImage> +CLWaveletNoiseEstimateKernel::get_output_buffer () +{ + SmartPtr<CLImage> image; + SmartPtr<CLWaveletDecompBuffer> buffer = _handler->get_decomp_buffer (_channel, _current_layer); + XCAM_ASSERT (buffer.ptr ()); + + if (_subband == CL_WAVELET_SUBBAND_HL) { + image = buffer->hl[1]; + } else if (_subband == CL_WAVELET_SUBBAND_LH) { + image = buffer->lh[1]; + } else if (_subband == CL_WAVELET_SUBBAND_HH) { + image = buffer->hh[1]; + } else { + image = buffer->ll; + } + return image; +} + +XCamReturn +CLWaveletNoiseEstimateKernel::prepare_arguments ( + CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + + SmartPtr<CLImage> image_in = get_input_buffer (); + SmartPtr<CLImage> image_out = get_output_buffer (); + + CLImageDesc cl_desc = image_in->get_image_desc (); + uint32_t cl_width = XCAM_ALIGN_UP (cl_desc.width, 2); + uint32_t cl_height = XCAM_ALIGN_UP (cl_desc.height, 2); + + XCAM_FAIL_RETURN ( + WARNING, + image_in->is_valid () && image_out->is_valid (), + XCAM_RETURN_ERROR_MEM, + "cl image kernel(%s) in/out memory not available", get_kernel_name ()); + + //set args; + args.push_back (new CLMemArgument (image_in)); + args.push_back (new CLMemArgument (image_out)); + args.push_back (new CLArgumentT<uint32_t> (_current_layer)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 8; + work_size.local[1] = 8; + work_size.global[0] = XCAM_ALIGN_UP (cl_width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (cl_height, work_size.local[1]); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLWaveletNoiseEstimateKernel::estimate_noise_variance (const VideoBufferInfo & video_info, SmartPtr<CLImage> image, float* noise_var) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + SmartPtr<CLEvent> map_event = new CLEvent; + void *buf_ptr = NULL; + + CLImageDesc cl_desc = image->get_image_desc (); + uint32_t cl_width = XCAM_ALIGN_UP (cl_desc.width, 2); + uint32_t cl_height = XCAM_ALIGN_UP (cl_desc.height, 2); + + uint32_t image_width = cl_width << 2; + uint32_t image_height = cl_height; + + size_t origin[3] = {0, 0, 0}; + size_t row_pitch = cl_desc.row_pitch; + size_t slice_pitch = 0; + size_t region[3] = {cl_width, cl_height, 1}; + + ret = image->enqueue_map (buf_ptr, + origin, region, + &row_pitch, &slice_pitch, + CL_MAP_READ, + CLEvent::EmptyList, + map_event); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("wavelet noise variance buffer enqueue map failed"); + } + XCAM_ASSERT (map_event->get_event_id ()); + + ret = map_event->wait (); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("wavelet noise variance buffer enqueue map event wait failed"); + } + + uint8_t* pixel = (uint8_t*)buf_ptr; + uint32_t pixel_count = image_width * image_height; + uint32_t pixel_sum = 0; + + uint32_t median_thresh = pixel_count >> 1; + float median = 0; + float noise_std_deviation = 0; + + uint32_t hist_bin_count = 1 << video_info.color_bits; + uint32_t hist_y[128] = {0}; + uint32_t hist_u[128] = {0}; + uint32_t hist_v[128] = {0}; + + if (_channel == CL_IMAGE_CHANNEL_Y) { + for (uint32_t i = 0; i < image_width; i++) { + for (uint32_t j = 0; j < image_height; j++) { + uint8_t base = (pixel[i + j * row_pitch] <= 127) ? 127 : 128; + hist_y[abs(pixel[i + j * row_pitch] - base)]++; + } + } + pixel_sum = 0; + median = 0; + for (uint32_t i = 0; i < (hist_bin_count - 1); i++) { + pixel_sum += hist_y[i]; + if (pixel_sum >= median_thresh) { + median = i; + break; + } + } + noise_std_deviation = median / 0.6745; + noise_var[0] = noise_std_deviation * noise_std_deviation; + } + if (_channel == CL_IMAGE_CHANNEL_UV) { + for (uint32_t i = 0; i < (image_width / 2); i++) { + for (uint32_t j = 0; j < image_height; j++) { + uint8_t base = (pixel[2 * i + j * row_pitch] <= 127) ? 127 : 128; + hist_u[abs(pixel[2 * i + j * row_pitch] - base)]++; + base = (pixel[2 * i + 1 + j * row_pitch] <= 127) ? 127 : 128; + hist_v[abs(pixel[2 * i + 1 + j * row_pitch] - base)]++; + } + } + pixel_sum = 0; + median = 0; + for (uint32_t i = 0; i < (hist_bin_count - 1); i++) { + pixel_sum += hist_u[i]; + if (pixel_sum >= median_thresh >> 1) { + median = i; + break; + } + } + noise_std_deviation = median / 0.6745; + noise_var[1] = noise_std_deviation * noise_std_deviation; + + pixel_sum = 0; + median = 0; + for (uint32_t i = 0; i < (hist_bin_count - 1); i++) { + pixel_sum += hist_v[i]; + if (pixel_sum >= median_thresh >> 1) { + median = i; + break; + } + } + noise_std_deviation = median / 0.6745; + noise_var[2] = noise_std_deviation * noise_std_deviation; + } + + map_event.release (); + + SmartPtr<CLEvent> unmap_event = new CLEvent; + ret = image->enqueue_unmap (buf_ptr, CLEvent::EmptyList, unmap_event); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("wavelet noise variance buffer enqueue unmap failed"); + } + XCAM_ASSERT (unmap_event->get_event_id ()); + + ret = unmap_event->wait (); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("wavelet noise variance buffer enqueue unmap event wait failed"); + } + unmap_event.release (); + + return ret; +} + +CLWaveletThresholdingKernel::CLWaveletThresholdingKernel ( + const SmartPtr<CLContext> &context, + const char *name, + SmartPtr<CLNewWaveletDenoiseImageHandler> &handler, + uint32_t channel, + uint32_t layer) + : CLImageKernel (context, name, true) + , _decomposition_levels (WAVELET_DECOMPOSITION_LEVELS) + , _channel (channel) + , _current_layer (layer) + , _handler (handler) +{ +} + +XCamReturn +CLWaveletThresholdingKernel::prepare_arguments ( + CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + float noise_variance[2]; + + xcam_mem_clear (noise_variance); + _decomposition_levels = WAVELET_DECOMPOSITION_LEVELS; + float soft_threshold = _handler->get_denoise_config ().threshold[0]; + float hard_threshold = _handler->get_denoise_config ().threshold[1]; + float anolog_gain_weight = 1.0 + 100 * _handler->get_denoise_config ().analog_gain; + + SmartPtr<CLWaveletDecompBuffer> buffer; + buffer = _handler->get_decomp_buffer (_channel, _current_layer); + + CLImageDesc cl_desc = buffer->ll->get_image_desc (); + + float weight = 4; + if (_channel == CL_IMAGE_CHANNEL_Y) { + noise_variance[0] = buffer->noise_variance[0] * weight; + noise_variance[1] = buffer->noise_variance[0] * weight; + } else { + noise_variance[0] = buffer->noise_variance[1] * weight; + noise_variance[1] = buffer->noise_variance[2] * weight; + } +#if 0 + { + SmartPtr<CLImage> save_image = buffer->hh[0]; + _handler->dump_coeff (save_image, _channel, _current_layer, CL_WAVELET_SUBBAND_HH); + } +#endif + if (_channel == CL_IMAGE_CHANNEL_Y) { + args.push_back (new CLArgumentT<float> (noise_variance[0])); + args.push_back (new CLArgumentT<float> (noise_variance[0])); + } else { + args.push_back (new CLArgumentT<float> (noise_variance[0])); + args.push_back (new CLArgumentT<float> (noise_variance[1])); + } + + args.push_back (new CLMemArgument (buffer->hl[0])); + args.push_back (new CLMemArgument (buffer->hl[1])); + args.push_back (new CLMemArgument (buffer->hl[2])); + + args.push_back (new CLMemArgument (buffer->lh[0])); + args.push_back (new CLMemArgument (buffer->lh[1])); + args.push_back (new CLMemArgument (buffer->lh[2])); + + args.push_back (new CLMemArgument (buffer->hh[0])); + args.push_back (new CLMemArgument (buffer->hh[1])); + args.push_back (new CLMemArgument (buffer->hh[2])); + + args.push_back (new CLArgumentT<uint32_t> (_current_layer)); + args.push_back (new CLArgumentT<uint32_t> (_decomposition_levels)); + args.push_back (new CLArgumentT<float> (hard_threshold)); + args.push_back (new CLArgumentT<float> (soft_threshold)); + args.push_back (new CLArgumentT<float> (anolog_gain_weight)); + + uint32_t cl_width = XCAM_ALIGN_UP (cl_desc.width, 2); + uint32_t cl_height = XCAM_ALIGN_UP (cl_desc.height, 2); + + //set args; + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 8; + work_size.local[1] = 4; + work_size.global[0] = XCAM_ALIGN_UP (cl_width , work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (cl_height, work_size.local[1]); + + return XCAM_RETURN_NO_ERROR; +} + +CLWaveletTransformKernel::CLWaveletTransformKernel ( + const SmartPtr<CLContext> &context, + const char *name, + SmartPtr<CLNewWaveletDenoiseImageHandler> &handler, + CLWaveletFilterBank fb, + uint32_t channel, + uint32_t layer, + bool bayes_shrink) + : CLImageKernel (context, name, true) + , _filter_bank (fb) + , _decomposition_levels (WAVELET_DECOMPOSITION_LEVELS) + , _channel (channel) + , _current_layer (layer) + , _bayes_shrink (bayes_shrink) + , _handler (handler) +{ +} + +XCamReturn +CLWaveletTransformKernel::prepare_arguments ( + CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<VideoBuffer> input = _handler->get_input_buf (); + SmartPtr<VideoBuffer> output = _handler->get_output_buf (); + SmartPtr<CLContext> context = get_context (); + + const VideoBufferInfo & video_info_in = input->get_video_info (); + const VideoBufferInfo & video_info_out = output->get_video_info (); + + _decomposition_levels = WAVELET_DECOMPOSITION_LEVELS; + float soft_threshold = _handler->get_denoise_config ().threshold[0]; + float hard_threshold = _handler->get_denoise_config ().threshold[1]; + + CLImageDesc cl_desc_in, cl_desc_out; + cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc_in.format.image_channel_order = CL_RGBA; + cl_desc_in.width = XCAM_ALIGN_UP (video_info_in.width, 4) / 4; + cl_desc_in.height = video_info_in.height; + cl_desc_in.row_pitch = video_info_in.strides[0]; + + cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc_out.format.image_channel_order = CL_RGBA; + cl_desc_out.width = XCAM_ALIGN_UP (video_info_out.width, 4) / 4; + cl_desc_out.height = video_info_out.height; + cl_desc_out.row_pitch = video_info_out.strides[0]; + + SmartPtr<CLImage> image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]); + SmartPtr<CLImage> image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[0]); + + cl_desc_in.height = XCAM_ALIGN_UP (video_info_in.height, 2) / 2; + cl_desc_in.row_pitch = video_info_in.strides[1]; + + cl_desc_out.height = XCAM_ALIGN_UP (video_info_out.height, 2) / 2; + cl_desc_out.row_pitch = video_info_out.strides[1]; + + SmartPtr<CLImage> image_in_uv = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[1]); + SmartPtr<CLImage> image_out_uv = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[1]); + + XCAM_FAIL_RETURN ( + WARNING, + image_in->is_valid () && image_in_uv->is_valid () && + image_out->is_valid () && image_out_uv->is_valid(), + XCAM_RETURN_ERROR_MEM, + "cl image kernel(%s) in/out memory not available", get_kernel_name ()); + + //set args; + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 8; + work_size.local[1] = 4; + if (_channel == CL_IMAGE_CHANNEL_Y) { + work_size.global[0] = XCAM_ALIGN_UP ((video_info_in.width >> _current_layer) / 4 , work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (video_info_in.height >> _current_layer, work_size.local[1]); + } else if (_channel == CL_IMAGE_CHANNEL_UV) { + work_size.global[0] = XCAM_ALIGN_UP ((video_info_in.width >> _current_layer) / 4 , work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (video_info_in.height >> (_current_layer + 1), work_size.local[1]); + } + + SmartPtr<CLWaveletDecompBuffer> buffer; + if (_current_layer == 1) { + if (_filter_bank == CL_WAVELET_HAAR_ANALYSIS) { + if (_channel == CL_IMAGE_CHANNEL_Y) { + args.push_back (new CLMemArgument (image_in)); + } else if (_channel == CL_IMAGE_CHANNEL_UV) { + args.push_back (new CLMemArgument (image_in_uv)); + } + } else if (_filter_bank == CL_WAVELET_HAAR_SYNTHESIS) { + if (_channel == CL_IMAGE_CHANNEL_Y) { + args.push_back (new CLMemArgument (image_out)); + } else if (_channel == CL_IMAGE_CHANNEL_UV) { + args.push_back (new CLMemArgument (image_out_uv)); + } + } + } else { + buffer = get_decomp_buffer (_channel, _current_layer - 1); + args.push_back (new CLMemArgument (buffer->ll)); + } + + buffer = get_decomp_buffer (_channel, _current_layer); + args.push_back (new CLMemArgument (buffer->ll)); + + if (_bayes_shrink == true) { + if (_filter_bank == CL_WAVELET_HAAR_ANALYSIS) { + args.push_back (new CLMemArgument (buffer->hl[0])); + args.push_back (new CLMemArgument (buffer->lh[0])); + args.push_back (new CLMemArgument (buffer->hh[0])); + } else if (_filter_bank == CL_WAVELET_HAAR_SYNTHESIS) { + args.push_back (new CLMemArgument (buffer->hl[2])); + args.push_back (new CLMemArgument (buffer->lh[2])); + args.push_back (new CLMemArgument (buffer->hh[2])); + } + } else { + args.push_back (new CLMemArgument (buffer->hl[0])); + args.push_back (new CLMemArgument (buffer->lh[0])); + args.push_back (new CLMemArgument (buffer->hh[0])); + } + + args.push_back (new CLArgumentT<uint32_t> (_current_layer)); + args.push_back (new CLArgumentT<uint32_t> (_decomposition_levels)); + args.push_back (new CLArgumentT<float> (hard_threshold)); + args.push_back (new CLArgumentT<float> (soft_threshold)); + + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<CLWaveletDecompBuffer> +CLWaveletTransformKernel::get_decomp_buffer (uint32_t channel, int layer) +{ + SmartPtr<CLWaveletDecompBuffer> buffer; + if (_handler.ptr ()) { + buffer = _handler->get_decomp_buffer (channel, layer); + } + + if (!buffer.ptr ()) { + XCAM_LOG_ERROR ("get channel(%d) layer(%d) decomposition buffer failed!", channel, layer); + } + XCAM_ASSERT (buffer.ptr ()); + return buffer; +} + +CLNewWaveletDenoiseImageHandler::CLNewWaveletDenoiseImageHandler ( + const SmartPtr<CLContext> &context, const char *name, uint32_t channel) + : CLImageHandler (context, name) + , _channel (channel) +{ + _config.decomposition_levels = 5; + _config.threshold[0] = 0.5; + _config.threshold[1] = 5.0; + xcam_mem_clear (_noise_variance); +} + +XCamReturn +CLNewWaveletDenoiseImageHandler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + CLImageHandler::prepare_output_buf(input, output); + + SmartPtr<CLContext> context = get_context (); + const VideoBufferInfo & video_info = input->get_video_info (); + CLImageDesc cl_desc; + SmartPtr<CLWaveletDecompBuffer> decompBuffer; + + CLImage::video_info_2_cl_image_desc (video_info, cl_desc); + + _decompBufferList.clear (); + + if (_channel & CL_IMAGE_CHANNEL_Y) { + for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { + decompBuffer = new CLWaveletDecompBuffer (); + if (decompBuffer.ptr ()) { + decompBuffer->width = XCAM_ALIGN_UP (video_info.width, 1 << layer) >> layer; + decompBuffer->height = XCAM_ALIGN_UP (video_info.height, 1 << layer) >> layer; + decompBuffer->width = XCAM_ALIGN_UP (decompBuffer->width, 4); + decompBuffer->height = XCAM_ALIGN_UP (decompBuffer->height, 2); + + decompBuffer->channel = CL_IMAGE_CHANNEL_Y; + decompBuffer->layer = layer; + decompBuffer->noise_variance[0] = 0; + + cl_desc.width = decompBuffer->width / 4; + cl_desc.height = decompBuffer->height; + cl_desc.slice_pitch = 0; + cl_desc.format.image_channel_order = CL_RGBA; + cl_desc.format.image_channel_data_type = CL_UNORM_INT8; + + decompBuffer->ll = new CLImage2D (context, cl_desc); + + decompBuffer->hl[0] = new CLImage2D (context, cl_desc); + decompBuffer->lh[0] = new CLImage2D (context, cl_desc); + decompBuffer->hh[0] = new CLImage2D (context, cl_desc); + /* + uint32_t width = decompBuffer->width / 4; + uint32_t height = decompBuffer->height; + SmartPtr<CLBuffer> hh_buffer = new CLBuffer ( + context, sizeof(uint8_t) * width * height, + CL_MEM_READ_WRITE, NULL); + CLImageDesc hh_desc; + hh_desc.format = {CL_RGBA, CL_UNORM_INT8}; + hh_desc.width = width; + hh_desc.height = height; + hh_desc.row_pitch = sizeof(uint8_t) * width; + hh_desc.slice_pitch = 0; + hh_desc.size = 0; + hh_desc.array_size = 0; + + decompBuffer->hh[0] = new CLImage2D ( + context, hh_desc, 0, hh_buffer); + */ + + cl_desc.format.image_channel_data_type = CL_UNORM_INT16; + decompBuffer->hl[1] = new CLImage2D (context, cl_desc); + decompBuffer->lh[1] = new CLImage2D (context, cl_desc); + decompBuffer->hh[1] = new CLImage2D (context, cl_desc); + + cl_desc.format.image_channel_data_type = CL_UNORM_INT8; + decompBuffer->hl[2] = new CLImage2D (context, cl_desc); + decompBuffer->lh[2] = new CLImage2D (context, cl_desc); + decompBuffer->hh[2] = new CLImage2D (context, cl_desc); + + _decompBufferList.push_back (decompBuffer); + } else { + XCAM_LOG_ERROR ("create Y decomposition buffer failed!"); + ret = XCAM_RETURN_ERROR_MEM; + } + } + } + + if (_channel & CL_IMAGE_CHANNEL_UV) { + for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { + decompBuffer = new CLWaveletDecompBuffer (); + if (decompBuffer.ptr ()) { + decompBuffer->width = XCAM_ALIGN_UP (video_info.width, 1 << layer) >> layer; + decompBuffer->height = XCAM_ALIGN_UP (video_info.height, 1 << (layer + 1)) >> (layer + 1); + decompBuffer->width = XCAM_ALIGN_UP (decompBuffer->width, 4); + decompBuffer->height = XCAM_ALIGN_UP (decompBuffer->height, 2); + + decompBuffer->channel = CL_IMAGE_CHANNEL_UV; + decompBuffer->layer = layer; + decompBuffer->noise_variance[1] = 0; + decompBuffer->noise_variance[2] = 0; + + cl_desc.width = decompBuffer->width / 4; + cl_desc.height = decompBuffer->height; + cl_desc.slice_pitch = 0; + cl_desc.format.image_channel_order = CL_RGBA; + cl_desc.format.image_channel_data_type = CL_UNORM_INT8; + + decompBuffer->ll = new CLImage2D (context, cl_desc); + + decompBuffer->hl[0] = new CLImage2D (context, cl_desc); + decompBuffer->lh[0] = new CLImage2D (context, cl_desc); + decompBuffer->hh[0] = new CLImage2D (context, cl_desc); + /* + uint32_t width = decompBuffer->width / 4; + uint32_t height = decompBuffer->height; + SmartPtr<CLBuffer> hh_buffer = new CLBuffer ( + context, sizeof(uint8_t) * width * height, + CL_MEM_READ_WRITE, NULL); + CLImageDesc hh_desc; + hh_desc.format = {CL_RGBA, CL_UNORM_INT8}; + hh_desc.width = width; + hh_desc.height = height; + hh_desc.row_pitch = sizeof(uint8_t) * width; + hh_desc.slice_pitch = 0; + hh_desc.size = 0; + hh_desc.array_size = 0; + decompBuffer->hh[0] = new CLImage2D ( + context, hh_desc, 0, hh_buffer); + */ + cl_desc.format.image_channel_data_type = CL_UNORM_INT16; + decompBuffer->hl[1] = new CLImage2D (context, cl_desc); + decompBuffer->lh[1] = new CLImage2D (context, cl_desc); + decompBuffer->hh[1] = new CLImage2D (context, cl_desc); + + cl_desc.format.image_channel_data_type = CL_UNORM_INT8; + decompBuffer->hl[2] = new CLImage2D (context, cl_desc); + decompBuffer->lh[2] = new CLImage2D (context, cl_desc); + decompBuffer->hh[2] = new CLImage2D (context, cl_desc); + + _decompBufferList.push_back (decompBuffer); + } else { + XCAM_LOG_ERROR ("create UV decomposition buffer failed!"); + ret = XCAM_RETURN_ERROR_MEM; + } + } + } + return ret; +} + +bool +CLNewWaveletDenoiseImageHandler::set_denoise_config (const XCam3aResultWaveletNoiseReduction& config) +{ + _config = config; + + return true; +} + +SmartPtr<CLWaveletDecompBuffer> +CLNewWaveletDenoiseImageHandler::get_decomp_buffer (uint32_t channel, int layer) +{ + SmartPtr<CLWaveletDecompBuffer> buffer; + + for (CLWaveletDecompBufferList::iterator it = _decompBufferList.begin (); + it != _decompBufferList.end (); ++it) { + if ((channel == (*it)->channel) && (layer == (*it)->layer)) + buffer = (*it); + } + return buffer; +} + +void +CLNewWaveletDenoiseImageHandler::set_estimated_noise_variation (float* noise_var) +{ + if (noise_var == NULL) { + XCAM_LOG_ERROR ("invalid input noise variation!"); + return; + } + _noise_variance[0] = noise_var[0]; + _noise_variance[1] = noise_var[1]; + _noise_variance[2] = noise_var[2]; +} + +void +CLNewWaveletDenoiseImageHandler::get_estimated_noise_variation (float* noise_var) +{ + if (noise_var == NULL) { + XCAM_LOG_ERROR ("invalid output parameters!"); + return; + } + noise_var[0] = _noise_variance[0]; + noise_var[1] = _noise_variance[1]; + noise_var[2] = _noise_variance[2]; +} + +void +CLNewWaveletDenoiseImageHandler::dump_coeff (SmartPtr<CLImage> image, uint32_t channel, uint32_t layer, uint32_t subband) +{ + FILE *file; + + void *buf_ptr = NULL; + SmartPtr<CLEvent> map_event = new CLEvent; + + CLImageDesc cl_desc = image->get_image_desc (); + + uint32_t cl_width = XCAM_ALIGN_UP (cl_desc.width, 2); + uint32_t cl_height = XCAM_ALIGN_UP (cl_desc.height, 2); + + size_t origin[3] = {0, 0, 0}; + size_t row_pitch = cl_desc.row_pitch; + size_t slice_pitch = 0; + size_t region[3] = {cl_width, cl_height, 1}; + + image->enqueue_map (buf_ptr, + origin, region, + &row_pitch, &slice_pitch, + CL_MAP_READ, + CLEvent::EmptyList, + map_event); + XCAM_ASSERT (map_event->get_event_id ()); + + map_event->wait (); + + uint8_t* pixel = (uint8_t*)buf_ptr; + uint32_t pixel_count = row_pitch * cl_height; + + char file_name[512]; + snprintf (file_name, sizeof(file_name), + "wavelet_cl_coeff_" + "channel%d_" + "layer%d_" + "subband%d_" + "rowpitch%d_" + "width%dxheight%d" + ".raw", + channel, layer, subband, (uint32_t)row_pitch, cl_width, cl_height); + file = fopen(file_name, "wb"); + + if (file != NULL) { + if (fwrite (pixel, pixel_count, 1, file) <= 0) { + XCAM_LOG_WARNING ("write frame failed."); + } + fclose (file); + } + map_event.release (); + + SmartPtr<CLEvent> unmap_event = new CLEvent; + image->enqueue_unmap (buf_ptr, CLEvent::EmptyList, unmap_event); + XCAM_ASSERT (unmap_event->get_event_id ()); + + unmap_event->wait (); + unmap_event.release (); +} + +static SmartPtr<CLWaveletTransformKernel> +create_kernel_haar_decomposition ( + const SmartPtr<CLContext> &context, + SmartPtr<CLNewWaveletDenoiseImageHandler> handler, + uint32_t channel, + uint32_t layer, + bool bayes_shrink) +{ + SmartPtr<CLWaveletTransformKernel> haar_decomp_kernel; + + char build_options[1024]; + xcam_mem_clear (build_options); + + snprintf (build_options, sizeof (build_options), + " -DWAVELET_DENOISE_Y=%d " + " -DWAVELET_DENOISE_UV=%d ", + (channel == CL_IMAGE_CHANNEL_Y ? 1 : 0), + (channel == CL_IMAGE_CHANNEL_UV ? 1 : 0)); + + haar_decomp_kernel = new CLWaveletTransformKernel (context, "kernel_wavelet_haar_decomposition", + handler, CL_WAVELET_HAAR_ANALYSIS, channel, layer, bayes_shrink); + + XCAM_ASSERT (haar_decomp_kernel.ptr ()); + XCAM_FAIL_RETURN ( + WARNING, + haar_decomp_kernel->build_kernel (kernel_new_wavelet_info[KernelWaveletDecompose], build_options) == XCAM_RETURN_NO_ERROR, + NULL, + "wavelet denoise build kernel(%s) failed", kernel_new_wavelet_info[KernelWaveletDecompose].kernel_name); + XCAM_ASSERT (haar_decomp_kernel->is_valid ()); + + return haar_decomp_kernel; +} + +static SmartPtr<CLWaveletTransformKernel> +create_kernel_haar_reconstruction ( + const SmartPtr<CLContext> &context, + SmartPtr<CLNewWaveletDenoiseImageHandler> handler, + uint32_t channel, + uint32_t layer, + bool bayes_shrink) +{ + SmartPtr<CLWaveletTransformKernel> haar_reconstruction_kernel; + + char build_options[1024]; + xcam_mem_clear (build_options); + snprintf (build_options, sizeof (build_options), + " -DWAVELET_DENOISE_Y=%d " + " -DWAVELET_DENOISE_UV=%d " + " -DWAVELET_BAYES_SHRINK=%d", + (channel == CL_IMAGE_CHANNEL_Y ? 1 : 0), + (channel == CL_IMAGE_CHANNEL_UV ? 1 : 0), + (bayes_shrink == true ? 1 : 0)); + + haar_reconstruction_kernel = new CLWaveletTransformKernel (context, "kernel_wavelet_haar_reconstruction", + handler, CL_WAVELET_HAAR_SYNTHESIS, channel, layer, bayes_shrink); + + XCAM_ASSERT (haar_reconstruction_kernel.ptr ()); + XCAM_FAIL_RETURN ( + WARNING, + haar_reconstruction_kernel->build_kernel (kernel_new_wavelet_info[KernelWaveletReconstruct], build_options) == XCAM_RETURN_NO_ERROR, + NULL, + "wavelet denoise build kernel(%s) failed", kernel_new_wavelet_info[KernelWaveletReconstruct].kernel_name); + XCAM_ASSERT (haar_reconstruction_kernel->is_valid ()); + + return haar_reconstruction_kernel; +} + +static SmartPtr<CLWaveletNoiseEstimateKernel> +create_kernel_noise_estimation ( + const SmartPtr<CLContext> &context, + SmartPtr<CLNewWaveletDenoiseImageHandler> handler, + uint32_t channel, uint32_t subband, uint32_t layer) +{ + SmartPtr<CLWaveletNoiseEstimateKernel> estimation_kernel; + + char build_options[1024]; + xcam_mem_clear (build_options); + + snprintf (build_options, sizeof (build_options), + " -DWAVELET_DENOISE_Y=%d " + " -DWAVELET_DENOISE_UV=%d ", + (channel == CL_IMAGE_CHANNEL_Y ? 1 : 0), + (channel == CL_IMAGE_CHANNEL_UV ? 1 : 0)); + + estimation_kernel = new CLWaveletNoiseEstimateKernel ( + context, "kernel_wavelet_coeff_variance", handler, channel, subband, layer); + XCAM_ASSERT (estimation_kernel.ptr ()); + XCAM_FAIL_RETURN ( + WARNING, + estimation_kernel->build_kernel (kernel_new_wavelet_info[KernelWaveletNoiseEstimate], build_options) == XCAM_RETURN_NO_ERROR, + NULL, + "wavelet denoise build kernel(%s) failed", kernel_new_wavelet_info[KernelWaveletNoiseEstimate].kernel_name); + XCAM_ASSERT (estimation_kernel->is_valid ()); + + return estimation_kernel; +} + +static SmartPtr<CLWaveletThresholdingKernel> +create_kernel_thresholding ( + const SmartPtr<CLContext> &context, + SmartPtr<CLNewWaveletDenoiseImageHandler> handler, + uint32_t channel, uint32_t layer) +{ + SmartPtr<CLWaveletThresholdingKernel> threshold_kernel; + + char build_options[1024]; + xcam_mem_clear (build_options); + + snprintf (build_options, sizeof (build_options), + " -DWAVELET_DENOISE_Y=%d " + " -DWAVELET_DENOISE_UV=%d ", + (channel == CL_IMAGE_CHANNEL_Y ? 1 : 0), + (channel == CL_IMAGE_CHANNEL_UV ? 1 : 0)); + + threshold_kernel = new CLWaveletThresholdingKernel (context, + "kernel_wavelet_coeff_thresholding", + handler, channel, layer); + XCAM_ASSERT (threshold_kernel.ptr ()); + XCAM_FAIL_RETURN ( + WARNING, + threshold_kernel->build_kernel (kernel_new_wavelet_info[KernelWaveletThreshold], build_options) == XCAM_RETURN_NO_ERROR, + NULL, + "wavelet denoise build kernel(%s) failed", kernel_new_wavelet_info[KernelWaveletThreshold].kernel_name); + XCAM_ASSERT (threshold_kernel->is_valid ()); + + return threshold_kernel; +} + +SmartPtr<CLImageHandler> +create_cl_newwavelet_denoise_image_handler ( + const SmartPtr<CLContext> &context, uint32_t channel, bool bayes_shrink) +{ + SmartPtr<CLNewWaveletDenoiseImageHandler> wavelet_handler; + SmartPtr<CLWaveletTransformKernel> haar_decomposition_kernel; + SmartPtr<CLWaveletTransformKernel> haar_reconstruction_kernel; + + wavelet_handler = new CLNewWaveletDenoiseImageHandler (context, "cl_newwavelet_denoise_handler", channel); + XCAM_ASSERT (wavelet_handler.ptr ()); + + if (channel & CL_IMAGE_CHANNEL_Y) { + for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { + SmartPtr<CLImageKernel> image_kernel = + create_kernel_haar_decomposition (context, wavelet_handler, CL_IMAGE_CHANNEL_Y, layer, bayes_shrink); + wavelet_handler->add_kernel (image_kernel); + } + + if (bayes_shrink) { + for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { + SmartPtr<CLImageKernel> image_kernel; + + image_kernel = create_kernel_noise_estimation (context, wavelet_handler, + CL_IMAGE_CHANNEL_Y, CL_WAVELET_SUBBAND_HH, layer); + wavelet_handler->add_kernel (image_kernel); + + image_kernel = create_kernel_noise_estimation (context, wavelet_handler, + CL_IMAGE_CHANNEL_Y, CL_WAVELET_SUBBAND_LH, layer); + wavelet_handler->add_kernel (image_kernel); + + image_kernel = create_kernel_noise_estimation (context, wavelet_handler, + CL_IMAGE_CHANNEL_Y, CL_WAVELET_SUBBAND_HL, layer); + wavelet_handler->add_kernel (image_kernel); + } + for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { + SmartPtr<CLImageKernel> image_kernel; + image_kernel = create_kernel_thresholding (context, wavelet_handler, CL_IMAGE_CHANNEL_Y, layer); + wavelet_handler->add_kernel (image_kernel); + } + } + + for (int layer = WAVELET_DECOMPOSITION_LEVELS; layer >= 1; layer--) { + SmartPtr<CLImageKernel> image_kernel = + create_kernel_haar_reconstruction (context, wavelet_handler, CL_IMAGE_CHANNEL_Y, layer, bayes_shrink); + wavelet_handler->add_kernel (image_kernel); + } + } + + if (channel & CL_IMAGE_CHANNEL_UV) { + for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { + SmartPtr<CLImageKernel> image_kernel = + create_kernel_haar_decomposition (context, wavelet_handler, CL_IMAGE_CHANNEL_UV, layer, bayes_shrink); + wavelet_handler->add_kernel (image_kernel); + } + + if (bayes_shrink) { + for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { + SmartPtr<CLImageKernel> image_kernel; + + image_kernel = create_kernel_noise_estimation (context, wavelet_handler, + CL_IMAGE_CHANNEL_UV, CL_WAVELET_SUBBAND_HH, layer); + wavelet_handler->add_kernel (image_kernel); + + image_kernel = create_kernel_noise_estimation (context, wavelet_handler, + CL_IMAGE_CHANNEL_UV, CL_WAVELET_SUBBAND_LH, layer); + wavelet_handler->add_kernel (image_kernel); + + image_kernel = create_kernel_noise_estimation (context, wavelet_handler, + CL_IMAGE_CHANNEL_UV, CL_WAVELET_SUBBAND_HL, layer); + wavelet_handler->add_kernel (image_kernel); + } + for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { + SmartPtr<CLImageKernel> image_kernel; + image_kernel = create_kernel_thresholding (context, wavelet_handler, CL_IMAGE_CHANNEL_UV, layer); + wavelet_handler->add_kernel (image_kernel); + } + } + + for (int layer = WAVELET_DECOMPOSITION_LEVELS; layer >= 1; layer--) { + SmartPtr<CLImageKernel> image_kernel = + create_kernel_haar_reconstruction (context, wavelet_handler, CL_IMAGE_CHANNEL_UV, layer, bayes_shrink); + wavelet_handler->add_kernel (image_kernel); + } + } + + return wavelet_handler; +} + +}; diff --git a/modules/ocl/cl_newwavelet_denoise_handler.h b/modules/ocl/cl_newwavelet_denoise_handler.h new file mode 100644 index 0000000..d09e6e2 --- /dev/null +++ b/modules/ocl/cl_newwavelet_denoise_handler.h @@ -0,0 +1,192 @@ +/* + * cl_newwavelet_denoise_handler.h - CL wavelet denoise handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wei Zong <wei.zong@intel.com> + */ + +#ifndef XCAM_CL_NEWWAVELET_DENOISE_HANLDER_H +#define XCAM_CL_NEWWAVELET_DENOISE_HANLDER_H + +#include <xcam_std.h> +#include <ocl/cl_image_handler.h> +#include <base/xcam_3a_result.h> + +namespace XCam { + +enum CLWaveletFilterBank { + CL_WAVELET_HAAR_ANALYSIS = 0, + CL_WAVELET_HAAR_SYNTHESIS = 1, +}; + +enum CLWaveletSubband { + CL_WAVELET_SUBBAND_LL = 0, + CL_WAVELET_SUBBAND_HL, + CL_WAVELET_SUBBAND_LH, + CL_WAVELET_SUBBAND_HH, +}; + +/*------------------------ + Wavelet decomposition + frequency block + + __ width__ + ___________________ + | | | | + | | | | + | LL | HL |height + | | | | + |_________|_________| | + | | | + | | | + | LH | HH | + | | | + |_________|_________| +--------------------------*/ +typedef struct _CLCLWaveletDecompBuffer { + int32_t width; + int32_t height; + uint32_t channel; + int32_t layer; + float noise_variance[3]; + SmartPtr<CLImage> ll; + SmartPtr<CLImage> hl[3]; + SmartPtr<CLImage> lh[3]; + SmartPtr<CLImage> hh[3]; +} CLWaveletDecompBuffer; + +class CLNewWaveletDenoiseImageHandler; + +class CLWaveletNoiseEstimateKernel + : public CLImageKernel +{ + +public: + explicit CLWaveletNoiseEstimateKernel ( + const SmartPtr<CLContext> &context, + const char *name, + SmartPtr<CLNewWaveletDenoiseImageHandler> &handler, + uint32_t channel, uint32_t subband, uint32_t layer); + + SmartPtr<CLImage> get_input_buffer (); + SmartPtr<CLImage> get_output_buffer (); + + XCamReturn estimate_noise_variance (const VideoBufferInfo & video_info, SmartPtr<CLImage> image, float* noise_var); + +protected: + virtual XCamReturn prepare_arguments ( + CLArgList &args, CLWorkSize &work_size); + +private: + uint32_t _decomposition_levels; + uint32_t _channel; + uint32_t _subband; + uint32_t _current_layer; + float _analog_gain; + + SmartPtr<CLNewWaveletDenoiseImageHandler> _handler; +}; + +class CLWaveletThresholdingKernel + : public CLImageKernel +{ + +public: + explicit CLWaveletThresholdingKernel ( + const SmartPtr<CLContext> &context, + const char *name, + SmartPtr<CLNewWaveletDenoiseImageHandler> &handler, + uint32_t channel, uint32_t layer); + +protected: + virtual XCamReturn prepare_arguments ( + CLArgList &args, CLWorkSize &work_size); + +private: + uint32_t _decomposition_levels; + uint32_t _channel; + uint32_t _current_layer; + SmartPtr<CLNewWaveletDenoiseImageHandler> _handler; +}; + +class CLWaveletTransformKernel + : public CLImageKernel +{ + +public: + explicit CLWaveletTransformKernel ( + const SmartPtr<CLContext> &context, + const char *name, + SmartPtr<CLNewWaveletDenoiseImageHandler> &handler, + CLWaveletFilterBank fb, + uint32_t channel, + uint32_t layer, + bool bayes_shrink); + + SmartPtr<CLWaveletDecompBuffer> get_decomp_buffer (uint32_t channel, int layer); + +protected: + virtual XCamReturn prepare_arguments ( + CLArgList &args, CLWorkSize &work_size); + +private: + CLWaveletFilterBank _filter_bank; + uint32_t _decomposition_levels; + uint32_t _channel; + uint32_t _current_layer; + bool _bayes_shrink; + + SmartPtr<CLNewWaveletDenoiseImageHandler> _handler; +}; + +class CLNewWaveletDenoiseImageHandler + : public CLImageHandler +{ + typedef std::list<SmartPtr<CLWaveletDecompBuffer>> CLWaveletDecompBufferList; + +public: + explicit CLNewWaveletDenoiseImageHandler ( + const SmartPtr<CLContext> &context, const char *name, uint32_t channel); + + bool set_denoise_config (const XCam3aResultWaveletNoiseReduction& config); + XCam3aResultWaveletNoiseReduction& get_denoise_config () { + return _config; + }; + + SmartPtr<CLWaveletDecompBuffer> get_decomp_buffer (uint32_t channel, int layer); + + void set_estimated_noise_variation (float* noise_var); + void get_estimated_noise_variation (float* noise_var); + + void dump_coeff (SmartPtr<CLImage> image, uint32_t channel, uint32_t layer, uint32_t subband); + +protected: + virtual XCamReturn prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + uint32_t _channel; + XCam3aResultWaveletNoiseReduction _config; + CLWaveletDecompBufferList _decompBufferList; + float _noise_variance[3]; +}; + +SmartPtr<CLImageHandler> +create_cl_newwavelet_denoise_image_handler ( + const SmartPtr<CLContext> &context, uint32_t channel, bool bayes_shrink); + +}; + +#endif //XCAM_CL_NEWWAVELET_DENOISE_HANLDER_H diff --git a/modules/ocl/cl_post_image_processor.cpp b/modules/ocl/cl_post_image_processor.cpp new file mode 100644 index 0000000..ebe9319 --- /dev/null +++ b/modules/ocl/cl_post_image_processor.cpp @@ -0,0 +1,543 @@ +/* + * cl_post_image_processor.cpp - CL post image processor + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include "cl_post_image_processor.h" +#include "cl_context.h" + +#include "cl_tnr_handler.h" +#include "cl_retinex_handler.h" +#include "cl_defog_dcp_handler.h" +#include "cl_wavelet_denoise_handler.h" +#include "cl_newwavelet_denoise_handler.h" +#include "cl_3d_denoise_handler.h" +#include "cl_image_scaler.h" +#include "cl_wire_frame_handler.h" +#include "cl_csc_handler.h" +#include "cl_image_warp_handler.h" +#include "cl_image_360_stitch.h" +#include "cl_video_stabilizer.h" + +#define XCAM_CL_POST_IMAGE_DEFAULT_POOL_SIZE 6 +#define XCAM_CL_POST_IMAGE_MAX_POOL_SIZE 12 + +namespace XCam { + +CLPostImageProcessor::CLPostImageProcessor () + : CLImageProcessor ("CLPostImageProcessor") + , _output_fourcc (V4L2_PIX_FMT_NV12) + , _out_sample_type (OutSampleYuv) + , _scaler_factor (1.0) + , _tnr_mode (TnrYuv) + , _defog_mode (CLPostImageProcessor::DefogDisabled) + , _wavelet_basis (CL_WAVELET_DISABLED) + , _wavelet_channel (CL_IMAGE_CHANNEL_UV) + , _wavelet_bayes_shrink (false) + , _3d_denoise_mode (CLPostImageProcessor::Denoise3DDisabled) + , _3d_denoise_ref_count (3) + , _enable_scaler (false) + , _enable_wireframe (false) + , _enable_image_warp (false) + , _enable_stitch (false) + , _stitch_enable_seam (false) + , _stitch_fisheye_map (false) + , _stitch_lsc (false) + , _stitch_fm_ocl (false) + , _stitch_scale_mode (CLBlenderScaleLocal) + , _stitch_width (0) + , _stitch_height (0) + , _stitch_res_mode (0) + , _surround_mode (SphereView) +{ + XCAM_LOG_DEBUG ("CLPostImageProcessor constructed"); +} + +CLPostImageProcessor::~CLPostImageProcessor () +{ + XCAM_LOG_DEBUG ("CLPostImageProcessor destructed"); +} + +bool +CLPostImageProcessor::set_output_format (uint32_t fourcc) +{ + switch (fourcc) { + case XCAM_PIX_FMT_RGBA64: + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_ARGB32: + case V4L2_PIX_FMT_XRGB32: + _out_sample_type = OutSampleRGB; + break; + case V4L2_PIX_FMT_NV12: + _out_sample_type = OutSampleYuv; + break; + default: + XCAM_LOG_WARNING ( + "cl post processor doesn't support output format: %s", + xcam_fourcc_to_string(fourcc)); + return false; + } + + _output_fourcc = fourcc; + return true; +} + +void +CLPostImageProcessor::set_stats_callback (const SmartPtr<StatsCallback> &callback) +{ + XCAM_ASSERT (callback.ptr ()); + _stats_callback = callback; +} + +bool +CLPostImageProcessor::set_scaler_factor (const double factor) +{ + _scaler_factor = factor; + + return true; +} + +bool +CLPostImageProcessor::can_process_result (SmartPtr < X3aResult > & result) +{ + if (!result.ptr ()) + return false; + + switch (result->get_type ()) { + case XCAM_3A_RESULT_TEMPORAL_NOISE_REDUCTION_YUV: + case XCAM_3A_RESULT_3D_NOISE_REDUCTION: + case XCAM_3A_RESULT_WAVELET_NOISE_REDUCTION: + case XCAM_3A_RESULT_FACE_DETECTION: + case XCAM_3A_RESULT_DVS: + return true; + default: + return false; + } + + return false; +} + +XCamReturn +CLPostImageProcessor::apply_3a_results (X3aResultList &results) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + for (X3aResultList::iterator iter = results.begin (); iter != results.end (); ++iter) + { + SmartPtr<X3aResult> &result = *iter; + ret = apply_3a_result (result); + if (ret != XCAM_RETURN_NO_ERROR) + break; + } + + return ret; +} + +XCamReturn +CLPostImageProcessor::apply_3a_result (SmartPtr<X3aResult> &result) +{ + STREAM_LOCK; + + if (!result.ptr ()) + return XCAM_RETURN_BYPASS; + + uint32_t res_type = result->get_type (); + + switch (res_type) { + case XCAM_3A_RESULT_TEMPORAL_NOISE_REDUCTION_YUV: { + SmartPtr<X3aTemporalNoiseReduction> tnr_res = result.dynamic_cast_ptr<X3aTemporalNoiseReduction> (); + XCAM_ASSERT (tnr_res.ptr ()); + if (_tnr.ptr ()) { + if (_defog_mode != CLPostImageProcessor::DefogDisabled) { + XCam3aResultTemporalNoiseReduction config; + xcam_mem_clear (config); + // isp processor + // config.gain = 0.12; + + // cl processor + config.gain = 0.22; + + config.threshold [0] = 0.00081; + config.threshold [1] = 0.00072; + _tnr->set_yuv_config (config); + } else { + _tnr->set_yuv_config (tnr_res->get_standard_result ()); + } + } + break; + } + case XCAM_3A_RESULT_3D_NOISE_REDUCTION: { + SmartPtr<X3aTemporalNoiseReduction> nr_res = result.dynamic_cast_ptr<X3aTemporalNoiseReduction> (); + XCAM_ASSERT (nr_res.ptr ()); + if (_3d_denoise.ptr ()) { + _3d_denoise->set_denoise_config (nr_res->get_standard_result ()); + } + break; + } + case XCAM_3A_RESULT_WAVELET_NOISE_REDUCTION: { + SmartPtr<X3aWaveletNoiseReduction> wavelet_res = result.dynamic_cast_ptr<X3aWaveletNoiseReduction> (); + XCAM_ASSERT (wavelet_res.ptr ()); + if (_wavelet.ptr()) { + _wavelet->set_denoise_config (wavelet_res->get_standard_result ()); + } + if (_newwavelet.ptr()) { + _newwavelet->set_denoise_config (wavelet_res->get_standard_result ()); + } + break; + } + case XCAM_3A_RESULT_FACE_DETECTION: { + SmartPtr<X3aFaceDetectionResult> fd_res = result.dynamic_cast_ptr<X3aFaceDetectionResult> (); + XCAM_ASSERT (fd_res.ptr ()); + if (_wireframe.ptr ()) { + _wireframe->set_wire_frame_config (fd_res->get_standard_result_ptr (), get_scaler_factor ()); + } + break; + } + case XCAM_3A_RESULT_DVS: { + SmartPtr<X3aDVSResult> dvs_res = result.dynamic_cast_ptr<X3aDVSResult> (); + XCAM_ASSERT (dvs_res.ptr ()); + if (_image_warp.ptr ()) { + _image_warp->set_warp_config (dvs_res->get_standard_result ()); + } + break; + } + default: + XCAM_LOG_WARNING ("CLPostImageProcessor unknown 3a result: %d", res_type); + break; + } + + return XCAM_RETURN_NO_ERROR; +} + + +XCamReturn +CLPostImageProcessor::create_handlers () +{ + SmartPtr<CLImageHandler> image_handler; + SmartPtr<CLContext> context = get_cl_context (); + + XCAM_ASSERT (context.ptr ()); + + /* defog: retinex */ + image_handler = create_cl_retinex_image_handler (context); + _retinex = image_handler.dynamic_cast_ptr<CLRetinexImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _retinex.ptr (), + XCAM_RETURN_ERROR_CL, + "CLPostImageProcessor create retinex handler failed"); + _retinex->enable_handler (_defog_mode == CLPostImageProcessor::DefogRetinex); + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + image_handler->set_pool_size (XCAM_CL_POST_IMAGE_MAX_POOL_SIZE); + add_handler (image_handler); + + /* defog: dark channel prior */ + image_handler = create_cl_defog_dcp_image_handler (context); + _defog_dcp = image_handler.dynamic_cast_ptr<CLDefogDcpImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _defog_dcp.ptr (), + XCAM_RETURN_ERROR_CL, + "CLPostImageProcessor create defog handler failed"); + _defog_dcp->enable_handler (_defog_mode == CLPostImageProcessor::DefogDarkChannelPrior); + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + image_handler->set_pool_size (XCAM_CL_POST_IMAGE_MAX_POOL_SIZE); + add_handler (image_handler); + + /* Temporal Noise Reduction */ + if (_defog_mode != CLPostImageProcessor::DefogDisabled) { + switch (_tnr_mode) { + case TnrYuv: { + image_handler = create_cl_tnr_image_handler (context, CL_TNR_TYPE_YUV); + _tnr = image_handler.dynamic_cast_ptr<CLTnrImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _tnr.ptr (), + XCAM_RETURN_ERROR_CL, + "CLPostImageProcessor create tnr handler failed"); + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + image_handler->set_pool_size (XCAM_CL_POST_IMAGE_DEFAULT_POOL_SIZE); + add_handler (image_handler); + break; + } + case TnrDisable: + XCAM_LOG_DEBUG ("CLPostImageProcessor disable tnr"); + break; + default: + XCAM_LOG_WARNING ("CLPostImageProcessor unknown tnr mode (%d)", _tnr_mode); + break; + } + } + + /* wavelet denoise */ + switch (_wavelet_basis) { + case CL_WAVELET_HAT: { + image_handler = create_cl_wavelet_denoise_image_handler (context, _wavelet_channel); + _wavelet = image_handler.dynamic_cast_ptr<CLWaveletDenoiseImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _wavelet.ptr (), + XCAM_RETURN_ERROR_CL, + "CLPostImageProcessor create wavelet denoise handler failed"); + _wavelet->enable_handler (true); + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + image_handler->set_pool_size (XCAM_CL_POST_IMAGE_DEFAULT_POOL_SIZE); + add_handler (image_handler); + break; + } + case CL_WAVELET_HAAR: { + image_handler = create_cl_newwavelet_denoise_image_handler (context, _wavelet_channel, _wavelet_bayes_shrink); + _newwavelet = image_handler.dynamic_cast_ptr<CLNewWaveletDenoiseImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _newwavelet.ptr (), + XCAM_RETURN_ERROR_CL, + "CLPostImageProcessor create new wavelet denoise handler failed"); + _newwavelet->enable_handler (true); + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + image_handler->set_pool_size (XCAM_CL_POST_IMAGE_DEFAULT_POOL_SIZE); + add_handler (image_handler); + break; + } + case CL_WAVELET_DISABLED: + default : + XCAM_LOG_DEBUG ("unknown or disable wavelet (%d)", _wavelet_basis); + break; + } + + /* 3D noise reduction */ + if (_3d_denoise_mode != CLPostImageProcessor::Denoise3DDisabled) { + uint32_t denoise_channel = CL_IMAGE_CHANNEL_UV; + + if (_3d_denoise_mode == CLPostImageProcessor::Denoise3DUV) { + denoise_channel = CL_IMAGE_CHANNEL_UV; + } else if (_3d_denoise_mode == CLPostImageProcessor::Denoise3DYuv) { + denoise_channel = CL_IMAGE_CHANNEL_Y | CL_IMAGE_CHANNEL_UV; + } + + image_handler = create_cl_3d_denoise_image_handler (context, denoise_channel, _3d_denoise_ref_count); + _3d_denoise = image_handler.dynamic_cast_ptr<CL3DDenoiseImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _3d_denoise.ptr (), + XCAM_RETURN_ERROR_CL, + "CL3aImageProcessor create 3D noise reduction handler failed"); + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + image_handler->set_pool_size (XCAM_CL_POST_IMAGE_MAX_POOL_SIZE); + image_handler->enable_handler (true); + add_handler (image_handler); + } + + /* image scaler */ + image_handler = create_cl_image_scaler_handler (context, V4L2_PIX_FMT_NV12); + _scaler = image_handler.dynamic_cast_ptr<CLImageScaler> (); + XCAM_FAIL_RETURN ( + WARNING, + _scaler.ptr (), + XCAM_RETURN_ERROR_CL, + "CLPostImageProcessor create scaler handler failed"); + _scaler->set_scaler_factor (_scaler_factor, _scaler_factor); + _scaler->set_buffer_callback (_stats_callback); + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + image_handler->enable_handler (_enable_scaler); + add_handler (image_handler); + + /* wire frame */ + image_handler = create_cl_wire_frame_image_handler (context); + _wireframe = image_handler.dynamic_cast_ptr<CLWireFrameImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _wireframe.ptr (), + XCAM_RETURN_ERROR_CL, + "CLPostImageProcessor create wire frame handler failed"); + _wireframe->enable_handler (_enable_wireframe); + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + image_handler->set_pool_size (XCAM_CL_POST_IMAGE_DEFAULT_POOL_SIZE); + add_handler (image_handler); + + /* image warp */ + image_handler = create_cl_image_warp_handler (context); + _image_warp = image_handler.dynamic_cast_ptr<CLImageWarpHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _image_warp.ptr (), + XCAM_RETURN_ERROR_CL, + "CLPostImageProcessor create image warp handler failed"); + _image_warp->enable_handler (_enable_image_warp); + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + image_handler->set_pool_size (XCAM_CL_POST_IMAGE_MAX_POOL_SIZE); + add_handler (image_handler); + + /* video stabilization */ + image_handler = create_cl_video_stab_handler (context); + _video_stab = image_handler.dynamic_cast_ptr<CLVideoStabilizer> (); + XCAM_FAIL_RETURN ( + WARNING, + _video_stab.ptr (), + XCAM_RETURN_ERROR_CL, + "CLPostImageProcessor create video stabilizer failed"); + _video_stab->enable_handler (false); + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + image_handler->set_pool_size (XCAM_CL_POST_IMAGE_MAX_POOL_SIZE); + add_handler (image_handler); + + /* image stitch */ + image_handler = + create_image_360_stitch (context, _stitch_enable_seam, _stitch_scale_mode, + _stitch_fisheye_map, _stitch_lsc, (SurroundMode) _surround_mode, (StitchResMode) _stitch_res_mode); + _stitch = image_handler.dynamic_cast_ptr<CLImage360Stitch> (); + XCAM_FAIL_RETURN ( + WARNING, + _stitch.ptr (), + XCAM_RETURN_ERROR_CL, + "CLPostImageProcessor create image stitch handler failed"); + _stitch->set_output_size (_stitch_width, _stitch_height); +#if HAVE_OPENCV + _stitch->set_feature_match_ocl (_stitch_fm_ocl); +#endif + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + image_handler->set_pool_size (XCAM_CL_POST_IMAGE_MAX_POOL_SIZE); + image_handler->enable_handler (_enable_stitch); + add_handler (image_handler); + + /* csc (nv12torgba) */ + image_handler = create_cl_csc_image_handler (context, CL_CSC_TYPE_NV12TORGBA); + _csc = image_handler.dynamic_cast_ptr<CLCscImageHandler> (); + XCAM_FAIL_RETURN ( + WARNING, + _csc .ptr (), + XCAM_RETURN_ERROR_CL, + "CLPostImageProcessor create csc handler failed"); + _csc->enable_handler (_out_sample_type == OutSampleRGB); + _csc->set_output_format (_output_fourcc); + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + image_handler->set_pool_size (XCAM_CL_POST_IMAGE_DEFAULT_POOL_SIZE); + add_handler (image_handler); + + return XCAM_RETURN_NO_ERROR; +} + +bool +CLPostImageProcessor::set_tnr (CLTnrMode mode) +{ + _tnr_mode = mode; + + STREAM_LOCK; + + return true; +} + +bool +CLPostImageProcessor::set_defog_mode (CLDefogMode mode) +{ + _defog_mode = mode; + + STREAM_LOCK; + + return true; +} + +bool +CLPostImageProcessor::set_wavelet (CLWaveletBasis basis, uint32_t channel, bool bayes_shrink) +{ + _wavelet_basis = basis; + _wavelet_channel = (CLImageChannel) channel; + _wavelet_bayes_shrink = bayes_shrink; + + STREAM_LOCK; + + return true; +} + +bool +CLPostImageProcessor::set_3ddenoise_mode (CL3DDenoiseMode mode, uint8_t ref_frame_count) +{ + _3d_denoise_mode = mode; + _3d_denoise_ref_count = ref_frame_count; + + STREAM_LOCK; + + return true; +} + +bool +CLPostImageProcessor::set_scaler (bool enable) +{ + _enable_scaler = enable; + + STREAM_LOCK; + + return true; +} + +bool +CLPostImageProcessor::set_wireframe (bool enable) +{ + _enable_wireframe = enable; + + STREAM_LOCK; + + return true; +} + +bool +CLPostImageProcessor::set_image_warp (bool enable) +{ + _enable_image_warp = enable; + + STREAM_LOCK; + + return true; +} + +bool +CLPostImageProcessor::set_image_stitch ( + bool enable_stitch, bool enable_seam, CLBlenderScaleMode scale_mode, bool enable_fisheye_map, + bool lsc, bool fm_ocl, uint32_t stitch_width, uint32_t stitch_height, uint32_t res_mode) +{ + XCAM_ASSERT (scale_mode < CLBlenderScaleMax); + + _enable_stitch = enable_stitch; + if (enable_stitch) + _stitch_enable_seam = enable_seam; + else + _stitch_enable_seam = false; + + _stitch_scale_mode = scale_mode; + _stitch_fisheye_map = enable_fisheye_map; + _stitch_lsc = lsc; + _stitch_width = stitch_width; + _stitch_height = stitch_height; + _stitch_res_mode = res_mode; + +#if HAVE_OPENCV + _stitch_fm_ocl = fm_ocl; +#else + XCAM_UNUSED (fm_ocl); +#endif + + STREAM_LOCK; + + return true; +} + +}; diff --git a/modules/ocl/cl_post_image_processor.h b/modules/ocl/cl_post_image_processor.h new file mode 100644 index 0000000..a06e007 --- /dev/null +++ b/modules/ocl/cl_post_image_processor.h @@ -0,0 +1,153 @@ +/* + * cl_post_image_processor.h - CL post image processor + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#ifndef XCAM_CL_POST_IMAGE_PROCESSOR_H +#define XCAM_CL_POST_IMAGE_PROCESSOR_H + +#include <xcam_std.h> +#include <base/xcam_3a_types.h> +#include <ocl/cl_image_processor.h> +#include <stats_callback_interface.h> +#include <ocl/cl_blender.h> +#include <ocl/cl_utils.h> + +namespace XCam { + +class CLTnrImageHandler; +class CLRetinexImageHandler; +class CLCscImageHandler; +class CLDefogDcpImageHandler; +class CLWaveletDenoiseImageHandler; +class CLNewWaveletDenoiseImageHandler; +class CL3DDenoiseImageHandler; +class CLImageScaler; +class CLWireFrameImageHandler; +class CLImageWarpHandler; +class CLImage360Stitch; +class CLVideoStabilizer; + +class CLPostImageProcessor + : public CLImageProcessor +{ +public: + enum OutSampleType { + OutSampleYuv, + OutSampleRGB, + OutSampleBayer, + }; + + enum CLTnrMode { + TnrDisable = 0, + TnrYuv, + }; + + enum CLDefogMode { + DefogDisabled = 0, + DefogRetinex, + DefogDarkChannelPrior, + }; + + enum CL3DDenoiseMode { + Denoise3DDisabled = 0, + Denoise3DYuv, + Denoise3DUV, + }; + +public: + explicit CLPostImageProcessor (); + virtual ~CLPostImageProcessor (); + + bool set_output_format (uint32_t fourcc); + void set_stats_callback (const SmartPtr<StatsCallback> &callback); + + bool set_scaler_factor (const double factor); + double get_scaler_factor () const { + return _scaler_factor; + } + bool is_scaled () { + return _enable_scaler; + } + + virtual bool set_tnr (CLTnrMode mode); + virtual bool set_defog_mode (CLDefogMode mode); + virtual bool set_wavelet (CLWaveletBasis basis, uint32_t channel, bool bayes_shrink); + virtual bool set_3ddenoise_mode (CL3DDenoiseMode mode, uint8_t ref_frame_count); + virtual bool set_scaler (bool enable); + virtual bool set_wireframe (bool enable); + virtual bool set_image_warp (bool enable); + virtual bool set_image_stitch ( + bool enable_stitch, bool enable_seam, CLBlenderScaleMode scale_mode, bool enable_fisheye_map, + bool lsc, bool fm_ocl, uint32_t stitch_width, uint32_t stitch_height, uint32_t res_mode); + +protected: + virtual bool can_process_result (SmartPtr<X3aResult> &result); + virtual XCamReturn apply_3a_results (X3aResultList &results); + virtual XCamReturn apply_3a_result (SmartPtr<X3aResult> &result); + +private: + virtual XCamReturn create_handlers (); + + XCAM_DEAD_COPY (CLPostImageProcessor); + +private: + uint32_t _output_fourcc; + OutSampleType _out_sample_type; + SmartPtr<StatsCallback> _stats_callback; + + SmartPtr<CLTnrImageHandler> _tnr; + SmartPtr<CLRetinexImageHandler> _retinex; + SmartPtr<CLDefogDcpImageHandler> _defog_dcp; + SmartPtr<CLWaveletDenoiseImageHandler> _wavelet; + SmartPtr<CLNewWaveletDenoiseImageHandler> _newwavelet; + SmartPtr<CL3DDenoiseImageHandler> _3d_denoise; + SmartPtr<CLImageScaler> _scaler; + SmartPtr<CLWireFrameImageHandler> _wireframe; + SmartPtr<CLCscImageHandler> _csc; + SmartPtr<CLImageWarpHandler> _image_warp; + SmartPtr<CLImage360Stitch> _stitch; + SmartPtr<CLVideoStabilizer> _video_stab; + + double _scaler_factor; + + CLTnrMode _tnr_mode; + CLDefogMode _defog_mode; + CLWaveletBasis _wavelet_basis; + uint32_t _wavelet_channel; + bool _wavelet_bayes_shrink; + CL3DDenoiseMode _3d_denoise_mode; + uint8_t _3d_denoise_ref_count; + bool _enable_scaler; + bool _enable_wireframe; + bool _enable_image_warp; + bool _enable_stitch; + bool _stitch_enable_seam; + bool _stitch_fisheye_map; + bool _stitch_lsc; + bool _stitch_fm_ocl; + CLBlenderScaleMode _stitch_scale_mode; + uint32_t _stitch_width; + uint32_t _stitch_height; + uint32_t _stitch_res_mode; + uint32_t _surround_mode; +}; + +}; +#endif // XCAM_CL_POST_IMAGE_PROCESSOR_H diff --git a/modules/ocl/cl_pyramid_blender.cpp b/modules/ocl/cl_pyramid_blender.cpp new file mode 100644 index 0000000..d42fdcf --- /dev/null +++ b/modules/ocl/cl_pyramid_blender.cpp @@ -0,0 +1,1854 @@ +/* + * cl_pyramid_blender.cpp - CL multi-band blender + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_pyramid_blender.h" +#include <algorithm> +#include "xcam_obj_debug.h" +#include "cl_device.h" +#include "cl_utils.h" + +#if CL_PYRAMID_ENABLE_DUMP +#define BLENDER_PROFILING_START(name) XCAM_STATIC_PROFILING_START(name) +#define BLENDER_PROFILING_END(name, times_of_print) XCAM_STATIC_PROFILING_END(name, times_of_print) +#else +#define BLENDER_PROFILING_START(name) +#define BLENDER_PROFILING_END(name, times_of_print) +#endif + +//#define SAMPLER_POSITION_OFFSET -0.25f +#define SAMPLER_POSITION_OFFSET 0.0f + +#define SEAM_POS_TYPE int16_t +#define SEAM_SUM_TYPE float +#define SEAM_MASK_TYPE uint8_t + +namespace XCam { + +enum { + KernelPyramidTransform = 0, + KernelPyramidReconstruct, + KernelPyramidBlender, + KernelPyramidScale, + KernelPyramidCopy, + KernelPyramidLap, + KernelImageDiff, + KernelSeamDP, + KernelSeamMaskScale, + KernelSeamMaskScaleSLM, + KernelSeamBlender +}; + +static const XCamKernelInfo kernels_info [] = { + { + "kernel_gauss_scale_transform", +#include "kernel_gauss_lap_pyramid.clx" + , 0, + }, + { + "kernel_gauss_lap_reconstruct", +#include "kernel_gauss_lap_pyramid.clx" + , 0, + }, + { + "kernel_pyramid_blend", +#include "kernel_gauss_lap_pyramid.clx" + , 0, + }, + { + "kernel_pyramid_scale", +#include "kernel_gauss_lap_pyramid.clx" + , 0, + }, + { + "kernel_pyramid_copy", +#include "kernel_gauss_lap_pyramid.clx" + , 0, + }, + { + "kernel_lap_transform", +#include "kernel_gauss_lap_pyramid.clx" + , 0, + }, + { + "kernel_image_diff", +#include "kernel_gauss_lap_pyramid.clx" + , 0, + }, + { + "kernel_seam_dp", +#include "kernel_gauss_lap_pyramid.clx" + , 0, + }, + { + "kernel_mask_gauss_scale", +#include "kernel_gauss_lap_pyramid.clx" + , 0, + }, + { + "kernel_mask_gauss_scale_slm", +#include "kernel_gauss_lap_pyramid.clx" + , 0, + }, + { + "kernel_seam_mask_blend", +#include "kernel_gauss_lap_pyramid.clx" + , 0, + } +}; + +static uint32_t +clamp(int32_t i, int32_t min, int32_t max) +{ + if (i < min) + return min; + if (i > max - 1) + return max - 1; + return i; +} + +static float* +get_gauss_coeffs (int radius, float sigma) +{ + static int g_radius = 0; + static float g_sigma = 0; + static float g_table[512] = {0.0f}; + + int i; + int scale = radius * 2 + 1; + float dis = 0.0f, sum = 0.0f; + + if (g_radius == radius && g_sigma == sigma) + return g_table; + + XCAM_ASSERT (scale < 512); + + for (i = 0; i < scale; i++) { + dis = ((float)i - radius) * ((float)i - radius); + g_table[i] = exp(-dis / (2.0f * sigma * sigma)); + sum += g_table[i]; + } + + for(i = 0; i < scale; i++) + g_table[i] = g_table[i] / sum; + + g_radius = radius; + g_sigma = sigma; + + return g_table; +} + +static bool +gauss_blur_buffer (SmartPtr<CLBuffer> &buf, int buf_len, int g_radius, float g_sigma) +{ + float *buf_ptr = NULL; + float *coeff = NULL; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + float *tmp_ptr = NULL; + + coeff = get_gauss_coeffs (g_radius, g_sigma); + XCAM_ASSERT (coeff); + + ret = buf->enqueue_map((void*&)buf_ptr, 0, buf_len * sizeof (float)); + XCAM_FAIL_RETURN (ERROR, ret == XCAM_RETURN_NO_ERROR, false, "gauss_blur_buffer failed on enqueue_map"); + + tmp_ptr = (float *)xcam_malloc (buf_len * sizeof (float)); + XCAM_ASSERT (tmp_ptr); + for (int i = 0; i < buf_len; ++i) { + tmp_ptr[i] = 0.0f; + for (int j = -g_radius; j <= (int)g_radius; ++j) { + tmp_ptr[i] += buf_ptr[clamp(i + j, 0, buf_len)] * coeff[g_radius + j]; + } + } + + for (int i = 0; i < buf_len; ++i) { + buf_ptr[i] = tmp_ptr[i]; + } + xcam_free (tmp_ptr); + buf->enqueue_unmap((void*)buf_ptr); + return true; +} + +PyramidLayer::PyramidLayer () + : blend_width (0) + , blend_height (0) +{ + for (int plane = 0; plane < CLBlenderPlaneMax; ++plane) { + for (int i = 0; i < XCAM_BLENDER_IMAGE_NUM; ++i) { + gauss_offset_x[plane][i] = 0; + lap_offset_x[plane][i] = 0; + } + mask_width [plane] = 0; + } +} + +CLPyramidBlender::CLPyramidBlender ( + const SmartPtr<CLContext> &context, const char *name, + int layers, bool need_uv, bool need_seam, CLBlenderScaleMode scale_mode) + : CLBlender (context, name, need_uv, scale_mode) + , _layers (0) + , _need_seam (need_seam) + , _seam_pos_stride (0) + , _seam_width (0) + , _seam_height (0) + , _seam_pos_offset_x (0) + , _seam_pos_valid_width (0) + , _seam_mask_done (false) +{ + if (layers <= 1) + _layers = 1; + else if (layers > XCAM_CL_PYRAMID_MAX_LEVEL) + _layers = XCAM_CL_PYRAMID_MAX_LEVEL; + else + _layers = (uint32_t)layers; +} + +CLPyramidBlender::~CLPyramidBlender () +{ +} + +SmartPtr<CLImage> +CLPyramidBlender::get_gauss_image (uint32_t layer, uint32_t buf_index, bool is_uv) +{ + XCAM_ASSERT (layer < _layers); + XCAM_ASSERT (buf_index < XCAM_BLENDER_IMAGE_NUM); + uint32_t plane = (is_uv ? 1 : 0); + return _pyramid_layers[layer].gauss_image[plane][buf_index]; +} + +SmartPtr<CLImage> +CLPyramidBlender::get_lap_image (uint32_t layer, uint32_t buf_index, bool is_uv) +{ + XCAM_ASSERT (layer < _layers); + XCAM_ASSERT (buf_index < XCAM_BLENDER_IMAGE_NUM); + uint32_t plane = (is_uv ? 1 : 0); + + return _pyramid_layers[layer].lap_image[plane][buf_index]; +} + +SmartPtr<CLImage> +CLPyramidBlender::get_blend_image (uint32_t layer, bool is_uv) +{ + XCAM_ASSERT (layer < _layers); + uint32_t plane = (is_uv ? 1 : 0); + + return _pyramid_layers[layer].blend_image[plane][BlendImageIndex]; +} + +SmartPtr<CLImage> +CLPyramidBlender::get_reconstruct_image (uint32_t layer, bool is_uv) +{ + XCAM_ASSERT (layer < _layers); + uint32_t plane = (is_uv ? 1 : 0); + return _pyramid_layers[layer].blend_image[plane][ReconstructImageIndex]; +} + +SmartPtr<CLImage> +CLPyramidBlender::get_scale_image (bool is_uv) +{ + uint32_t plane = (is_uv ? 1 : 0); + return _pyramid_layers[0].scale_image[plane]; +} + +SmartPtr<CLBuffer> +CLPyramidBlender::get_blend_mask (uint32_t layer, bool is_uv) +{ + XCAM_ASSERT (layer < _layers); + uint32_t plane = (is_uv ? 1 : 0); + return _pyramid_layers[layer].blend_mask[plane]; +} + +SmartPtr<CLImage> +CLPyramidBlender::get_seam_mask (uint32_t layer) +{ + XCAM_ASSERT (layer < _layers); + return _pyramid_layers[layer].seam_mask[CLSeamMaskCoeff]; +} + +const PyramidLayer & +CLPyramidBlender::get_pyramid_layer (uint32_t layer) const +{ + return _pyramid_layers[layer]; +} + +const SmartPtr<CLImage> & +CLPyramidBlender::get_image_diff () const +{ + return _image_diff; +} + +void +CLPyramidBlender::get_seam_info (uint32_t &width, uint32_t &height, uint32_t &stride) const +{ + width = _seam_width; + height = _seam_height; + stride = _seam_pos_stride; +} + +void +CLPyramidBlender::get_seam_pos_info (uint32_t &offset_x, uint32_t &valid_width) const +{ + offset_x = _seam_pos_offset_x; + valid_width = _seam_pos_valid_width; +} + +void +PyramidLayer::bind_buf_to_layer0 ( + SmartPtr<CLContext> context, + SmartPtr<VideoBuffer> &input0, SmartPtr<VideoBuffer> &input1, SmartPtr<VideoBuffer> &output, + const Rect &merge0_rect, const Rect &merge1_rect, bool need_uv, CLBlenderScaleMode scale_mode) +{ + const VideoBufferInfo &in0_info = input0->get_video_info (); + const VideoBufferInfo &in1_info = input1->get_video_info (); + const VideoBufferInfo &out_info = output->get_video_info (); + int max_plane = (need_uv ? 2 : 1); + uint32_t divider_vert[2] = {1, 2}; + + XCAM_ASSERT (in0_info.height == in1_info.height); + XCAM_ASSERT (merge0_rect.width == merge1_rect.width); + + this->blend_width = XCAM_ALIGN_UP (merge0_rect.width, XCAM_CL_BLENDER_ALIGNMENT_X); + this->blend_height = merge0_rect.height; + + CLImageDesc cl_desc; + cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_desc.format.image_channel_order = CL_RGBA; + + for (int i_plane = 0; i_plane < max_plane; ++i_plane) { + cl_desc.width = in0_info.width / 8; + cl_desc.height = in0_info.height / divider_vert[i_plane]; + cl_desc.row_pitch = in0_info.strides[i_plane]; + this->gauss_image[i_plane][0] = convert_to_climage (context, input0, cl_desc, in0_info.offsets[i_plane]); + this->gauss_offset_x[i_plane][0] = merge0_rect.pos_x; // input0 offset + + cl_desc.width = in1_info.width / 8; + cl_desc.height = in1_info.height / divider_vert[i_plane]; + cl_desc.row_pitch = in1_info.strides[i_plane]; + this->gauss_image[i_plane][1] = convert_to_climage (context, input1, cl_desc, in1_info.offsets[i_plane]); + this->gauss_offset_x[i_plane][1] = merge1_rect.pos_x; // input1 offset + + cl_desc.width = out_info.width / 8; + cl_desc.height = out_info.height / divider_vert[i_plane]; + cl_desc.row_pitch = out_info.strides[i_plane]; + + if (scale_mode == CLBlenderScaleLocal) { + this->scale_image[i_plane] = convert_to_climage (context, output, cl_desc, out_info.offsets[i_plane]); + + cl_desc.width = XCAM_ALIGN_UP (this->blend_width, XCAM_CL_BLENDER_ALIGNMENT_X) / 8; + cl_desc.height = XCAM_ALIGN_UP (this->blend_height, divider_vert[i_plane]) / divider_vert[i_plane]; + uint32_t row_pitch = CLImage::calculate_pixel_bytes (cl_desc.format) * + XCAM_ALIGN_UP (cl_desc.width, XCAM_CL_IMAGE_ALIGNMENT_X); + uint32_t size = row_pitch * cl_desc.height; + SmartPtr<CLBuffer> cl_buf = new CLBuffer (context, size); + XCAM_ASSERT (cl_buf.ptr () && cl_buf->is_valid ()); + cl_desc.row_pitch = row_pitch; + this->blend_image[i_plane][ReconstructImageIndex] = new CLImage2D (context, cl_desc, 0, cl_buf); + } else { + this->blend_image[i_plane][ReconstructImageIndex] = + convert_to_climage (context, output, cl_desc, out_info.offsets[i_plane]); + } + XCAM_ASSERT (this->blend_image[i_plane][ReconstructImageIndex].ptr ()); + } + +} + +void +PyramidLayer::init_layer0 (SmartPtr<CLContext> context, bool last_layer, bool need_uv, int mask_radius, float mask_sigma) +{ + XCAM_ASSERT (this->blend_width && this->blend_height); + + //init mask + this->mask_width[0] = this->blend_width; + uint32_t mask_size = this->mask_width[0] * sizeof (float); + this->blend_mask[0] = new CLBuffer(context, mask_size); + float *blend_ptr = NULL; + XCamReturn ret = this->blend_mask[0]->enqueue_map((void*&)blend_ptr, 0, mask_size); + if (!xcam_ret_is_ok (ret)) { + XCAM_LOG_ERROR ("PyramidLayer init layer0 failed in blend_mask mem_map"); + return; + } + + for (uint32_t i_ptr = 0; i_ptr < this->mask_width[0]; ++i_ptr) { + if (i_ptr <= this->mask_width[0] / 2) + blend_ptr[i_ptr] = 1.0f; + else + blend_ptr[i_ptr] = 0.0f; + } + this->blend_mask[0]->enqueue_unmap ((void*)blend_ptr); + gauss_blur_buffer (this->blend_mask[0], this->mask_width[0], mask_radius, mask_sigma); + + if (need_uv) + copy_mask_from_y_to_uv (context); + + if (last_layer) + return; + + int max_plane = (need_uv ? 2 : 1); + uint32_t divider_vert[2] = {1, 2}; + CLImageDesc cl_desc; + cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_desc.format.image_channel_order = CL_RGBA; + for (int i_plane = 0; i_plane < max_plane; ++i_plane) { + cl_desc.width = this->blend_width / 8; + cl_desc.height = XCAM_ALIGN_UP (this->blend_height, divider_vert[i_plane]) / divider_vert[i_plane]; + + this->blend_image[i_plane][BlendImageIndex] = new CLImage2D (context, cl_desc); + this->lap_image[i_plane][0] = new CLImage2D (context, cl_desc); + this->lap_image[i_plane][1] = new CLImage2D (context, cl_desc); + this->lap_offset_x[i_plane][0] = this->lap_offset_x[i_plane][1] = 0; + +#if CL_PYRAMID_ENABLE_DUMP + this->dump_gauss_resize[i_plane] = new CLImage2D (context, cl_desc); + this->dump_original[i_plane][0] = new CLImage2D (context, cl_desc); + this->dump_original[i_plane][1] = new CLImage2D (context, cl_desc); + this->dump_final[i_plane] = new CLImage2D (context, cl_desc); +#endif + } +} + +void +PyramidLayer::build_cl_images (SmartPtr<CLContext> context, bool last_layer, bool need_uv) +{ + uint32_t size = 0, row_pitch = 0; + CLImageDesc cl_desc_set; + SmartPtr<CLBuffer> cl_buf; + uint32_t divider_vert[2] = {1, 2}; + uint32_t max_plane = (need_uv ? 2 : 1); + + cl_desc_set.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_desc_set.format.image_channel_order = CL_RGBA; + + for (uint32_t plane = 0; plane < max_plane; ++plane) { + for (int i_image = 0; i_image < XCAM_BLENDER_IMAGE_NUM; ++i_image) { + cl_desc_set.row_pitch = 0; + cl_desc_set.width = XCAM_ALIGN_UP (this->blend_width, XCAM_CL_BLENDER_ALIGNMENT_X) / 8; + cl_desc_set.height = XCAM_ALIGN_UP (this->blend_height, divider_vert[plane]) / divider_vert[plane]; + + //gauss y image created by cl buffer + row_pitch = CLImage::calculate_pixel_bytes (cl_desc_set.format) * + XCAM_ALIGN_UP (cl_desc_set.width, XCAM_CL_IMAGE_ALIGNMENT_X); + size = row_pitch * cl_desc_set.height; + cl_buf = new CLBuffer (context, size); + XCAM_ASSERT (cl_buf.ptr () && cl_buf->is_valid ()); + cl_desc_set.row_pitch = row_pitch; + this->gauss_image[plane][i_image] = new CLImage2D (context, cl_desc_set, 0, cl_buf); + XCAM_ASSERT (this->gauss_image[plane][i_image].ptr ()); + this->gauss_offset_x[plane][i_image] = 0; // offset to 0, need recalculate if for deep multi-band blender + } + + cl_desc_set.width = XCAM_ALIGN_UP (this->blend_width, XCAM_CL_BLENDER_ALIGNMENT_X) / 8; + cl_desc_set.height = XCAM_ALIGN_UP (this->blend_height, divider_vert[plane]) / divider_vert[plane]; + row_pitch = CLImage::calculate_pixel_bytes (cl_desc_set.format) * + XCAM_ALIGN_UP (cl_desc_set.width, XCAM_CL_IMAGE_ALIGNMENT_X); + size = row_pitch * cl_desc_set.height; + cl_buf = new CLBuffer (context, size); + XCAM_ASSERT (cl_buf.ptr () && cl_buf->is_valid ()); + cl_desc_set.row_pitch = row_pitch; + this->blend_image[plane][ReconstructImageIndex] = new CLImage2D (context, cl_desc_set, 0, cl_buf); + XCAM_ASSERT (this->blend_image[plane][ReconstructImageIndex].ptr ()); +#if CL_PYRAMID_ENABLE_DUMP + this->dump_gauss_resize[plane] = new CLImage2D (context, cl_desc_set); + this->dump_original[plane][0] = new CLImage2D (context, cl_desc_set); + this->dump_original[plane][1] = new CLImage2D (context, cl_desc_set); + this->dump_final[plane] = new CLImage2D (context, cl_desc_set); +#endif + if (!last_layer) { + cl_desc_set.row_pitch = 0; + this->blend_image[plane][BlendImageIndex] = new CLImage2D (context, cl_desc_set); + XCAM_ASSERT (this->blend_image[plane][BlendImageIndex].ptr ()); + for (int i_image = 0; i_image < XCAM_BLENDER_IMAGE_NUM; ++i_image) { + this->lap_image[plane][i_image] = new CLImage2D (context, cl_desc_set); + XCAM_ASSERT (this->lap_image[plane][i_image].ptr ()); + this->lap_offset_x[plane][i_image] = 0; // offset to 0, need calculate from next layer if for deep multi-band blender + } + } + } +} + +bool +PyramidLayer::copy_mask_from_y_to_uv (SmartPtr<CLContext> &context) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + XCAM_ASSERT (this->mask_width[0]); + XCAM_ASSERT (this->blend_mask[0].ptr ()); + + this->mask_width[1] = (this->mask_width[0] + 1) / 2; + this->blend_mask[1] = new CLBuffer (context, this->mask_width[1] * sizeof(float)); + XCAM_ASSERT (this->blend_mask[1].ptr ()); + + float *from_ptr = NULL; + float *to_ptr = NULL; + ret = this->blend_mask[1]->enqueue_map ((void*&)to_ptr, 0, this->mask_width[1] * sizeof(float)); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), false, "PyramidLayer copy mask failed in blend_mask[1] mem_map"); + ret = this->blend_mask[0]->enqueue_map((void*&)from_ptr, 0, this->mask_width[0] * sizeof(float)); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), false, "PyramidLayer copy mask failed in blend_mask[0] mem_map"); + + for (int i = 0; i < (int)this->mask_width[1]; ++i) { + if (i * 2 + 1 >= (int)this->mask_width[0]) { // todo i* 2 + 1 + XCAM_ASSERT (i * 2 < (int)this->mask_width[0]); + to_ptr[i] = from_ptr[i * 2] / 2.0f; + } else { + to_ptr[i] = (from_ptr[i * 2] + from_ptr[i * 2 + 1]) / 2.0f; + } + } + this->blend_mask[1]->enqueue_unmap ((void*)to_ptr); + this->blend_mask[0]->enqueue_unmap ((void*)from_ptr); + + return true; +} + +void +CLPyramidBlender::last_layer_buffer_redirect () +{ + PyramidLayer &layer = _pyramid_layers[_layers - 1]; + uint32_t max_plane = (need_uv () ? 2 : 1); + + for (uint32_t plane = 0; plane < max_plane; ++plane) { + layer.blend_image[plane][BlendImageIndex] = layer.blend_image[plane][ReconstructImageIndex]; + + for (uint32_t i_image = 0; i_image < XCAM_BLENDER_IMAGE_NUM; ++i_image) { + layer.lap_image[plane][i_image] = layer.gauss_image[plane][i_image]; + } + } +} + +void +CLPyramidBlender::dump_layer_mask (uint32_t layer, bool is_uv) +{ + const PyramidLayer &pyr_layer = get_pyramid_layer (layer); + int plane = (is_uv ? 1 : 0); + + float *mask_ptr = NULL; + XCamReturn ret = pyr_layer.blend_mask[plane]->enqueue_map ((void*&)mask_ptr, 0, pyr_layer.mask_width[plane] * sizeof(float)); + if (!xcam_ret_is_ok (ret)) { + XCAM_LOG_ERROR ("CLPyramidBlender dump mask failed in blend_mask(layer:%d) mem_map", layer); + return; + } + + printf ("layer(%d)(-%s) mask, width:%d\n", layer, (is_uv ? "UV" : "Y"), pyr_layer.mask_width[plane]); + for (uint32_t i = 0; i < pyr_layer.mask_width[plane]; ++i) { + printf ("%.03f\t", mask_ptr[i]); + } + printf ("\n"); + + pyr_layer.blend_mask[plane]->enqueue_unmap ((void*)mask_ptr); +} + +static bool +gauss_fill_mask ( + SmartPtr<CLContext> context, PyramidLayer &prev, PyramidLayer &to, bool need_uv, + int mask_radius, float mask_sigma) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + uint32_t mask_size = to.blend_width * sizeof (float); + uint32_t prev_size = prev.mask_width[0] * sizeof (float); + float *pre_ptr = NULL; + int i; + + //gauss to[0] + to.mask_width[0] = to.blend_width; + to.blend_mask[0] = new CLBuffer (context, mask_size); + XCAM_ASSERT (to.blend_mask[0].ptr ()); + float *mask0_ptr = NULL; + ret = to.blend_mask[0]->enqueue_map((void*&)mask0_ptr, 0, mask_size); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), false, "gauss_fill_mask failed in destination image mem_map"); + + ret = prev.blend_mask[0]->enqueue_map((void*&)pre_ptr, 0, prev_size); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), false, "gauss_fill_mask failed in source image mem_map"); + + for (i = 0; i < (int)to.blend_width; ++i) { + if (i * 2 + 1 >= (int)prev.mask_width[0]) { // todo i* 2 + 1 + XCAM_ASSERT (i * 2 < (int)prev.mask_width[0]); + mask0_ptr[i] = pre_ptr[i * 2] / 2.0f; + } else { + mask0_ptr[i] = (pre_ptr[i * 2] + pre_ptr[i * 2 + 1]) / 2.0f; + } + } + prev.blend_mask[0]->enqueue_unmap ((void*)pre_ptr); + to.blend_mask[0]->enqueue_unmap ((void*)mask0_ptr); + + gauss_blur_buffer (to.blend_mask[0], to.mask_width[0], mask_radius, mask_sigma); + + if (need_uv) + to.copy_mask_from_y_to_uv (context); + + return true; +} + +XCamReturn +CLPyramidBlender::allocate_cl_buffers ( + SmartPtr<CLContext> context, + SmartPtr<VideoBuffer> &input0, SmartPtr<VideoBuffer> &input1, + SmartPtr<VideoBuffer> &output) +{ + uint32_t index = 0; + const Rect & window = get_merge_window (); + bool need_reallocate = true; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + BLENDER_PROFILING_START (allocate_cl_buffers); + + need_reallocate = + (window.width != (int32_t)_pyramid_layers[0].blend_width || + (window.height != 0 && window.height != (int32_t)_pyramid_layers[0].blend_height)); + _pyramid_layers[0].bind_buf_to_layer0 ( + context, input0, input1, output, + get_input_merge_area (0), get_input_merge_area (1), + need_uv (), get_scale_mode ()); + + if (need_reallocate) { + int g_radius = (((float)(window.width - 1) / 2) / (1 << _layers)) * 1.2f; + float g_sigma = (float)g_radius; + + _pyramid_layers[0].init_layer0 (context, (0 == _layers - 1), need_uv(), g_radius, g_sigma); + + for (index = 1; index < _layers; ++index) { + _pyramid_layers[index].blend_width = (_pyramid_layers[index - 1].blend_width + 1) / 2; + _pyramid_layers[index].blend_height = (_pyramid_layers[index - 1].blend_height + 1) / 2; + + _pyramid_layers[index].build_cl_images (context, (index == _layers - 1), need_uv ()); + if (!_need_seam) { + gauss_fill_mask (context, _pyramid_layers[index - 1], _pyramid_layers[index], need_uv (), g_radius, g_sigma); + } + } + + if (_need_seam) { + ret = init_seam_buffers (context); + XCAM_FAIL_RETURN (ERROR, ret == XCAM_RETURN_NO_ERROR, ret, "CLPyramidBlender init seam buffer failed"); + } + } + + //last layer buffer redirect + last_layer_buffer_redirect (); + _seam_mask_done = false; + + BLENDER_PROFILING_END (allocate_cl_buffers, 50); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLPyramidBlender::init_seam_buffers (SmartPtr<CLContext> context) +{ + const PyramidLayer &layer0 = get_pyramid_layer (0); + CLImageDesc cl_desc; + + _seam_width = layer0.blend_width; + _seam_height = layer0.blend_height; + _seam_pos_stride = XCAM_ALIGN_UP (_seam_width, 64); // need a buffer large enough to avoid judgement in kernel + _seam_pos_offset_x = XCAM_ALIGN_UP (_seam_width / 4, XCAM_CL_BLENDER_ALIGNMENT_X); + if (_seam_pos_offset_x >= _seam_width) + _seam_pos_offset_x = 0; + _seam_pos_valid_width = XCAM_ALIGN_DOWN (_seam_width / 2, XCAM_CL_BLENDER_ALIGNMENT_X); + if (_seam_pos_valid_width <= 0) + _seam_pos_valid_width = XCAM_CL_BLENDER_ALIGNMENT_X; + XCAM_ASSERT (_seam_pos_offset_x + _seam_pos_valid_width <= _seam_width); + + XCAM_ASSERT (layer0.blend_width > 0 && layer0.blend_height > 0); + cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_desc.format.image_channel_order = CL_RGBA; + cl_desc.width = _seam_width / 8; + cl_desc.height = _seam_height; + cl_desc.row_pitch = CLImage::calculate_pixel_bytes (cl_desc.format) * + XCAM_ALIGN_UP (cl_desc.width, XCAM_CL_IMAGE_ALIGNMENT_X); + + uint32_t image_diff_size = cl_desc.row_pitch * _seam_height; + SmartPtr<CLBuffer> cl_diff_buf = new CLBuffer (context, image_diff_size); + XCAM_FAIL_RETURN ( + ERROR, + cl_diff_buf.ptr () && cl_diff_buf->is_valid (), + XCAM_RETURN_ERROR_CL, + "CLPyramidBlender init seam buffer failed to create image_difference buffers"); + + _image_diff = new CLImage2D (context, cl_desc, 0, cl_diff_buf); + XCAM_FAIL_RETURN ( + ERROR, + _image_diff.ptr () && _image_diff->is_valid (), + XCAM_RETURN_ERROR_CL, + "CLPyramidBlender init seam buffer failed to bind image_difference data"); + + uint32_t pos_buf_size = sizeof (SEAM_POS_TYPE) * _seam_pos_stride * _seam_height; + uint32_t sum_buf_size = sizeof (SEAM_SUM_TYPE) * _seam_pos_stride * 2; // 2 lines + _seam_pos_buf = new CLBuffer (context, pos_buf_size, CL_MEM_READ_WRITE); + _seam_sum_buf = new CLBuffer (context, sum_buf_size, CL_MEM_READ_WRITE); + XCAM_FAIL_RETURN ( + ERROR, + _seam_pos_buf.ptr () && _seam_pos_buf->is_valid () && + _seam_sum_buf.ptr () && _seam_sum_buf->is_valid (), + XCAM_RETURN_ERROR_CL, + "CLPyramidBlender init seam buffer failed to create seam buffers"); + + uint32_t mask_width = XCAM_ALIGN_UP(_seam_width, XCAM_CL_BLENDER_ALIGNMENT_X); + uint32_t mask_height = XCAM_ALIGN_UP(_seam_height, 2); + for (uint32_t i = 0; i < _layers; ++i) { + cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT16; + cl_desc.format.image_channel_order = CL_RGBA; + cl_desc.width = mask_width / 8; + cl_desc.height = mask_height; + cl_desc.row_pitch = CLImage::calculate_pixel_bytes (cl_desc.format) * + XCAM_ALIGN_UP (cl_desc.width, XCAM_CL_IMAGE_ALIGNMENT_X); + + uint32_t mask_size = cl_desc.row_pitch * mask_height; + SmartPtr<CLBuffer> cl_buf0 = new CLBuffer (context, mask_size); + SmartPtr<CLBuffer> cl_buf1 = new CLBuffer (context, mask_size); + XCAM_ASSERT (cl_buf0.ptr () && cl_buf0->is_valid () && cl_buf1.ptr () && cl_buf1->is_valid ()); + + _pyramid_layers[i].seam_mask[CLSeamMaskTmp] = new CLImage2D (context, cl_desc, 0, cl_buf0); + _pyramid_layers[i].seam_mask[CLSeamMaskCoeff] = new CLImage2D (context, cl_desc, 0, cl_buf1); + XCAM_FAIL_RETURN ( + ERROR, + _pyramid_layers[i].seam_mask[CLSeamMaskTmp].ptr () && _pyramid_layers[i].seam_mask[CLSeamMaskTmp]->is_valid () && + _pyramid_layers[i].seam_mask[CLSeamMaskCoeff].ptr () && _pyramid_layers[i].seam_mask[CLSeamMaskCoeff]->is_valid (), + XCAM_RETURN_ERROR_CL, + "CLPyramidBlender init seam buffer failed to create seam_mask buffer"); + + mask_width = XCAM_ALIGN_UP(mask_width / 2, XCAM_CL_BLENDER_ALIGNMENT_X); + mask_height = XCAM_ALIGN_UP(mask_height / 2, 2); + } + + return XCAM_RETURN_NO_ERROR; +} + +static void +assign_mask_line (SEAM_MASK_TYPE *mask_ptr, int line, int stride, int delimiter) +{ +#define MASK_1 0xFFFF +#define MASK_0 0x00 + + SEAM_MASK_TYPE *line_ptr = mask_ptr + line * stride; + int mask_1_len = delimiter + 1; + + memset (line_ptr, MASK_1, sizeof (SEAM_MASK_TYPE) * mask_1_len); + memset (line_ptr + mask_1_len, MASK_0, sizeof (SEAM_MASK_TYPE) * (stride - mask_1_len)); +} + +XCamReturn +CLPyramidBlender::fill_seam_mask () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + XCAM_ASSERT (_seam_pos_buf.ptr () && _seam_sum_buf.ptr ()); + uint32_t pos_buf_size = sizeof (SEAM_POS_TYPE) * _seam_pos_stride * _seam_height; + uint32_t sum_buf_size = sizeof (SEAM_SUM_TYPE) * _seam_pos_stride * 2; + SEAM_SUM_TYPE *sum_ptr; + SEAM_POS_TYPE *pos_ptr; + SEAM_MASK_TYPE *mask_ptr; + + if (_seam_mask_done) + return XCAM_RETURN_NO_ERROR; + + ret = _seam_sum_buf->enqueue_map ((void *&)sum_ptr, 0, sum_buf_size, CL_MAP_READ); + XCAM_FAIL_RETURN (ERROR, ret == XCAM_RETURN_NO_ERROR, ret, "CLPyramidBlender map seam_sum_buf failed"); + + float min_sum = 9999999999.0f, tmp_sum; + int pos = 0, min_pos0, min_pos1; + int i = 0; + SEAM_SUM_TYPE *sum_ptr0 = sum_ptr, *sum_ptr1 = sum_ptr + _seam_pos_stride; + for (i = (int)_seam_pos_offset_x; i < (int)(_seam_pos_offset_x + _seam_pos_valid_width); ++i) { + tmp_sum = sum_ptr0[i] + sum_ptr1[i]; + if (tmp_sum >= min_sum) + continue; + pos = (int)i; + min_sum = tmp_sum; + } + _seam_sum_buf->enqueue_unmap ((void*)sum_ptr); + min_pos0 = min_pos1 = pos; + + BLENDER_PROFILING_START (fill_seam_mask); + + // reset layer0 seam_mask + SmartPtr<CLImage> seam_mask = _pyramid_layers[0].seam_mask[CLSeamMaskTmp]; + const CLImageDesc &mask_desc = seam_mask->get_image_desc (); + size_t mask_origin[3] = {0, 0, 0}; + size_t mask_region[3] = {mask_desc.width, mask_desc.height, 1}; + size_t mask_row_pitch; + size_t mask_slice_pitch; + ret = seam_mask->enqueue_map ((void *&)mask_ptr, mask_origin, mask_region, + &mask_row_pitch, &mask_slice_pitch, CL_MAP_READ); + XCAM_FAIL_RETURN (ERROR, ret == XCAM_RETURN_NO_ERROR, ret, "CLPyramidBlender map seam_mask failed"); + uint32_t mask_stride = mask_row_pitch / sizeof (SEAM_MASK_TYPE); + ret = _seam_pos_buf->enqueue_map ((void *&)pos_ptr, 0, pos_buf_size, CL_MAP_READ); + XCAM_FAIL_RETURN (ERROR, ret == XCAM_RETURN_NO_ERROR, ret, "CLPyramidBlender map seam_pos_buf failed"); + //printf ("***********min sum:%.3f, pos:%d, sum0:%.3f, sum1:%.3f\n", min_sum, pos, sum_ptr0[pos], sum_ptr1[pos]); + for (i = _seam_height / 2 - 1; i >= 0; --i) { + assign_mask_line (mask_ptr, i, mask_stride, min_pos0); + min_pos0 = pos_ptr [i * _seam_pos_stride + min_pos0]; + } + + for (i = _seam_height / 2; i < (int)_seam_height; ++i) { + assign_mask_line (mask_ptr, i, mask_stride, min_pos1); + min_pos1 = pos_ptr [i * _seam_pos_stride + min_pos1]; + } + for (; i < (int)mask_desc.height; ++i) { + assign_mask_line (mask_ptr, i, mask_stride, min_pos1); + } + + seam_mask->enqueue_unmap ((void*)mask_ptr); + _seam_pos_buf->enqueue_unmap ((void*)pos_ptr); + + _seam_mask_done = true; + + BLENDER_PROFILING_END (fill_seam_mask, 50); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLPyramidBlender::execute_done (SmartPtr<VideoBuffer> &output) +{ + int max_plane = (need_uv () ? 2 : 1); + XCAM_UNUSED (output); + +#if CL_PYRAMID_ENABLE_DUMP + dump_buffers (); +#endif + + for (int i_plane = 0; i_plane < max_plane; ++i_plane) { + _pyramid_layers[0].gauss_image[i_plane][0].release (); + _pyramid_layers[0].gauss_image[i_plane][1].release (); + _pyramid_layers[0].blend_image[i_plane][ReconstructImageIndex].release (); + + if (_layers <= 1) { + _pyramid_layers[_layers - 1].blend_image[i_plane][BlendImageIndex].release (); + _pyramid_layers[_layers - 1].lap_image[i_plane][0].release (); + _pyramid_layers[_layers - 1].lap_image[i_plane][1].release (); + } + } + + return XCAM_RETURN_NO_ERROR; +} + +CLPyramidBlendKernel::CLPyramidBlendKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, bool is_uv, bool need_seam) + : CLImageKernel (context) + , _blender (blender) + , _layer (layer) + , _is_uv (is_uv) + , _need_seam (need_seam) +{ +} + +XCamReturn +CLPyramidBlendKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + + SmartPtr<CLImage> image_in0 = get_input_0 (); + SmartPtr<CLImage> image_in1 = get_input_1 (); + SmartPtr<CLImage> image_out = get_output (); + SmartPtr<CLMemory> buf_mask; + if (_need_seam) + buf_mask = get_seam_mask (); + else + buf_mask = get_blend_mask (); + + XCAM_ASSERT (image_in0.ptr () && image_in1.ptr () && image_out.ptr ()); + const CLImageDesc &cl_desc_out = image_out->get_image_desc (); + + args.push_back (new CLMemArgument (image_in0)); + args.push_back (new CLMemArgument (image_in1)); + args.push_back (new CLMemArgument (buf_mask)); + args.push_back (new CLMemArgument (image_out)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 8; + work_size.local[1] = 8; + work_size.global[0] = XCAM_ALIGN_UP (cl_desc_out.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (cl_desc_out.height, work_size.local[1]); + return XCAM_RETURN_NO_ERROR; +} + +CLPyramidTransformKernel::CLPyramidTransformKernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, + uint32_t buf_index, + bool is_uv) + : CLImageKernel (context) + , _blender (blender) + , _layer (layer) + , _buf_index (buf_index) + , _is_uv (is_uv) +{ + XCAM_ASSERT (layer <= XCAM_CL_PYRAMID_MAX_LEVEL); + XCAM_ASSERT (buf_index <= XCAM_BLENDER_IMAGE_NUM); +} + +static bool +change_image_format ( + SmartPtr<CLContext> context, SmartPtr<CLImage> input, + SmartPtr<CLImage> &output, const CLImageDesc &new_desc) +{ + SmartPtr<CLImage2D> previous = input.dynamic_cast_ptr<CLImage2D> (); + if (!previous.ptr () || !previous->get_bind_buf ().ptr ()) + return false; + + SmartPtr<CLBuffer> bind_buf = previous->get_bind_buf (); + output = new CLImage2D (context, new_desc, 0, bind_buf); + if (!output.ptr ()) + return false; + return true; +} + +int32_t +CLPyramidTransformKernel::get_input_gauss_offset_x () +{ + const PyramidLayer &layer = _blender->get_pyramid_layer (_layer); + uint32_t plane_index = (_is_uv ? 1 : 0); + return layer.gauss_offset_x[plane_index][_buf_index]; +} + +XCamReturn +CLPyramidTransformKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + + SmartPtr<CLImage> image_in_gauss = get_input_gauss(); + SmartPtr<CLImage> image_out_gauss = get_output_gauss(); + //SmartPtr<CLImage> image_out_lap = get_output_lap (); + const CLImageDesc &cl_desc_out_gauss_pre = image_out_gauss->get_image_desc (); + + CLImageDesc cl_desc_out_gauss; + cl_desc_out_gauss.format.image_channel_data_type = CL_UNSIGNED_INT8; + cl_desc_out_gauss.format.image_channel_order = CL_RGBA; + cl_desc_out_gauss.width = cl_desc_out_gauss_pre.width * 2; + cl_desc_out_gauss.height = cl_desc_out_gauss_pre.height; + cl_desc_out_gauss.row_pitch = cl_desc_out_gauss_pre.row_pitch; + SmartPtr<CLImage> format_image_out; + change_image_format (context, image_out_gauss, format_image_out, cl_desc_out_gauss); + XCAM_FAIL_RETURN ( + ERROR, + format_image_out.ptr () && format_image_out->is_valid (), + XCAM_RETURN_ERROR_CL, + "CLPyramidTransformKernel change output gauss image format failed"); + + int gauss_offset_x = get_input_gauss_offset_x () / 8; + XCAM_ASSERT (gauss_offset_x * 8 == get_input_gauss_offset_x ()); + + args.push_back (new CLMemArgument (image_in_gauss)); + args.push_back (new CLArgumentT<int> (gauss_offset_x)); + args.push_back (new CLMemArgument (format_image_out)); + +#if CL_PYRAMID_ENABLE_DUMP + int plane = _is_uv ? 1 : 0; + SmartPtr<CLImage> dump_original = _blender->get_pyramid_layer (_layer).dump_original[plane][_buf_index]; + + args.push_back (new CLMemArgument (dump_original)); + + printf ("L%dI%d: gauss_offset_x:%d \n", _layer, _buf_index, gauss_offset_x); +#endif + + const int workitem_lines = 2; + int gloabal_y = XCAM_ALIGN_UP (cl_desc_out_gauss.height, workitem_lines) / workitem_lines; + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 16; + work_size.local[1] = 4; + work_size.global[0] = XCAM_ALIGN_UP (cl_desc_out_gauss.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (gloabal_y, work_size.local[1]); + + return XCAM_RETURN_NO_ERROR; +} + +CLSeamDiffKernel::CLSeamDiffKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender) + : CLImageKernel (context) + , _blender (blender) +{ +} + +XCamReturn +CLSeamDiffKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + const PyramidLayer &layer0 = _blender->get_pyramid_layer (0); + SmartPtr<CLImage> image0 = layer0.gauss_image[CLBlenderPlaneY][0]; + SmartPtr<CLImage> image1 = layer0.gauss_image[CLBlenderPlaneY][1]; + SmartPtr<CLImage> out_diff = _blender->get_image_diff (); + CLImageDesc out_diff_desc = out_diff->get_image_desc (); + + int image_offset_x[XCAM_BLENDER_IMAGE_NUM]; + + for (uint32_t i = 0; i < XCAM_BLENDER_IMAGE_NUM; ++i) { + image_offset_x[i] = layer0.gauss_offset_x[CLBlenderPlaneY][i] / 8; + } + + args.push_back (new CLMemArgument (image0)); + args.push_back (new CLArgumentT<int> (image_offset_x[0])); + args.push_back (new CLMemArgument (image1)); + args.push_back (new CLArgumentT<int> (image_offset_x[1])); + args.push_back (new CLMemArgument (out_diff)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 8; + work_size.local[1] = 4; + work_size.global[0] = XCAM_ALIGN_UP (out_diff_desc.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (out_diff_desc.height, work_size.local[1]); + + return XCAM_RETURN_NO_ERROR; +} + +CLSeamDPKernel::CLSeamDPKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender) + : CLImageKernel (context) + , _blender (blender) +{ +} + +XCamReturn +CLSeamDPKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ +#define ELEMENT_PIXEL 1 + + uint32_t width, height, stride; + uint32_t pos_offset_x, pos_valid_width; + _blender->get_seam_info (width, height, stride); + _blender->get_seam_pos_info (pos_offset_x, pos_valid_width); + int seam_height = (int)height; + int seam_stride = (int)stride / ELEMENT_PIXEL; + int seam_offset_x = (int)pos_offset_x / ELEMENT_PIXEL; // ushort8 + int seam_valid_with = (int)pos_valid_width / ELEMENT_PIXEL; + int max_pos = (int)(pos_offset_x + pos_valid_width - 1); + + SmartPtr<CLImage> image = _blender->get_image_diff (); + SmartPtr<CLBuffer> pos_buf = _blender->get_seam_pos_buf (); + SmartPtr<CLBuffer> sum_buf = _blender->get_seam_sum_buf (); + XCAM_ASSERT (image.ptr () && pos_buf.ptr () && sum_buf.ptr ()); + + CLImageDesc cl_orig = image->get_image_desc (); + CLImageDesc cl_desc_convert; + cl_desc_convert.format.image_channel_data_type = CL_UNSIGNED_INT8; + cl_desc_convert.format.image_channel_order = CL_R; + cl_desc_convert.width = cl_orig.width * (8 / ELEMENT_PIXEL); + cl_desc_convert.height = cl_orig.height; + cl_desc_convert.row_pitch = cl_orig.row_pitch; + + SmartPtr<CLImage> convert_image; + change_image_format (get_context (), image, convert_image, cl_desc_convert); + XCAM_ASSERT (convert_image.ptr () && convert_image->is_valid ()); + + args.push_back (new CLMemArgument (convert_image)); + args.push_back (new CLMemArgument (pos_buf)); + args.push_back (new CLMemArgument (sum_buf)); + args.push_back (new CLArgumentT<int> (seam_offset_x)); + args.push_back (new CLArgumentT<int> (seam_valid_with)); + args.push_back (new CLArgumentT<int> (max_pos)); + args.push_back (new CLArgumentT<int> (seam_height)); + args.push_back (new CLArgumentT<int> (seam_stride)); + + work_size.dim = 1; + work_size.local[0] = XCAM_ALIGN_UP(seam_valid_with, 16); + work_size.global[0] = work_size.local[0] * 2; + + return XCAM_RETURN_NO_ERROR; +} + +CLPyramidSeamMaskKernel::CLPyramidSeamMaskKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, bool scale, bool need_slm) + : CLImageKernel (context) + , _blender (blender) + , _layer (layer) + , _need_scale (scale) + , _need_slm (need_slm) +{ + XCAM_ASSERT (layer < blender->get_layers ()); +} + +XCamReturn +CLPyramidSeamMaskKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + ret = _blender->fill_seam_mask (); + XCAM_FAIL_RETURN (ERROR, ret == XCAM_RETURN_NO_ERROR, ret, "CLPyramidSeamMaskKernel fill seam mask failed"); + + SmartPtr<CLContext> context = get_context (); + const PyramidLayer &cur_layer = _blender->get_pyramid_layer (_layer); + SmartPtr<CLImage> input_image = cur_layer.seam_mask[CLSeamMaskTmp]; + SmartPtr<CLImage> out_gauss = cur_layer.seam_mask[CLSeamMaskCoeff]; + CLImageDesc out_gauss_desc = out_gauss->get_image_desc (); + + XCAM_ASSERT (input_image.ptr () && out_gauss.ptr ()); + XCAM_ASSERT (input_image->is_valid () && out_gauss->is_valid ()); + + args.push_back (new CLMemArgument (input_image)); + args.push_back (new CLMemArgument (out_gauss)); + + + + if (_need_slm) { + int image_width = out_gauss_desc.width; + args.push_back (new CLArgumentT<int> (image_width)); + } + + if (_need_scale) { + const PyramidLayer &next_layer = _blender->get_pyramid_layer (_layer + 1); + SmartPtr<CLImage> out_orig = next_layer.seam_mask[CLSeamMaskTmp]; + CLImageDesc input_desc, output_desc; + input_desc = out_orig->get_image_desc (); + output_desc.format.image_channel_data_type = CL_UNSIGNED_INT8; + output_desc.format.image_channel_order = CL_RGBA; + output_desc.width = input_desc.width * 2; + output_desc.height = input_desc.height; + output_desc.row_pitch = input_desc.row_pitch; + + SmartPtr<CLImage> output_scale_image; + change_image_format (context, out_orig, output_scale_image, output_desc); + args.push_back (new CLMemArgument (output_scale_image)); + } + + uint32_t workitem_height = XCAM_ALIGN_UP (out_gauss_desc.height, 2) / 2; + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + + if (_need_slm) { + work_size.local[0] = XCAM_ALIGN_UP (out_gauss_desc.width, 16); + work_size.local[1] = 1; + work_size.global[0] = work_size.local[0]; + work_size.global[1] = workitem_height; + } else { + work_size.local[0] = 8; + work_size.local[1] = 4; + work_size.global[0] = XCAM_ALIGN_UP (out_gauss_desc.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (workitem_height, work_size.local[1]); + } + + return XCAM_RETURN_NO_ERROR; +} + +CLPyramidLapKernel::CLPyramidLapKernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, + uint32_t buf_index, + bool is_uv) + : CLImageKernel (context) + , _blender (blender) + , _layer (layer) + , _buf_index (buf_index) + , _is_uv (is_uv) +{ + XCAM_ASSERT (layer <= XCAM_CL_PYRAMID_MAX_LEVEL); + XCAM_ASSERT (buf_index <= XCAM_BLENDER_IMAGE_NUM); +} + +int32_t +CLPyramidLapKernel::get_cur_gauss_offset_x () +{ + const PyramidLayer &layer = _blender->get_pyramid_layer (_layer); + uint32_t plane_index = (_is_uv ? 1 : 0); + return layer.gauss_offset_x[plane_index][_buf_index]; +} + +int32_t +CLPyramidLapKernel::get_output_lap_offset_x () +{ + const PyramidLayer &layer = _blender->get_pyramid_layer (_layer); + uint32_t plane_index = (_is_uv ? 1 : 0); + return layer.lap_offset_x[plane_index][_buf_index]; +} + +XCamReturn +CLPyramidLapKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + + SmartPtr<CLImage> cur_gauss_image = get_current_gauss(); + SmartPtr<CLImage> next_gauss_image_tmp = get_next_gauss(); + SmartPtr<CLImage> image_out_lap = get_output_lap (); + const CLImageDesc &cl_desc_next_gauss_tmp = next_gauss_image_tmp->get_image_desc (); + const CLImageDesc &cl_desc_out_lap = image_out_lap->get_image_desc (); + float next_gauss_pixel_width = 0.0f, next_gauss_pixel_height = 0.0f; + + CLImageDesc cl_desc_next_gauss; + if (!_is_uv) { + cl_desc_next_gauss.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc_next_gauss.format.image_channel_order = CL_R; + cl_desc_next_gauss.width = cl_desc_next_gauss_tmp.width * 8; + } else { + cl_desc_next_gauss.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc_next_gauss.format.image_channel_order = CL_RG; + cl_desc_next_gauss.width = cl_desc_next_gauss_tmp.width * 4; + } + cl_desc_next_gauss.height = cl_desc_next_gauss_tmp.height; + cl_desc_next_gauss.row_pitch = cl_desc_next_gauss_tmp.row_pitch; + SmartPtr<CLImage> next_gauss; + change_image_format (context, next_gauss_image_tmp, next_gauss, cl_desc_next_gauss); + XCAM_FAIL_RETURN ( + ERROR, + next_gauss.ptr () && next_gauss->is_valid (), + XCAM_RETURN_ERROR_CL, + "CLPyramidTransformKernel change output gauss image format failed"); + + next_gauss_pixel_width = cl_desc_next_gauss.width; + next_gauss_pixel_height = cl_desc_next_gauss.height; + + // out format(current layer): CL_UNSIGNED_INT16 + CL_RGBA + float out_width = CLImage::calculate_pixel_bytes (cl_desc_next_gauss.format) * cl_desc_next_gauss.width * 2.0f / 8.0f; + float out_height = next_gauss_pixel_height * 2.0f; + float sampler_offset_x = SAMPLER_POSITION_OFFSET / next_gauss_pixel_width; + float sampler_offset_y = SAMPLER_POSITION_OFFSET / next_gauss_pixel_height; + + int cur_gauss_offset_x = get_cur_gauss_offset_x () / 8; + XCAM_ASSERT (cur_gauss_offset_x * 8 == get_cur_gauss_offset_x ()); + int lap_offset_x = get_output_lap_offset_x () / 8; + XCAM_ASSERT (lap_offset_x * 8 == get_output_lap_offset_x ()); + + args.push_back (new CLMemArgument (cur_gauss_image)); + args.push_back (new CLArgumentT<int> (cur_gauss_offset_x)); + args.push_back (new CLMemArgument (next_gauss)); + args.push_back (new CLArgumentT<float> (sampler_offset_x)); + args.push_back (new CLArgumentT<float> (sampler_offset_y)); + args.push_back (new CLMemArgument (image_out_lap)); + args.push_back (new CLArgumentT<int> (lap_offset_x)); + args.push_back (new CLArgumentT<float> (out_width)); + args.push_back (new CLArgumentT<float> (out_height)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 8; + work_size.local[1] = 4; + work_size.global[0] = XCAM_ALIGN_UP (cl_desc_out_lap.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (cl_desc_out_lap.height, work_size.local[1]); + + return XCAM_RETURN_NO_ERROR; +} + +CLPyramidReconstructKernel::CLPyramidReconstructKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, bool is_uv) + : CLImageKernel (context) + , _blender (blender) + , _layer (layer) + , _is_uv (is_uv) +{ + XCAM_ASSERT (layer <= XCAM_CL_PYRAMID_MAX_LEVEL); +} + +int +CLPyramidReconstructKernel::get_output_reconstrcut_offset_x () +{ + if (_layer > 0) + return 0; + const Rect & window = _blender->get_merge_window (); + XCAM_ASSERT (window.pos_x % XCAM_CL_BLENDER_ALIGNMENT_X == 0); + return window.pos_x; +} + +XCamReturn +CLPyramidReconstructKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + + SmartPtr<CLImage> image_in_reconst = get_input_reconstruct(); + SmartPtr<CLImage> image_in_lap = get_input_lap (); + SmartPtr<CLImage> image_out_reconst = get_output_reconstruct(); + const CLImageDesc &cl_desc_in_reconst_pre = image_in_reconst->get_image_desc (); + // out_desc should be same as image_in_lap + const CLImageDesc &cl_desc_out_reconst = image_in_lap->get_image_desc (); // don't change + float input_gauss_width = 0.0f, input_gauss_height = 0.0f; + + CLImageDesc cl_desc_in_reconst; + cl_desc_in_reconst.format.image_channel_data_type = CL_UNORM_INT8; + if (_is_uv) { + cl_desc_in_reconst.format.image_channel_order = CL_RG; + cl_desc_in_reconst.width = cl_desc_in_reconst_pre.width * 4; + } else { + cl_desc_in_reconst.format.image_channel_order = CL_R; + cl_desc_in_reconst.width = cl_desc_in_reconst_pre.width * 8; + } + cl_desc_in_reconst.height = cl_desc_in_reconst_pre.height; + cl_desc_in_reconst.row_pitch = cl_desc_in_reconst_pre.row_pitch; + SmartPtr<CLImage> input_reconstruct; + change_image_format (context, image_in_reconst, input_reconstruct, cl_desc_in_reconst); + XCAM_FAIL_RETURN ( + ERROR, + input_reconstruct.ptr () && input_reconstruct->is_valid (), + XCAM_RETURN_ERROR_CL, + "CLPyramidTransformKernel change output gauss image format failed"); + + input_gauss_width = cl_desc_in_reconst.width; + input_gauss_height = cl_desc_in_reconst.height; + + float out_reconstruct_width = CLImage::calculate_pixel_bytes (cl_desc_in_reconst.format) * cl_desc_in_reconst.width * 2.0f / 8.0f; + float out_reconstruct_height = input_gauss_height * 2.0f; + float in_sampler_offset_x = SAMPLER_POSITION_OFFSET / input_gauss_width; + float in_sampler_offset_y = SAMPLER_POSITION_OFFSET / input_gauss_height; + int out_reconstruct_offset_x = 0; + + if (_blender->get_scale_mode () == CLBlenderScaleLocal) { + out_reconstruct_offset_x = 0; + } else { + out_reconstruct_offset_x = get_output_reconstrcut_offset_x () / 8; + XCAM_ASSERT (out_reconstruct_offset_x * 8 == get_output_reconstrcut_offset_x ()); + } + + args.push_back (new CLMemArgument (input_reconstruct)); + args.push_back (new CLArgumentT<float> (in_sampler_offset_x)); + args.push_back (new CLArgumentT<float> (in_sampler_offset_y)); + args.push_back (new CLMemArgument (image_in_lap)); + args.push_back (new CLMemArgument (image_out_reconst)); + args.push_back (new CLArgumentT<int> (out_reconstruct_offset_x)); + args.push_back (new CLArgumentT<float> (out_reconstruct_width)); + args.push_back (new CLArgumentT<float> (out_reconstruct_height)); + +#if CL_PYRAMID_ENABLE_DUMP + int i_plane = (_is_uv ? 1 : 0); + const PyramidLayer &cur_layer = _blender->get_pyramid_layer (_layer); + SmartPtr<CLImage> dump_gauss_resize = cur_layer.dump_gauss_resize[i_plane]; + SmartPtr<CLImage> dump_final = cur_layer.dump_final[i_plane]; + + args.push_back (new CLMemArgument (dump_gauss_resize)); + args.push_back (new CLMemArgument (dump_final)); + + printf ("Rec%d: reconstruct_offset_x:%d, out_width:%.2f, out_height:%.2f, in_sampler_offset_x:%.2f, in_sampler_offset_y:%.2f\n", + _layer, out_reconstruct_offset_x, out_reconstruct_width, out_reconstruct_height, + in_sampler_offset_x, in_sampler_offset_y); +#endif + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 4; + work_size.local[1] = 8; + work_size.global[0] = XCAM_ALIGN_UP (cl_desc_out_reconst.width, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (cl_desc_out_reconst.height, work_size.local[1]); + + return XCAM_RETURN_NO_ERROR; +} + + +void +CLPyramidBlender::dump_buffers () +{ + static int frame_count = 0; + SmartPtr<CLImage> image; + ++frame_count; + + // dump difference between original image and final image +#if 0 +#define CM_NUM 3 + SmartPtr<CLImage> images[CM_NUM]; + const Rect & window = get_merge_window (); + int offsets[3] = {window.pos_x, window.pos_x, 0}; + //right edge + //int offsets[3] = {0 + window.width - 8, window.pos_x + window.width - 8, window.width - 8}; + size_t row_pitch[CM_NUM]; + size_t slice_pitch[CM_NUM]; + uint8_t *ptr[CM_NUM] = {NULL, NULL, NULL}; + uint32_t i = 0; + +#if 1 + // Y + // left edge + images[0] = this->get_pyramid_layer (0).gauss_image[0][0]; + // right edge + //images[0] = this->get_pyramid_layer (0).gauss_image[0][1]; + images[1] = this->get_pyramid_layer (0).blend_image[0][ReconstructImageIndex]; + images[2] = this->get_pyramid_layer (0).dump_final[0]; +#else + // UV + // left edge + images[0] = this->get_pyramid_layer (0).gauss_image[1][0]; + // right edge + //images[0] = this->get_pyramid_layer (0).gauss_image[1][1]; + images[1] = this->get_pyramid_layer (0).blend_image[1][ReconstructImageIndex]; + images[2] = this->get_pyramid_layer (0).dump_final[1]; +#endif + + for (i = 0; i < CM_NUM; ++i) { + const CLImageDesc &desc = images[i]->get_image_desc (); + size_t origin[3] = {0, 0, 0}; + size_t region[3] = {desc.width, desc.height, 1}; + XCamReturn ret = images[i]->enqueue_map ((void *&)ptr[i], origin, region, &row_pitch[i], &slice_pitch[i], CL_MAP_READ); + XCAM_ASSERT (ret == XCAM_RETURN_NO_ERROR); + } + // offset UV, workaround of beignet + //offsets[0] += row_pitch[0] * 1088; + //offsets[1] += row_pitch[1] * 1088; + + printf ("layer 0(UV) comparison, original / final-image / reconstruct offset:%d, width:%d\n", window.pos_x, window.width); + for (int ih = 250; ih < 280; ++ih) { + uint8_t *lines[CM_NUM]; + for (i = 0; i < 2 /*CM_NUM*/; ++i) { + uint8_t *l = (uint8_t *)ptr[i] + offsets[i] + row_pitch[i] * ih + 0; + lines[i] = l; + printf ("%02x%02x%02x%02x%02x%02x%02x%02x ", l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7]); + } + //printf differrence between original and final image + printf ("delta(orig - final):"); + for (i = 0; i < 10; ++i) { + printf ("%02x", (uint32_t)(lines[0][i] - lines[1][i]) & 0xFF); + } + printf ("\n"); + } + + for (i = 0; i < CM_NUM; ++i) { + images[i]->enqueue_unmap (ptr[i]); + } +#endif + +#define DUMP_IMAGE(prefix, image, layer) \ + desc = (image)->get_image_desc (); \ + snprintf (filename, sizeof(filename), prefix "_L%d-%dx%d", \ + layer, (image)->get_pixel_bytes () * desc.width, desc.height); \ + dump_image (image, filename) + + // dump image data to file + CLImageDesc desc; + char filename[1024]; + + image = this->get_image_diff (); + if (image.ptr ()) { + DUMP_IMAGE ("dump_image_diff", image, 0); + } + + for (uint32_t i_layer = 0; i_layer < get_layers (); ++i_layer) { + //dump seam mask + image = this->get_pyramid_layer(i_layer).seam_mask[CLSeamMaskTmp]; + if (image.ptr ()) { + DUMP_IMAGE ("dump_seam_tmp", image, i_layer); + } + + image = this->get_pyramid_layer(i_layer).seam_mask[CLSeamMaskCoeff]; + if (image.ptr ()) { + DUMP_IMAGE ("dump_seam_coeff", image, i_layer); + } + + image = this->get_blend_image (i_layer, false); // layer 1 + DUMP_IMAGE ("dump_blend", image, i_layer); + + if (i_layer > 0) { //layer : [1, _layers -1] + image = this->get_gauss_image (i_layer, 0, false); + DUMP_IMAGE ("dump_gaussI0", image, i_layer); + image = this->get_gauss_image (i_layer, 1, false); + DUMP_IMAGE ("dump_gaussI1", image, i_layer); + } + + if (i_layer < get_layers () - 1) { + image = this->get_lap_image (i_layer, 0, false); // layer : [0, _layers -2] + DUMP_IMAGE ("dump_lap_I0", image, i_layer); + } + } + +#if CL_PYRAMID_ENABLE_DUMP + image = this->get_pyramid_layer (0).dump_gauss_resize[0]; + DUMP_IMAGE ("dump_gauss_resize", image, 0); + + image = this->get_pyramid_layer (0).dump_original[0][0]; + DUMP_IMAGE ("dump_orginalI0", image, 0); + image = this->get_pyramid_layer (0).dump_original[0][1]; + DUMP_IMAGE ("dump_orginalI1", image, 0); + + image = this->get_pyramid_layer (0).dump_final[CLBlenderPlaneY]; + DUMP_IMAGE ("dump_final", image, 0); +#endif + +#if 0 + this->dump_layer_mask (0, false); + this->dump_layer_mask (1, false); + + //this->dump_layer_mask (0, true); + //this->dump_layer_mask (1, true); +#endif + +} + +CLBlenderLocalScaleKernel::CLBlenderLocalScaleKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, bool is_uv) + : CLBlenderScaleKernel (context, is_uv) + , _blender (blender) +{ +} + +SmartPtr<CLImage> +CLBlenderLocalScaleKernel::get_input_image () +{ + SmartPtr<CLContext> context = get_context (); + + SmartPtr<CLImage> rec_image = _blender->get_reconstruct_image (0, _is_uv); + const CLImageDesc &rec_desc = rec_image->get_image_desc (); + + CLImageDesc new_desc; + new_desc.format.image_channel_data_type = CL_UNORM_INT8; + if (_is_uv) { + new_desc.format.image_channel_order = CL_RG; + new_desc.width = rec_desc.width * 4; + } else { + new_desc.format.image_channel_order = CL_R; + new_desc.width = rec_desc.width * 8; + } + new_desc.height = rec_desc.height; + new_desc.row_pitch = rec_desc.row_pitch; + SmartPtr<CLImage> new_image; + change_image_format (context, rec_image, new_image, new_desc); + XCAM_FAIL_RETURN ( + ERROR, + new_image.ptr () && new_image->is_valid (), + NULL, + "CLBlenderLocalScaleKernel change image format failed"); + + _image_in = new_image; + return new_image; +} + +SmartPtr<CLImage> +CLBlenderLocalScaleKernel::get_output_image () +{ + return _blender->get_scale_image (_is_uv); +} + +bool +CLBlenderLocalScaleKernel::get_output_info ( + uint32_t &out_width, uint32_t &out_height, int &out_offset_x) +{ + XCAM_ASSERT (_image_in.ptr ()); + + const Rect &window = _blender->get_merge_window (); + const CLImageDesc &desc_in = _image_in->get_image_desc (); + + out_width = window.width / 8; + out_height = desc_in.height; + out_offset_x = window.pos_x / 8; + + XCAM_FAIL_RETURN (ERROR, out_width != 0, false, "get output info failed"); + return true; +} + +CLPyramidCopyKernel::CLPyramidCopyKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, + uint32_t buf_index, bool is_uv) + : CLImageKernel (context) + , _blender (blender) + , _is_uv (is_uv) + , _buf_index (buf_index) +{ +} + +XCamReturn +CLPyramidCopyKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + + SmartPtr<CLImage> from = get_input (); + SmartPtr<CLImage> to = get_output (); + + const CLImageDesc &to_desc = to->get_image_desc (); + const Rect &window = _blender->get_merge_window (); + const Rect &input_area = _blender->get_input_valid_area (_buf_index); + const Rect &merge_area = _blender->get_input_merge_area (_buf_index); + int in_offset_x = 0; + int out_offset_x = 0; + int max_g_x = 0, max_g_y = 0; + + if (_buf_index == 0) { + in_offset_x = input_area.pos_x / 8; + max_g_x = (merge_area.pos_x - input_area.pos_x) / 8; + out_offset_x = window.pos_x / 8 - max_g_x; + } else { + in_offset_x = (merge_area.pos_x + merge_area.width) / 8; + out_offset_x = (window.pos_x + window.width) / 8; + max_g_x = (input_area.pos_x + input_area.width) / 8 - in_offset_x; + } + max_g_y = to_desc.height; + XCAM_ASSERT (max_g_x > 0 && max_g_x <= (int)to_desc.width); + +#if CL_PYRAMID_ENABLE_DUMP + printf ("copy(%d), in_offset_x:%d, out_offset_x:%d, max_x:%d\n", _buf_index, in_offset_x, out_offset_x, max_g_x); +#endif + + args.push_back (new CLMemArgument (from)); + args.push_back (new CLArgumentT<int> (in_offset_x)); + args.push_back (new CLMemArgument (to)); + args.push_back (new CLArgumentT<int> (out_offset_x)); + args.push_back (new CLArgumentT<int> (max_g_x)); + args.push_back (new CLArgumentT<int> (max_g_y)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 16; + work_size.local[1] = 4; + work_size.global[0] = XCAM_ALIGN_UP (max_g_x, work_size.local[0]); + work_size.global[1] = XCAM_ALIGN_UP (max_g_y, work_size.local[1]); + + return XCAM_RETURN_NO_ERROR; +} + +static SmartPtr<CLImageKernel> +create_pyramid_transform_kernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, uint32_t buf_index, bool is_uv) +{ + char transform_option[1024]; + snprintf ( + transform_option, sizeof(transform_option), + "-DPYRAMID_UV=%d -DCL_PYRAMID_ENABLE_DUMP=%d", (is_uv ? 1 : 0), CL_PYRAMID_ENABLE_DUMP); + + SmartPtr<CLImageKernel> kernel; + kernel = new CLPyramidTransformKernel (context, blender, layer, buf_index, is_uv); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, + kernel->build_kernel (kernels_info[KernelPyramidTransform], transform_option) == XCAM_RETURN_NO_ERROR, + NULL, + "load pyramid blender kernel(%s) failed", (is_uv ? "UV" : "Y")); + return kernel; +} + +static SmartPtr<CLImageKernel> +create_pyramid_lap_kernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, uint32_t buf_index, bool is_uv) +{ + char transform_option[1024]; + snprintf ( + transform_option, sizeof(transform_option), + "-DPYRAMID_UV=%d -DCL_PYRAMID_ENABLE_DUMP=%d", (is_uv ? 1 : 0), CL_PYRAMID_ENABLE_DUMP); + + SmartPtr<CLImageKernel> kernel; + kernel = new CLPyramidLapKernel (context, blender, layer, buf_index, is_uv); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, + kernel->build_kernel (kernels_info[KernelPyramidLap], transform_option) == XCAM_RETURN_NO_ERROR, + NULL, + "load pyramid blender kernel(%s) failed", (is_uv ? "UV" : "Y")); + return kernel; +} + +static SmartPtr<CLImageKernel> +create_pyramid_reconstruct_kernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, + bool is_uv) +{ + char transform_option[1024]; + snprintf ( + transform_option, sizeof(transform_option), + "-DPYRAMID_UV=%d -DCL_PYRAMID_ENABLE_DUMP=%d", (is_uv ? 1 : 0), CL_PYRAMID_ENABLE_DUMP); + + SmartPtr<CLImageKernel> kernel; + kernel = new CLPyramidReconstructKernel (context, blender, layer, is_uv); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, + kernel->build_kernel (kernels_info[KernelPyramidReconstruct], transform_option) == XCAM_RETURN_NO_ERROR, + NULL, + "load pyramid blender kernel(%s) failed", (is_uv ? "UV" : "Y")); + return kernel; +} + +static SmartPtr<CLImageKernel> +create_pyramid_blend_kernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, + bool is_uv, + bool need_seam) +{ + char transform_option[1024]; + snprintf ( + transform_option, sizeof(transform_option), + "-DPYRAMID_UV=%d -DCL_PYRAMID_ENABLE_DUMP=%d", (is_uv ? 1 : 0), CL_PYRAMID_ENABLE_DUMP); + + SmartPtr<CLImageKernel> kernel; + kernel = new CLPyramidBlendKernel (context, blender, layer, is_uv, need_seam); + uint32_t index = KernelPyramidBlender; + if (need_seam) + index = KernelSeamBlender; + + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, + kernel->build_kernel (kernels_info[index], transform_option) == XCAM_RETURN_NO_ERROR, + NULL, + "load pyramid blender kernel(%s) failed", (is_uv ? "UV" : "Y")); + return kernel; +} + +static SmartPtr<CLImageKernel> +create_pyramid_blender_local_scale_kernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLPyramidBlender> &blender, + bool is_uv) +{ + char transform_option[1024]; + snprintf (transform_option, sizeof(transform_option), "-DPYRAMID_UV=%d", is_uv ? 1 : 0); + + SmartPtr<CLImageKernel> kernel; + kernel = new CLBlenderLocalScaleKernel (context, blender, is_uv); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, + kernel->build_kernel (kernels_info[KernelPyramidScale], transform_option) == XCAM_RETURN_NO_ERROR, + NULL, + "load pyramid blender local scaling kernel(%s) failed", is_uv ? "UV" : "Y"); + return kernel; +} + +static SmartPtr<CLImageKernel> +create_pyramid_copy_kernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLPyramidBlender> &blender, + uint32_t buf_index, + bool is_uv) +{ + char transform_option[1024]; + snprintf (transform_option, sizeof(transform_option), "-DPYRAMID_UV=%d", (is_uv ? 1 : 0)); + + SmartPtr<CLImageKernel> kernel; + kernel = new CLPyramidCopyKernel (context, blender, buf_index, is_uv); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, + kernel->build_kernel (kernels_info[KernelPyramidCopy], transform_option) == XCAM_RETURN_NO_ERROR, + NULL, + "load pyramid blender kernel(%s) failed", (is_uv ? "UV" : "Y")); + return kernel; +} + +static SmartPtr<CLImageKernel> +create_seam_diff_kernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender) +{ + SmartPtr<CLImageKernel> kernel; + kernel = new CLSeamDiffKernel (context, blender); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, + kernel->build_kernel (kernels_info[KernelImageDiff], NULL) == XCAM_RETURN_NO_ERROR, + NULL, + "load seam diff kernel failed"); + return kernel; +} + +static SmartPtr<CLImageKernel> +create_seam_DP_kernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender) +{ + SmartPtr<CLImageKernel> kernel; + kernel = new CLSeamDPKernel (context, blender); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, + kernel->build_kernel (kernels_info[KernelSeamDP], NULL) == XCAM_RETURN_NO_ERROR, + NULL, + "load seam DP kernel failed"); + return kernel; +} + +static SmartPtr<CLImageKernel> +create_seam_mask_scale_kernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, + bool need_scale, + bool need_slm) +{ + char build_option[1024]; + snprintf (build_option, sizeof(build_option), "-DENABLE_MASK_GAUSS_SCALE=%d", (need_scale ? 1 : 0)); + int kernel_idx = (need_slm ? KernelSeamMaskScaleSLM : KernelSeamMaskScale); + + SmartPtr<CLImageKernel> kernel; + kernel = new CLPyramidSeamMaskKernel (context, blender, layer, need_scale, need_slm); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, + kernel->build_kernel (kernels_info[kernel_idx], build_option) == XCAM_RETURN_NO_ERROR, + NULL, + "load seam mask scale kernel failed"); + return kernel; +} + +SmartPtr<CLImageHandler> +create_pyramid_blender ( + const SmartPtr<CLContext> &context, int layer, bool need_uv, + bool need_seam, CLBlenderScaleMode scale_mode) +{ + SmartPtr<CLPyramidBlender> blender; + SmartPtr<CLImageKernel> kernel; + int i = 0; + uint32_t buf_index = 0; + int max_plane = (need_uv ? 2 : 1); + bool uv_status[2] = {false, true}; + + XCAM_FAIL_RETURN ( + ERROR, + layer > 0 && layer <= XCAM_CL_PYRAMID_MAX_LEVEL, + NULL, + "create_pyramid_blender failed with wrong layer:%d, please set it between %d and %d", + layer, 1, XCAM_CL_PYRAMID_MAX_LEVEL); + + blender = new CLPyramidBlender (context, "cl_pyramid_blender", layer, need_uv, need_seam, scale_mode); + XCAM_ASSERT (blender.ptr ()); + + if (need_seam) { + kernel = create_seam_diff_kernel (context, blender); + XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create seam diff kernel failed"); + blender->add_kernel (kernel); + + kernel = create_seam_DP_kernel (context, blender); + XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create seam DP kernel failed"); + blender->add_kernel (kernel); + + for (i = 0; i < layer; ++i) { + bool need_scale = (i < layer - 1); + bool need_slm = (i == 0); + kernel = create_seam_mask_scale_kernel (context, blender, (uint32_t)i, need_scale, need_slm); + XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create seam mask scale kernel failed"); + blender->add_kernel (kernel); + } + } + + for (int plane = 0; plane < max_plane; ++plane) { + for (buf_index = 0; buf_index < XCAM_BLENDER_IMAGE_NUM; ++buf_index) { + for (i = 0; i < layer - 1; ++i) { + kernel = create_pyramid_transform_kernel (context, blender, (uint32_t)i, buf_index, uv_status[plane]); + XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create pyramid transform kernel failed"); + blender->add_kernel (kernel); + + kernel = create_pyramid_lap_kernel (context, blender, (uint32_t)i, buf_index, uv_status[plane]); + XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create pyramid lap transform kernel failed"); + blender->add_kernel (kernel); + } + } + + for (i = 0; i < layer; ++i) { + kernel = create_pyramid_blend_kernel (context, blender, (uint32_t)i, uv_status[plane], need_seam); + XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create pyramid blend kernel failed"); + blender->add_kernel (kernel); + } + + for (i = layer - 2; i >= 0 && i < layer; --i) { + kernel = create_pyramid_reconstruct_kernel (context, blender, (uint32_t)i, uv_status[plane]); + XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create pyramid reconstruct kernel failed"); + blender->add_kernel (kernel); + } + + if (scale_mode == CLBlenderScaleLocal) { + kernel = create_pyramid_blender_local_scale_kernel (context, blender, uv_status[plane]); + XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create pyramid blender local scaling kernel failed"); + blender->add_kernel (kernel); + } + + for (buf_index = 0; buf_index < XCAM_BLENDER_IMAGE_NUM; ++buf_index) { + kernel = create_pyramid_copy_kernel (context, blender, buf_index, uv_status[plane]); + XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create pyramid copy kernel failed"); + blender->add_kernel (kernel); + } + } + + return blender; +} + +} diff --git a/modules/ocl/cl_pyramid_blender.h b/modules/ocl/cl_pyramid_blender.h new file mode 100644 index 0000000..a89f107 --- /dev/null +++ b/modules/ocl/cl_pyramid_blender.h @@ -0,0 +1,391 @@ +/* + * cl_pyramid_blender.h - CL pyramid blender + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_PYRAMID_BLENDER_H +#define XCAM_CL_PYRAMID_BLENDER_H + +#include <xcam_std.h> +#include <ocl/cl_blender.h> + +#define CL_PYRAMID_ENABLE_DUMP 0 + +#define XCAM_CL_PYRAMID_MAX_LEVEL 4 + +namespace XCam { + +class CLPyramidBlender; + +enum { + BlendImageIndex = 0, + ReconstructImageIndex, + BlendImageCount +}; + +enum { + CLSeamMaskTmp = 0, + CLSeamMaskCoeff, + CLSeamMaskCount +}; + +struct PyramidLayer { + uint32_t blend_width; // blend, gauss, and lap + uint32_t blend_height; + SmartPtr<CLImage> gauss_image[CLBlenderPlaneMax][XCAM_BLENDER_IMAGE_NUM]; + int32_t gauss_offset_x[CLBlenderPlaneMax][XCAM_BLENDER_IMAGE_NUM]; // aligned with XCAM_BLENDER_ALIGNED_WIDTH + SmartPtr<CLImage> lap_image[CLBlenderPlaneMax][XCAM_BLENDER_IMAGE_NUM]; + int32_t lap_offset_x[CLBlenderPlaneMax][XCAM_BLENDER_IMAGE_NUM]; // aligned with XCAM_BLENDER_ALIGNED_WIDTH + SmartPtr<CLImage> blend_image[CLBlenderPlaneMax][BlendImageCount]; // 0 blend-image, 1 reconstruct image + uint32_t mask_width[CLBlenderPlaneMax]; + SmartPtr<CLBuffer> blend_mask[CLBlenderPlaneMax]; // sizeof(float) * mask_width + SmartPtr<CLImage> seam_mask[CLSeamMaskCount]; + SmartPtr<CLImage> scale_image[CLBlenderPlaneMax]; + +#if CL_PYRAMID_ENABLE_DUMP + SmartPtr<CLImage> dump_gauss_resize[CLBlenderPlaneMax]; + SmartPtr<CLImage> dump_original[CLBlenderPlaneMax][BlendImageCount]; + SmartPtr<CLImage> dump_final[CLBlenderPlaneMax]; +#endif + + PyramidLayer (); + void bind_buf_to_layer0 ( + SmartPtr<CLContext> context, + SmartPtr<VideoBuffer> &input0, SmartPtr<VideoBuffer> &input1, SmartPtr<VideoBuffer> &output, + const Rect &merge0_rect, const Rect &merge1_rect, bool need_uv, CLBlenderScaleMode scale_mode); + void init_layer0 (SmartPtr<CLContext> context, bool last_layer, bool need_uv, int mask_radius, float mask_sigma); + void build_cl_images (SmartPtr<CLContext> context, bool need_lap, bool need_uv); + bool copy_mask_from_y_to_uv (SmartPtr<CLContext> &context); +}; + +class CLLinearBlenderKernel; + +class CLPyramidBlendKernel; + +class CLPyramidBlender + : public CLBlender +{ + friend class CLPyramidBlendKernel; + +public: + explicit CLPyramidBlender ( + const SmartPtr<CLContext> &context, const char *name, + int layers, bool need_uv, bool need_seam, CLBlenderScaleMode scale_mode); + ~CLPyramidBlender (); + + //void set_blend_kernel (SmartPtr<CLLinearBlenderKernel> kernel, int index); + SmartPtr<CLImage> get_gauss_image (uint32_t layer, uint32_t buf_index, bool is_uv); + SmartPtr<CLImage> get_lap_image (uint32_t layer, uint32_t buf_index, bool is_uv); + SmartPtr<CLImage> get_blend_image (uint32_t layer, bool is_uv); + SmartPtr<CLImage> get_reconstruct_image (uint32_t layer, bool is_uv); + SmartPtr<CLImage> get_scale_image (bool is_uv); + SmartPtr<CLBuffer> get_blend_mask (uint32_t layer, bool is_uv); + SmartPtr<CLImage> get_seam_mask (uint32_t layer); + const PyramidLayer &get_pyramid_layer (uint32_t layer) const; + const SmartPtr<CLImage> &get_image_diff () const; + void get_seam_info (uint32_t &width, uint32_t &height, uint32_t &stride) const; + void get_seam_pos_info (uint32_t &offset_x, uint32_t &valid_width) const; + SmartPtr<CLBuffer> &get_seam_pos_buf () { + return _seam_pos_buf; + } + SmartPtr<CLBuffer> &get_seam_sum_buf () { + return _seam_sum_buf; + } + uint32_t get_layers () const { + return _layers; + } + XCamReturn fill_seam_mask (); + +protected: + // from CLImageHandler + virtual XCamReturn execute_done (SmartPtr<VideoBuffer> &output); + + // from CLBlender + virtual XCamReturn allocate_cl_buffers ( + SmartPtr<CLContext> context, SmartPtr<VideoBuffer> &input0, + SmartPtr<VideoBuffer> &input1, SmartPtr<VideoBuffer> &output); + +private: + XCamReturn init_seam_buffers (SmartPtr<CLContext> context); + void last_layer_buffer_redirect (); + + void dump_layer_mask (uint32_t layer, bool is_uv); + void dump_buffers (); + + XCAM_DEAD_COPY (CLPyramidBlender); + +private: + uint32_t _layers; + PyramidLayer _pyramid_layers[XCAM_CL_PYRAMID_MAX_LEVEL]; + + //calculate seam masks + bool _need_seam; + SmartPtr<CLImage> _image_diff; // image difference in blending area, only Y + uint32_t _seam_pos_stride; + uint32_t _seam_width, _seam_height; + uint32_t _seam_pos_offset_x, _seam_pos_valid_width; + SmartPtr<CLBuffer> _seam_pos_buf; // width = _seam_width; height = _seam_height; + SmartPtr<CLBuffer> _seam_sum_buf; // size = _seam_width + bool _seam_mask_done; + //SmartPtr<CLImage> _seam_mask; +}; + +class CLPyramidBlendKernel + : public CLImageKernel +{ +public: + explicit CLPyramidBlendKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, bool is_uv, bool need_seam); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); +private: + SmartPtr<CLImage> get_input_0 () { + return _blender->get_lap_image (_layer, 0, _is_uv); + } + SmartPtr<CLImage> get_input_1 () { + return _blender->get_lap_image (_layer, 1, _is_uv); + } + SmartPtr<CLImage> get_output () { + return _blender->get_blend_image (_layer, _is_uv); + } + SmartPtr<CLBuffer> get_blend_mask () { + return _blender->get_blend_mask (_layer, _is_uv); + } + SmartPtr<CLImage> get_seam_mask () { + return _blender->get_seam_mask (_layer); + } +private: + XCAM_DEAD_COPY (CLPyramidBlendKernel); + +private: + SmartPtr<CLPyramidBlender> _blender; + uint32_t _layer; + bool _is_uv; + bool _need_seam; + +}; + +class CLPyramidTransformKernel + : public CLImageKernel +{ +public: + explicit CLPyramidTransformKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, uint32_t buf_index, bool is_uv); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + +private: + SmartPtr<CLImage> get_input_gauss () { + return _blender->get_gauss_image (_layer, _buf_index, _is_uv); + } + int32_t get_input_gauss_offset_x (); + SmartPtr<CLImage> get_output_gauss () { + // need reset format + return _blender->get_gauss_image (_layer + 1, _buf_index, _is_uv); + } + + + XCAM_DEAD_COPY (CLPyramidTransformKernel); + +private: + SmartPtr<CLPyramidBlender> _blender; + uint32_t _layer; + uint32_t _buf_index; + bool _is_uv; +}; + +class CLSeamDiffKernel + : public CLImageKernel +{ +public: + explicit CLSeamDiffKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + +private: + SmartPtr<CLPyramidBlender> _blender; + +}; + +class CLSeamDPKernel + : public CLImageKernel +{ +public: + explicit CLSeamDPKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + +private: + SmartPtr<CLPyramidBlender> _blender; + int _seam_stride; + int _seam_height; + +}; + +class CLPyramidSeamMaskKernel + : public CLImageKernel +{ +public: + explicit CLPyramidSeamMaskKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, bool scale, bool need_slm); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + +private: + SmartPtr<CLPyramidBlender> _blender; + int _layer; + bool _need_scale; + bool _need_slm; +}; + +class CLPyramidLapKernel + : public CLImageKernel +{ +public: + explicit CLPyramidLapKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, uint32_t buf_index, bool is_uv); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + +private: + SmartPtr<CLImage> get_current_gauss () { + return _blender->get_gauss_image (_layer, _buf_index, _is_uv); + } + SmartPtr<CLImage> get_next_gauss () { + return _blender->get_gauss_image (_layer + 1, _buf_index, _is_uv); + } + int32_t get_cur_gauss_offset_x (); + int32_t get_output_lap_offset_x (); + + SmartPtr<CLImage> get_output_lap () { + return _blender->get_lap_image (_layer, _buf_index, _is_uv); + } + + XCAM_DEAD_COPY (CLPyramidLapKernel); + +private: + SmartPtr<CLPyramidBlender> _blender; + uint32_t _layer; + uint32_t _buf_index; + bool _is_uv; +}; + +class CLPyramidReconstructKernel + : public CLImageKernel +{ +public: + explicit CLPyramidReconstructKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, + uint32_t layer, bool is_uv); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + +private: + SmartPtr<CLImage> get_input_reconstruct () { + return _blender->get_reconstruct_image (_layer + 1, _is_uv); + } + SmartPtr<CLImage> get_input_lap () { + return _blender->get_blend_image (_layer, _is_uv); + } + SmartPtr<CLImage> get_output_reconstruct () { + return _blender->get_reconstruct_image (_layer, _is_uv); + } + + int get_output_reconstrcut_offset_x (); + + + XCAM_DEAD_COPY (CLPyramidReconstructKernel); + +private: + SmartPtr<CLPyramidBlender> _blender; + uint32_t _layer; + bool _is_uv; +}; + +class CLBlenderLocalScaleKernel + : public CLBlenderScaleKernel +{ +public: + explicit CLBlenderLocalScaleKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, bool is_uv); + +protected: + virtual SmartPtr<CLImage> get_input_image (); + virtual SmartPtr<CLImage> get_output_image (); + + virtual bool get_output_info (uint32_t &out_width, uint32_t &out_height, int &out_offset_x); + +private: + XCAM_DEAD_COPY (CLBlenderLocalScaleKernel); + +private: + SmartPtr<CLPyramidBlender> _blender; + SmartPtr<CLImage> _image_in; +}; + +class CLPyramidCopyKernel + : public CLImageKernel +{ +public: + explicit CLPyramidCopyKernel ( + const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, + uint32_t buf_index, bool is_uv); + +protected: + virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size); + +private: + SmartPtr<CLImage> get_input () { + return _blender->get_gauss_image (0, _buf_index, _is_uv); + } + SmartPtr<CLImage> get_output () { + if (_blender->get_scale_mode () == CLBlenderScaleLocal) + return _blender->get_scale_image (_is_uv); + else + return _blender->get_reconstruct_image (0, _is_uv); + } + + XCAM_DEAD_COPY (CLPyramidCopyKernel); + +private: + SmartPtr<CLPyramidBlender> _blender; + bool _is_uv; + int _buf_index; + + // parameters + int _max_g_x; + int _max_g_y; +}; + +}; + +#endif //XCAM_CL_PYRAMID_BLENDER_H + diff --git a/modules/ocl/cl_retinex_handler.cpp b/modules/ocl/cl_retinex_handler.cpp new file mode 100644 index 0000000..79b5dd1 --- /dev/null +++ b/modules/ocl/cl_retinex_handler.cpp @@ -0,0 +1,371 @@ +/* + * cl_retinex_handler.cpp - CL retinex handler + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: wangfei <feix.w.wang@intel.com> + * Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_utils.h" +#include "cl_retinex_handler.h" +#include <algorithm> +#include "cl_device.h" + +namespace XCam { + +static uint32_t retinex_gauss_scale [3] = {2, 8, 20}; //{20, 60, 150}; +static float retinex_gauss_sigma [3] = {2.0f, 8.0f, 20.0f}; //{12.0f, 40.0f, 120.0f}; +static float retinex_config_log_min = -0.12f; // -0.18f +static float retinex_config_log_max = 0.18f; //0.2f + +enum { + KernelScaler = 0, + KernelGaussian, + KernelRetinex, +}; + +const static XCamKernelInfo kernel_retinex_info [] = { + { + "kernel_image_scaler", +#include "kernel_image_scaler.clx" + , 0, + }, + { + "kernel_gauss", +#include "kernel_gauss.clx" + , 0, + }, + { + "kernel_retinex", +#include "kernel_retinex.clx" + , 0, + }, +}; + +CLRetinexScalerImageKernel::CLRetinexScalerImageKernel ( + const SmartPtr<CLContext> &context, + const CLImageScalerMemoryLayout mem_layout, + SmartPtr<CLRetinexImageHandler> &retinex) + : CLScalerKernel (context, mem_layout) + , _retinex(retinex) +{ +} + +SmartPtr<VideoBuffer> +CLRetinexScalerImageKernel::get_input_buffer () +{ + return _retinex->get_input_buf (); +} + +SmartPtr<VideoBuffer> +CLRetinexScalerImageKernel::get_output_buffer () +{ + return _retinex->get_scaler_buf1 (); +} + +CLRetinexGaussImageKernel::CLRetinexGaussImageKernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLRetinexImageHandler> &retinex, + uint32_t index, + uint32_t radius, float sigma) + : CLGaussImageKernel (context, radius, sigma) + , _retinex (retinex) + , _index (index) +{ +} + +SmartPtr<VideoBuffer> +CLRetinexGaussImageKernel::get_input_buf () +{ + return _retinex->get_scaler_buf1 (); +} + +SmartPtr<VideoBuffer> +CLRetinexGaussImageKernel::get_output_buf () +{ + return _retinex->get_gaussian_buf (_index); +} + +CLRetinexImageKernel::CLRetinexImageKernel (const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> &retinex) + : CLImageKernel (context, "kernel_retinex"), + _retinex (retinex) +{ +} + +XCamReturn +CLRetinexImageKernel::prepare_arguments ( + CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + SmartPtr<VideoBuffer> input = _retinex->get_input_buf (); + SmartPtr<VideoBuffer> output = _retinex->get_output_buf (); + + const VideoBufferInfo & video_info_in = input->get_video_info (); + const VideoBufferInfo & video_info_out = output->get_video_info (); + SmartPtr<CLImage> image_in, image_in_uv; + SmartPtr<CLImage> image_out, image_out_uv; + SmartPtr<CLImage> image_in_ga[XCAM_RETINEX_MAX_SCALE]; + + CLImageDesc cl_desc_in, cl_desc_out, cl_desc_ga; + + cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8; //CL_UNSIGNED_INT32; + cl_desc_in.format.image_channel_order = CL_RGBA; + cl_desc_in.width = video_info_in.width / 4; // 16; + cl_desc_in.height = video_info_in.height; + cl_desc_in.row_pitch = video_info_in.strides[0]; + image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]); + + cl_desc_in.height = video_info_in.height / 2; + cl_desc_in.row_pitch = video_info_in.strides[1]; + image_in_uv = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[1]); + + cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8; //CL_UNSIGNED_INT32; + cl_desc_out.format.image_channel_order = CL_RGBA; + cl_desc_out.width = video_info_out.width / 4; // 16; + cl_desc_out.height = video_info_out.height; + cl_desc_out.row_pitch = video_info_out.strides[0]; + image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[0]); + + cl_desc_out.height = video_info_out.height / 2; + cl_desc_out.row_pitch = video_info_out.strides[1]; + image_out_uv = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[1]); + + XCAM_FAIL_RETURN ( + WARNING, + image_in->is_valid () && image_in_uv->is_valid () && + image_out->is_valid () && image_out_uv->is_valid(), + XCAM_RETURN_ERROR_MEM, + "cl image kernel(%s) in/out memory not available", get_kernel_name ()); + + for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) { + SmartPtr<VideoBuffer> gaussian_buf = _retinex->get_gaussian_buf (i); + XCAM_ASSERT (gaussian_buf.ptr ()); + + const VideoBufferInfo & video_info_gauss = gaussian_buf->get_video_info (); + + cl_desc_ga.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc_ga.format.image_channel_order = CL_R; + cl_desc_ga.width = video_info_gauss.width; + cl_desc_ga.height = video_info_gauss.height; + cl_desc_ga.row_pitch = video_info_gauss.strides[0]; + image_in_ga[i] = convert_to_climage (context, gaussian_buf, cl_desc_ga, video_info_gauss.offsets[0]); + + XCAM_FAIL_RETURN ( + WARNING, + image_in_ga[i]->is_valid (), + XCAM_RETURN_ERROR_MEM, + "cl image kernel(%s) gauss memory[%d] is invalid", get_kernel_name (), i); + } + CLRetinexConfig retinex_config; + retinex_config.log_min = retinex_config_log_min; + retinex_config.log_max = retinex_config_log_max; + retinex_config.gain = 1.0f / (retinex_config.log_max - retinex_config.log_min); + retinex_config.width = (float)video_info_in.width; + retinex_config.height = (float)video_info_in.height; + + //set args; + args.push_back (new CLMemArgument (image_in)); + args.push_back (new CLMemArgument (image_in_uv)); + for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) { + args.push_back (new CLMemArgument (image_in_ga[i])); + } + args.push_back (new CLMemArgument (image_out)); + args.push_back (new CLMemArgument (image_out_uv)); + args.push_back (new CLArgumentT<CLRetinexConfig> (retinex_config)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.global[0] = video_info_out.width / 4; + work_size.global[1] = video_info_out.height; + work_size.local[0] = 16; + work_size.local[1] = 2; + + return XCAM_RETURN_NO_ERROR; +} + +CLRetinexImageHandler::CLRetinexImageHandler (const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) + , _scaler_factor(XCAM_RETINEX_SCALER_FACTOR) +{ +} + +void +CLRetinexImageHandler::emit_stop () +{ + if (_scaler_buf_pool.ptr ()) + _scaler_buf_pool->stop (); +} + +XCamReturn +CLRetinexImageHandler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + CLImageHandler::prepare_output_buf(input, output); + XCamReturn ret = XCAM_RETURN_NO_ERROR; + ret = prepare_scaler_buf (input->get_video_info ()); + XCAM_FAIL_RETURN( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "CLRetinexImageHandler prepare scaled video buf failed"); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLRetinexImageHandler::prepare_scaler_buf (const VideoBufferInfo &video_info) +{ + if (!_scaler_buf_pool.ptr ()) { + SmartPtr<CLContext> context = get_context (); + VideoBufferInfo scaler_video_info; + uint32_t new_width = XCAM_ALIGN_UP ((uint32_t)(video_info.width * _scaler_factor), 8); + uint32_t new_height = XCAM_ALIGN_UP ((uint32_t)(video_info.height * _scaler_factor), 4); + + scaler_video_info.init (video_info.format, new_width, new_height); + + _scaler_buf_pool = new CLVideoBufferPool (); + XCAM_ASSERT (_scaler_buf_pool.ptr ()); + _scaler_buf_pool->set_video_info (scaler_video_info); + _scaler_buf_pool->reserve (XCAM_RETINEX_MAX_SCALE + 1); + + _scaler_buf1 = _scaler_buf_pool->get_buffer (_scaler_buf_pool); + XCAM_ASSERT (_scaler_buf1.ptr ()); + + for (int i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) { + _gaussian_buf[i] = _scaler_buf_pool->get_buffer (_scaler_buf_pool); + XCAM_ASSERT (_gaussian_buf[i].ptr ()); + } + } + + return XCAM_RETURN_NO_ERROR; +} + +bool +CLRetinexImageHandler::set_retinex_kernel(SmartPtr<CLRetinexImageKernel> &kernel) +{ + SmartPtr<CLImageKernel> image_kernel = kernel; + add_kernel (image_kernel); + _retinex_kernel = kernel; + return true; +} + +bool +CLRetinexImageHandler::set_retinex_scaler_kernel(SmartPtr<CLRetinexScalerImageKernel> &kernel) +{ + SmartPtr<CLImageKernel> image_kernel = kernel; + add_kernel (image_kernel); + _retinex_scaler_kernel = kernel; + return true; +} + +static SmartPtr<CLRetinexScalerImageKernel> +create_kernel_retinex_scaler ( + const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> handler) +{ + SmartPtr<CLRetinexScalerImageKernel> kernel; + + kernel = new CLRetinexScalerImageKernel (context, CL_IMAGE_SCALER_NV12_Y, handler); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, kernel->build_kernel (kernel_retinex_info[KernelScaler], NULL) == XCAM_RETURN_NO_ERROR, NULL, + "build retinex scaler kernel(%s) failed", kernel_retinex_info[KernelScaler].kernel_name); + + XCAM_ASSERT (kernel->is_valid ()); + return kernel; +} + +static SmartPtr<CLRetinexGaussImageKernel> +create_kernel_retinex_gaussian ( + const SmartPtr<CLContext> &context, + SmartPtr<CLRetinexImageHandler> handler, + uint32_t index, + uint32_t radius, float sigma) +{ + SmartPtr<CLRetinexGaussImageKernel> kernel; + char build_options[1024]; + + xcam_mem_clear (build_options); + snprintf (build_options, sizeof (build_options), " -DGAUSS_RADIUS=%d ", radius); + + kernel = new CLRetinexGaussImageKernel (context, handler, index, radius, sigma); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, kernel->build_kernel (kernel_retinex_info[KernelGaussian], build_options) == XCAM_RETURN_NO_ERROR, NULL, + "build retinex gaussian kernel(%s) failed", kernel_retinex_info[KernelGaussian].kernel_name); + + XCAM_ASSERT (kernel->is_valid ()); + + return kernel; +} + +static SmartPtr<CLRetinexImageKernel> +create_kernel_retinex (const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> handler) +{ + SmartPtr<CLRetinexImageKernel> kernel; + char build_options[1024]; + + xcam_mem_clear (build_options); + snprintf (build_options, sizeof (build_options), " -DRETINEX_SCALE_SIZE=%d ", XCAM_RETINEX_MAX_SCALE); + + kernel = new CLRetinexImageKernel (context, handler); + XCAM_ASSERT (kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, kernel->build_kernel (kernel_retinex_info[KernelRetinex], build_options) == XCAM_RETURN_NO_ERROR, NULL, + "build retinex kernel(%s) failed", kernel_retinex_info[KernelRetinex].kernel_name); + + XCAM_ASSERT (kernel->is_valid ()); + return kernel; +} + +SmartPtr<CLImageHandler> +create_cl_retinex_image_handler (const SmartPtr<CLContext> &context) +{ + SmartPtr<CLRetinexImageHandler> retinex_handler; + + SmartPtr<CLRetinexScalerImageKernel> retinex_scaler_kernel; + SmartPtr<CLRetinexImageKernel> retinex_kernel; + + retinex_handler = new CLRetinexImageHandler (context, "cl_handler_retinex"); + retinex_scaler_kernel = create_kernel_retinex_scaler (context, retinex_handler); + XCAM_FAIL_RETURN ( + ERROR, + retinex_scaler_kernel.ptr () && retinex_scaler_kernel->is_valid (), + NULL, + "Retinex handler create scaler kernel failed"); + retinex_handler->set_retinex_scaler_kernel (retinex_scaler_kernel); + + for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) { + SmartPtr<CLImageKernel> retinex_gauss_kernel; + retinex_gauss_kernel = create_kernel_retinex_gaussian ( + context, retinex_handler, i, retinex_gauss_scale [i], retinex_gauss_sigma [i]); + XCAM_FAIL_RETURN ( + ERROR, + retinex_gauss_kernel.ptr () && retinex_gauss_kernel->is_valid (), + NULL, + "Retinex handler create gaussian kernel failed"); + retinex_handler->add_kernel (retinex_gauss_kernel); + } + + retinex_kernel = create_kernel_retinex (context, retinex_handler); + XCAM_FAIL_RETURN ( + ERROR, + retinex_kernel.ptr () && retinex_kernel->is_valid (), + NULL, + "Retinex handler create retinex kernel failed"); + retinex_handler->set_retinex_kernel (retinex_kernel); + + return retinex_handler; +} + +} diff --git a/modules/ocl/cl_retinex_handler.h b/modules/ocl/cl_retinex_handler.h new file mode 100644 index 0000000..72dd724 --- /dev/null +++ b/modules/ocl/cl_retinex_handler.h @@ -0,0 +1,140 @@ +/* + * cl_retinex_handler.h - CL retinex handler. + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: wangfei <feix.w.wang@intel.com> + * Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_RETINEX_HANLDER_H +#define XCAM_CL_RETINEX_HANLDER_H + +#include <xcam_std.h> +#include <base/xcam_3a_result.h> +#include <x3a_stats_pool.h> +#include <ocl/cl_image_scaler.h> +#include <ocl/cl_gauss_handler.h> + +#define XCAM_RETINEX_MAX_SCALE 2 +#define XCAM_RETINEX_SCALER_FACTOR 0.5 + +namespace XCam { + +typedef struct { + float gain; + float threshold; + float log_min; + float log_max; + float width; + float height; +} CLRetinexConfig; + +class CLRetinexImageHandler; + +class CLRetinexScalerImageKernel + : public CLScalerKernel +{ +public: + explicit CLRetinexScalerImageKernel ( + const SmartPtr<CLContext> &context, + CLImageScalerMemoryLayout mem_layout, + SmartPtr<CLRetinexImageHandler> &retinex); + +protected: + //derived from CLScalerKernel + virtual SmartPtr<VideoBuffer> get_input_buffer (); + virtual SmartPtr<VideoBuffer> get_output_buffer (); + +private: + SmartPtr<CLRetinexImageHandler> _retinex; + +}; + +class CLRetinexGaussImageKernel + : public CLGaussImageKernel +{ +public: + explicit CLRetinexGaussImageKernel ( + const SmartPtr<CLContext> &context, + SmartPtr<CLRetinexImageHandler> &retinex, + uint32_t index, + uint32_t radius, float sigma); + virtual SmartPtr<VideoBuffer> get_input_buf (); + virtual SmartPtr<VideoBuffer> get_output_buf (); + + +private: + SmartPtr<CLRetinexImageHandler> _retinex; + uint32_t _index; + +}; + +class CLRetinexImageKernel + : public CLImageKernel +{ +public: + explicit CLRetinexImageKernel (const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> &retinex); + +protected: + virtual XCamReturn prepare_arguments ( + CLArgList &args, CLWorkSize &work_size); + +private: + SmartPtr<CLRetinexImageHandler> _retinex; +}; + +class CLRetinexImageHandler + : public CLImageHandler +{ +public: + explicit CLRetinexImageHandler (const SmartPtr<CLContext> &context, const char *name); + bool set_retinex_kernel(SmartPtr<CLRetinexImageKernel> &kernel); + bool set_retinex_scaler_kernel(SmartPtr<CLRetinexScalerImageKernel> &kernel); + //bool set_retinex_gauss_kernel(SmartPtr<CLRetinexGaussImageKernel> &kernel); + SmartPtr<VideoBuffer> &get_scaler_buf1 () { + return _scaler_buf1; + }; + SmartPtr<VideoBuffer> &get_gaussian_buf (uint index) { + XCAM_ASSERT (index < XCAM_RETINEX_MAX_SCALE); + return _gaussian_buf[index]; + }; + + virtual void emit_stop (); + +protected: + virtual XCamReturn prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + XCamReturn prepare_scaler_buf (const VideoBufferInfo &video_info); + +private: + SmartPtr<CLRetinexImageKernel> _retinex_kernel; + SmartPtr<CLRetinexScalerImageKernel> _retinex_scaler_kernel; + //SmartPtr<CLRetinexGaussImageKernel> _retinex_gauss_kernel; + + double _scaler_factor; + SmartPtr<BufferPool> _scaler_buf_pool; + SmartPtr<VideoBuffer> _scaler_buf1; + SmartPtr<VideoBuffer> _gaussian_buf[XCAM_RETINEX_MAX_SCALE]; + +}; + +SmartPtr<CLImageHandler> +create_cl_retinex_image_handler (const SmartPtr<CLContext> &context); + +}; + +#endif //XCAM_CL_RETINEX_HANLDER_H diff --git a/modules/ocl/cl_rgb_pipe_handler.cpp b/modules/ocl/cl_rgb_pipe_handler.cpp new file mode 100644 index 0000000..d49b4b4 --- /dev/null +++ b/modules/ocl/cl_rgb_pipe_handler.cpp @@ -0,0 +1,152 @@ +/* + * cl_rgb_pipe_handler.cpp - CL rgb pipe handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Shincy Tu <shincy.tu@intel.com> + * Author: Wei Zong <wei.zong@intel.com> + * Author: Wangfei <feix.w.wang@intel.com> + */ + +#include "cl_utils.h" +#include "base/xcam_3a_result.h" +#include "cl_rgb_pipe_handler.h" + +namespace XCam { + +static const XCamKernelInfo kernel_rgb_pipe_info = { + "kernel_rgb_pipe", +#include "kernel_rgb_pipe.clx" + , 0, +}; + +CLRgbPipeImageKernel::CLRgbPipeImageKernel (const SmartPtr<CLContext> &context) + : CLImageKernel (context, "kernel_rgb_pipe") +{ +} + +CLRgbPipeImageHandler::CLRgbPipeImageHandler (const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) +{ + _tnr_config.thr_r = 0.064; + _tnr_config.thr_g = 0.045; + _tnr_config.thr_b = 0.073; +} + +bool +CLRgbPipeImageHandler::set_rgb_pipe_kernel(SmartPtr<CLRgbPipeImageKernel> &kernel) +{ + SmartPtr<CLImageKernel> image_kernel = kernel; + add_kernel (image_kernel); + _rgb_pipe_kernel = kernel; + return true; +} + +bool +CLRgbPipeImageHandler::set_tnr_config (const XCam3aResultTemporalNoiseReduction& config) +{ + if (!_rgb_pipe_kernel->is_valid ()) { + XCAM_LOG_ERROR ("set config error, invalid TNR kernel !"); + } + + _tnr_config.gain = (float)config.gain; + _tnr_config.thr_r = (float)config.threshold[0]; + _tnr_config.thr_g = (float)config.threshold[1]; + _tnr_config.thr_b = (float)config.threshold[2]; + XCAM_LOG_DEBUG ("set TNR RGB config: _gain(%f), _thr_r(%f), _thr_g(%f), _thr_b(%f)", + _tnr_config.gain, _tnr_config.thr_r, _tnr_config.thr_g, _tnr_config.thr_b); + + return true; +} + +XCamReturn +CLRgbPipeImageHandler::prepare_parameters ( + SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + SmartPtr<CLContext> context = get_context (); + const VideoBufferInfo & video_info = input->get_video_info (); + CLArgList args; + CLWorkSize work_size; + + CLImageDesc desc; + desc.format.image_channel_order = CL_RGBA; + desc.format.image_channel_data_type = CL_UNORM_INT16; + desc.width = video_info.width; + desc.height = video_info.height; + desc.array_size = 0; + desc.row_pitch = video_info.strides[0]; + desc.slice_pitch = 0; + + XCAM_ASSERT (_rgb_pipe_kernel.ptr ()); + SmartPtr<CLImage> image_in = convert_to_climage (context, input, desc); + SmartPtr<CLImage> image_out = convert_to_climage (context, output, desc); + + if (_image_in_list.size () < 4) { + while (_image_in_list.size () < 4) { + _image_in_list.push_back (image_in); + } + } else { + _image_in_list.pop_front (); + _image_in_list.push_back (image_in); + } + XCAM_FAIL_RETURN ( + WARNING, + image_in->is_valid () && image_out->is_valid (), + XCAM_RETURN_ERROR_MEM, + "cl image handler(%s) in/out memory not available", XCAM_STR(get_name ())); + + //set args; + args.push_back (new CLMemArgument (image_out)); + args.push_back (new CLArgumentT<CLRgbPipeTnrConfig> (_tnr_config)); + + for (CLImagePtrList::iterator it = _image_in_list.begin (); it != _image_in_list.end (); it++) { + args.push_back (new CLMemArgument (*it)); + } + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.global[0] = XCAM_ALIGN_UP(video_info.width, 16); + work_size.global[1] = XCAM_ALIGN_UP(video_info.height, 16); + work_size.local[0] = 8; + work_size.local[1] = 4; + + XCAM_ASSERT (_rgb_pipe_kernel.ptr ()); + XCamReturn ret = _rgb_pipe_kernel->set_arguments (args, work_size); + XCAM_FAIL_RETURN ( + WARNING, ret == XCAM_RETURN_NO_ERROR, ret, + "rgb pipe kernel set arguments failed."); + + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<CLImageHandler> +create_cl_rgb_pipe_image_handler (const SmartPtr<CLContext> &context) +{ + SmartPtr<CLRgbPipeImageHandler> rgb_pipe_handler; + SmartPtr<CLRgbPipeImageKernel> rgb_pipe_kernel; + + rgb_pipe_kernel = new CLRgbPipeImageKernel (context); + XCAM_ASSERT (rgb_pipe_kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, rgb_pipe_kernel->build_kernel (kernel_rgb_pipe_info, NULL) == XCAM_RETURN_NO_ERROR, NULL, + "build rgb-pipe kernel(%s) failed", kernel_rgb_pipe_info.kernel_name); + + XCAM_ASSERT (rgb_pipe_kernel->is_valid ()); + rgb_pipe_handler = new CLRgbPipeImageHandler (context, "cl_handler_rgb_pipe"); + rgb_pipe_handler->set_rgb_pipe_kernel (rgb_pipe_kernel); + + return rgb_pipe_handler; +} + +}; diff --git a/modules/ocl/cl_rgb_pipe_handler.h b/modules/ocl/cl_rgb_pipe_handler.h new file mode 100644 index 0000000..def6ea9 --- /dev/null +++ b/modules/ocl/cl_rgb_pipe_handler.h @@ -0,0 +1,69 @@ +/* + * cl_rgb_pipe_handler.h - CL rgb pipe handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Shincy Tu <shincy.tu@intel.com> + * Author: Wei Zong <wei.zong@intel.com> + * Author: Wangfei <feix.w.wang@intel.com> + */ + +#ifndef XCAM_CL_RGB_PIPE_HANLDER_H +#define XCAM_CL_RGB_PIPE_HANLDER_H + +#include <xcam_std.h> +#include <ocl/cl_image_handler.h> + +namespace XCam { + +typedef struct { + float thr_r; + float thr_g; + float thr_b; + float gain; +} CLRgbPipeTnrConfig; + +class CLRgbPipeImageKernel + : public CLImageKernel +{ +public: + explicit CLRgbPipeImageKernel (const SmartPtr<CLContext> &context); +}; + +class CLRgbPipeImageHandler + : public CLImageHandler +{ + typedef std::list<SmartPtr<CLImage>> CLImagePtrList; +public: + explicit CLRgbPipeImageHandler (const SmartPtr<CLContext> &context, const char *name); + bool set_rgb_pipe_kernel (SmartPtr<CLRgbPipeImageKernel> &kernel); + bool set_tnr_config (const XCam3aResultTemporalNoiseReduction& config); + +protected: + virtual XCamReturn prepare_parameters ( + SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + SmartPtr<CLRgbPipeImageKernel> _rgb_pipe_kernel; + CLRgbPipeTnrConfig _tnr_config; + CLImagePtrList _image_in_list; +}; + +SmartPtr<CLImageHandler> +create_cl_rgb_pipe_image_handler (const SmartPtr<CLContext> &context); + +}; + +#endif //XCAM_CL_RGB_PIPE_HANLDER_H diff --git a/modules/ocl/cl_tnr_handler.cpp b/modules/ocl/cl_tnr_handler.cpp new file mode 100644 index 0000000..acbb644 --- /dev/null +++ b/modules/ocl/cl_tnr_handler.cpp @@ -0,0 +1,467 @@ +/* + * cl_tnr_handler.cpp - CL tnr handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wei Zong <wei.zong@intel.com> + */ + +#include "cl_tnr_handler.h" + +#define TNR_PROCESSING_FRAME_COUNT 4 +#define TNR_LIST_FRAME_COUNT 4 +#define TNR_MOTION_THRESHOLD 2 + +namespace XCam { + +static const XCamKernelInfo kernel_tnr_yuv_info = { + "kernel_tnr_yuv", +#include "kernel_tnr.clx" + , 0 +}; + +static const XCamKernelInfo kernel_tnr_rgb_info = { + "kernel_tnr_rgb", +#include "kernel_tnr.clx" + , 0, +}; + +CLTnrImageHandler::CLTnrMotionInfo::CLTnrMotionInfo () + : hor_shift (0) + , ver_shift (0) + , hor_corr (0) + , ver_corr (0) +{ +} + +CLTnrImageHandler::CLTnrHistogram::CLTnrHistogram() { + hor_hist_bin = 0; + ver_hist_bin = 0; + hor_hist_current = NULL; + hor_hist_reference = NULL; + ver_hist_current = NULL; + ver_hist_reference = NULL; +}; + +CLTnrImageHandler::CLTnrHistogram::CLTnrHistogram(uint32_t width, uint32_t height) { + hor_hist_bin = width; + ver_hist_bin = height; + if ((NULL == hor_hist_current) && (hor_hist_bin != 0)) { + hor_hist_current = (float*)xcam_malloc0(hor_hist_bin * sizeof(float)); + } + if ((NULL == ver_hist_current) && (ver_hist_bin != 0)) { + ver_hist_current = (float*)xcam_malloc0(ver_hist_bin * sizeof(float)); + } + if ((NULL == hor_hist_reference) && (hor_hist_bin != 0)) { + hor_hist_reference = (float*)xcam_malloc0(hor_hist_bin * sizeof(float)); + } + if ((NULL == ver_hist_reference) && (ver_hist_bin != 0)) { + ver_hist_reference = (float*)xcam_malloc0(ver_hist_bin * sizeof(float)); + } +}; + +CLTnrImageHandler::CLTnrHistogram::~CLTnrHistogram() { + if (NULL != hor_hist_current) { + xcam_free(hor_hist_current); + hor_hist_current = NULL; + } + if (NULL != ver_hist_current) { + xcam_free(ver_hist_current); + ver_hist_current = NULL; + } + if (NULL != hor_hist_reference) { + xcam_free(hor_hist_reference); + hor_hist_reference = NULL; + } + if (NULL != ver_hist_reference) { + xcam_free(ver_hist_reference); + ver_hist_reference = NULL; + } + hor_hist_bin = 0; + ver_hist_bin = 0; +} + +CLTnrImageKernel::CLTnrImageKernel ( + const SmartPtr<CLContext> &context, CLTnrType type) + : CLImageKernel (context) + , _type (type) +{ +} + +bool +CLTnrImageHandler::calculate_image_histogram (XCam3AStats* stats, CLTnrHistogramType type, float* histogram) +{ + if ( NULL == stats || NULL == histogram ) { + return false; + } + + uint32_t normalize_factor = (1 << stats->info.bit_depth) - 1; + uint32_t image_width = stats->info.width; + uint32_t image_height = stats->info.height; + uint32_t image_aligned_width = stats->info.aligned_width; + uint32_t hor_hist_bin = image_width; + uint32_t ver_hist_bin = image_height; + + switch (type) { + case CL_TNR_HIST_HOR_PROJECTION : + for (uint32_t bin = 0; bin < hor_hist_bin; bin++) { + for (uint32_t row_index = 0; row_index < image_height; row_index++) { + histogram[bin] += (float)(stats->stats[row_index * image_aligned_width + bin].avg_y) + / (1.0 * normalize_factor); + } + } + break; + case CL_TNR_HIST_VER_PROJECTION : + for (uint32_t bin = 0; bin < ver_hist_bin; bin++) { + for (uint32_t col_index = 0; col_index < image_width; col_index++) { + histogram[bin] += (float)(stats->stats[col_index + bin * image_aligned_width].avg_y) + / (1.0 * normalize_factor); + } + } + break; + case CL_TNR_HIST_BRIGHTNESS : + for (uint32_t row_index = 0; row_index < image_height; row_index++) { + for (uint32_t col_index = 0; col_index < image_width; col_index++) { + uint8_t bin = (stats->stats[row_index * image_aligned_width + col_index].avg_y * 255) + / normalize_factor; + histogram[bin]++; + } + } + break; + default : + break; + } + + return true; +} + +bool +CLTnrImageHandler::calculate_image_histogram (SmartPtr<VideoBuffer> &input, CLTnrHistogramType type, float* histogram) +{ + if ( NULL == histogram ) { + return false; + } + + uint32_t normalize_factor = (1 << input->get_video_info ().color_bits) - 1; + uint32_t image_width = input->get_video_info ().width; + uint32_t image_height = input->get_video_info ().height; + uint32_t image_aligned_width = input->get_video_info ().aligned_width; + uint32_t stride = input->get_video_info ().strides[0]; + + uint32_t hor_hist_bin = image_width; + uint32_t ver_hist_bin = image_height; + uint32_t pxiel_bytes = stride / image_aligned_width; + + uint32_t format = input->get_video_info ().format; + if (XCAM_PIX_FMT_RGBA64 != format) { + XCAM_LOG_ERROR ("Only support RGBA64 format !"); + return false; + } + + uint8_t* image_buffer = input->map(); + if (NULL == image_buffer) { + return false; + } + + switch (type) { + case CL_TNR_HIST_HOR_PROJECTION : + for (uint32_t bin = 0; bin < hor_hist_bin; bin++) { + for (uint32_t row_index = 0; row_index < image_height; row_index++) { + histogram[bin] += (float)(image_buffer[row_index * stride + pxiel_bytes * bin] + + (image_buffer[row_index * stride + pxiel_bytes * bin + 1] << 8) + + image_buffer[row_index * stride + pxiel_bytes * bin + 2] + + (image_buffer[row_index * stride + pxiel_bytes * bin + 3] << 8) + + image_buffer[row_index * stride + pxiel_bytes * bin + 4] + + (image_buffer[row_index * stride + pxiel_bytes * bin + 5] << 8) ) + / (3.0 * normalize_factor); + } + } + break; + case CL_TNR_HIST_VER_PROJECTION : + for (uint32_t bin = 0; bin < ver_hist_bin; bin++) { + for (uint32_t col_index = 0; col_index < stride; col_index += pxiel_bytes) { + histogram[bin] += (float)(image_buffer[col_index + bin * stride] + + (image_buffer[col_index + bin * stride + 1] << 8) + + image_buffer[col_index + bin * stride + 2] + + (image_buffer[col_index + bin * stride + 3] << 8) + + image_buffer[col_index + bin * stride + 4] + + (image_buffer[col_index + bin * stride + 5] << 8) ) + / (3.0 * normalize_factor); + } + } + break; + case CL_TNR_HIST_BRIGHTNESS : + for (uint32_t row_index = 0; row_index < image_height; row_index++) { + for (uint32_t col_index = 0; col_index < stride; col_index += pxiel_bytes) { + uint8_t bin = (image_buffer[row_index * stride + col_index] + + (image_buffer[row_index * stride + col_index + 1] << 8) + + image_buffer[row_index * stride + col_index + 2] + + (image_buffer[row_index * stride + col_index + 3] << 8) + + image_buffer[row_index * stride + col_index + 4] + + (image_buffer[row_index * stride + col_index + 5] << 8) ) * 255 + / (3 * normalize_factor); + histogram[bin]++; + } + } + break; + default : + break; + } + + input->unmap(); + + return true; +} + +void +CLTnrImageHandler::print_image_histogram () +{ + uint32_t hor_hist_bin = _image_histogram.hor_hist_bin; + uint32_t ver_hist_bin = _image_histogram.ver_hist_bin; + + XCAM_LOG_DEBUG ("hor hist bin = %d, ver hist bin = %d", hor_hist_bin, ver_hist_bin); + + printf("float hor_hist_current[] = { "); + for (uint32_t i = 0; i < hor_hist_bin; i++) { + printf("%f, ", _image_histogram.hor_hist_current[i]); + } + printf(" }; \n\n\n"); + + printf("float ver_hist_current[] = { "); + for (uint32_t i = 0; i < ver_hist_bin; i++) { + printf("%f, ", _image_histogram.ver_hist_current[i]); + } + printf(" }; \n\n\n"); + + printf("float hor_hist_reference[] = { "); + for (uint32_t i = 0; i < hor_hist_bin; i++) { + printf("%f, ", _image_histogram.hor_hist_reference[i]); + } + printf(" }; \n\n\n"); + + printf("float ver_hist_reference[] = { "); + for (uint32_t i = 0; i < ver_hist_bin; i++) { + printf("%f, ", _image_histogram.ver_hist_reference[i]); + } + printf(" }; \n\n\n"); +} + +CLTnrImageHandler::CLTnrImageHandler (const SmartPtr<CLContext> &context, CLTnrType type, const char *name) + : CLImageHandler (context, name) + , _type (type) + , _gain_yuv (1.0) + , _thr_y (0.05) + , _thr_uv (0.05) + , _gain_rgb (0.0) + , _thr_r (0.064) // set high initial threshold to get strong denoise effect + , _thr_g (0.045) + , _thr_b (0.073) + , _frame_count (TNR_PROCESSING_FRAME_COUNT) +{ +} + +bool +CLTnrImageHandler::set_tnr_kernel(SmartPtr<CLTnrImageKernel> &kernel) +{ + SmartPtr<CLImageKernel> image_kernel = kernel; + add_kernel (image_kernel); + _tnr_kernel = kernel; + return true; +} + +bool +CLTnrImageHandler::set_framecount (uint8_t count) +{ + if (!_tnr_kernel->is_valid ()) { + XCAM_LOG_ERROR ("set framecount error, invalid TNR kernel !"); + return false; + } + + XCAM_ASSERT (count >= 2 && count <= 4); + _frame_count = count; + + return true; +} + +bool +CLTnrImageHandler::set_rgb_config (const XCam3aResultTemporalNoiseReduction& config) + +{ + if (!_tnr_kernel->is_valid ()) { + XCAM_LOG_ERROR ("set threshold error, invalid TNR kernel !"); + return false; + } + _gain_rgb = (float)config.gain; + _thr_r = (float)config.threshold[0]; + _thr_g = (float)config.threshold[1]; + _thr_b = (float)config.threshold[2]; + XCAM_LOG_DEBUG ("set TNR RGB config: _gain(%f), _thr_r(%f), _thr_g(%f), _thr_b(%f)", + _gain_rgb, _thr_r, _thr_g, _thr_b); + + return true; +} + +bool +CLTnrImageHandler::set_yuv_config (const XCam3aResultTemporalNoiseReduction& config) + +{ + if (!_tnr_kernel->is_valid ()) { + XCAM_LOG_ERROR ("set threshold error, invalid TNR kernel !"); + return false; + } + + _gain_yuv = (float)config.gain; + _thr_y = (float)config.threshold[0]; + _thr_uv = (float)config.threshold[1]; + + XCAM_LOG_DEBUG ("set TNR YUV config: _gain(%f), _thr_y(%f), _thr_uv(%f)", + _gain_yuv, _thr_y, _thr_uv); + + return true; +} + +XCamReturn +CLTnrImageHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + SmartPtr<CLContext> context = get_context (); + const VideoBufferInfo & video_info = input->get_video_info (); + CLArgList args; + CLWorkSize work_size; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (_tnr_kernel.ptr ()); + + CLImageDesc desc; + if (CL_TNR_TYPE_YUV == _type) { + desc.format.image_channel_order = CL_R; + desc.format.image_channel_data_type = CL_UNORM_INT8; + desc.width = video_info.aligned_width; + desc.height = video_info.aligned_height + video_info.height / 2; + desc.row_pitch = video_info.strides[0]; + desc.array_size = 2; + desc.slice_pitch = video_info.strides [0] * video_info.aligned_height; + } else if (CL_TNR_TYPE_RGB == _type) { + desc.format.image_channel_order = CL_RGBA; + desc.format.image_channel_data_type = CL_UNORM_INT8; + desc.width = video_info.aligned_width; + desc.height = video_info.height; + desc.row_pitch = video_info.strides[0]; + desc.array_size = 0; + desc.slice_pitch = 0; + } + + SmartPtr<CLImage> image_in = convert_to_climage (context, input, desc); + SmartPtr<CLImage> image_out = convert_to_climage (context, output, desc); + + XCAM_FAIL_RETURN ( + WARNING, + image_in->is_valid () && image_out->is_valid (), + XCAM_RETURN_ERROR_MEM, + "cl image kernel(%s) in/out memory not available", _tnr_kernel->get_kernel_name ()); + + if (CL_TNR_TYPE_YUV == _type) { + if (!_image_out_prev.ptr ()) { + _image_out_prev = image_in; + } + } else if (CL_TNR_TYPE_RGB == _type) { + // analyze motion between the latest adjacent two frames + // Todo: enable analyze when utilize motion compensation next step + + if (_image_in_list.size () < TNR_LIST_FRAME_COUNT) { + while (_image_in_list.size () < TNR_LIST_FRAME_COUNT) { + _image_in_list.push_back (image_in); + } + } else { + _image_in_list.pop_front (); + _image_in_list.push_back (image_in); + } + } + + uint32_t vertical_offset = video_info.aligned_height; + + //set args; + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 8; + work_size.local[1] = 4; + if (CL_TNR_TYPE_YUV == _type) { + args.push_back (new CLMemArgument (image_in)); + args.push_back (new CLMemArgument (_image_out_prev)); + args.push_back (new CLMemArgument (image_out)); + args.push_back (new CLArgumentT<uint> (vertical_offset)); + + args.push_back (new CLArgumentT<float> (_gain_yuv)); + args.push_back (new CLArgumentT<float> (_thr_y)); + args.push_back (new CLArgumentT<float> (_thr_uv)); + + work_size.global[0] = video_info.width / 2; + work_size.global[1] = video_info.height / 2; + } + else if (CL_TNR_TYPE_RGB == _type) { + const CLImageDesc out_info = image_out->get_image_desc (); + work_size.global[0] = out_info.width; + work_size.global[1] = out_info.height; + + args.push_back (new CLMemArgument (image_out)); + args.push_back (new CLArgumentT<float> (_gain_rgb)); + args.push_back (new CLArgumentT<float> (_thr_r)); + args.push_back (new CLArgumentT<float> (_thr_g)); + args.push_back (new CLArgumentT<float> (_thr_b)); + args.push_back (new CLArgumentT<uint8_t> (_frame_count)); + + for (std::list<SmartPtr<CLImage>>::iterator it = _image_in_list.begin (); it != _image_in_list.end (); it++) { + args.push_back (new CLMemArgument (*it)); + } + } + + XCAM_ASSERT (_tnr_kernel.ptr ()); + ret = _tnr_kernel->set_arguments (args, work_size); + XCAM_FAIL_RETURN ( + WARNING, ret == XCAM_RETURN_NO_ERROR, ret, + "tnr kernel set arguments failed."); + + _image_out_prev = image_out; + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<CLImageHandler> +create_cl_tnr_image_handler (const SmartPtr<CLContext> &context, CLTnrType type) +{ + SmartPtr<CLTnrImageHandler> tnr_handler; + SmartPtr<CLTnrImageKernel> tnr_kernel; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + tnr_kernel = new CLTnrImageKernel (context, type); + XCAM_ASSERT (tnr_kernel.ptr ()); + if (CL_TNR_TYPE_YUV == type) { + ret = tnr_kernel->build_kernel (kernel_tnr_yuv_info, NULL); + } else if (CL_TNR_TYPE_RGB == type) { + ret = tnr_kernel->build_kernel (kernel_tnr_rgb_info, NULL); + } else { + XCAM_LOG_ERROR ("create cl tnr image handler failed, unknown type:%d", type); + return NULL; + } + + XCAM_FAIL_RETURN ( + ERROR, ret == XCAM_RETURN_NO_ERROR, NULL, + "build tnr kernel failed"); + + tnr_handler = new CLTnrImageHandler (context, type, "cl_handler_tnr"); + XCAM_ASSERT (tnr_kernel->is_valid ()); + tnr_handler->set_tnr_kernel (tnr_kernel); + + return tnr_handler; +} + +}; diff --git a/modules/ocl/cl_tnr_handler.h b/modules/ocl/cl_tnr_handler.h new file mode 100644 index 0000000..2f8d2f7 --- /dev/null +++ b/modules/ocl/cl_tnr_handler.h @@ -0,0 +1,142 @@ +/* + * cl_tnr_handler.h - CL tnr handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wei Zong <wei.zong@intel.com> + */ + +#ifndef XCAM_CL_TNR_HANLDER_H +#define XCAM_CL_TNR_HANLDER_H + +#include "cl_utils.h" +#include "base/xcam_3a_result.h" +#include "x3a_stats_pool.h" +#include "ocl/cl_image_handler.h" + +namespace XCam { + +enum CLTnrType { + CL_TNR_DISABLE = 0, + CL_TNR_TYPE_YUV = 1 << 0, + CL_TNR_TYPE_RGB = 1 << 1, +}; + +#define TNR_GRID_HOR_COUNT 8 +#define TNR_GRID_VER_COUNT 8 + +class CLTnrImageKernel + : public CLImageKernel +{ +public: + explicit CLTnrImageKernel ( + const SmartPtr<CLContext> &context, CLTnrType type); + + virtual ~CLTnrImageKernel () { + } + +private: + CLTnrType _type; +}; + +class CLTnrImageHandler + : public CLImageHandler +{ +private: + typedef std::list<SmartPtr<CLImage>> CLImagePtrList; + + enum CLTnrHistogramType { + CL_TNR_HIST_BRIGHTNESS = 0, + CL_TNR_HIST_HOR_PROJECTION = 1, + CL_TNR_HIST_VER_PROJECTION = 2, + }; + + enum CLTnrAnalyzeDateType { + CL_TNR_ANALYZE_STATS = 0, + CL_TNR_ANALYZE_RGB = 1, + }; + + struct CLTnrMotionInfo { + int32_t hor_shift; /*!< pixel count of horizontal direction (X) shift */ + int32_t ver_shift; /*!< pixel count of vertical direction (Y) shift */ + float hor_corr; /*!< horizontal direction (X) correlation */ + float ver_corr; /*!< vertical direction (Y) correlation */ + CLTnrMotionInfo (); + }; + + typedef std::list<CLTnrMotionInfo> CLTnrMotionInfoList; + + struct CLTnrHistogram { + CLTnrHistogram (); + CLTnrHistogram (uint32_t width, uint32_t height); + ~CLTnrHistogram (); + + XCAM_DEAD_COPY (CLTnrHistogram); + + float* hor_hist_current; + float* hor_hist_reference; + float* ver_hist_current; + float* ver_hist_reference; + uint32_t hor_hist_bin; + uint32_t ver_hist_bin; + }; + +public: + explicit CLTnrImageHandler (const SmartPtr<CLContext> &context, CLTnrType type, const char *name); + bool set_tnr_kernel (SmartPtr<CLTnrImageKernel> &kernel); + bool set_framecount (uint8_t count) ; + bool set_rgb_config (const XCam3aResultTemporalNoiseReduction& config); + bool set_yuv_config (const XCam3aResultTemporalNoiseReduction& config); + uint32_t get_frame_count () { + return _frame_count; + } + +protected: + virtual XCamReturn prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + XCAM_DEAD_COPY (CLTnrImageHandler); + + bool calculate_image_histogram (XCam3AStats *stats, CLTnrHistogramType type, float* histogram); + bool calculate_image_histogram (SmartPtr<VideoBuffer> &input, CLTnrHistogramType type, float* histogram); + void print_image_histogram (); + +private: + SmartPtr<CLTnrImageKernel> _tnr_kernel; + CLTnrType _type; + + float _gain_yuv; + float _thr_y; + float _thr_uv; + + float _gain_rgb; + float _thr_r; + float _thr_g; + float _thr_b; + + CLTnrMotionInfo _motion_info[TNR_GRID_HOR_COUNT * TNR_GRID_VER_COUNT]; + CLImagePtrList _image_in_list; + CLTnrHistogram _image_histogram; + SmartPtr<CLImage> _image_out_prev; + + uint8_t _frame_count; +}; + +SmartPtr<CLImageHandler> +create_cl_tnr_image_handler (const SmartPtr<CLContext> &context, CLTnrType type); + +}; + +#endif //XCAM_CL_TNR_HANLDER_H diff --git a/modules/ocl/cl_tonemapping_handler.cpp b/modules/ocl/cl_tonemapping_handler.cpp new file mode 100644 index 0000000..77c5657 --- /dev/null +++ b/modules/ocl/cl_tonemapping_handler.cpp @@ -0,0 +1,229 @@ +/* + * cl_tonemapping_handler.cpp - CL tonemapping handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wu Junkai <junkai.wu@intel.com> + */ + +#include "cl_utils.h" +#include "cl_tonemapping_handler.h" + +namespace XCam { + +static const XCamKernelInfo kernel_tonemapping_info = { + "kernel_tonemapping", +#include "kernel_tonemapping.clx" + , 0, +}; + +CLTonemappingImageKernel::CLTonemappingImageKernel ( + const SmartPtr<CLContext> &context, const char *name) + : CLImageKernel (context, name) +{ +} + +CLTonemappingImageHandler::CLTonemappingImageHandler ( + const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) + , _output_format (XCAM_PIX_FMT_SGRBG16_planar) +{ + _wb_config.r_gain = 1.0; + _wb_config.gr_gain = 1.0; + _wb_config.gb_gain = 1.0; + _wb_config.b_gain = 1.0; +} + +bool +CLTonemappingImageHandler::set_tonemapping_kernel(SmartPtr<CLTonemappingImageKernel> &kernel) +{ + SmartPtr<CLImageKernel> image_kernel = kernel; + add_kernel (image_kernel); + _tonemapping_kernel = kernel; + return true; +} + +bool +CLTonemappingImageHandler::set_wb_config (const XCam3aResultWhiteBalance &wb) +{ + _wb_config.r_gain = (float)wb.r_gain; + _wb_config.gr_gain = (float)wb.gr_gain; + _wb_config.gb_gain = (float)wb.gb_gain; + _wb_config.b_gain = (float)wb.b_gain; + return true; +} + +XCamReturn +CLTonemappingImageHandler::prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, + VideoBufferInfo &output) +{ + bool format_inited = output.init (_output_format, input.width, input.height); + + XCAM_FAIL_RETURN ( + WARNING, + format_inited, + XCAM_RETURN_ERROR_PARAM, + "CL image handler(%s) output format(%s) unsupported", + XCAM_STR(get_name ()), xcam_fourcc_to_string (_output_format)); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLTonemappingImageHandler::prepare_parameters ( + SmartPtr<VideoBuffer> &input, + SmartPtr<VideoBuffer> &output) +{ + SmartPtr<CLContext> context = get_context (); + float y_max = 0.0f, y_target = 0.0f; + CLArgList args; + CLWorkSize work_size; + XCAM_ASSERT (_tonemapping_kernel.ptr ()); + + const VideoBufferInfo &video_info = input->get_video_info (); + + CLImageDesc desc; + desc.format.image_channel_order = CL_RGBA; + desc.format.image_channel_data_type = CL_UNORM_INT16; + desc.width = video_info.aligned_width / 4; + desc.height = video_info.aligned_height * 4; + desc.row_pitch = video_info.strides[0]; + desc.array_size = 4; + desc.slice_pitch = video_info.strides [0] * video_info.aligned_height; + + SmartPtr<CLImage> image_in = convert_to_climage (context, input, desc); + SmartPtr<CLImage> image_out = convert_to_climage (context, output, desc); + int image_height = video_info.aligned_height; + + XCAM_FAIL_RETURN ( + WARNING, + image_in->is_valid () && image_out->is_valid (), + XCAM_RETURN_ERROR_MEM, + "cl image handler(%s) in/out memory not available", XCAM_STR(get_name ())); + + SmartPtr<X3aStats> stats; + SmartPtr<CLVideoBuffer> cl_buf = input.dynamic_cast_ptr<CLVideoBuffer> (); + if (cl_buf.ptr ()) { + stats = cl_buf->find_3a_stats (); + } +#if HAVE_LIBDRM + else { + SmartPtr<DrmBoBuffer> bo_buf = input.dynamic_cast_ptr<DrmBoBuffer> (); + stats = bo_buf->find_3a_stats (); + } +#endif + XCAM_FAIL_RETURN ( + ERROR, + stats.ptr (), + XCAM_RETURN_ERROR_MEM, + "CLTonemappingImageKernel find_3a_stats failed"); + XCam3AStats *stats_ptr = stats->get_stats (); + XCAM_ASSERT (stats_ptr); + + int pixel_totalnum = stats_ptr->info.aligned_width * stats_ptr->info.aligned_height; + int pixel_num = 0; + int hist_bin_count = 1 << stats_ptr->info.bit_depth; + int64_t cumulative_value = 0; + int saturated_thresh = pixel_totalnum * 0.003f; + int percent_90_thresh = pixel_totalnum * 0.1f; + int medium_thresh = pixel_totalnum * 0.5f; + float y_saturated = 0; + float y_percent_90 = 0; + float y_average = 0; + float y_medium = 0; + + for (int i = (hist_bin_count - 1); i >= 0; i--) + { + pixel_num += stats_ptr->hist_y[i]; + if ((y_saturated == 0) && (pixel_num >= saturated_thresh)) + { + y_saturated = i; + } + if ((y_percent_90 == 0) && (pixel_num >= percent_90_thresh)) + { + y_percent_90 = i; + } + if ((y_medium == 0) && (pixel_num >= medium_thresh)) + { + y_medium = i; + } + cumulative_value += i * stats_ptr->hist_y[i]; + } + + y_average = cumulative_value / pixel_totalnum; + + if (y_saturated < (hist_bin_count - 1)) { + y_saturated = y_saturated + 1; + } + + y_target = (hist_bin_count / y_saturated) * (1.5 * y_medium + 0.5 * y_average) / 2; + + if (y_target < 4) { + y_target = 4; + } + if ((y_target > y_saturated) || (y_saturated < 4)) { + y_target = y_saturated / 4; + } + + y_max = hist_bin_count * (2 * y_saturated + y_target) / y_saturated - y_saturated - y_target; + + y_target = y_target / pow(2, stats_ptr->info.bit_depth - 8); + y_max = y_max / pow(2, stats_ptr->info.bit_depth - 8); + + //set args; + args.push_back (new CLMemArgument (image_in)); + args.push_back (new CLMemArgument (image_out)); + args.push_back (new CLArgumentT<float> (y_max)); + args.push_back (new CLArgumentT<float> (y_target)); + args.push_back (new CLArgumentT<int> (image_height)); + + const CLImageDesc out_info = image_out->get_image_desc (); + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.global[0] = out_info.width; + work_size.global[1] = out_info.height / 4; + work_size.local[0] = 8; + work_size.local[1] = 8; + + XCAM_ASSERT (_tonemapping_kernel.ptr ()); + XCamReturn ret = _tonemapping_kernel->set_arguments (args, work_size); + XCAM_FAIL_RETURN ( + WARNING, ret == XCAM_RETURN_NO_ERROR, ret, + "tone mapping kernel set arguments failed."); + + return XCAM_RETURN_NO_ERROR; +} + + +SmartPtr<CLImageHandler> +create_cl_tonemapping_image_handler (const SmartPtr<CLContext> &context) +{ + SmartPtr<CLTonemappingImageHandler> tonemapping_handler; + SmartPtr<CLTonemappingImageKernel> tonemapping_kernel; + + tonemapping_kernel = new CLTonemappingImageKernel (context, "kernel_tonemapping"); + XCAM_ASSERT (tonemapping_kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, tonemapping_kernel->build_kernel (kernel_tonemapping_info, NULL) == XCAM_RETURN_NO_ERROR, NULL, + "build tonemapping kernel(%s) failed", kernel_tonemapping_info.kernel_name); + + XCAM_ASSERT (tonemapping_kernel->is_valid ()); + tonemapping_handler = new CLTonemappingImageHandler(context, "cl_handler_tonemapping"); + tonemapping_handler->set_tonemapping_kernel(tonemapping_kernel); + + return tonemapping_handler; +} + +}; diff --git a/modules/ocl/cl_tonemapping_handler.h b/modules/ocl/cl_tonemapping_handler.h new file mode 100644 index 0000000..cb55955 --- /dev/null +++ b/modules/ocl/cl_tonemapping_handler.h @@ -0,0 +1,65 @@ +/* + * cl_tonemapping_handler.h - CL tonemapping handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wu Junkai <junkai.wu@intel.com> + */ + +#ifndef XCAM_CL_TONEMAPPING_HANLDER_H +#define XCAM_CL_TONEMAPPING_HANLDER_H + +#include <xcam_std.h> +#include <x3a_stats_pool.h> +#include <ocl/cl_image_handler.h> +#include <ocl/cl_bayer_basic_handler.h> + +namespace XCam { + +class CLTonemappingImageKernel + : public CLImageKernel +{ +public: + explicit CLTonemappingImageKernel ( + const SmartPtr<CLContext> &context, const char *name); +}; + +class CLTonemappingImageHandler + : public CLImageHandler +{ +public: + explicit CLTonemappingImageHandler (const SmartPtr<CLContext> &context, const char *name); + bool set_tonemapping_kernel(SmartPtr<CLTonemappingImageKernel> &kernel); + bool set_wb_config (const XCam3aResultWhiteBalance &wb); + +protected: + virtual XCamReturn prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, VideoBufferInfo &output); + virtual XCamReturn prepare_parameters ( + SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + XCAM_DEAD_COPY (CLTonemappingImageHandler); + SmartPtr<CLTonemappingImageKernel> _tonemapping_kernel; + int32_t _output_format; + CLWBConfig _wb_config; +}; + +SmartPtr<CLImageHandler> +create_cl_tonemapping_image_handler (const SmartPtr<CLContext> &context); + +}; + +#endif //XCAM_CL_TONEMAPPING_HANLDER_H diff --git a/modules/ocl/cl_utils.cpp b/modules/ocl/cl_utils.cpp new file mode 100644 index 0000000..b8ce3a9 --- /dev/null +++ b/modules/ocl/cl_utils.cpp @@ -0,0 +1,434 @@ +/* + * cl_utils.cpp - CL Utilities + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_utils.h" +#include "image_file_handle.h" +#if HAVE_LIBDRM +#include "intel/cl_intel_context.h" +#include "intel/cl_va_memory.h" +#endif + +namespace XCam { + +struct NV12Pixel { + float x_pos; + float y_pos; + + float y; + float u; + float v; + + NV12Pixel () + : x_pos (0.0f), y_pos (0.0f) + , y (0.0f), u (0.0f), v (0.0f) + {} +}; + +static inline void +clamp (float &value, float min, float max) +{ + value = (value < min) ? min : ((value > max) ? max : value); +} + +bool +dump_image (SmartPtr<CLImage> image, const char *file_name) +{ + XCAM_ASSERT (file_name); + + const CLImageDesc &desc = image->get_image_desc (); + void *ptr = NULL; + size_t origin[3] = {0, 0, 0}; + size_t region[3] = {desc.width, desc.height, 1}; + size_t row_pitch; + size_t slice_pitch; + + XCamReturn ret = image->enqueue_map (ptr, origin, region, &row_pitch, &slice_pitch, CL_MAP_READ); + XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), false, "dump image failed in enqueue_map"); + XCAM_ASSERT (ptr); + XCAM_ASSERT (row_pitch == desc.row_pitch); + uint8_t *buf_start = (uint8_t *)ptr; + uint32_t width = image->get_pixel_bytes () * desc.width; + + FILE *fp = fopen (file_name, "wb"); + XCAM_FAIL_RETURN (ERROR, fp, false, "open file(%s) failed", file_name); + + for (uint32_t i = 0; i < desc.height; ++i) { + uint8_t *buf_line = buf_start + row_pitch * i; + fwrite (buf_line, width, 1, fp); + } + image->enqueue_unmap (ptr); + fclose (fp); + XCAM_LOG_INFO ("write image:%s\n", file_name); + return true; +} + +SmartPtr<CLBuffer> +convert_to_clbuffer ( + const SmartPtr<CLContext> &context, + const SmartPtr<VideoBuffer> &buf) +{ + SmartPtr<CLBuffer> cl_buf; + + SmartPtr<CLVideoBuffer> cl_video_buf = buf.dynamic_cast_ptr<CLVideoBuffer> (); + if (cl_video_buf.ptr ()) { + cl_buf = cl_video_buf; + } +#if HAVE_LIBDRM + else { + SmartPtr<DrmBoBuffer> bo_buf = buf.dynamic_cast_ptr<DrmBoBuffer> (); + SmartPtr<CLIntelContext> ctx = context.dynamic_cast_ptr<CLIntelContext> (); + XCAM_ASSERT (bo_buf.ptr () && ctx.ptr ()); + + cl_buf = new CLVaBuffer (ctx, bo_buf); + } +#else + XCAM_UNUSED (context); +#endif + + XCAM_FAIL_RETURN (WARNING, cl_buf.ptr (), NULL, "convert to clbuffer failed"); + return cl_buf; +} + +SmartPtr<CLImage> +convert_to_climage ( + const SmartPtr<CLContext> &context, + SmartPtr<VideoBuffer> &buf, + const CLImageDesc &desc, + uint32_t offset, + cl_mem_flags flags) +{ + SmartPtr<CLImage> cl_image; + + SmartPtr<CLVideoBuffer> cl_video_buf = buf.dynamic_cast_ptr<CLVideoBuffer> (); + if (cl_video_buf.ptr ()) { + SmartPtr<CLBuffer> cl_buf; + + if (offset == 0) { + cl_buf = cl_video_buf; + } else { + uint32_t row_pitch = CLImage::calculate_pixel_bytes (desc.format) * + XCAM_ALIGN_UP (desc.width, XCAM_CL_IMAGE_ALIGNMENT_X); + uint32_t size = row_pitch * desc.height; + + cl_buf = new CLSubBuffer (context, cl_video_buf, flags, offset, size); + } + + cl_image = new CLImage2D (context, desc, flags, cl_buf); + } +#if HAVE_LIBDRM + else { + SmartPtr<DrmBoBuffer> bo_buf = buf.dynamic_cast_ptr<DrmBoBuffer> (); + SmartPtr<CLIntelContext> ctx = context.dynamic_cast_ptr<CLIntelContext> (); + XCAM_ASSERT (bo_buf.ptr () && ctx.ptr ()); + + cl_image = new CLVaImage (ctx, bo_buf, desc, offset); + } +#endif + + XCAM_FAIL_RETURN (WARNING, cl_image.ptr (), NULL, "convert to climage failed"); + return cl_image; +} + +XCamReturn +convert_nv12_mem_to_video_buffer ( + void *nv12_mem, uint32_t width, uint32_t height, uint32_t row_pitch, uint32_t offset_uv, + SmartPtr<VideoBuffer> &buf) +{ + XCAM_ASSERT (nv12_mem); + XCAM_ASSERT (row_pitch >= width); + + VideoBufferPlanarInfo planar; + const VideoBufferInfo info = buf->get_video_info (); + XCAM_FAIL_RETURN ( + DEBUG, (width == info.width) && (height == info.height), XCAM_RETURN_ERROR_PARAM, + "convert mem to video buffer failed since image sizes are not matched."); + + uint8_t *out_mem = buf->map (); + XCAM_FAIL_RETURN (ERROR, out_mem, XCAM_RETURN_ERROR_MEM, "map buffer failed"); + + uint8_t *src = (uint8_t *)nv12_mem; + uint8_t *dest = NULL; + for (uint32_t index = 0; index < info.components; index++) { + info.get_planar_info (planar, index); + + dest = out_mem + info.offsets[index]; + for (uint32_t i = 0; i < planar.height; i++) { + memcpy (dest, src, width); + src += row_pitch; + dest += info.strides[index]; + } + + src = (uint8_t *)nv12_mem + offset_uv; + } + + buf->unmap (); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +interpolate_pixel_value ( + uint8_t* stitch_mem, + float image_coord_x, float image_coord_y, + float &y, float &u, float &v, + const VideoBufferInfo& stitch_info) +{ + XCAM_ASSERT (image_coord_y < stitch_info.height && image_coord_x < stitch_info.width); + + uint8_t y00, y01, y10, y11; + uint8_t u00, u01, u10, u11; + uint8_t v00, v01, v10, v11; + + uint32_t x0 = (uint32_t) image_coord_x; + uint32_t x1 = (x0 < stitch_info.width - 1) ? (x0 + 1) : x0; + uint32_t y0 = (uint32_t) image_coord_y; + uint32_t y1 = (y0 < stitch_info.height - 1) ? (y0 + 1) : y0; + + float rate00 = (x0 + 1 - image_coord_x) * (y0 + 1 - image_coord_y); + float rate01 = (x0 + 1 - image_coord_x) * (image_coord_y - y0); + float rate10 = (image_coord_x - x0) * (y0 + 1 - image_coord_y); + float rate11 = (image_coord_x - x0) * (image_coord_y - y0); + + y00 = stitch_mem[y0 * stitch_info.strides[0] + x0]; + y01 = stitch_mem[y1 * stitch_info.strides[0] + x0]; + y10 = stitch_mem[y0 * stitch_info.strides[0] + x1]; + y11 = stitch_mem[y1 * stitch_info.strides[0] + x1]; + + u00 = stitch_mem[stitch_info.offsets[1] + y0 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x0, 2)]; + u01 = stitch_mem[stitch_info.offsets[1] + y1 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x0, 2)]; + u10 = stitch_mem[stitch_info.offsets[1] + y0 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x1, 2)]; + u11 = stitch_mem[stitch_info.offsets[1] + y1 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x1, 2)]; + + v00 = stitch_mem[stitch_info.offsets[1] + y0 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x0, 2) + 1]; + v01 = stitch_mem[stitch_info.offsets[1] + y1 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x0, 2) + 1]; + v10 = stitch_mem[stitch_info.offsets[1] + y0 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x1, 2) + 1]; + v11 = stitch_mem[stitch_info.offsets[1] + y1 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x1, 2) + 1]; + + y = y00 * rate00 + y01 * rate01 + y10 * rate10 + y11 * rate11; + u = u00 * rate00 + u01 * rate01 + u10 * rate10 + u11 * rate11; + v = v00 * rate00 + v01 * rate01 + v10 * rate10 + v11 * rate11; + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +map_to_specific_view ( + uint8_t *specific_view_mem, uint8_t* stitch_mem, + uint32_t row, uint32_t col, + float image_coord_x, float image_coord_y, + const VideoBufferInfo& specific_view_info, const VideoBufferInfo& stitch_info) +{ + XCAM_ASSERT (row < specific_view_info.height && col < specific_view_info.width); + + float y, u, v; + + interpolate_pixel_value (stitch_mem, image_coord_x, image_coord_y, y, u, v, stitch_info); + + uint32_t y_index = row * specific_view_info.strides[0] + col; + uint32_t u_index = specific_view_info.offsets[1] + row / 2 * specific_view_info.strides[1] + XCAM_ALIGN_DOWN (col, 2); + + specific_view_mem[y_index] = (uint8_t)y; + specific_view_mem[u_index] = (uint8_t)u; + specific_view_mem[u_index + 1] = (uint8_t)v; + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +generate_topview_map_table ( + const VideoBufferInfo &stitch_info, + const BowlDataConfig &config, + std::vector<PointFloat2> &map_table, + int width, int height) +{ + int center_x = width / 2; + int center_y = height / 2; + + float show_width_mm = 5000.0f; + float length_per_pixel = show_width_mm / height; + + map_table.resize (height * width); + + for(int row = 0; row < height; row++) { + for(int col = 0; col < width; col++) { + PointFloat3 world; + world.x = (col - center_x) * length_per_pixel; + world.y = (center_y - row) * length_per_pixel; + world.z = 0.0f; + + PointFloat2 image_pos = + bowl_view_coords_to_image (config, world, stitch_info.width, stitch_info.height); + + map_table[row * width + col] = image_pos; + } + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +generate_rectifiedview_map_table ( + const VideoBufferInfo &stitch_info, + const BowlDataConfig &config, + std::vector<PointFloat2> &map_table, + float angle_start, float angle_end, + int width, int height) +{ + float center_x = width / 2; + + float focal_plane_dist = 6000.0f; + + float angle_center = (angle_start + angle_end) / 2.0f; + float theta = degree2radian((angle_end - angle_start)) / 2.0f; + float length_per_pixel_x = 2 * focal_plane_dist * tan (theta) / width; + + float fov_up = degree2radian (20.0f); + float fov_down = degree2radian (35.0f); + + float length_per_pixel_y = (focal_plane_dist * tan (fov_up) + focal_plane_dist * tan (fov_down)) / height; + + float center_y = tan (fov_up) / (tan (fov_up) + tan (fov_down)) * height; + + PointFloat3 world_pos; + float plane_center_coords[3]; + + plane_center_coords[0] = focal_plane_dist * cos (degree2radian (angle_center)); + plane_center_coords[1] = -focal_plane_dist * sin (degree2radian (angle_center)); + plane_center_coords[2] = 0.0f; + + map_table.resize (width * height); + + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + float plane_point_coords[3]; + plane_point_coords[0] = (center_x - col) * length_per_pixel_x * cos (PI / 2 - degree2radian (angle_center)) + plane_center_coords[0]; + plane_point_coords[1] = (center_x - col) * length_per_pixel_x * sin (PI / 2 - degree2radian (angle_center)) + plane_center_coords[1]; + plane_point_coords[2] = (center_y - row) * length_per_pixel_y + plane_center_coords[2]; + + float rate_xz, rate_yz; + if (XCAM_DOUBLE_EQUAL_AROUND (plane_point_coords[2], 0.0f) && XCAM_DOUBLE_EQUAL_AROUND (plane_point_coords[1], 0.0f)) { + world_pos.x = config.a; + world_pos.y = 0; + world_pos.z = 0; + } else if (XCAM_DOUBLE_EQUAL_AROUND (plane_point_coords[2], 0.0f)) { + world_pos.z = 0.0f; + + float rate_xy = plane_point_coords[0] / plane_point_coords[1]; + float square_y = 1 / (rate_xy * rate_xy / (config.a * config.a) + 1 / (config.b * config.b)); + world_pos.y = (plane_point_coords[1] > 0) ? sqrt (square_y) : -sqrt (square_y); + world_pos.x = rate_xy * world_pos.y; + } else { + rate_xz = plane_point_coords[0] / plane_point_coords[2]; + rate_yz = plane_point_coords[1] / plane_point_coords[2]; + + float square_z = 1 / (rate_xz * rate_xz / (config.a * config.a) + rate_yz * rate_yz / (config.b * config.b) + 1 / (config.c * config.c)); + world_pos.z = (plane_point_coords[2] > 0) ? sqrt (square_z) : -sqrt (square_z); + world_pos.z = (world_pos.z <= -config.center_z) ? -config.center_z : world_pos.z; + world_pos.x = rate_xz * world_pos.z; + world_pos.y = rate_yz * world_pos.z; + } + + world_pos.z += config.center_z; + + PointFloat2 image_coord = + bowl_view_coords_to_image (config, world_pos, stitch_info.width, stitch_info.height); + + map_table[row * width + col] = image_coord; + } + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +sample_generate_top_view ( + SmartPtr<VideoBuffer> &stitch_buf, + SmartPtr<VideoBuffer> top_view_buf, + const BowlDataConfig &config, + std::vector<PointFloat2> &map_table) +{ + const VideoBufferInfo top_view_info = top_view_buf->get_video_info (); + const VideoBufferInfo stitch_info = stitch_buf->get_video_info (); + + int top_view_resolution_w = top_view_buf->get_video_info ().width; + int top_view_resolution_h = top_view_buf->get_video_info ().height; + + if((int)map_table.size () != top_view_resolution_w * top_view_resolution_h) { + map_table.clear (); + generate_topview_map_table (stitch_info, config, map_table, top_view_resolution_w, top_view_resolution_h); + } + + uint8_t *top_view_mem = NULL; + uint8_t *stitch_mem = NULL; + top_view_mem = top_view_buf->map (); + stitch_mem = stitch_buf->map (); + + for(int row = 0; row < top_view_resolution_h; row++) { + for(int col = 0; col < top_view_resolution_w; col++) { + PointFloat2 image_coord = map_table[row * top_view_resolution_w + col]; + + map_to_specific_view (top_view_mem, stitch_mem, row, col, image_coord.x, image_coord.y, top_view_info, stitch_info); + } + } + + top_view_buf->unmap(); + stitch_buf->unmap(); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +sample_generate_rectified_view ( + SmartPtr<VideoBuffer> &stitch_buf, + SmartPtr<VideoBuffer> rectified_view_buf, + const BowlDataConfig &config, + float angle_start, float angle_end, + std::vector<PointFloat2> &map_table) +{ + const VideoBufferInfo rectified_view_info = rectified_view_buf->get_video_info (); + const VideoBufferInfo stitch_info = stitch_buf->get_video_info (); + + int rectified_view_resolution_w = rectified_view_buf->get_video_info ().width; + int rectified_view_resolution_h = rectified_view_buf->get_video_info ().height; + + if((int)map_table.size () != rectified_view_resolution_w * rectified_view_resolution_h) { + map_table.clear (); + generate_rectifiedview_map_table (stitch_info, config, map_table, angle_start, angle_end, rectified_view_resolution_w, rectified_view_resolution_h); + } + + uint8_t *rectified_view_mem = NULL; + uint8_t *stitch_mem = NULL; + rectified_view_mem = rectified_view_buf->map (); + stitch_mem = stitch_buf->map (); + + for(int row = 0; row < rectified_view_resolution_h; row++) { + for(int col = 0; col < rectified_view_resolution_w; col++) { + PointFloat2 image_coord = map_table[row * rectified_view_resolution_w + col]; + + map_to_specific_view (rectified_view_mem, stitch_mem, row, col, image_coord.x, image_coord.y, rectified_view_info, stitch_info); + } + } + + rectified_view_buf->unmap(); + stitch_buf->unmap(); + + return XCAM_RETURN_NO_ERROR; +} + +} diff --git a/modules/ocl/cl_utils.h b/modules/ocl/cl_utils.h new file mode 100644 index 0000000..51d7fa1 --- /dev/null +++ b/modules/ocl/cl_utils.h @@ -0,0 +1,95 @@ +/* + * cl_utils.h - CL Utilities + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_UTILS_H +#define XCAM_CL_UTILS_H + +#include "xcam_utils.h" +#include "interface/data_types.h" +#include "ocl/cl_context.h" +#include "ocl/cl_memory.h" +#include "ocl/cl_video_buffer.h" +#if HAVE_LIBDRM +#include "drm_bo_buffer.h" +#endif + +#define XCAM_CL_IMAGE_ALIGNMENT_X 4 + +namespace XCam { + +enum CLWaveletBasis { + CL_WAVELET_DISABLED = 0, + CL_WAVELET_HAT, + CL_WAVELET_HAAR, +}; + +enum CLImageChannel { + CL_IMAGE_CHANNEL_Y = 1, + CL_IMAGE_CHANNEL_UV = 1 << 1, +}; + +bool dump_image (SmartPtr<CLImage> image, const char *file_name); + +SmartPtr<CLBuffer> convert_to_clbuffer ( + const SmartPtr<CLContext> &context, + const SmartPtr<VideoBuffer> &buf); + +SmartPtr<CLImage> convert_to_climage ( + const SmartPtr<CLContext> &context, + SmartPtr<VideoBuffer> &buf, + const CLImageDesc &desc, + uint32_t offset = 0, + cl_mem_flags flags = CL_MEM_READ_WRITE); + +XCamReturn convert_nv12_mem_to_video_buffer ( + void *nv12_mem, uint32_t width, uint32_t height, uint32_t row_pitch, uint32_t offset_uv, + SmartPtr<VideoBuffer> &buf); + +XCamReturn +generate_topview_map_table ( + const VideoBufferInfo &stitch_info, + const BowlDataConfig &config, + std::vector<PointFloat2> &map_table, + int width, int height); + +XCamReturn +generate_rectifiedview_map_table ( + const VideoBufferInfo &stitch_info, + const BowlDataConfig &config, + std::vector<PointFloat2> &map_table, + float angle_start, float angle_end, + int width, int height); + +XCamReturn sample_generate_top_view ( + SmartPtr<VideoBuffer> &stitch_buf, + SmartPtr<VideoBuffer> top_view_buf, + const BowlDataConfig &config, + std::vector<PointFloat2> &map_table); + +XCamReturn sample_generate_rectified_view ( + SmartPtr<VideoBuffer> &stitch_buf, + SmartPtr<VideoBuffer> rectified_view_buf, + const BowlDataConfig &config, + float angle_start, float angle_end, + std::vector<PointFloat2> &map_table); +} + +#endif //XCAM_CL_UTILS_H + diff --git a/modules/ocl/cl_video_buffer.cpp b/modules/ocl/cl_video_buffer.cpp new file mode 100644 index 0000000..032dd3d --- /dev/null +++ b/modules/ocl/cl_video_buffer.cpp @@ -0,0 +1,150 @@ +/* + * cl_video_buffer.cpp - cl video buffer + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "ocl/cl_memory.h" +#include "ocl/cl_device.h" +#include "ocl/cl_video_buffer.h" + +namespace XCam { + +CLVideoBufferData::CLVideoBufferData (SmartPtr<CLBuffer> &body) + : _buf_ptr (NULL) + , _buf (body) +{ + XCAM_ASSERT (body.ptr ()); +} + +CLVideoBufferData::~CLVideoBufferData () +{ + unmap (); + _buf.release (); +} + +cl_mem & +CLVideoBufferData::get_mem_id () { + return _buf->get_mem_id (); +} + +uint8_t * +CLVideoBufferData::map () +{ + if (_buf_ptr) + return _buf_ptr; + + uint32_t size = _buf->get_buf_size (); + XCamReturn ret = _buf->enqueue_map ((void*&) _buf_ptr, 0, size); + XCAM_FAIL_RETURN ( + ERROR, + ret == XCAM_RETURN_NO_ERROR, + NULL, + "CLVideoBufferData map data failed"); + + return _buf_ptr; +} + +bool +CLVideoBufferData::unmap () +{ + if (!_buf_ptr) + return true; + + XCamReturn ret = _buf->enqueue_unmap ((void*&) _buf_ptr); + XCAM_FAIL_RETURN ( + ERROR, + ret == XCAM_RETURN_NO_ERROR, + NULL, + "CLVideoBufferData unmap data failed"); + + _buf_ptr = NULL; + return true; +} + +CLVideoBuffer::CLVideoBuffer ( + const SmartPtr<CLContext> &context, const VideoBufferInfo &info, const SmartPtr<CLVideoBufferData> &data) + : BufferProxy (info, data) + , CLBuffer (context) +{ + XCAM_ASSERT (data.ptr ()); + + SmartPtr<CLBuffer> cl_buf = data->get_cl_buffer (); + XCAM_ASSERT (cl_buf.ptr ()); + set_mem_id (cl_buf->get_mem_id (), false); + set_buf_size (cl_buf->get_buf_size ()); +} + +SmartPtr<CLBuffer> +CLVideoBuffer::get_cl_buffer () +{ + SmartPtr<BufferData> data = get_buffer_data (); + SmartPtr<CLVideoBufferData> cl_data = data.dynamic_cast_ptr<CLVideoBufferData> (); + XCAM_FAIL_RETURN( + WARNING, + cl_data.ptr(), + NULL, + "CLVideoBuffer get buffer data failed with NULL"); + + return cl_data->get_cl_buffer (); +} + +SmartPtr<X3aStats> +CLVideoBuffer::find_3a_stats () +{ + return find_typed_attach<X3aStats> (); +} + +bool +CLVideoBufferPool::fixate_video_info (VideoBufferInfo &info) +{ + if (info.format != V4L2_PIX_FMT_NV12) + return true; + + VideoBufferInfo out_info; + out_info.init (info.format, info.width, info.height, info.aligned_width, info.aligned_height); + + return true; +} + +SmartPtr<BufferData> +CLVideoBufferPool::allocate_data (const VideoBufferInfo &buffer_info) +{ + SmartPtr<CLContext> context = CLDevice::instance ()->get_context (); + + SmartPtr<CLBuffer> buf = new CLBuffer (context, buffer_info.size); + XCAM_ASSERT (buf.ptr ()); + + return new CLVideoBufferData (buf); +} + +SmartPtr<BufferProxy> +CLVideoBufferPool::create_buffer_from_data (SmartPtr<BufferData> &data) +{ + SmartPtr<CLContext> context = CLDevice::instance ()->get_context (); + const VideoBufferInfo & info = get_video_info (); + SmartPtr<CLVideoBufferData> cl_data = data.dynamic_cast_ptr<CLVideoBufferData> (); + XCAM_ASSERT (cl_data.ptr ()); + + SmartPtr<CLVideoBuffer> buf = new CLVideoBuffer (context, info, cl_data); + XCAM_ASSERT (buf.ptr ()); + + return buf; +} + +}; diff --git a/modules/ocl/cl_video_buffer.h b/modules/ocl/cl_video_buffer.h new file mode 100644 index 0000000..969bff1 --- /dev/null +++ b/modules/ocl/cl_video_buffer.h @@ -0,0 +1,106 @@ +/* + * cl_video_buffer.h - cl video buffer + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ +#ifndef XCAM_CL_VIDEO_BUFFER_H +#define XCAM_CL_VIDEO_BUFFER_H + +#include <xcam_std.h> +#include <safe_list.h> +#include <xcam_mutex.h> +#include <buffer_pool.h> +#include <x3a_stats_pool.h> +#include <ocl/cl_context.h> + +namespace XCam { + +class CLBuffer; +class CLVideoBufferPool; + +class CLVideoBufferData + : public BufferData +{ + friend class CLVideoBufferPool; + +public: + ~CLVideoBufferData (); + + cl_mem &get_mem_id (); + SmartPtr<CLBuffer> get_cl_buffer () { + return _buf; + } + + //derived from BufferData + virtual uint8_t *map (); + virtual bool unmap (); + +protected: + explicit CLVideoBufferData (SmartPtr<CLBuffer> &body); + +private: + XCAM_DEAD_COPY (CLVideoBufferData); + +private: + uint8_t *_buf_ptr; + SmartPtr<CLBuffer> _buf; +}; + +class CLVideoBuffer + : public BufferProxy + , public CLBuffer +{ + friend class CLVideoBufferPool; + +public: + explicit CLVideoBuffer ( + const SmartPtr<CLContext> &context, const VideoBufferInfo &info, const SmartPtr<CLVideoBufferData> &data); + virtual ~CLVideoBuffer () {} + + SmartPtr<CLBuffer> get_cl_buffer (); + SmartPtr<X3aStats> find_3a_stats (); + +protected: + CLVideoBuffer (const VideoBufferInfo &info, const SmartPtr<CLVideoBufferData> &data); + +private: + XCAM_DEAD_COPY (CLVideoBuffer); +}; + +class CLVideoBufferPool + : public BufferPool +{ + friend class CLVideoBuffer; + +public: + explicit CLVideoBufferPool () {} + ~CLVideoBufferPool () {} + +protected: + // derived from BufferPool + virtual bool fixate_video_info (VideoBufferInfo &info); + virtual SmartPtr<BufferData> allocate_data (const VideoBufferInfo &buffer_info); + virtual SmartPtr<BufferProxy> create_buffer_from_data (SmartPtr<BufferData> &data); + +private: + XCAM_DEAD_COPY (CLVideoBufferPool); +}; + +}; + +#endif // XCAM_CL_VIDEO_BUFFER_H diff --git a/modules/ocl/cl_video_stabilizer.cpp b/modules/ocl/cl_video_stabilizer.cpp new file mode 100644 index 0000000..73b92fe --- /dev/null +++ b/modules/ocl/cl_video_stabilizer.cpp @@ -0,0 +1,423 @@ +/* + * cl_video_stabilizer.cpp - Digital Video Stabilization using IMU (Gyroscope, Accelerometer) + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include "cl_video_stabilizer.h" +#include "cl_utils.h" + +namespace XCam { + +static const XCamKernelInfo kernel_video_stab_warp_info [] = { + { + "kernel_image_warp_8_pixel", +#include "kernel_image_warp.clx" + , 0, + }, + { + "kernel_image_warp_1_pixel", +#include "kernel_image_warp.clx" + , 0, + } +}; + +CLVideoStabilizerKernel::CLVideoStabilizerKernel ( + const SmartPtr<CLContext> &context, + const char *name, + uint32_t channel, + SmartPtr<CLImageHandler> &handler) + : CLImageWarpKernel (context, name, channel, handler) +{ + _handler = handler.dynamic_cast_ptr<CLVideoStabilizer> (); +} + +CLVideoStabilizer::CLVideoStabilizer (const SmartPtr<CLContext> &context, const char *name) + : CLImageWarpHandler (context, name) +{ + _projector = new ImageProjector (); + _filter_radius = 15; + _motion_filter = new MotionFilter (_filter_radius, 10); + + CoordinateSystemConv world_to_device (AXIS_X, AXIS_MINUS_Z, AXIS_NONE); + CoordinateSystemConv device_to_image (AXIS_X, AXIS_Y, AXIS_Y); + + align_coordinate_system (world_to_device, device_to_image); + + _input_frame_id = -1; + _frame_ts[0] = 0; + _frame_ts[1] = 0; + _stabilized_frame_id = -1; +} + +SmartPtr<VideoBuffer> +CLVideoStabilizer::get_warp_input_buf () +{ + XCAM_ASSERT (_input_buf_list.size () >= 1); + + SmartPtr<VideoBuffer> buf = (*_input_buf_list.begin ()); + return buf; +} + +bool +CLVideoStabilizer::is_ready () +{ + return CLImageHandler::is_ready (); +} + +void +CLVideoStabilizer::reset_counter () +{ + XCAM_LOG_DEBUG ("reset video stabilizer counter"); + + _input_frame_id = -1; + _stabilized_frame_id = -1; + xcam_mem_clear (_frame_ts); + _device_pose[0].clear (); + _device_pose[1].clear (); + _input_buf_list.clear (); +} + +XCamReturn +CLVideoStabilizer::execute_done (SmartPtr<VideoBuffer> &output) +{ + if (!_input_buf_list.empty ()) { + _input_buf_list.pop_front (); + } + + CLImageWarpHandler::execute_done (output); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLVideoStabilizer::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + XCAM_ASSERT (input.ptr () && output.ptr ()); + XCAM_UNUSED (output); + + if (_input_buf_list.size () >= 2 * _filter_radius + 1) { + _input_buf_list.pop_front (); + } + _input_buf_list.push_back (input); + _input_frame_id++; + + const VideoBufferInfo & video_info_in = input->get_video_info (); + + _frame_ts[_input_frame_id % 2] = input->get_timestamp (); + + SmartPtr<DevicePose> data = input->find_typed_metadata<DevicePose> (); + while (data.ptr ()) { + _device_pose[_input_frame_id % 2].push_back (data); + + input->remove_metadata (data); + + data = input->find_typed_metadata<DevicePose> (); + } + + Mat3d homography; + if (_input_frame_id > 0) { + homography = analyze_motion ( + _frame_ts[(_input_frame_id - 1) % 2], + _device_pose[(_input_frame_id - 1) % 2], + _frame_ts[_input_frame_id % 2], + _device_pose[_input_frame_id % 2]); + + if (_motions.size () >= 2 * _filter_radius + 1) { + _motions.pop_front (); + } + _motions.push_back (homography); + + _device_pose[(_input_frame_id - 1) % 2].clear (); + } + + Mat3d proj_mat; + XCamDVSResult warp_config; + if (_input_frame_id >= _filter_radius) + { + _stabilized_frame_id = _input_frame_id - _filter_radius; + int32_t cur_stabilized_pos = XCAM_MIN (_stabilized_frame_id, _filter_radius + 1); + + XCAM_LOG_DEBUG ("input id(%ld), stab id(%ld), cur stab pos(%d), filter r(%d)", + _input_frame_id, + _stabilized_frame_id, + cur_stabilized_pos, + _filter_radius); + + proj_mat = stabilize_motion (cur_stabilized_pos, _motions); + + Mat3d proj_inv_mat = proj_mat.inverse (); + warp_config.frame_id = _stabilized_frame_id; + warp_config.frame_width = video_info_in.width; + warp_config.frame_height = video_info_in.height; + + for( int i = 0; i < 3; i++ ) { + for (int j = 0; j < 3; j++) { + warp_config.proj_mat[i * 3 + j] = proj_inv_mat(i, j); + } + } + + set_warp_config (warp_config); + } else { + ret = XCAM_RETURN_BYPASS; + } + + return ret; +} + +XCamReturn +CLVideoStabilizer::set_sensor_calibration (CalibrationParams ¶ms) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + if (_projector.ptr ()) { + _projector->set_sensor_calibration (params); + } else { + ret = XCAM_RETURN_ERROR_PARAM; + } + + return ret; +} + +XCamReturn +CLVideoStabilizer::set_camera_intrinsics ( + double focal_x, + double focal_y, + double offset_x, + double offset_y, + double skew) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + if (_projector.ptr ()) { + _projector->set_camera_intrinsics( + focal_x, + focal_y, + offset_x, + offset_y, + skew); + } else { + ret = XCAM_RETURN_ERROR_PARAM; + } + + return ret; +} + +XCamReturn +CLVideoStabilizer::align_coordinate_system ( + CoordinateSystemConv &world_to_device, + CoordinateSystemConv &device_to_image) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + _world_to_device = world_to_device; + _device_to_image = device_to_image; + + return ret; +} + +XCamReturn +CLVideoStabilizer::set_motion_filter (uint32_t radius, float stdev) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + _filter_radius = radius; + + if (_motion_filter.ptr ()) { + _motion_filter->set_filters (radius, stdev); + } else { + ret = XCAM_RETURN_ERROR_PARAM; + } + + return ret; +} + +Mat3d +CLVideoStabilizer::analyze_motion ( + int64_t frame0_ts, + DevicePoseList pose0_list, + int64_t frame1_ts, + DevicePoseList pose1_list) +{ + if (pose0_list.empty () || pose1_list.empty () || !_projector.ptr ()) { + return Mat3d (); + } + XCAM_ASSERT (frame0_ts < frame1_ts); + + Mat3d ext0 = _projector->calc_camera_extrinsics (frame0_ts, pose0_list); + + Mat3d ext1 = _projector->calc_camera_extrinsics (frame1_ts, pose1_list); + + Mat3d extrinsic0 = _projector->align_coordinate_system ( + _world_to_device, + ext0, + _device_to_image); + + Mat3d extrinsic1 = _projector->align_coordinate_system ( + _world_to_device, + ext1, + _device_to_image); + + return _projector->calc_projective (extrinsic0, extrinsic1); +} + +Mat3d +CLVideoStabilizer::stabilize_motion (int32_t stab_frame_id, std::list<Mat3d> &motions) +{ + if (_motion_filter.ptr ()) { + return _motion_filter->stabilize (stab_frame_id, motions, _input_frame_id); + } else { + return Mat3d (); + } +} + +static SmartPtr<CLVideoStabilizerKernel> +create_kernel_video_stab ( + const SmartPtr<CLContext> &context, + uint32_t channel, + SmartPtr<CLImageHandler> handler) +{ + SmartPtr<CLVideoStabilizerKernel> stab_kernel; + + const char *name = (channel == CL_IMAGE_CHANNEL_Y ? "kernel_image_warp_y" : "kernel_image_warp_uv"); + char build_options[1024]; + xcam_mem_clear (build_options); + + snprintf (build_options, sizeof (build_options), + " -DWARP_Y=%d ", + (channel == CL_IMAGE_CHANNEL_Y ? 1 : 0)); + + stab_kernel = new CLVideoStabilizerKernel (context, name, channel, handler); + XCAM_ASSERT (stab_kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, stab_kernel->build_kernel (kernel_video_stab_warp_info[KernelImageWarp], build_options) == XCAM_RETURN_NO_ERROR, + NULL, "build video stab kernel failed"); + XCAM_ASSERT (stab_kernel->is_valid ()); + + return stab_kernel; +} + +SmartPtr<CLImageHandler> +create_cl_video_stab_handler (const SmartPtr<CLContext> &context) +{ + SmartPtr<CLImageHandler> video_stab; + SmartPtr<CLImageKernel> stab_kernel; + + video_stab = new CLVideoStabilizer (context); + XCAM_ASSERT (video_stab.ptr ()); + + stab_kernel = create_kernel_video_stab (context, CL_IMAGE_CHANNEL_Y, video_stab); + XCAM_ASSERT (stab_kernel.ptr ()); + video_stab->add_kernel (stab_kernel); + + stab_kernel = create_kernel_video_stab (context, CL_IMAGE_CHANNEL_UV, video_stab); + XCAM_ASSERT (stab_kernel.ptr ()); + video_stab->add_kernel (stab_kernel); + + return video_stab; +} + +MotionFilter::MotionFilter (uint32_t radius, float stdev) + : _radius (radius), + _stdev (stdev) +{ + set_filters (radius, stdev); +} + +MotionFilter::~MotionFilter () +{ + _weight.clear (); +} + +void +MotionFilter::set_filters (uint32_t radius, float stdev) +{ + _radius = radius; + _stdev = stdev > 0.f ? stdev : std::sqrt (static_cast<float>(radius)); + + int scale = 2 * _radius + 1; + float dis = 0.0f; + float sum = 0.0f; + + _weight.resize (2 * _radius + 1); + + for (int i = 0; i < scale; i++) { + dis = ((float)i - radius) * ((float)i - radius); + _weight[i] = exp(-dis / (_stdev * _stdev)); + sum += _weight[i]; + } + + for (int i = 0; i <= scale; i++) { + _weight[i] /= sum; + } + +} + +Mat3d +MotionFilter::cumulate_motion (uint32_t index, uint32_t from, std::list<Mat3d> &motions) +{ + Mat3d motion; + motion.eye (); + + uint32_t id = 0; + std::list<Mat3d>::iterator it; + + if (from < index) { + for (id = 0, it = motions.begin (); it != motions.end (); id++, ++it) { + if (from <= id && id < index) { + motion = (*it) * motion; + } + } + motion = motion.inverse (); + } else if (from > index) { + for (id = 0, it = motions.begin (); it != motions.end (); id++, ++it) { + if (index <= id && id < from) { + motion = (*it) * motion; + } + } + } + + return motion; +} + +Mat3d +MotionFilter::stabilize (int32_t index, + std::list<Mat3d> &motions, + int32_t max) +{ + Mat3d res; + res.zeros (); + + double sum = 0.0f; + int32_t idx_min = XCAM_MAX ((index - _radius), 0); + int32_t idx_max = XCAM_MIN ((index + _radius), max); + + for (int32_t i = idx_min; i <= idx_max; ++i) + { + res = res + cumulate_motion (index, i, motions) * _weight[i]; + sum += _weight[i]; + } + if (sum > 0.0f) { + return res * (1 / sum); + } + else { + return Mat3d (); + } +} + +} diff --git a/modules/ocl/cl_video_stabilizer.h b/modules/ocl/cl_video_stabilizer.h new file mode 100644 index 0000000..315bd4a --- /dev/null +++ b/modules/ocl/cl_video_stabilizer.h @@ -0,0 +1,158 @@ +/* + * cl_video_stabilizer.h - Digital Video Stabilization using IMU (Gyroscope, Accelerometer) + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#ifndef XCAM_CL_VIDEO_STABILIZER_H +#define XCAM_CL_VIDEO_STABILIZER_H + +#include <xcam_std.h> +#include <meta_data.h> +#include <vec_mat.h> +#include <image_projector.h> +#include <ocl/cl_image_warp_handler.h> + +namespace XCam { + +class MotionFilter; +class ImageProjector; +class CLVideoStabilizer; +class CLImageWarpKernel; +class CLImageWarpHandler; + +class CLVideoStabilizerKernel + : public CLImageWarpKernel +{ +public: + explicit CLVideoStabilizerKernel ( + const SmartPtr<CLContext> &context, + const char *name, + uint32_t channel, + SmartPtr<CLImageHandler> &handler); + +private: + XCAM_DEAD_COPY (CLVideoStabilizerKernel); + + SmartPtr<CLVideoStabilizer> _handler; +}; + +class CLVideoStabilizer + : public CLImageWarpHandler +{ + typedef std::list<SmartPtr<VideoBuffer>> CLImageBufferList; + +public: + explicit CLVideoStabilizer ( + const SmartPtr<CLContext> &context, + const char *name = "CLVideoStabilizer"); + + virtual ~CLVideoStabilizer () { + _input_buf_list.clear (); + } + + virtual SmartPtr<VideoBuffer> get_warp_input_buf (); + + virtual bool is_ready (); + + void reset_counter (); + + XCamReturn set_sensor_calibration (CalibrationParams ¶ms); + XCamReturn set_camera_intrinsics ( + double focal_x, + double focal_y, + double offset_x, + double offset_y, + double skew); + + XCamReturn align_coordinate_system ( + CoordinateSystemConv& world_to_device, + CoordinateSystemConv& device_to_image); + + XCamReturn set_motion_filter (uint32_t radius, float stdev); + uint32_t filter_radius () const { + return _filter_radius; + }; + + Mat3d analyze_motion ( + int64_t frame0_ts, + DevicePoseList pose0_list, + int64_t frame1_ts, + DevicePoseList pose1_list); + + Mat3d stabilize_motion (int32_t stab_frame_id, std::list<Mat3d> &motions); + +protected: + virtual XCamReturn prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + virtual XCamReturn execute_done (SmartPtr<VideoBuffer> &output); + +private: + XCAM_DEAD_COPY (CLVideoStabilizer); + +private: + Mat3d _intrinsics; + CalibrationParams _calib_params; + SmartPtr<ImageProjector> _projector; + SmartPtr<MotionFilter> _motion_filter; + CoordinateSystemConv _world_to_device; + CoordinateSystemConv _device_to_image; + int64_t _input_frame_id; + int64_t _frame_ts[2]; + int64_t _stabilized_frame_id; + DevicePoseList _device_pose[2]; + std::list<Mat3d> _motions; //motions[i] calculated from frame i to i+1 + uint32_t _filter_radius; + CLImageBufferList _input_buf_list; +}; + +SmartPtr<CLImageHandler> +create_cl_video_stab_handler (const SmartPtr<CLContext> &context); + + +class MotionFilter +{ +public: + MotionFilter (uint32_t radius = 15, float stdev = 10); + virtual ~MotionFilter (); + + void set_filters (uint32_t radius, float stdev); + + uint32_t radius () const { + return _radius; + }; + float stdev () const { + return _stdev; + }; + + Mat3d stabilize (int32_t index, + std::list<Mat3d> &motions, + int32_t max); + +protected: + Mat3d cumulate_motion (uint32_t index, uint32_t from, std::list<Mat3d> &motions); + +private: + XCAM_DEAD_COPY (MotionFilter); + +private: + int32_t _radius; + float _stdev; + std::vector<float> _weight; +}; + +} +#endif diff --git a/modules/ocl/cl_wavelet_denoise_handler.cpp b/modules/ocl/cl_wavelet_denoise_handler.cpp new file mode 100644 index 0000000..02dd273 --- /dev/null +++ b/modules/ocl/cl_wavelet_denoise_handler.cpp @@ -0,0 +1,184 @@ +/* + * cl_wavelet_denoise_handler.cpp - CL wavelet denoise handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wei Zong <wei.zong@intel.com> + */ +#include "cl_utils.h" +#include "x3a_stats_pool.h" +#include "cl_context.h" +#include "cl_device.h" +#include "cl_wavelet_denoise_handler.h" + +#define WAVELET_DECOMPOSITION_LEVELS 4 + +namespace XCam { + +static const XCamKernelInfo kernel_wavelet_denoise_info = { + "kernel_wavelet_denoise", +#include "kernel_wavelet_denoise.clx" + , 0, +}; + +CLWaveletDenoiseImageKernel::CLWaveletDenoiseImageKernel ( + const SmartPtr<CLContext> &context, + const char *name, + SmartPtr<CLWaveletDenoiseImageHandler> &handler, + uint32_t channel, + uint32_t layer) + : CLImageKernel (context, name) + , _channel (channel) + , _current_layer (layer) + , _handler (handler) +{ +} + +XCamReturn +CLWaveletDenoiseImageKernel::prepare_arguments ( + CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<CLContext> context = get_context (); + SmartPtr<VideoBuffer> input = _handler->get_input_buf (); + SmartPtr<VideoBuffer> output = _handler->get_output_buf (); + + const VideoBufferInfo &video_info_in = input->get_video_info (); + const VideoBufferInfo &video_info_out = output->get_video_info (); + + SmartPtr<CLMemory> input_image = convert_to_clbuffer (context, input); + SmartPtr<CLMemory> reconstruct_image = convert_to_clbuffer (context, output); + + SmartPtr<CLMemory> details_image = _handler->get_details_image (); + SmartPtr<CLMemory> approx_image = _handler->get_approx_image (); + + uint32_t decomposition_levels = WAVELET_DECOMPOSITION_LEVELS; + float soft_threshold = _handler->get_denoise_config ().threshold[0]; + float hard_threshold = _handler->get_denoise_config ().threshold[1]; + + uint32_t input_y_offset = video_info_in.offsets[0] / 4; + uint32_t output_y_offset = video_info_out.offsets[0] / 4; + + uint32_t input_uv_offset = video_info_in.aligned_height; + uint32_t output_uv_offset = video_info_out.aligned_height; + + XCAM_FAIL_RETURN ( + WARNING, + input_image->is_valid () && reconstruct_image->is_valid (), + XCAM_RETURN_ERROR_MEM, + "cl image kernel(%s) in/out memory not available", XCAM_STR(get_kernel_name ())); + + //set args; + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.local[0] = 8; + work_size.local[1] = 4; + + if (_current_layer % 2) { + args.push_back (new CLMemArgument (input_image)); + args.push_back (new CLMemArgument (approx_image)); + } else { + args.push_back (new CLMemArgument (approx_image)); + args.push_back (new CLMemArgument (input_image)); + } + args.push_back (new CLMemArgument (details_image)); + args.push_back (new CLMemArgument (reconstruct_image)); + args.push_back (new CLArgumentT<uint32_t> (input_y_offset)); + args.push_back (new CLArgumentT<uint32_t> (output_y_offset)); + args.push_back (new CLArgumentT<uint32_t> (input_uv_offset)); + args.push_back (new CLArgumentT<uint32_t> (output_uv_offset)); + args.push_back (new CLArgumentT<uint32_t> (_current_layer)); + args.push_back (new CLArgumentT<uint32_t> (decomposition_levels)); + args.push_back (new CLArgumentT<float> (hard_threshold)); + args.push_back (new CLArgumentT<float> (soft_threshold)); + + if (_channel & CL_IMAGE_CHANNEL_UV) { + work_size.global[0] = video_info_in.width / 16; + work_size.global[1] = video_info_in.height / 2; + } else { + work_size.global[0] = video_info_in.width / 16; + work_size.global[1] = video_info_in.height; + } + + return XCAM_RETURN_NO_ERROR; +} + +CLWaveletDenoiseImageHandler::CLWaveletDenoiseImageHandler ( + const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) +{ + _config.decomposition_levels = 5; + _config.threshold[0] = 0.5; + _config.threshold[1] = 5.0; +} + +XCamReturn +CLWaveletDenoiseImageHandler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + CLImageHandler::prepare_output_buf(input, output); + + if (!_approx_image.ptr ()) { + const VideoBufferInfo & video_info = input->get_video_info (); + uint32_t buffer_size = video_info.width * video_info.aligned_height; + + _approx_image = new CLBuffer (get_context (), buffer_size, + CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, NULL); + } + + if (!_details_image.ptr ()) { + const VideoBufferInfo & video_info = input->get_video_info (); + uint32_t buffer_size = sizeof(float) * video_info.width * video_info.height; + + _details_image = new CLBuffer (get_context (), buffer_size, + CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, NULL); + } + return ret; +} + +bool +CLWaveletDenoiseImageHandler::set_denoise_config (const XCam3aResultWaveletNoiseReduction& config) + +{ + _config = config; + + return true; +} + +SmartPtr<CLImageHandler> +create_cl_wavelet_denoise_image_handler (const SmartPtr<CLContext> &context, uint32_t channel) +{ + SmartPtr<CLWaveletDenoiseImageHandler> wavelet_handler; + SmartPtr<CLWaveletDenoiseImageKernel> wavelet_kernel; + + wavelet_handler = new CLWaveletDenoiseImageHandler (context, "cl_handler_wavelet_denoise"); + XCAM_ASSERT (wavelet_handler.ptr ()); + + for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { + wavelet_kernel = new CLWaveletDenoiseImageKernel ( + context, "kernel_wavelet_denoise", wavelet_handler, channel, layer); + const char *build_options = + (channel & CL_IMAGE_CHANNEL_UV) ? "-DWAVELET_DENOISE_UV=1" : "-DWAVELET_DENOISE_UV=0"; + + XCAM_ASSERT (wavelet_kernel.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, wavelet_kernel->build_kernel (kernel_wavelet_denoise_info, build_options) == XCAM_RETURN_NO_ERROR, NULL, + "build wavelet denoise kernel(%s) failed", kernel_wavelet_denoise_info.kernel_name); + XCAM_ASSERT (wavelet_kernel->is_valid ()); + + wavelet_handler->add_kernel (wavelet_kernel); + } + return wavelet_handler; +} + +}; diff --git a/modules/ocl/cl_wavelet_denoise_handler.h b/modules/ocl/cl_wavelet_denoise_handler.h new file mode 100644 index 0000000..0513336 --- /dev/null +++ b/modules/ocl/cl_wavelet_denoise_handler.h @@ -0,0 +1,93 @@ +/* + * cl_wavelet_denoise_handler.h - CL wavelet denoise handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wei Zong <wei.zong@intel.com> + */ + +#ifndef XCAM_CL_WAVELET_DENOISE_HANLDER_H +#define XCAM_CL_WAVELET_DENOISE_HANLDER_H + +#include <xcam_std.h> +#include <ocl/cl_image_handler.h> +#include <base/xcam_3a_result.h> + +namespace XCam { + +class CLWaveletDenoiseImageHandler; + +class CLWaveletDenoiseImageKernel + : public CLImageKernel +{ + +private: + +public: + explicit CLWaveletDenoiseImageKernel ( + const SmartPtr<CLContext> &context, + const char *name, + SmartPtr<CLWaveletDenoiseImageHandler> &handler, + uint32_t channel, + uint32_t layer); + + virtual ~CLWaveletDenoiseImageKernel () { + } + +protected: + virtual XCamReturn prepare_arguments ( + CLArgList &args, CLWorkSize &work_size); + +private: + uint32_t _channel; + uint32_t _current_layer; + + SmartPtr<CLWaveletDenoiseImageHandler> _handler; +}; + +class CLWaveletDenoiseImageHandler + : public CLImageHandler +{ +public: + explicit CLWaveletDenoiseImageHandler (const SmartPtr<CLContext> &context, const char *name); + + bool set_denoise_config (const XCam3aResultWaveletNoiseReduction& config); + XCam3aResultWaveletNoiseReduction& get_denoise_config () { + return _config; + }; + + SmartPtr<CLMemory> &get_details_image () { + return _details_image; + }; + + SmartPtr<CLMemory> &get_approx_image () { + return _approx_image; + }; + +protected: + virtual XCamReturn prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + XCam3aResultWaveletNoiseReduction _config; + SmartPtr<CLMemory> _details_image; + SmartPtr<CLMemory> _approx_image; +}; + +SmartPtr<CLImageHandler> +create_cl_wavelet_denoise_image_handler (const SmartPtr<CLContext> &context, uint32_t channel); + +}; + +#endif //XCAM_CL_WAVELET_DENOISE_HANLDER_H diff --git a/modules/ocl/cl_wire_frame_handler.cpp b/modules/ocl/cl_wire_frame_handler.cpp new file mode 100644 index 0000000..9e181ab --- /dev/null +++ b/modules/ocl/cl_wire_frame_handler.cpp @@ -0,0 +1,246 @@ +/* + * cl_wire_frame_handler.cpp - CL wire frame handler + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include "cl_utils.h" +#include "cl_wire_frame_handler.h" + +namespace XCam { + +static const XCamKernelInfo kernel_info = { + "kernel_wire_frame", +#include "kernel_wire_frame.clx" + , 0, +}; + +static float border_y = 120.0f; +static float border_u = -58.0f; +static float border_v = -104.0f; +static uint32_t border_size = 2; + +CLWireFrameImageKernel::CLWireFrameImageKernel ( + const SmartPtr<CLContext> &context, + const SmartPtr<CLWireFrameImageHandler> &handler, + const char *name) + : CLImageKernel (context, name) + , _handler (handler) + , _wire_frames_coords_num (0) + , _wire_frames_coords (NULL) +{ +} + +CLWireFrameImageKernel::~CLWireFrameImageKernel () +{ + xcam_free (_wire_frames_coords); +} + + +bool +CLWireFrameImageHandler::set_wire_frame_config (const XCamFDResult *config, double scaler_factor) +{ + if (!config) { + XCAM_LOG_ERROR ("set wire frame config error, invalid config parameters !"); + return false; + } + + _wire_frames_num = config->face_num; + xcam_mem_clear (_wire_frames); + for (uint32_t i = 0; i < _wire_frames_num && i < XCAM_WIRE_FRAME_MAX_COUNT; i++) { + _wire_frames [i].pos_x = (uint32_t)(config->faces [i].pos_x / scaler_factor / 2) * 2; + _wire_frames [i].pos_y = (uint32_t)(config->faces [i].pos_y / scaler_factor / 2) * 2; + _wire_frames [i].width = (uint32_t)(config->faces [i].width / scaler_factor / 2) * 2; + _wire_frames [i].height = (uint32_t)(config->faces [i].height / scaler_factor / 2) * 2; + } + + return true; +} + +bool +CLWireFrameImageHandler::check_wire_frames_validity (uint32_t image_width, uint32_t image_height) +{ + for (uint32_t i = 0; i < _wire_frames_num; i++) { + if (_wire_frames [i].pos_x > image_width) { + XCAM_LOG_ERROR ("check_wire_frames_validity: invalid pos_x (%d)", _wire_frames [i].pos_x); + return false; + } + if (_wire_frames [i].pos_y > image_height) { + XCAM_LOG_ERROR ("check_wire_frames_validity: invalid pos_y (%d)", _wire_frames [i].pos_y); + return false; + } + if (_wire_frames [i].pos_x + _wire_frames [i].width > image_width) { + XCAM_LOG_ERROR ("check_wire_frames_validity: invalid width (%d)", _wire_frames [i].width); + return false; + } + if (_wire_frames [i].pos_y + _wire_frames [i].height > image_width) { + XCAM_LOG_ERROR ("check_wire_frames_validity: invalid height (%d)", _wire_frames [i].height); + return false; + } + } + + return true; +} + +uint32_t +CLWireFrameImageHandler::get_border_coordinates_num () +{ + uint32_t coords_num = 0; + for (uint32_t i = 0; i < _wire_frames_num; i++) { + coords_num += _wire_frames [i].width * _wire_frames [i].height + - (_wire_frames [i].width - 2 * border_size) * (_wire_frames [i].height - 2 * border_size); + } + + return coords_num / 2; +} + +bool +CLWireFrameImageHandler::get_border_coordinates (uint32_t *coords) +{ + uint32_t index = 0; + for (uint32_t i = 0; i < _wire_frames_num; i++) { + for (uint32_t j = 0; j < border_size; j++) { + for (uint32_t k = 0; k < _wire_frames [i].width; k += 2) { + coords [index++] = _wire_frames [i].pos_x + k; + coords [index++] = _wire_frames [i].pos_y + j; + } + } + + for (uint32_t j = 0; j < border_size; j++) { + for (uint32_t k = 0; k < _wire_frames [i].width; k += 2) { + coords [index++] = _wire_frames [i].pos_x + k; + coords [index++] = _wire_frames [i].pos_y + _wire_frames [i].height - border_size + j; + } + } + + for (uint32_t j = 0; j < _wire_frames [i].height - 2 * border_size; j++) { + for (uint32_t k = 0; k < border_size; k += 2) { + coords [index++] = _wire_frames [i].pos_x + k; + coords [index++] = _wire_frames [i].pos_y + border_size + j; + } + } + + for (uint32_t j = 0; j < _wire_frames [i].height - 2 * border_size; j++) { + for (uint32_t k = 0; k < border_size; k += 2) { + coords [index++] = _wire_frames [i].pos_x + _wire_frames [i].width - border_size + k; + coords [index++] = _wire_frames [i].pos_y + border_size + j; + } + } + } + + return true; +} + +XCamReturn +CLWireFrameImageKernel::prepare_arguments ( + CLArgList &args, CLWorkSize &work_size) +{ + SmartPtr<VideoBuffer> output = _handler->get_output_buf (); + SmartPtr<CLContext> context = get_context (); + const VideoBufferInfo &video_info_out = output->get_video_info (); + CLImageDesc cl_desc_out; + + cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8; + cl_desc_out.format.image_channel_order = CL_RG; + cl_desc_out.width = video_info_out.width / 2; + cl_desc_out.height = video_info_out.height; + cl_desc_out.row_pitch = video_info_out.strides [0]; + SmartPtr<CLImage> image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets [0]); + + cl_desc_out.height = video_info_out.height / 2; + cl_desc_out.row_pitch = video_info_out.strides [1]; + SmartPtr<CLImage> image_out_uv = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets [1]); + + XCAM_FAIL_RETURN ( + WARNING, + image_out->is_valid () && image_out_uv->is_valid (), + XCAM_RETURN_ERROR_MEM, + "cl image kernel (%s) in/out memory not available", get_kernel_name ()); + + XCAM_FAIL_RETURN ( + ERROR, + _handler->check_wire_frames_validity (video_info_out.width, video_info_out.height), + XCAM_RETURN_ERROR_PARAM, + "prepare_arguments: invalid wire frames parameters"); + _wire_frames_coords_num = _handler->get_border_coordinates_num (); + xcam_free (_wire_frames_coords); + _wire_frames_coords = (uint32_t *) xcam_malloc0 (_wire_frames_coords_num * sizeof (uint32_t) * 2 + 1); + XCAM_ASSERT (_wire_frames_coords); + _handler->get_border_coordinates (_wire_frames_coords); + + SmartPtr<CLBuffer> wire_frames_coords_buf = new CLBuffer ( + context, + _wire_frames_coords_num * sizeof (uint32_t) * 2 + 1, + CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, _wire_frames_coords); + + /* set args */ + args.push_back (new CLMemArgument (image_out)); + args.push_back (new CLMemArgument (image_out_uv)); + args.push_back (new CLMemArgument (wire_frames_coords_buf)); + args.push_back (new CLArgumentT<uint32_t> (_wire_frames_coords_num)); + args.push_back (new CLArgumentT<float> (border_y)); + args.push_back (new CLArgumentT<float> (border_u)); + args.push_back (new CLArgumentT<float> (border_v)); + + work_size.dim = 1; + work_size.local [0] = 16; + work_size.global [0] = _wire_frames_coords_num ? XCAM_ALIGN_UP (_wire_frames_coords_num, work_size.local [0]) : work_size.local [0]; + + return XCAM_RETURN_NO_ERROR; +} + +CLWireFrameImageHandler::CLWireFrameImageHandler (const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) + , _wire_frames_num (0) +{ +} + +bool +CLWireFrameImageHandler::set_wire_frame_kernel (SmartPtr<CLWireFrameImageKernel> &kernel) +{ + SmartPtr<CLImageKernel> image_kernel = kernel; + add_kernel (image_kernel); + _wire_frame_kernel = kernel; + return true; +} + +XCamReturn +CLWireFrameImageHandler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + output = input; + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<CLImageHandler> +create_cl_wire_frame_image_handler (const SmartPtr<CLContext> &context) +{ + SmartPtr<CLWireFrameImageHandler> wire_frame_handler; + SmartPtr<CLWireFrameImageKernel> wire_frame_kernel; + + wire_frame_handler = new CLWireFrameImageHandler (context, "cl_handler_wire_frame"); + wire_frame_kernel = new CLWireFrameImageKernel (context, wire_frame_handler, "kernel_wire_frame"); + + XCAM_FAIL_RETURN ( + ERROR, wire_frame_kernel->build_kernel (kernel_info, NULL) == XCAM_RETURN_NO_ERROR, NULL, + "build wire_frame kernel(%s) failed", kernel_info.kernel_name); + XCAM_ASSERT (wire_frame_kernel->is_valid ()); + wire_frame_handler->set_wire_frame_kernel (wire_frame_kernel); + + return wire_frame_handler; +} + +}; diff --git a/modules/ocl/cl_wire_frame_handler.h b/modules/ocl/cl_wire_frame_handler.h new file mode 100644 index 0000000..b576f7c --- /dev/null +++ b/modules/ocl/cl_wire_frame_handler.h @@ -0,0 +1,87 @@ +/* + * cl_wire_frame_handler.h - CL wire frame handler + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#ifndef XCAM_CL_WIRE_FRAME_H +#define XCAM_CL_WIRE_FRAME_H + +#include "ocl/cl_image_handler.h" + +#define XCAM_WIRE_FRAME_MAX_COUNT 160 + +namespace XCam { + +typedef struct _CLWireFrame { + uint32_t pos_x; + uint32_t pos_y; + uint32_t width; + uint32_t height; +} CLWireFrame; + +class CLWireFrameImageHandler; + +class CLWireFrameImageKernel + : public CLImageKernel +{ +public: + explicit CLWireFrameImageKernel ( + const SmartPtr<CLContext> &context, + const SmartPtr<CLWireFrameImageHandler> &handler, + const char *name); + ~CLWireFrameImageKernel (); + +protected: + virtual XCamReturn prepare_arguments ( + CLArgList &args, CLWorkSize &work_size); + +private: + SmartPtr<CLWireFrameImageHandler> _handler; + uint32_t _wire_frames_coords_num; + uint32_t *_wire_frames_coords; +}; + +class CLWireFrameImageHandler + : public CLImageHandler +{ +public: + explicit CLWireFrameImageHandler (const SmartPtr<CLContext> &context, const char *name); + bool set_wire_frame_kernel (SmartPtr<CLWireFrameImageKernel> &kernel); + bool set_wire_frame_config (const XCamFDResult *config, double scaler_factor = 1.0); + + bool check_wire_frames_validity (uint32_t image_width, uint32_t image_height); + uint32_t get_border_coordinates_num (); + bool get_border_coordinates (uint32_t *coords); + +protected: + virtual XCamReturn prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + XCAM_DEAD_COPY (CLWireFrameImageHandler); + SmartPtr<CLWireFrameImageKernel> _wire_frame_kernel; + + uint32_t _wire_frames_num; + CLWireFrame _wire_frames [XCAM_WIRE_FRAME_MAX_COUNT]; +}; + +SmartPtr<CLImageHandler> +create_cl_wire_frame_image_handler (const SmartPtr<CLContext> &context); + +}; + +#endif // XCAM_CL_WIRE_FRAME_H diff --git a/modules/ocl/cl_yuv_pipe_handler.cpp b/modules/ocl/cl_yuv_pipe_handler.cpp new file mode 100644 index 0000000..a13d8ef --- /dev/null +++ b/modules/ocl/cl_yuv_pipe_handler.cpp @@ -0,0 +1,262 @@ +/* + * cl_yuv_pipe_handler.cpp - CL YuvPipe Pipe handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wangfei <feix.w.wang@intel.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_utils.h" +#include "cl_yuv_pipe_handler.h" + +#define USE_BUFFER_OBJECT 0 + +namespace XCam { + +static const XCamKernelInfo kernel_yuv_pipe_info = { + "kernel_yuv_pipe", +#include "kernel_yuv_pipe.clx" + , 0, +}; + +float default_matrix[XCAM_COLOR_MATRIX_SIZE] = { + 0.299f, 0.587f, 0.114f, + -0.14713f, -0.28886f, 0.436f, + 0.615f, -0.51499f, -0.10001f, +}; +float default_macc[XCAM_CHROMA_AXIS_SIZE * XCAM_CHROMA_MATRIX_SIZE] = { + 1.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 1.000000f, + 1.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 1.000000f, + 1.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 1.000000f, + 1.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 1.000000f, + 1.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 1.000000f, + 1.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 1.000000f, + 1.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 1.000000f, + 1.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 1.000000f, +}; + +CLYuvPipeImageKernel::CLYuvPipeImageKernel (const SmartPtr<CLContext> &context) + : CLImageKernel (context, "kernel_yuv_pipe") + +{ +} + +CLYuvPipeImageHandler::CLYuvPipeImageHandler (const SmartPtr<CLContext> &context, const char *name) + : CLImageHandler (context, name) + , _output_format(V4L2_PIX_FMT_NV12) + , _enable_tnr_yuv (0) + , _gain_yuv (1.0) + , _thr_y (0.05) + , _thr_uv (0.05) + , _enable_tnr_yuv_state (0) + +{ + memcpy(_macc_table, default_macc, sizeof(float)*XCAM_CHROMA_AXIS_SIZE * XCAM_CHROMA_MATRIX_SIZE); + memcpy(_rgbtoyuv_matrix, default_matrix, sizeof(float)*XCAM_COLOR_MATRIX_SIZE); +} + +bool +CLYuvPipeImageHandler::set_macc_table (const XCam3aResultMaccMatrix &macc) +{ + for(int i = 0; i < XCAM_CHROMA_AXIS_SIZE * XCAM_CHROMA_MATRIX_SIZE; i++) + _macc_table[i] = (float)macc.table[i]; + return true; +} + +bool +CLYuvPipeImageHandler::set_rgbtoyuv_matrix (const XCam3aResultColorMatrix &matrix) +{ + for (int i = 0; i < XCAM_COLOR_MATRIX_SIZE; i++) + _rgbtoyuv_matrix[i] = (float)matrix.matrix[i]; + return true; +} + +XCamReturn +CLYuvPipeImageHandler::prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, + VideoBufferInfo &output) +{ + bool format_inited = output.init (_output_format, input.width, input.height); + + XCAM_FAIL_RETURN ( + WARNING, + format_inited, + XCAM_RETURN_ERROR_PARAM, + "CL image handler(%s) output format(%s) unsupported", + get_name (), xcam_fourcc_to_string (_output_format)); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CLYuvPipeImageHandler::prepare_parameters ( + SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) +{ + SmartPtr<CLContext> context = get_context (); + const VideoBufferInfo & video_info_in = input->get_video_info (); + const VideoBufferInfo & video_info_out = output->get_video_info (); + CLArgList args; + CLWorkSize work_size; + + XCAM_ASSERT (_yuv_pipe_kernel.ptr ()); + SmartPtr<CLMemory> buffer_in, buffer_out, buffer_out_UV; + +#if !USE_BUFFER_OBJECT + CLImageDesc in_image_info; + in_image_info.format.image_channel_order = CL_RGBA; + in_image_info.format.image_channel_data_type = CL_UNSIGNED_INT32; + in_image_info.width = video_info_in.aligned_width / 8; + in_image_info.height = video_info_in.aligned_height * 3; + in_image_info.row_pitch = video_info_in.strides[0]; + + CLImageDesc out_image_info; + out_image_info.format.image_channel_order = CL_RGBA; + out_image_info.format.image_channel_data_type = CL_UNSIGNED_INT16; + out_image_info.width = video_info_out.width / 8; + out_image_info.height = video_info_out.aligned_height; + out_image_info.row_pitch = video_info_out.strides[0]; + + buffer_in = convert_to_climage (context, input, in_image_info); + buffer_out = convert_to_climage (context, output, out_image_info, video_info_out.offsets[0]); + + out_image_info.height = video_info_out.aligned_height / 2; + out_image_info.row_pitch = video_info_out.strides[1]; + buffer_out_UV = convert_to_climage (context, output, out_image_info, video_info_out.offsets[1]); +#else + buffer_in = convert_to_clbuffer (context, input); + buffer_out = convert_to_clbuffer (context, output); +#endif + SmartPtr<CLBuffer> matrix_buffer = new CLBuffer ( + context, sizeof(float)*XCAM_COLOR_MATRIX_SIZE, + CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR , &_rgbtoyuv_matrix); + SmartPtr<CLBuffer> macc_table_buffer = new CLBuffer( + context, sizeof(float)*XCAM_CHROMA_AXIS_SIZE * XCAM_CHROMA_MATRIX_SIZE, + CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR , &_macc_table); + + uint32_t plannar_offset = video_info_in.aligned_height; + + if (!_buffer_out_prev.ptr ()) { + _buffer_out_prev = buffer_out; + _buffer_out_prev_UV = buffer_out_UV; + _enable_tnr_yuv_state = _enable_tnr_yuv; + _enable_tnr_yuv = 0; + } + else { + if (_enable_tnr_yuv == 0) + _enable_tnr_yuv = _enable_tnr_yuv_state; + } + XCAM_FAIL_RETURN ( + WARNING, + buffer_in->is_valid () && buffer_out->is_valid (), + XCAM_RETURN_ERROR_MEM, + "cl image handler(%s) in/out memory not available", XCAM_STR (get_name ())); + + //set args; + args.push_back (new CLMemArgument (buffer_out)); + +#if !USE_BUFFER_OBJECT + args.push_back (new CLMemArgument (buffer_out_UV)); +#endif + + args.push_back (new CLMemArgument (_buffer_out_prev)); + +#if !USE_BUFFER_OBJECT + args.push_back (new CLMemArgument (_buffer_out_prev_UV)); +#else + uint32_t vertical_offset = video_info_out.aligned_height; + args.push_back (new CLArgumentT<uint32_t> (vertical_offset)); +#endif + args.push_back (new CLArgumentT<uint32_t> (plannar_offset)); + args.push_back (new CLMemArgument (matrix_buffer)); + args.push_back (new CLMemArgument (macc_table_buffer)); + args.push_back (new CLArgumentT<float> (_gain_yuv)); + args.push_back (new CLArgumentT<float> (_thr_y)); + args.push_back (new CLArgumentT<float> (_thr_uv)); + args.push_back (new CLArgumentT<uint32_t> (_enable_tnr_yuv)); + args.push_back (new CLMemArgument (buffer_in)); + + work_size.dim = XCAM_DEFAULT_IMAGE_DIM; + work_size.global[0] = video_info_out.width / 8 ; + work_size.global[1] = video_info_out.aligned_height / 2 ; + work_size.local[0] = 8; + work_size.local[1] = 4; + + XCAM_ASSERT (_yuv_pipe_kernel.ptr ()); + XCamReturn ret = _yuv_pipe_kernel->set_arguments (args, work_size); + XCAM_FAIL_RETURN ( + WARNING, ret == XCAM_RETURN_NO_ERROR, ret, + "yuv pipe kernel set arguments failed."); + + if (buffer_out->is_valid ()) { + _buffer_out_prev = buffer_out; + _buffer_out_prev_UV = buffer_out_UV; + } + + return XCAM_RETURN_NO_ERROR; +} + +bool +CLYuvPipeImageHandler::set_yuv_pipe_kernel(SmartPtr<CLYuvPipeImageKernel> &kernel) +{ + SmartPtr<CLImageKernel> image_kernel = kernel; + add_kernel (image_kernel); + _yuv_pipe_kernel = kernel; + return true; +} + +bool +CLYuvPipeImageHandler::set_tnr_yuv_config (const XCam3aResultTemporalNoiseReduction& config) +{ + if (!_yuv_pipe_kernel->is_valid ()) { + XCAM_LOG_ERROR ("set config error, invalid YUV-Pipe kernel !"); + } + + _gain_yuv = (float)config.gain; + _thr_y = (float)config.threshold[0]; + _thr_uv = (float)config.threshold[1]; + XCAM_LOG_DEBUG ("set TNR YUV config: _gain(%f), _thr_y(%f), _thr_uv(%f)", + _gain_yuv, _thr_y, _thr_uv); + return true; +} + +bool +CLYuvPipeImageHandler::set_tnr_enable (bool enable_tnr_yuv) +{ + _enable_tnr_yuv = (enable_tnr_yuv ? 1 : 0); + return true; +} + +SmartPtr<CLImageHandler> +create_cl_yuv_pipe_image_handler (const SmartPtr<CLContext> &context) +{ + SmartPtr<CLYuvPipeImageHandler> yuv_pipe_handler; + SmartPtr<CLYuvPipeImageKernel> yuv_pipe_kernel; + + yuv_pipe_kernel = new CLYuvPipeImageKernel (context); + XCAM_ASSERT (yuv_pipe_kernel.ptr ()); + const char * options = USE_BUFFER_OBJECT ? "-DUSE_BUFFER_OBJECT=1" : "-DUSE_BUFFER_OBJECT=0"; + XCAM_FAIL_RETURN ( + ERROR, yuv_pipe_kernel->build_kernel (kernel_yuv_pipe_info, options) == XCAM_RETURN_NO_ERROR, NULL, + "build yuv-pipe kernel(%s) failed", kernel_yuv_pipe_info.kernel_name); + + XCAM_ASSERT (yuv_pipe_kernel->is_valid ()); + yuv_pipe_handler = new CLYuvPipeImageHandler (context, "cl_handler_pipe_yuv"); + yuv_pipe_handler->set_yuv_pipe_kernel (yuv_pipe_kernel); + + return yuv_pipe_handler; +} + +}; diff --git a/modules/ocl/cl_yuv_pipe_handler.h b/modules/ocl/cl_yuv_pipe_handler.h new file mode 100644 index 0000000..9f0df25 --- /dev/null +++ b/modules/ocl/cl_yuv_pipe_handler.h @@ -0,0 +1,80 @@ +/* + * cl_yuv_pipe_handler.h - CL Yuv Pipe handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wangfei <feix.w.wang@intel.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_YUV_PIPE_HANLDER_H +#define XCAM_CL_YUV_PIPE_HANLDER_H + +#include <xcam_std.h> +#include <ocl/cl_image_handler.h> +#include <base/xcam_3a_result.h> + +namespace XCam { + +class CLYuvPipeImageKernel + : public CLImageKernel +{ + +public: + explicit CLYuvPipeImageKernel (const SmartPtr<CLContext> &context); +}; + +class CLYuvPipeImageHandler + : public CLImageHandler +{ +public: + explicit CLYuvPipeImageHandler (const SmartPtr<CLContext> &context, const char *name); + bool set_yuv_pipe_kernel(SmartPtr<CLYuvPipeImageKernel> &kernel); + bool set_macc_table (const XCam3aResultMaccMatrix &macc); + bool set_rgbtoyuv_matrix (const XCam3aResultColorMatrix &matrix); + bool set_tnr_yuv_config (const XCam3aResultTemporalNoiseReduction& config); + bool set_tnr_enable (bool enable_tnr_yuv); + +protected: + virtual XCamReturn prepare_buffer_pool_video_info ( + const VideoBufferInfo &input, VideoBufferInfo &output); + virtual XCamReturn prepare_parameters ( + SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output); + +private: + XCAM_DEAD_COPY (CLYuvPipeImageHandler); + SmartPtr<CLYuvPipeImageKernel> _yuv_pipe_kernel; + uint32_t _output_format; + + float _macc_table[XCAM_CHROMA_AXIS_SIZE * XCAM_CHROMA_MATRIX_SIZE]; + float _rgbtoyuv_matrix[XCAM_COLOR_MATRIX_SIZE]; + + //TNR + uint32_t _enable_tnr_yuv; + float _gain_yuv; + float _thr_y; + float _thr_uv; + + uint32_t _enable_tnr_yuv_state; + SmartPtr<CLMemory> _buffer_out_prev; + SmartPtr<CLMemory> _buffer_out_prev_UV; +}; + +SmartPtr<CLImageHandler> +create_cl_yuv_pipe_image_handler (const SmartPtr<CLContext> &context); + +}; + +#endif //XCAM_CL_YUV_PIPE_HANLDER_H diff --git a/modules/ocl/cv_base_class.cpp b/modules/ocl/cv_base_class.cpp new file mode 100644 index 0000000..7dbecaa --- /dev/null +++ b/modules/ocl/cv_base_class.cpp @@ -0,0 +1,67 @@ +/* + * cv_base_class.cpp - base class for all OpenCV related features + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cv_base_class.h" + +namespace XCam { + +CVBaseClass::CVBaseClass () +{ + _cv_context = CVContext::instance (); + XCAM_ASSERT (_cv_context.ptr ()); + _use_ocl = _cv_context->is_ocl_enabled (); +} + +bool +CVBaseClass::set_ocl (bool use_ocl) +{ + if (use_ocl && !_cv_context->is_ocl_enabled ()) { + return false; + } + _use_ocl = use_ocl; + return true; +} + +bool +CVBaseClass::convert_to_mat (SmartPtr<VideoBuffer> buffer, cv::Mat &image) +{ + + VideoBufferInfo info = buffer->get_video_info (); + XCAM_FAIL_RETURN (WARNING, info.format == V4L2_PIX_FMT_NV12, false, "convert_to_mat only support NV12 format"); + + uint8_t *ptr = buffer->map (); + XCAM_FAIL_RETURN (WARNING, ptr, false, "convert_to_mat buffer map failed"); + + cv::Mat mat = cv::Mat (info.aligned_height * 3 / 2, info.width, CV_8UC1, ptr, info.strides[0]); + cv::cvtColor (mat, image, cv::COLOR_YUV2BGR_NV12); + //buffer->unmap (); + + return true; +} + +bool +convert_to_mat (SmartPtr<VideoBuffer> buffer, cv::Mat &image) +{ + CVBaseClass cv_obj; + return cv_obj.convert_to_mat (buffer, image); +} + +} diff --git a/modules/ocl/cv_base_class.h b/modules/ocl/cv_base_class.h new file mode 100644 index 0000000..70641c2 --- /dev/null +++ b/modules/ocl/cv_base_class.h @@ -0,0 +1,52 @@ +/* + * cv_base_class.h - base class for all OpenCV related features + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CV_BASE_CLASS_H +#define XCAM_CV_BASE_CLASS_H + +#include <xcam_std.h> +#include <video_buffer.h> +#include <ocl/cv_context.h> + +namespace XCam { + +class CVBaseClass +{ +public: + explicit CVBaseClass (); + bool set_ocl (bool use_ocl); + bool is_ocl_path () { + return _use_ocl; + } + bool convert_to_mat (SmartPtr<VideoBuffer> buffer, cv::Mat &image); + +protected: + XCAM_DEAD_COPY (CVBaseClass); + SmartPtr<CVContext> _cv_context; + bool _use_ocl; +}; + +extern bool +convert_to_mat (SmartPtr<VideoBuffer> buffer, cv::Mat &image); + +} + +#endif // XCAM_CV_BASE_CLASS_H diff --git a/modules/ocl/cv_context.cpp b/modules/ocl/cv_context.cpp new file mode 100644 index 0000000..babf5ef --- /dev/null +++ b/modules/ocl/cv_context.cpp @@ -0,0 +1,82 @@ +/* + * cv_context.cpp - used to init_opencv_ocl once + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cv_context.h" +#include "cl_device.h" +#include "cl_memory.h" + +namespace XCam { + +Mutex CVContext::_init_mutex; +SmartPtr<CVContext> CVContext::_instance; + + +SmartPtr<CVContext> +CVContext::instance () +{ + SmartLock locker (_init_mutex); + if (_instance.ptr()) + return _instance; + + _instance = new CVContext (); + _instance->init_opencv_ocl (); + return _instance; +} + +void +CVContext::init_opencv_ocl () +{ + _context = CLDevice::instance()->get_context(); + cl_platform_id platform_id = CLDevice::instance()->get_platform_id (); + char *platform_name = CLDevice::instance()->get_platform_name (); + cl_device_id device_id = CLDevice::instance()->get_device_id (); + cl_context _context_id = _context->get_context_id (); + cv::ocl::attachContext (platform_name, platform_id, _context_id, device_id); + cv::ocl::setUseOpenCL (cv::ocl::haveOpenCL()); + XCAM_LOG_DEBUG("Use OpenCL is: %s", cv::ocl::haveOpenCL() ? "true" : "false"); +} + +bool +CVContext::enable_ocl (bool flag) +{ + if (flag && !cv::ocl::haveOpenCL()) { + return false; + } + cv::ocl::setUseOpenCL (flag); + return true; +} + +bool +CVContext::is_ocl_enabled () const +{ + return cv::ocl::useOpenCL (); +} + +CVContext::CVContext () +{ + +} + +CVContext::~CVContext () { + +} + +} diff --git a/modules/ocl/cv_context.h b/modules/ocl/cv_context.h new file mode 100644 index 0000000..17363be --- /dev/null +++ b/modules/ocl/cv_context.h @@ -0,0 +1,62 @@ +/* + * cv_context.h - used to init_opencv_ocl once + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CV_CONTEXT_H +#define XCAM_CV_CONTEXT_H + +#include <xcam_std.h> +#include <xcam_obj_debug.h> +#include <xcam_mutex.h> +#include <ocl/cl_context.h> + +#include <opencv2/opencv.hpp> +#include <opencv2/core/ocl.hpp> + +namespace XCam { + +class CVContext +{ +public: + static SmartPtr<CVContext> instance (); + + SmartPtr<CLContext> get_cl_context () { + return _context; + } + ~CVContext(); + bool enable_ocl (bool flag); + bool is_ocl_enabled () const; + +private: + CVContext (); + void init_opencv_ocl (); + + static Mutex _init_mutex; + static SmartPtr<CVContext> _instance; + + SmartPtr<CLContext> _context; + + XCAM_DEAD_COPY (CVContext); + +}; + +} + +#endif // XCAM_CV_CONTEXT_H diff --git a/modules/ocl/cv_edgetaper.cpp b/modules/ocl/cv_edgetaper.cpp new file mode 100644 index 0000000..ab79238 --- /dev/null +++ b/modules/ocl/cv_edgetaper.cpp @@ -0,0 +1,84 @@ +/* + * cv_edgetaper.cpp - used in deblurring to remove ringing artifacts + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cv_edgetaper.h" + +namespace XCam { + + +CVEdgetaper::CVEdgetaper () + : CVBaseClass () +{ + +} + +void +CVEdgetaper::create_weights (const cv::Mat &image, const cv::Mat &psf, cv::Mat &coefficients) +{ + cv::Mat rows_proj, cols_proj; + cv::Mat rows_proj_border, cols_proj_border; + cv::Mat rows_cor, cols_cor; + // get psf rows and cols projections + cv::reduce (psf, rows_proj, 1, CV_REDUCE_SUM, -1); + cv::reduce (psf, cols_proj, 0, CV_REDUCE_SUM, -1); + // calculate correlation for psf projections + cv::copyMakeBorder (rows_proj, rows_proj_border, (psf.rows - 1) / 2, (psf.rows - 1) / 2, 0, 0, cv::BORDER_CONSTANT, cv::Scalar::all (0)); + cv::copyMakeBorder (cols_proj, cols_proj_border, 0, 0, (psf.cols - 1) / 2, (psf.cols - 1) / 2, cv::BORDER_CONSTANT, cv::Scalar::all (0)); + cv::matchTemplate (rows_proj_border, rows_proj, rows_cor, CV_TM_CCORR); + cv::matchTemplate (cols_proj_border, cols_proj, cols_cor, CV_TM_CCORR); + // make it symmetric on both sides + cv::Mat rows_add = cv::Mat_<float>(1, 1) << rows_proj.at<float> (0, 0); + cv::Mat cols_add = cv::Mat_<float>(1, 1) << cols_proj.at<float> (0, 0); + cv::vconcat (rows_cor, rows_add, rows_cor); + cv::hconcat (cols_cor, cols_add, cols_cor); + double min, max; + cv::minMaxLoc (rows_cor, &min, &max); + rows_cor /= max; + cv::minMaxLoc (cols_cor, &min, &max); + cols_cor /= max; + // get matrix from projections + cv::Mat alpha = (cv::Scalar (1) - rows_proj) * (cv::Scalar (1) - cols_proj); + // expand it to the image size + int nc = image.cols / psf.cols + 1; + int nr = image.rows / psf.rows + 1; + cv::Mat expanded; + cv::repeat (alpha, nr, nc, expanded); + cv::Mat weights = expanded (cv::Rect (expanded.cols / 2 - image.cols / 2, expanded.rows / 2 - image.rows / 2, image.cols, image.rows)); + coefficients = weights.clone (); +} + +void +CVEdgetaper::edgetaper (const cv::Mat &img, const cv::Mat &psf, cv::Mat &output) +{ + cv::Mat blurred = cv::Mat::zeros (img.rows, img.cols, CV_32FC1); + // flip PSF to perform convolution + cv::Mat psf_flipped; + cv::flip (psf, psf_flipped, -1); + cv::filter2D (img, blurred, CV_32FC1, psf_flipped, cv::Point (-1, -1), 0, cv::BORDER_CONSTANT); + cv::Mat coefficients; + create_weights (img, psf, coefficients); + cv::Mat result; + img.convertTo (result, CV_32FC1); + result = result.mul (coefficients) + blurred.mul (cv::Scalar (1.0f) - coefficients); + output = result.clone (); +} + +} diff --git a/modules/ocl/cv_edgetaper.h b/modules/ocl/cv_edgetaper.h new file mode 100644 index 0000000..1ead29f --- /dev/null +++ b/modules/ocl/cv_edgetaper.h @@ -0,0 +1,49 @@ +/* + * cv_edgetaper.h - used in deblurring to remove ringing artifacts + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CV_EDGETAPER_H +#define XCAM_CV_EDGETAPER_H + +#include <xcam_std.h> +#include <ocl/cv_base_class.h> + +#include <opencv2/opencv.hpp> +#include <opencv2/core/ocl.hpp> + +namespace XCam { + + +class CVEdgetaper : public CVBaseClass +{ + +public: + explicit CVEdgetaper (); + void edgetaper (const cv::Mat &image, const cv::Mat &psf, cv::Mat &output); + +private: + void create_weights (const cv::Mat &image, const cv::Mat &psf, cv::Mat &coefficients); + + XCAM_DEAD_COPY (CVEdgetaper); +}; + +} + +#endif // XCAM_CV_EDGETAPER_H diff --git a/modules/ocl/cv_feature_match.cpp b/modules/ocl/cv_feature_match.cpp new file mode 100644 index 0000000..e4e2ea8 --- /dev/null +++ b/modules/ocl/cv_feature_match.cpp @@ -0,0 +1,292 @@ +/* + * cv_feature_match.cpp - optical flow feature match + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include "cv_feature_match.h" +#include "xcam_obj_debug.h" +#include "image_file_handle.h" +#include "cl_utils.h" + +#define XCAM_CV_FM_DEBUG 0 +#define XCAM_CV_OF_DRAW_SCALE 2 + +namespace XCam { +#if XCAM_CV_FM_DEBUG +static void debug_write_image ( + const SmartPtr<VideoBuffer> &buf, const Rect &rect, char *img_name, char *frame_str, char *fm_idx_str); +#endif + +CVFeatureMatch::CVFeatureMatch () + : CVBaseClass () + , FeatureMatch () +{ + XCAM_ASSERT (_cv_context.ptr ()); +} + +bool +CVFeatureMatch::get_crop_image ( + const SmartPtr<VideoBuffer> &buffer, const Rect &crop_rect, cv::UMat &img) +{ + SmartPtr<CLBuffer> cl_buffer = convert_to_clbuffer (_cv_context->get_cl_context (), buffer); + VideoBufferInfo info = buffer->get_video_info (); + cl_mem cl_mem_id = cl_buffer->get_mem_id (); + + cv::UMat umat; + cv::ocl::convertFromBuffer (cl_mem_id, info.strides[0], info.height, info.width, CV_8U, umat); + if (umat.empty ()) { + XCAM_LOG_ERROR ("FeatureMatch(idx:%d): convert bo buffer to UMat failed", _fm_idx); + return false; + } + + img = umat (cv::Rect(crop_rect.pos_x, crop_rect.pos_y, crop_rect.width, crop_rect.height)); + + return true; +} + +void +CVFeatureMatch::add_detected_data ( + cv::InputArray image, cv::Ptr<cv::Feature2D> detector, std::vector<cv::Point2f> &corners) +{ + std::vector<cv::KeyPoint> keypoints; + detector->detect (image, keypoints); + corners.reserve (corners.size () + keypoints.size ()); + for (size_t i = 0; i < keypoints.size (); ++i) { + cv::KeyPoint &kp = keypoints[i]; + corners.push_back (kp.pt); + } +} + +void +CVFeatureMatch::get_valid_offsets ( + std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1, + std::vector<uchar> &status, std::vector<float> &error, + std::vector<float> &offsets, float &sum, int &count, + cv::InputOutputArray debug_img, cv::Size &img0_size) +{ + count = 0; + sum = 0.0f; + for (uint32_t i = 0; i < status.size (); ++i) { + if (!status[i]) + continue; + +#if XCAM_CV_FM_DEBUG + cv::Point start = cv::Point(corner0[i]) * XCAM_CV_OF_DRAW_SCALE; + cv::circle (debug_img, start, 4, cv::Scalar(255), XCAM_CV_OF_DRAW_SCALE); +#endif + if (error[i] > _config.max_track_error) + continue; + if (fabs(corner0[i].y - corner1[i].y) >= _config.max_valid_offset_y) + continue; + if (corner1[i].x < 0.0f || corner1[i].x > img0_size.width) + continue; + + float offset = corner1[i].x - corner0[i].x; + sum += offset; + ++count; + offsets.push_back (offset); + +#if XCAM_CV_FM_DEBUG + cv::Point end = (cv::Point(corner1[i]) + cv::Point (img0_size.width, 0)) * XCAM_CV_OF_DRAW_SCALE; + cv::line (debug_img, start, end, cv::Scalar(255), XCAM_CV_OF_DRAW_SCALE); +#else + XCAM_UNUSED (debug_img); + XCAM_UNUSED (img0_size); +#endif + } +} + +void +CVFeatureMatch::calc_of_match ( + cv::InputArray image0, cv::InputArray image1, + std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1, + std::vector<uchar> &status, std::vector<float> &error, + int &last_count, float &last_mean_offset, float &out_x_offset) +{ + cv::_InputOutputArray debug_img; + cv::Size img0_size = image0.size (); + XCAM_ASSERT (img0_size.height == image1.rows ()); + XCAM_UNUSED (image1); + +#if XCAM_CV_FM_DEBUG + cv::Mat mat; + cv::UMat umat; + cv::Size img1_size = image1.size (); + cv::Size size (img0_size.width + img1_size.width, img0_size.height); + + if (image0.isUMat ()) { + umat.create (size, image0.type ()); + debug_img = cv::_InputOutputArray (umat); + + image0.copyTo (umat (cv::Rect(0, 0, img0_size.width, img0_size.height))); + image1.copyTo (umat (cv::Rect(img0_size.width, 0, img1_size.width, img1_size.height))); + umat.copyTo (debug_img); + } else { + mat.create (size, image0.type ()); + debug_img = cv::_InputOutputArray (mat); + + image0.copyTo (mat (cv::Rect(0, 0, img0_size.width, img0_size.height))); + image1.copyTo (mat (cv::Rect(img0_size.width, 0, img1_size.width, img1_size.height))); + mat.copyTo (debug_img); + } + + cv::Size scale_size = size * XCAM_CV_OF_DRAW_SCALE; + cv::resize (debug_img, debug_img, scale_size, 0, 0); +#endif + + std::vector<float> offsets; + float offset_sum = 0.0f; + int count = 0; + float mean_offset = 0.0f; + offsets.reserve (corner0.size ()); + get_valid_offsets (corner0, corner1, status, error, + offsets, offset_sum, count, debug_img, img0_size); +#if XCAM_CV_FM_DEBUG + XCAM_LOG_INFO ("FeatureMatch(idx:%d): valid offsets:%d", _fm_idx, offsets.size ()); + char file_name[256]; + std::snprintf (file_name, 256, "fm_optical_flow_%d_%d.jpg", _frame_num, _fm_idx); + cv::imwrite (file_name, debug_img); +#endif + + bool ret = get_mean_offset (offsets, offset_sum, count, mean_offset); + if (ret) { + if (fabs (mean_offset - last_mean_offset) < _config.delta_mean_offset) { + out_x_offset = out_x_offset * _config.offset_factor + mean_offset * (1.0f - _config.offset_factor); + + if (fabs (out_x_offset) > _config.max_adjusted_offset) + out_x_offset = (out_x_offset > 0.0f) ? _config.max_adjusted_offset : (-_config.max_adjusted_offset); + } + } + + last_count = count; + last_mean_offset = mean_offset; +} + +void +CVFeatureMatch::detect_and_match ( + cv::InputArray img_left, cv::InputArray img_right, Rect &crop_left, Rect &crop_right, + int &valid_count, float &mean_offset, float &x_offset, int dst_width) +{ + std::vector<float> err; + std::vector<uchar> status; + std::vector<cv::Point2f> corner_left, corner_right; + cv::Ptr<cv::Feature2D> fast_detector; + cv::Size win_size = cv::Size (5, 5); + + if (img_left.isUMat ()) + win_size = cv::Size (16, 16); + + fast_detector = cv::FastFeatureDetector::create (20, true); + add_detected_data (img_left, fast_detector, corner_left); + + if (corner_left.empty ()) { + return; + } + + cv::calcOpticalFlowPyrLK ( + img_left, img_right, corner_left, corner_right, status, err, win_size, 3, + cv::TermCriteria (cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 10, 0.01f)); + cv::ocl::finish(); + + calc_of_match (img_left, img_right, corner_left, corner_right, + status, err, valid_count, mean_offset, x_offset); + + adjust_stitch_area (dst_width, x_offset, crop_left, crop_right); + +#if XCAM_CV_FM_DEBUG + XCAM_LOG_INFO ( + "FeatureMatch(idx:%d): stiching area: left_area(pos_x:%d, width:%d), right_area(pos_x:%d, width:%d)", + _fm_idx, crop_left.pos_x, crop_left.width, crop_right.pos_x, crop_right.width); +#endif +} + +void +CVFeatureMatch::optical_flow_feature_match ( + const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf, + Rect &left_crop_rect, Rect &right_crop_rect, int dst_width) +{ + cv::UMat left_umat, right_umat; + cv::Mat left_mat, right_mat; + cv::_InputArray left_img, right_img; + + if (!get_crop_image (left_buf, left_crop_rect, left_umat) + || !get_crop_image (right_buf, right_crop_rect, right_umat)) + return; + + if (_use_ocl) { + left_img = cv::_InputArray (left_umat); + right_img = cv::_InputArray (right_umat); + } else { + left_mat = left_umat.getMat (cv::ACCESS_READ); + right_mat = right_umat.getMat (cv::ACCESS_READ); + + left_img = cv::_InputArray (left_mat); + right_img = cv::_InputArray (right_mat); + } + + detect_and_match (left_img, right_img, left_crop_rect, right_crop_rect, + _valid_count, _mean_offset, _x_offset, dst_width); + +#if XCAM_CV_FM_DEBUG + XCAM_ASSERT (_fm_idx >= 0); + + char frame_str[64] = {'\0'}; + std::snprintf (frame_str, 64, "frame:%d", _frame_num); + char fm_idx_str[64] = {'\0'}; + std::snprintf (fm_idx_str, 64, "fm_idx:%d", _fm_idx); + + char img_name[256] = {'\0'}; + std::snprintf (img_name, 256, "fm_in_stitch_area_%d_%d_0.jpg", _frame_num, _fm_idx); + debug_write_image (left_buf, left_crop_rect, img_name, frame_str, fm_idx_str); + + std::snprintf (img_name, 256, "fm_in_stitch_area_%d_%d_1.jpg", _frame_num, _fm_idx); + debug_write_image (right_buf, right_crop_rect, img_name, frame_str, fm_idx_str); + + XCAM_LOG_INFO ("FeatureMatch(idx:%d): frame number:%d done", _fm_idx, _frame_num); + _frame_num++; +#endif +} + +#if XCAM_CV_FM_DEBUG +static void +debug_write_image ( + const SmartPtr<VideoBuffer> &buf, const Rect &rect, char *img_name, char *frame_str, char *fm_idx_str) +{ + cv::Scalar color = cv::Scalar(0, 0, 255); + VideoBufferInfo info = buf->get_video_info (); + + cv::Mat mat; + CVBaseClass cv_obj; + cv_obj.convert_to_mat (buf, mat); + + cv::putText (mat, frame_str, cv::Point(rect.pos_x, 30), cv::FONT_HERSHEY_COMPLEX, 0.8f, color, 2, 8, false); + cv::putText (mat, fm_idx_str, cv::Point(rect.pos_x, 70), cv::FONT_HERSHEY_COMPLEX, 0.8f, color, 2, 8, false); + + cv::line (mat, cv::Point(rect.pos_x, rect.pos_y), cv::Point(rect.pos_x + rect.width, rect.pos_y), color, 1); + cv::line (mat, cv::Point(rect.pos_x, rect.pos_y + rect.height), + cv::Point(rect.pos_x + rect.width, rect.pos_y + rect.height), color, 1); + + cv::line (mat, cv::Point(rect.pos_x, 0), cv::Point(rect.pos_x, info.height), color, 2); + cv::line (mat, cv::Point(rect.pos_x + rect.width, 0), cv::Point(rect.pos_x + rect.width, info.height), color, 2); + + cv::imwrite (img_name, mat); +} +#endif + +} diff --git a/modules/ocl/cv_feature_match.h b/modules/ocl/cv_feature_match.h new file mode 100644 index 0000000..ed53fae --- /dev/null +++ b/modules/ocl/cv_feature_match.h @@ -0,0 +1,79 @@ +/* + * cv_feature_match.h - optical flow feature match + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#ifndef XCAM_CV_FEATURE_MATCH_H +#define XCAM_CV_FEATURE_MATCH_H + +#include <xcam_std.h> +#include <video_buffer.h> +#include <ocl/cv_base_class.h> +#include <interface/feature_match.h> +#include <interface/data_types.h> + +#include <ocl/cl_context.h> +#include <ocl/cl_device.h> +#include <ocl/cl_memory.h> + +namespace XCam { + +class CVFeatureMatch + : public CVBaseClass + , public FeatureMatch +{ +public: + explicit CVFeatureMatch (); + + void optical_flow_feature_match ( + const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf, + Rect &left_img_crop, Rect &right_img_crop, int dst_width); + + void set_ocl (bool use_ocl) { + CVBaseClass::set_ocl (use_ocl); + } + bool is_ocl_path () { + return CVBaseClass::is_ocl_path (); + } + +protected: + bool get_crop_image (const SmartPtr<VideoBuffer> &buffer, const Rect &crop_rect, cv::UMat &img); + + void add_detected_data (cv::InputArray image, cv::Ptr<cv::Feature2D> detector, std::vector<cv::Point2f> &corners); + void get_valid_offsets (std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1, + std::vector<uchar> &status, std::vector<float> &error, + std::vector<float> &offsets, float &sum, int &count, + cv::InputOutputArray debug_img, cv::Size &img0_size); + + void calc_of_match (cv::InputArray image0, cv::InputArray image1, + std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1, + std::vector<uchar> &status, std::vector<float> &error, + int &last_count, float &last_mean_offset, float &out_x_offset); + + void detect_and_match (cv::InputArray img_left, cv::InputArray img_right, Rect &crop_left, Rect &crop_right, + int &valid_count, float &mean_offset, float &x_offset, int dst_width); + +private: + XCAM_DEAD_COPY (CVFeatureMatch); + +}; + +} + +#endif // XCAM_CV_FEATURE_MATCH_H diff --git a/modules/ocl/cv_image_deblurring.cpp b/modules/ocl/cv_image_deblurring.cpp new file mode 100644 index 0000000..730eb42 --- /dev/null +++ b/modules/ocl/cv_image_deblurring.cpp @@ -0,0 +1,226 @@ +/* + * cv_image_deblurring.cpp - iterative blind deblurring + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cv_image_deblurring.h" + +namespace XCam { + + +CVImageDeblurring::CVImageDeblurring () + : CVBaseClass () +{ + _helper = new CVImageProcessHelper (); + _sharp = new CVImageSharp (); + _edgetaper = new CVEdgetaper (); + _wiener = new CVWienerFilter (); +} + +void +CVImageDeblurring::set_config (CVIDConfig config) +{ + _config = config; +} + +CVIDConfig +CVImageDeblurring::get_config () +{ + return _config; +} + +void +CVImageDeblurring::crop_border (cv::Mat &thresholded) +{ + int top = 0; + int left = 0; + int right = 0; + int bottom = 0; + for (int i = 0; i < thresholded.rows; i++) + { + for (int j = 0; j < thresholded.cols; j++) + { + if (thresholded.at<unsigned char>(i , j) == 255) + { + top = i; + break; + } + } + if (top) + break; + } + + for (int i = thresholded.rows - 1; i > 0; i--) + { + for (int j = 0; j < thresholded.cols; j++) + { + if (thresholded.at<unsigned char>(i , j) == 255) + { + bottom = i; + break; + } + } + if (bottom) + break; + } + + for (int i = 0; i < thresholded.cols; i++) + { + for (int j = 0; j < thresholded.rows; j++) + { + if (thresholded.at<unsigned char>(j , i) == 255) + { + left = i; + break; + } + } + if (left) + break; + } + + for (int i = thresholded.cols - 1; i > 0; i--) + { + for (int j = 0; j < thresholded.rows; j++) + { + if (thresholded.at<unsigned char>(j, i) == 255) + { + right = i; + break; + } + } + if (right) + break; + } + thresholded = thresholded (cv::Rect(left, top, right - left, bottom - top)); +} + +int +CVImageDeblurring::estimate_kernel_size (const cv::Mat &image) +{ + int kernel_size = 0; + cv::Mat thresholded; + cv::Mat dst; + cv::Laplacian (image, dst, -1, 3, 1, 0, cv::BORDER_CONSTANT); + dst.convertTo (dst, CV_32FC1); + cv::filter2D (dst, thresholded, -1, dst, cv::Point(-1, -1), 0, cv::BORDER_CONSTANT); + + for (int i = 0; i < 10; i++) + { + cv::Mat thresholded_new; + double min_val; + double max_val; + cv::minMaxLoc (thresholded, &min_val, &max_val); + cv::threshold (thresholded, thresholded, round(max_val / 3.5), 255, cv::THRESH_BINARY); + thresholded.convertTo (thresholded, CV_8UC1); + crop_border (thresholded); + if (thresholded.rows < 3) + { + break; + } + int filter_size = (int)(std::max(3, ((thresholded.rows + thresholded.cols) / 2) / 10)); + if (!(filter_size & 1)) + { + filter_size++; + } + cv::Mat filter = cv::Mat::ones (filter_size, filter_size, CV_32FC1) / (float)(filter_size * filter_size - 1); + filter.at<float> (filter_size / 2, filter_size / 2) = 0; + cv::filter2D (thresholded, thresholded_new, -1, filter, cv::Point(-1, -1), 0, cv::BORDER_CONSTANT); + kernel_size = (thresholded_new.rows + thresholded_new.cols) / 2; + if (!(kernel_size & 1)) + { + kernel_size++; + } + thresholded = thresholded_new.clone(); + } + return kernel_size; +} + +void +CVImageDeblurring::blind_deblurring (const cv::Mat &blurred, cv::Mat &deblurred, cv::Mat &kernel, int kernel_size, float noise_power, bool use_edgetaper) +{ + cv::Mat gray_blurred; + cv::cvtColor (blurred, gray_blurred, CV_BGR2GRAY); + if (noise_power < 0) + { + cv::Mat median_blurred; + medianBlur (gray_blurred, median_blurred, 3); + noise_power = 1.0f / _helper->get_snr (gray_blurred, median_blurred); + XCAM_LOG_DEBUG ("estimated inv snr %f", noise_power); + } + if (kernel_size < 0) + { + kernel_size = estimate_kernel_size (gray_blurred); + XCAM_LOG_DEBUG ("estimated kernel size %d", kernel_size); + } + if (use_edgetaper) { + XCAM_LOG_DEBUG ("edgetaper will be used"); + } + else { + XCAM_LOG_DEBUG ("edgetaper will not be used"); + } + std::vector<cv::Mat> blurred_rgb (3); + cv::split (blurred, blurred_rgb); + std::vector<cv::Mat> deblurred_rgb (3); + cv::Mat result_deblurred; + cv::Mat result_kernel; + blind_deblurring_one_channel (gray_blurred, result_kernel, kernel_size, noise_power); + for (int i = 0; i < 3; i++) + { + cv::Mat input; + if (use_edgetaper) + { + _edgetaper->edgetaper (blurred_rgb[i], result_kernel, input); + } + else + { + input = blurred_rgb[i].clone (); + } + _wiener->wiener_filter (input, result_kernel, deblurred_rgb[i], noise_power); + _helper->apply_constraints (deblurred_rgb[i], 0); + } + cv::merge (deblurred_rgb, result_deblurred); + result_deblurred.convertTo (result_deblurred, CV_8UC3); + fastNlMeansDenoisingColored (result_deblurred, deblurred, 3, 3, 7, 21); + kernel = result_kernel.clone (); +} + +void +CVImageDeblurring::blind_deblurring_one_channel (const cv::Mat &blurred, cv::Mat &kernel, int kernel_size, float noise_power) +{ + cv::Mat kernel_current = cv::Mat::zeros (kernel_size, kernel_size, CV_32FC1); + cv::Mat deblurred_current = _helper->erosion (blurred, 2, 0); + float sigmar = 20; + for (int i = 0; i < _config.iterations; i++) + { + cv::Mat sharpened = _sharp->sharp_image_gray (deblurred_current, sigmar); + _wiener->wiener_filter (blurred, sharpened.clone (), kernel_current, noise_power); + kernel_current = kernel_current (cv::Rect (0, 0, kernel_size, kernel_size)); + double min_val; + double max_val; + cv::minMaxLoc (kernel_current, &min_val, &max_val); + _helper->apply_constraints (kernel_current, (float)max_val / 20); + _helper->normalize_weights (kernel_current); + _wiener->wiener_filter (blurred, kernel_current.clone(), deblurred_current, noise_power); + _helper->apply_constraints (deblurred_current, 0); + sigmar *= 0.9; + } + kernel = kernel_current.clone (); +} + +} diff --git a/modules/ocl/cv_image_deblurring.h b/modules/ocl/cv_image_deblurring.h new file mode 100644 index 0000000..afac22c --- /dev/null +++ b/modules/ocl/cv_image_deblurring.h @@ -0,0 +1,69 @@ +/* + * cv_image_deblurring.h - iterative blind deblurring + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CV_FEATURE_DEBLURRING_H +#define XCAM_CV_FEATURE_DEBLURRING_H + +#include <xcam_std.h> +#include <video_buffer.h> +#include <ocl/cv_base_class.h> +#include <ocl/cv_image_process_helper.h> +#include <ocl/cv_image_sharp.h> +#include <ocl/cv_edgetaper.h> +#include <ocl/cv_wiener_filter.h> + +namespace XCam { + +struct CVIDConfig { + int iterations; // number of iterations for IBD algorithm + + CVIDConfig (unsigned int _iterations = 50) + { + iterations = _iterations; + } +}; + +class CVImageDeblurring : public CVBaseClass +{ + +public: + explicit CVImageDeblurring (); + void set_config (CVIDConfig config); + CVIDConfig get_config (); + void blind_deblurring (const cv::Mat &blurred, cv::Mat &deblurred, cv::Mat &kernel, int kernel_size = -1, float noise_power = -1.0f, bool use_edgetaper = true); + +private: + void blind_deblurring_one_channel (const cv::Mat &blurred, cv::Mat &kernel, int kernel_size, float noise_power); + int estimate_kernel_size (const cv::Mat &blurred); + void crop_border (cv::Mat &image); + + XCAM_DEAD_COPY (CVImageDeblurring); + + CVIDConfig _config; + SmartPtr<CVImageProcessHelper> _helper; + SmartPtr<CVImageSharp> _sharp; + SmartPtr<CVEdgetaper> _edgetaper; + SmartPtr<CVWienerFilter> _wiener; +}; + +} + +#endif // XCAM_CV_IMAGE_DEBLURRING_H diff --git a/modules/ocl/cv_image_process_helper.cpp b/modules/ocl/cv_image_process_helper.cpp new file mode 100644 index 0000000..0d08289 --- /dev/null +++ b/modules/ocl/cv_image_process_helper.cpp @@ -0,0 +1,103 @@ +/* + * cv_image_process_helper.cpp - OpenCV image processing helpers functions + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cv_image_process_helper.h" + +namespace XCam { + + +CVImageProcessHelper::CVImageProcessHelper () + : CVBaseClass () +{ + +} + +cv::Mat +CVImageProcessHelper::erosion (const cv::Mat &image, int erosion_size, int erosion_type) +{ + cv::Mat element = cv::getStructuringElement (erosion_type, + cv::Size (2 * erosion_size + 1, 2 * erosion_size + 1), + cv::Point (erosion_size, erosion_size)); + cv::Mat eroded; + cv::erode (image, eroded, element); + return eroded.clone (); +} + +float +CVImageProcessHelper::get_snr (const cv::Mat &noisy, const cv::Mat &noiseless) +{ + cv::Mat temp_noisy, temp_noiseless; + noisy.convertTo (temp_noisy, CV_32FC1); + noiseless.convertTo (temp_noiseless, CV_32FC1); + cv::Mat numerator, denominator; + cv::pow (temp_noisy, 2, numerator); + cv::pow (temp_noisy - temp_noiseless, 2, denominator); + float res = cv::sum (numerator)[0] / cv::sum (denominator)[0]; + res = sqrt (res); + return res; +} + +void +CVImageProcessHelper::compute_dft (const cv::Mat &image, cv::Mat &result) +{ + cv::Mat padded; + int m = cv::getOptimalDFTSize (image.rows); + int n = cv::getOptimalDFTSize (image.cols); + cv::copyMakeBorder (image, padded, 0, m - image.rows, 0, n - image.cols, cv::BORDER_CONSTANT, cv::Scalar::all(0)); + cv::Mat planes[] = {cv::Mat_<float> (padded), cv::Mat::zeros (padded.size (), CV_32FC1)}; + cv::merge (planes, 2, result); + cv::dft (result, result); +} + +void +CVImageProcessHelper::compute_idft (cv::Mat *input, cv::Mat &result) +{ + cv::Mat fimg; + cv::merge (input, 2, fimg); + cv::idft (fimg, result, cv::DFT_REAL_OUTPUT + cv::DFT_SCALE); +} + +void +CVImageProcessHelper::apply_constraints (cv::Mat &image, float threshold_min_value, float threshold_max_value, float min_value, float max_value) +{ + for (int i = 0; i < image.rows; i++) { + for (int j = 0; j < image.cols; j++) { + if (image.at<float>(i, j) < threshold_min_value) + { + image.at<float>(i, j) = min_value; + } + if (image.at<float>(i, j) > threshold_max_value) + { + image.at<float>(i, j) = max_value; + } + } + } +} + +void +CVImageProcessHelper::normalize_weights (cv::Mat &weights) +{ + weights.convertTo (weights, CV_32FC1); + float sum = cv::sum (weights)[0]; + weights /= sum; +} + +} diff --git a/modules/ocl/cv_image_process_helper.h b/modules/ocl/cv_image_process_helper.h new file mode 100644 index 0000000..137ff6b --- /dev/null +++ b/modules/ocl/cv_image_process_helper.h @@ -0,0 +1,50 @@ +/* + * cv_image_process_helper.h - OpenCV image processing helpers functions + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CV_IMAGE_PROCESS_HELPER_H +#define XCAM_CV_IMAGE_PROCESS_HELPER_H + +#include <xcam_std.h> +#include <video_buffer.h> +#include <ocl/cv_base_class.h> + +namespace XCam { + + +class CVImageProcessHelper : public CVBaseClass +{ + +public: + explicit CVImageProcessHelper (); + + void compute_dft (const cv::Mat &image, cv::Mat &result); + void compute_idft (cv::Mat *input, cv::Mat &result); + void apply_constraints (cv::Mat &image, float threshold_min_value = 0.0f, float threshold_max_value = 255.0f, float min_value = 0.0f, float max_value = 255.0f); + float get_snr (const cv::Mat &noisy, const cv::Mat &noiseless); + cv::Mat erosion (const cv::Mat &image, int erosion_size, int erosion_type); + void normalize_weights (cv::Mat &weights); + + XCAM_DEAD_COPY (CVImageProcessHelper); +}; + +} + +#endif // XCAM_CV_IMAGE_PROCESS_HELPER_H diff --git a/modules/ocl/cv_image_sharp.cpp b/modules/ocl/cv_image_sharp.cpp new file mode 100644 index 0000000..0a309af --- /dev/null +++ b/modules/ocl/cv_image_sharp.cpp @@ -0,0 +1,61 @@ +/* + * cv_image_sharp.cpp - image sharp + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cv_image_sharp.h" + +namespace XCam { + + +CVImageSharp::CVImageSharp () + : CVBaseClass () +{ + +} + +cv::Mat +CVImageSharp::sharp_image_gray (const cv::Mat &image, float sigmar) +{ + cv::Mat temp_image; + image.convertTo (temp_image, CV_32FC1); + cv::Mat bilateral_image; + cv::bilateralFilter (temp_image, bilateral_image, 5, sigmar, 2); + + cv::Mat sharp_filter = (cv::Mat_<float>(3, 3) << -1, -1, -1, -1, 8, -1, -1, -1, -1); + cv::Mat filtered_image; + cv::filter2D (bilateral_image, filtered_image, -1, sharp_filter); + cv::normalize (filtered_image, filtered_image, 0, 255.0f, cv::NORM_MINMAX); + cv::Mat sharpened = temp_image + filtered_image; + cv::normalize (sharpened, sharpened, 0, 255.0f, cv::NORM_MINMAX); + return sharpened.clone (); +} + +float +CVImageSharp::measure_sharp (const cv::Mat &image) +{ + cv::Mat dst; + cv::Laplacian (image, dst, -1, 3, 1, 0, cv::BORDER_CONSTANT); + dst.convertTo (dst, CV_8UC1); + float sum = cv::sum (dst)[0]; + sum /= (image.rows * image.cols); + return sum; +} + +} diff --git a/modules/ocl/cv_image_sharp.h b/modules/ocl/cv_image_sharp.h new file mode 100644 index 0000000..74e0ce4 --- /dev/null +++ b/modules/ocl/cv_image_sharp.h @@ -0,0 +1,45 @@ +/* + * cv_sharp.h - sharp image + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CV_IMAGE_SHARP_H +#define XCAM_CV_IMAGE_SHARP_H + +#include <xcam_std.h> +#include <video_buffer.h> +#include <ocl/cv_base_class.h> + +namespace XCam { + +class CVImageSharp : public CVBaseClass +{ + +public: + explicit CVImageSharp (); + + float measure_sharp (const cv::Mat &image); + cv::Mat sharp_image_gray (const cv::Mat &image, float sigmar); + + XCAM_DEAD_COPY (CVImageSharp); +}; + +} + +#endif // XCAM_CV_IMAGE_SHARP_H diff --git a/modules/ocl/cv_wiener_filter.cpp b/modules/ocl/cv_wiener_filter.cpp new file mode 100644 index 0000000..ff96e5c --- /dev/null +++ b/modules/ocl/cv_wiener_filter.cpp @@ -0,0 +1,72 @@ +/* + * cv_image_deblurring.cpp - iterative blind deblurring + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cv_wiener_filter.h" + +namespace XCam { + + +CVWienerFilter::CVWienerFilter () + : CVBaseClass () +{ + _helpers = new CVImageProcessHelper (); +} + +void +CVWienerFilter::wiener_filter (const cv::Mat &blurred_image, const cv::Mat &known, cv::Mat &unknown, float noise_power) +{ + int image_w = blurred_image.size ().width; + int image_h = blurred_image.size ().height; + cv::Mat y_ft; + _helpers->compute_dft (blurred_image, y_ft); + + cv::Mat padded = cv::Mat::zeros (image_h, image_w, CV_32FC1); + int padx = padded.cols - known.cols; + int pady = padded.rows - known.rows; + cv::copyMakeBorder (known, padded, 0, pady, 0, padx, cv::BORDER_CONSTANT, cv::Scalar::all(0)); + cv::Mat padded_ft; + _helpers->compute_dft (padded, padded_ft); + + cv::Mat temp_unknown; + cv::Mat unknown_ft[2]; + unknown_ft[0] = cv::Mat::zeros (image_h, image_w, CV_32FC1); + unknown_ft[1] = cv::Mat::zeros (image_h, image_w, CV_32FC1); + + cv::Mat denominator; + cv::Mat denominator_splitted[] = {cv::Mat::zeros (blurred_image.size (), CV_32FC1), cv::Mat::zeros (blurred_image.size (), CV_32FC1)}; + cv::mulSpectrums (padded_ft, padded_ft, denominator, 0, true); + cv::split (denominator, denominator_splitted); + denominator_splitted[0] = denominator_splitted[0] (cv::Rect (0, 0, blurred_image.cols, blurred_image.rows)); + denominator_splitted[0] += cv::Scalar (noise_power); + + cv::Mat numerator; + cv::Mat numerator_splitted[] = {cv::Mat::zeros (blurred_image.size (), CV_32FC1), cv::Mat::zeros (blurred_image.size (), CV_32FC1)}; + cv::mulSpectrums (y_ft, padded_ft, numerator, 0, true); + cv::split (numerator, numerator_splitted); + numerator_splitted[0] = numerator_splitted[0] (cv::Rect (0, 0, blurred_image.cols, blurred_image.rows)); + numerator_splitted[1] = numerator_splitted[1] (cv::Rect (0, 0, blurred_image.cols, blurred_image.rows)); + cv::divide (numerator_splitted[0], denominator_splitted[0], unknown_ft[0]); + cv::divide (numerator_splitted[1], denominator_splitted[0], unknown_ft[1]); + _helpers->compute_idft (unknown_ft, temp_unknown); + unknown = temp_unknown.clone(); +} + +} diff --git a/modules/ocl/cv_wiener_filter.h b/modules/ocl/cv_wiener_filter.h new file mode 100644 index 0000000..fa70812 --- /dev/null +++ b/modules/ocl/cv_wiener_filter.h @@ -0,0 +1,49 @@ +/* + * cv_wiener_filter.h - wierner filter for non-blind deblurring + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CV_WIENER_FILTER_H +#define XCAM_CV_WIENER_FILTER_H + +#include <xcam_std.h> +#include <video_buffer.h> +#include <ocl/cv_base_class.h> +#include <ocl/cv_image_process_helper.h> + +namespace XCam { + +class CVWienerFilter : public CVBaseClass +{ + +public: + explicit CVWienerFilter (); + + void wiener_filter (const cv::Mat &blurred_image, const cv::Mat &known, cv::Mat &unknown, float noise_power); + +private: + + XCAM_DEAD_COPY (CVWienerFilter); + + SmartPtr<CVImageProcessHelper> _helpers; +}; + +} + +#endif // XCAM_CV_WIENER_FILTER_H diff --git a/modules/ocl/intel/cl_intel_context.cpp b/modules/ocl/intel/cl_intel_context.cpp new file mode 100644 index 0000000..0d6c864 --- /dev/null +++ b/modules/ocl/intel/cl_intel_context.cpp @@ -0,0 +1,144 @@ +/* + * cl_intel_context.cpp - CL intel context + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_intel_context.h" +#include "cl_device.h" +#include "cl_va_memory.h" + +#define OCL_EXT_NAME_CREATE_BUFFER_FROM_LIBVA_INTEL "clCreateBufferFromLibvaIntel" +#define OCL_EXT_NAME_CREATE_BUFFER_FROM_FD_INTEL "clCreateBufferFromFdINTEL" +#define OCL_EXT_NAME_CREATE_IMAGE_FROM_LIBVA_INTEL "clCreateImageFromLibvaIntel" +#define OCL_EXT_NAME_CREATE_IMAGE_FROM_FD_INTEL "clCreateImageFromFdINTEL" +#define OCL_EXT_NAME_GET_MEM_OBJECT_FD_INTEL "clGetMemObjectFdIntel" + +namespace XCam { + +CLIntelContext::CLIntelContext (SmartPtr<CLDevice> &device) + : CLContext (device) +{ +} + +cl_mem +CLIntelContext::create_va_buffer (uint32_t bo_name) +{ + cl_mem mem_id = NULL; + cl_int errcode = CL_SUCCESS; + if (!is_valid()) + return NULL; + + clCreateBufferFromLibvaIntel_fn oclCreateBufferFromLibvaIntel = + (clCreateBufferFromLibvaIntel_fn) _device->get_extension_function (OCL_EXT_NAME_CREATE_BUFFER_FROM_LIBVA_INTEL); + XCAM_FAIL_RETURN(ERROR, oclCreateBufferFromLibvaIntel, NULL, "create buffer failed since extension was not found"); + + mem_id = oclCreateBufferFromLibvaIntel (_context_id, bo_name, &errcode); + XCAM_FAIL_RETURN( + WARNING, + errcode == CL_SUCCESS, + NULL, + "create cl memory from va image failed"); + return mem_id; +} + +cl_mem +CLIntelContext::import_dma_buffer (const cl_import_buffer_info_intel &import_info) +{ + cl_mem mem_id = NULL; + cl_int errcode = CL_SUCCESS; + if (!is_valid()) + return NULL; + + clCreateBufferFromFdINTEL_fn oclCreateBufferFromFdINTEL = + (clCreateBufferFromFdINTEL_fn) _device->get_extension_function (OCL_EXT_NAME_CREATE_BUFFER_FROM_FD_INTEL); + XCAM_FAIL_RETURN(ERROR, oclCreateBufferFromFdINTEL, NULL, "import buffer failed since extension was not found"); + + mem_id = oclCreateBufferFromFdINTEL (_context_id, &import_info, &errcode); + XCAM_FAIL_RETURN( + WARNING, + errcode == CL_SUCCESS, + NULL, + "import cl memory from dma buffer failed"); + + return mem_id; +} + +cl_mem +CLIntelContext::create_va_image (const cl_libva_image &image_info) +{ + cl_mem mem_id = NULL; + cl_int errcode = CL_SUCCESS; + if (!is_valid()) + return NULL; + + clCreateImageFromLibvaIntel_fn oclCreateImageFromLibvaIntel = + (clCreateImageFromLibvaIntel_fn) _device->get_extension_function (OCL_EXT_NAME_CREATE_IMAGE_FROM_LIBVA_INTEL); + XCAM_FAIL_RETURN(ERROR, oclCreateImageFromLibvaIntel, NULL, "create image failed since extension was not found"); + + mem_id = oclCreateImageFromLibvaIntel (_context_id, &image_info, &errcode); + XCAM_FAIL_RETURN( + WARNING, + errcode == CL_SUCCESS, + NULL, + "create cl memory from va image failed"); + return mem_id; +} + +cl_mem +CLIntelContext::import_dma_image (const cl_import_image_info_intel &import_info) +{ + cl_mem mem_id = NULL; + cl_int errcode = CL_SUCCESS; + if (!is_valid()) + return NULL; + + clCreateImageFromFdINTEL_fn oclCreateImageFromFdINTEL = + (clCreateImageFromFdINTEL_fn) _device->get_extension_function (OCL_EXT_NAME_CREATE_IMAGE_FROM_FD_INTEL); + XCAM_FAIL_RETURN(ERROR, oclCreateImageFromFdINTEL, NULL, "create image failed since extension was not found"); + + mem_id = oclCreateImageFromFdINTEL (_context_id, &import_info, &errcode); + XCAM_FAIL_RETURN( + WARNING, + errcode == CL_SUCCESS, + NULL, + "import cl memory from dma image failed, errcode:%d", errcode); + + return mem_id; +} + +int32_t +CLIntelContext::export_mem_fd (cl_mem mem_id) +{ + cl_int errcode = CL_SUCCESS; + int32_t fd = -1; + + clGetMemObjectFdIntel_fn oclGetMemObjectFdIntel = + (clGetMemObjectFdIntel_fn) _device->get_extension_function (OCL_EXT_NAME_GET_MEM_OBJECT_FD_INTEL); + XCAM_FAIL_RETURN(ERROR, oclGetMemObjectFdIntel, -1, "export fd failed since extension was not found"); + + XCAM_ASSERT (mem_id); + errcode = oclGetMemObjectFdIntel (_context_id, mem_id, &fd); + XCAM_FAIL_RETURN ( + WARNING, + errcode == CL_SUCCESS, + -1, + "export cl mem fd failed"); + return fd; +} + +}; diff --git a/modules/ocl/intel/cl_intel_context.h b/modules/ocl/intel/cl_intel_context.h new file mode 100644 index 0000000..bd7a78e --- /dev/null +++ b/modules/ocl/intel/cl_intel_context.h @@ -0,0 +1,56 @@ +/* + * cl_intel_context.h - CL intel context + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_INTEL_CONTEXT_H +#define XCAM_CL_INTEL_CONTEXT_H + +#include <CL/cl_intel.h> +#include <ocl/cl_context.h> + +namespace XCam { + +class CLIntelContext + : public CLContext +{ + friend class CLMemory; + friend class CLDevice; + friend class CLVaBuffer; + friend class CLVaImage; + +public: + ~CLIntelContext () {} + +private: + explicit CLIntelContext (SmartPtr<CLDevice> &device); + + cl_mem create_va_buffer (uint32_t bo_name); + cl_mem import_dma_buffer (const cl_import_buffer_info_intel &import_info); + cl_mem create_va_image (const cl_libva_image &image_info); + cl_mem import_dma_image (const cl_import_image_info_intel &image_info); + + int32_t export_mem_fd (cl_mem mem_id); + +private: + XCAM_DEAD_COPY (CLIntelContext); +}; + +}; + +#endif //XCAM_CL_CONTEXT_H diff --git a/modules/ocl/intel/cl_va_memory.cpp b/modules/ocl/intel/cl_va_memory.cpp new file mode 100644 index 0000000..27b3658 --- /dev/null +++ b/modules/ocl/intel/cl_va_memory.cpp @@ -0,0 +1,191 @@ +/* + * cl_va_memory.cpp - CL va memory + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "cl_va_memory.h" +#include "cl_image_bo_buffer.h" + +namespace XCam { + +CLVaBuffer::CLVaBuffer ( + const SmartPtr<CLIntelContext> &context, + SmartPtr<DrmBoBuffer> &bo) + : CLBuffer (context) + , _bo (bo) +{ + init_va_buffer (context, bo); +} + +bool +CLVaBuffer::init_va_buffer (const SmartPtr<CLIntelContext> &context, SmartPtr<DrmBoBuffer> &bo) +{ + cl_mem mem_id = NULL; + uint32_t bo_name = 0; + cl_import_buffer_info_intel import_buffer_info; + + xcam_mem_clear (import_buffer_info); + import_buffer_info.fd = bo->get_fd (); + import_buffer_info.size = bo->get_size (); + if (import_buffer_info.fd != -1) { + mem_id = context->import_dma_buffer (import_buffer_info); + } + + if (mem_id == NULL) { + drm_intel_bo_flink (bo->get_bo (), &bo_name); + mem_id = context->create_va_buffer (bo_name); + if (mem_id == NULL) { + XCAM_LOG_WARNING ("CLVaBuffer create va buffer failed"); + return false; + } + } + + set_mem_id (mem_id); + return true; +} + +CLVaImage::CLVaImage ( + const SmartPtr<CLIntelContext> &context, + SmartPtr<DrmBoBuffer> &bo, + uint32_t offset, + bool single_plane) + : CLImage (context) + , _bo (bo) +{ + CLImageDesc cl_desc; + + const VideoBufferInfo & video_info = bo->get_video_info (); + if (!video_info_2_cl_image_desc (video_info, cl_desc)) { + XCAM_LOG_WARNING ("CLVaImage create va image failed on default videoinfo"); + return; + } + if (single_plane) { + cl_desc.array_size = 0; + cl_desc.slice_pitch = 0; + } else if (!merge_multi_plane (video_info, cl_desc)) { + XCAM_LOG_WARNING ("CLVaImage create va image failed on merging planes"); + return; + } + + init_va_image (context, bo, cl_desc, offset); +} + +CLVaImage::CLVaImage ( + const SmartPtr<CLIntelContext> &context, + SmartPtr<DrmBoBuffer> &bo, + const CLImageDesc &image_info, + uint32_t offset) + : CLImage (context) + , _bo (bo) +{ + init_va_image (context, bo, image_info, offset); +} + +bool +CLVaImage::merge_multi_plane ( + const VideoBufferInfo &video_info, + CLImageDesc &cl_desc) +{ + if (cl_desc.array_size <= 1) + return true; + + switch (video_info.format) { + case V4L2_PIX_FMT_NV12: + cl_desc.height = video_info.aligned_height + video_info.height / 2; + break; + + case XCAM_PIX_FMT_RGB48_planar: + case XCAM_PIX_FMT_RGB24_planar: + cl_desc.height = video_info.aligned_height * 3; + break; + + case XCAM_PIX_FMT_SGRBG16_planar: + case XCAM_PIX_FMT_SGRBG8_planar: + cl_desc.height = video_info.aligned_height * 4; + break; + + default: + XCAM_LOG_WARNING ("CLVaImage unknown format(%s) plane change", xcam_fourcc_to_string(video_info.format)); + return false; + } + cl_desc.array_size = 0; + cl_desc.slice_pitch = 0; + return true; +} + +bool +CLVaImage::init_va_image ( + const SmartPtr<CLIntelContext> &context, SmartPtr<DrmBoBuffer> &bo, + const CLImageDesc &cl_desc, uint32_t offset) +{ + + uint32_t bo_name = 0; + cl_mem mem_id = 0; + bool need_create = true; + cl_libva_image va_image_info; + cl_import_image_info_intel import_image_info; + + xcam_mem_clear (va_image_info); + xcam_mem_clear (import_image_info); + import_image_info.offset = va_image_info.offset = offset; + import_image_info.width = va_image_info.width = cl_desc.width; + import_image_info.height = va_image_info.height = cl_desc.height; + import_image_info.fmt = va_image_info.fmt = cl_desc.format; + import_image_info.row_pitch = va_image_info.row_pitch = cl_desc.row_pitch; + import_image_info.size = cl_desc.size; + import_image_info.type = CL_MEM_OBJECT_IMAGE2D; + + XCAM_ASSERT (bo.ptr ()); + + SmartPtr<CLImageBoBuffer> cl_image_buffer = bo.dynamic_cast_ptr<CLImageBoBuffer> (); + if (cl_image_buffer.ptr ()) { + SmartPtr<CLImage> cl_image_data = cl_image_buffer->get_cl_image (); + XCAM_ASSERT (cl_image_data.ptr ()); + CLImageDesc old_desc = cl_image_data->get_image_desc (); + if (cl_desc == old_desc) { + need_create = false; + mem_id = cl_image_data->get_mem_id (); + } + } + + if (need_create) { + import_image_info.fd = bo->get_fd(); + if (import_image_info.fd != -1) + mem_id = context->import_dma_image (import_image_info); + + if (mem_id == NULL) { + if (drm_intel_bo_flink (bo->get_bo (), &bo_name) == 0) { + va_image_info.bo_name = bo_name; + mem_id = context->create_va_image (va_image_info); + } + if (mem_id == NULL) { + XCAM_LOG_WARNING ("create va image failed"); + return false; + } + } + } else { + va_image_info.bo_name = uint32_t(-1); + } + + set_mem_id (mem_id, need_create); + init_desc_by_image (); + _va_image_info = va_image_info; + return true; +} + +}; diff --git a/modules/ocl/intel/cl_va_memory.h b/modules/ocl/intel/cl_va_memory.h new file mode 100644 index 0000000..91f1429 --- /dev/null +++ b/modules/ocl/intel/cl_va_memory.h @@ -0,0 +1,79 @@ +/* + * cl_va_memory.h - CL va memory + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_CL_VA_MEMORY_H +#define XCAM_CL_VA_MEMORY_H + +#include "ocl/cl_memory.h" +#include "ocl/intel/cl_intel_context.h" +#include "drm_bo_buffer.h" + +namespace XCam { + +class CLVaBuffer + : public CLBuffer +{ +public: + explicit CLVaBuffer ( + const SmartPtr<CLIntelContext> &context, + SmartPtr<DrmBoBuffer> &bo); + +private: + bool init_va_buffer (const SmartPtr<CLIntelContext> &context, SmartPtr<DrmBoBuffer> &bo); + + XCAM_DEAD_COPY (CLVaBuffer); + +private: + SmartPtr<DrmBoBuffer> _bo; +}; + +class CLVaImage + : public CLImage +{ +public: + explicit CLVaImage ( + const SmartPtr<CLIntelContext> &context, + SmartPtr<DrmBoBuffer> &bo, + uint32_t offset = 0, + bool single_plane = false); + explicit CLVaImage ( + const SmartPtr<CLIntelContext> &context, + SmartPtr<DrmBoBuffer> &bo, + const CLImageDesc &image_info, + uint32_t offset = 0); + ~CLVaImage () {} + +private: + bool init_va_image ( + const SmartPtr<CLIntelContext> &context, SmartPtr<DrmBoBuffer> &bo, + const CLImageDesc &cl_desc, uint32_t offset); + bool merge_multi_plane ( + const VideoBufferInfo &video_info, + CLImageDesc &cl_desc); + + XCAM_DEAD_COPY (CLVaImage); + +private: + SmartPtr<DrmBoBuffer> _bo; + cl_libva_image _va_image_info; +}; + +}; +#endif // diff --git a/modules/ocl/priority_buffer_queue.cpp b/modules/ocl/priority_buffer_queue.cpp new file mode 100644 index 0000000..e0cf48f --- /dev/null +++ b/modules/ocl/priority_buffer_queue.cpp @@ -0,0 +1,60 @@ +/* + * priority_buffer_queue.cpp - priority buffer queue + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "priority_buffer_queue.h" + +#define XCAM_PRIORITY_BUFFER_FIXED_DELAY 8 + +namespace XCam { + +bool +PriorityBuffer::priority_greater_than (const PriorityBuffer& buf) const +{ + int32_t result = + ((int32_t)(buf.seq_num - this->seq_num) * XCAM_PRIORITY_BUFFER_FIXED_DELAY + + (int32_t)(buf.rank - this->rank)); + if (result == 0) { + return (int32_t)(buf.seq_num - this->seq_num) > 0; + } + return result > 0; +} + + +bool +PriorityBufferQueue::push_priority_buf (const SmartPtr<PriorityBuffer> &buf) +{ + XCAM_ASSERT (buf.ptr ()); + SmartLock lock (_mutex); + + ObjList::iterator iter = _obj_list.begin (); + + for (; iter != _obj_list.end (); ++iter) { + SmartPtr<PriorityBuffer> ¤t = *iter; + XCAM_ASSERT (current.ptr ()); + if (buf->priority_greater_than (*current.ptr())) + break; + } + + _obj_list.insert (iter, buf); + _new_obj_cond.signal (); + return true; +} + +}; diff --git a/modules/ocl/priority_buffer_queue.h b/modules/ocl/priority_buffer_queue.h new file mode 100644 index 0000000..346e6ed --- /dev/null +++ b/modules/ocl/priority_buffer_queue.h @@ -0,0 +1,74 @@ +/* + * priority_buffer_queue.h - priority buffer queue + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_PRIORITY_BUFFER_QUEUE_H +#define XCAM_PRIORITY_BUFFER_QUEUE_H + +#include <xcam_std.h> +#include <safe_list.h> +#include <ocl/cl_image_handler.h> + +namespace XCam { + +struct PriorityBuffer +{ + SmartPtr<VideoBuffer> data; + SmartPtr<CLImageHandler> handler; + uint32_t rank; + uint32_t seq_num; + +public: + PriorityBuffer () + : rank (0) + , seq_num (0) + {} + + void set_seq_num (const uint32_t value) { + seq_num = value; + } + uint32_t get_seq_num () const { + return seq_num; + } + + // when change to next rank + void down_rank () { + ++rank; + } + + bool priority_greater_than (const PriorityBuffer& buf) const; +}; + +class PriorityBufferQueue + : public SafeList<PriorityBuffer> +{ +public: + + PriorityBufferQueue () {} + ~PriorityBufferQueue () {} + + bool push_priority_buf (const SmartPtr<PriorityBuffer> &buf); + +private: + XCAM_DEAD_COPY (PriorityBufferQueue); +}; + +}; + +#endif //XCAM_PRIORITY_BUFFER_QUEUE_H diff --git a/modules/soft/Makefile.am b/modules/soft/Makefile.am new file mode 100644 index 0000000..b1cd92b --- /dev/null +++ b/modules/soft/Makefile.am @@ -0,0 +1,75 @@ +lib_LTLIBRARIES = libxcam_soft.la + +XCAMSOFT_CXXFLAGS = \ + $(LIBCL_CFLAGS) \ + -I$(top_srcdir)/xcore \ + -I$(top_srcdir)/modules \ + $(NULL) + +XCAMSOFT_LIBS = + +xcam_soft_sources = \ + soft_handler.cpp \ + soft_video_buf_allocator.cpp \ + soft_worker.cpp \ + soft_blender_tasks_priv.cpp \ + soft_blender.cpp \ + soft_geo_mapper.cpp \ + soft_geo_tasks_priv.cpp \ + soft_copy_task.cpp \ + soft_stitcher.cpp \ + $(NULL) + +if HAVE_OPENCV +XCAMSOFT_CXXFLAGS += $(OPENCV_CFLAGS) + +XCAMSOFT_LIBS += $(OPENCV_LIBS) + +xcam_soft_sources += \ + cv_capi_feature_match.cpp \ + $(NULL) + +endif + +libxcam_soft_la_SOURCES = \ + $(xcam_soft_sources) \ + $(NULL) + +libxcam_soft_la_CXXFLAGS = \ + $(XCAMSOFT_CXXFLAGS) \ + $(XCAM_CXXFLAGS) \ + $(NULL) + +libxcam_soft_la_LIBADD = \ + $(top_builddir)/xcore/libxcam_core.la \ + $(XCAMSOFT_LIBS) \ + $(NULL) + +libxcam_soft_la_LDFLAGS = \ + $(XCAM_LT_LDFLAGS) \ + $(PTHREAD_LDFLAGS) \ + $(NULL) + +libxcam_softincludedir = $(includedir)/xcam/soft + +nobase_libxcam_softinclude_HEADERS = \ + soft_handler.h \ + soft_video_buf_allocator.h \ + soft_worker.h \ + soft_image.h \ + soft_blender.h \ + soft_geo_mapper.h \ + soft_copy_task.h \ + soft_stitcher.h \ + $(NULL) + +noinst_HEADERS = \ + soft_blender_tasks_priv.h \ + soft_geo_tasks_priv.h \ + $(NULL) + +if HAVE_OPENCV +noinst_HEADERS += cv_capi_feature_match.h +endif + +libxcam_soft_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/modules/soft/cv_capi_feature_match.cpp b/modules/soft/cv_capi_feature_match.cpp new file mode 100644 index 0000000..0e0081c --- /dev/null +++ b/modules/soft/cv_capi_feature_match.cpp @@ -0,0 +1,287 @@ +/* + * cv_capi_feature_match.cpp - optical flow feature match + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include "cv_capi_feature_match.h" + +#define XCAM_CV_CAPI_FM_DEBUG 0 + +#if XCAM_CV_CAPI_FM_DEBUG +#include "ocl/cv_base_class.h" +#endif + +namespace XCam { +#if XCAM_CV_CAPI_FM_DEBUG +static void +debug_write_image ( + const SmartPtr<VideoBuffer> &buf, const Rect &rect, char *img_name, char *frame_str, char *fm_idx_str); +#endif + +CVCapiFeatureMatch::CVCapiFeatureMatch () + : FeatureMatch() +{ +} + +bool +CVCapiFeatureMatch::get_crop_image ( + const SmartPtr<VideoBuffer> &buffer, const Rect &crop_rect, std::vector<char> &crop_image, CvMat &img) +{ + VideoBufferInfo info = buffer->get_video_info (); + + uint8_t* image_buffer = buffer->map(); + int offset = info.strides[NV12PlaneYIdx] * crop_rect.pos_y + crop_rect.pos_x; + + crop_image.resize (crop_rect.width * crop_rect.height); + for (int i = 0; i < crop_rect.height; i++) { + for (int j = 0; j < crop_rect.width; j++) { + crop_image[i * crop_rect.width + j] = + image_buffer[offset + i * info.strides[NV12PlaneYIdx] + j]; + } + } + + img = cvMat (crop_rect.height, crop_rect.width, CV_8UC1, (void*)&crop_image[0]); + + return true; +} + +void +CVCapiFeatureMatch::add_detected_data ( + CvArr* image, std::vector<CvPoint2D32f> &corners) +{ + std::vector<CvPoint2D32f> keypoints; + + int found_num = 300; + double quality = 0.01; + double min_dist = 5; + + corners.resize (found_num); + CvPoint2D32f* corner_points = &corners[0]; + + cvGoodFeaturesToTrack (image, NULL, NULL, corner_points, &found_num, quality, min_dist); + XCAM_ASSERT (found_num <= 300); + +#if XCAM_CV_CAPI_FM_DEBUG + XCAM_LOG_INFO ("FeatureMatch(idx:%d): detected corners:%d, reserved size:%d", _fm_idx, found_num, (int)corners.size ()); +#endif + if (found_num < (int)corners.size ()) + corners.resize (found_num); +} + +void +CVCapiFeatureMatch::get_valid_offsets ( + std::vector<CvPoint2D32f> &corner0, std::vector<CvPoint2D32f> &corner1, + std::vector<char> &status, std::vector<float> &error, + std::vector<float> &offsets, float &sum, int &count, + CvArr* image, CvSize &img0_size) +{ + count = 0; + sum = 0.0f; + + for (uint32_t i = 0; i < status.size (); ++i) { + if (!status[i]) + continue; + +#if XCAM_CV_CAPI_FM_DEBUG + cv::Mat mat = cv::cvarrToMat (image); + cv::Point start = cv::Point (corner0[i].x, corner0[i].y); + cv::circle (mat, start, 2, cv::Scalar(255), 2); +#endif + if (error[i] > _config.max_track_error) + continue; + if (fabs(corner0[i].y - corner1[i].y) >= _config.max_valid_offset_y) + continue; + if (corner1[i].x < 0.0f || corner1[i].x > img0_size.width) + continue; + + float offset = corner1[i].x - corner0[i].x; + sum += offset; + ++count; + offsets.push_back (offset); + +#if XCAM_CV_CAPI_FM_DEBUG + cv::line (mat, start, cv::Point(corner1[i].x + img0_size.width, corner1[i].y), cv::Scalar(255), 2); +#else + XCAM_UNUSED (image); + XCAM_UNUSED (img0_size); +#endif + } +} + +void +CVCapiFeatureMatch::calc_of_match ( + CvArr* image0, CvArr* image1, + std::vector<CvPoint2D32f> &corner0, std::vector<CvPoint2D32f> &corner1, + std::vector<char> &status, std::vector<float> &error, + int &last_count, float &last_mean_offset, float &out_x_offset) +{ + CvMat debug_image; + CvSize img0_size = cvSize(((CvMat*)image0)->width, ((CvMat*)image0)->height); + XCAM_ASSERT (img0_size.height == ((CvMat*)image1)->height); + XCAM_UNUSED (image1); + + std::vector<float> offsets; + float offset_sum = 0.0f; + int count = 0; + float mean_offset = 0.0f; + offsets.reserve (corner0.size ()); + +#if XCAM_CV_CAPI_FM_DEBUG + CvSize img1_size = cvSize(((CvMat*)image1)->width, ((CvMat*)image1)->height); + cv::Mat mat; + mat.create (img0_size.height, img0_size.width + img1_size.width, ((CvMat*)image0)->type); + debug_image = cvMat (img0_size.height, img0_size.width + img1_size.width, ((CvMat*)image0)->type, mat.ptr()); + cv::cvarrToMat(image0, true).copyTo (mat (cv::Rect(0, 0, img0_size.width, img0_size.height))); + cv::cvarrToMat(image1, true).copyTo (mat (cv::Rect(img0_size.width, 0, img1_size.width, img1_size.height))); +#endif + + get_valid_offsets (corner0, corner1, status, error, + offsets, offset_sum, count, &debug_image, img0_size); + +#if XCAM_CV_CAPI_FM_DEBUG + XCAM_LOG_INFO ("FeatureMatch(idx:%d): valid offsets:%d", _fm_idx, offsets.size ()); + char file_name[256] = {'\0'}; + std::snprintf (file_name, 256, "fm_optical_flow_%d_%d.jpg", _frame_num, _fm_idx); + cv::imwrite (file_name, mat); +#endif + + bool ret = get_mean_offset (offsets, offset_sum, count, mean_offset); + if (ret) { + if (fabs (mean_offset - last_mean_offset) < _config.delta_mean_offset) { + out_x_offset = out_x_offset * _config.offset_factor + mean_offset * (1.0f - _config.offset_factor); + + if (fabs (out_x_offset) > _config.max_adjusted_offset) + out_x_offset = (out_x_offset > 0.0f) ? _config.max_adjusted_offset : (-_config.max_adjusted_offset); + } + } + + last_count = count; + last_mean_offset = mean_offset; +} + +void +CVCapiFeatureMatch::detect_and_match ( + CvArr* img_left, CvArr* img_right, Rect &crop_left, Rect &crop_right, + int &valid_count, float &mean_offset, float &x_offset, int dst_width) +{ + std::vector<float> err; + std::vector<char> status; + std::vector<CvPoint2D32f> corner_left, corner_right; + + CvSize win_size = cvSize (41, 41); + + add_detected_data (img_left, corner_left); + int count = corner_left.size (); + if (corner_left.empty ()) { + return; + } + + // find the corresponding points in img_right + corner_right.resize (count); + status.resize (count); + err.resize (count); + + CvPoint2D32f* corner_points1 = &corner_left[0]; + CvPoint2D32f* corner_points2 = &corner_right[0]; + char* optflow_status = &status[0]; + float* optflow_errs = &err[0]; + + cvCalcOpticalFlowPyrLK ( + img_left, img_right, 0, 0, corner_points1, corner_points2, count, win_size, 3, + optflow_status, optflow_errs, cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 10, 0.01f), 0); + +#if XCAM_CV_CAPI_FM_DEBUG + XCAM_LOG_INFO ("FeatureMatch(idx:%d): matched corners:%d", _fm_idx, count); +#endif + + calc_of_match (img_left, img_right, corner_left, corner_right, + status, err, valid_count, mean_offset, x_offset); + + adjust_stitch_area (dst_width, x_offset, crop_left, crop_right); + +#if XCAM_CV_CAPI_FM_DEBUG + XCAM_LOG_INFO ( + "FeatureMatch(idx:%d): stiching area: left_area(pos_x:%d, width:%d), right_area(pos_x:%d, width:%d)", + _fm_idx, crop_left.pos_x, crop_left.width, crop_right.pos_x, crop_right.width); +#endif +} + +void +CVCapiFeatureMatch::optical_flow_feature_match ( + const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf, + Rect &left_crop_rect, Rect &right_crop_rect, int dst_width) +{ + CvMat left_img, right_img; + + if (!get_crop_image (left_buf, left_crop_rect, _left_crop_image, left_img) + || !get_crop_image (right_buf, right_crop_rect, _right_crop_image, right_img)) + return; + + detect_and_match ((CvArr*)(&left_img), (CvArr*)(&right_img), left_crop_rect, right_crop_rect, + _valid_count, _mean_offset, _x_offset, dst_width); + +#if XCAM_CV_CAPI_FM_DEBUG + XCAM_ASSERT (_fm_idx >= 0); + + char frame_str[64] = {'\0'}; + std::snprintf (frame_str, 64, "frame:%d", _frame_num); + char fm_idx_str[64] = {'\0'}; + std::snprintf (fm_idx_str, 64, "fm_idx:%d", _fm_idx); + + char img_name[256] = {'\0'}; + std::snprintf (img_name, 256, "fm_in_stitch_area_%d_%d_0.jpg", _frame_num, _fm_idx); + debug_write_image (left_buf, left_crop_rect, img_name, frame_str, fm_idx_str); + + std::snprintf (img_name, 256, "fm_in_stitch_area_%d_%d_1.jpg", _frame_num, _fm_idx); + debug_write_image (right_buf, right_crop_rect, img_name, frame_str, fm_idx_str); + + XCAM_LOG_INFO ("FeatureMatch(idx:%d): frame number:%d done", _fm_idx, _frame_num); + + _frame_num++; +#endif +} + +#if XCAM_CV_CAPI_FM_DEBUG +static void +debug_write_image ( + const SmartPtr<VideoBuffer> &buf, const Rect &rect, char *img_name, char *frame_str, char *fm_idx_str) +{ + cv::Scalar color = cv::Scalar(0, 0, 255); + VideoBufferInfo info = buf->get_video_info (); + + cv::Mat mat; + CVBaseClass cv_obj; + cv_obj.convert_to_mat (buf, mat); + + cv::putText (mat, frame_str, cv::Point(rect.pos_x, 30), cv::FONT_HERSHEY_COMPLEX, 0.8f, color, 2, 8, false); + cv::putText (mat, fm_idx_str, cv::Point(rect.pos_x, 70), cv::FONT_HERSHEY_COMPLEX, 0.8f, color, 2, 8, false); + + cv::line (mat, cv::Point(rect.pos_x, rect.pos_y), cv::Point(rect.pos_x + rect.width, rect.pos_y), color, 1); + cv::line (mat, cv::Point(rect.pos_x, rect.pos_y + rect.height), + cv::Point(rect.pos_x + rect.width, rect.pos_y + rect.height), color, 1); + + cv::line (mat, cv::Point(rect.pos_x, 0), cv::Point(rect.pos_x, info.height), color, 2); + cv::line (mat, cv::Point(rect.pos_x + rect.width, 0), cv::Point(rect.pos_x + rect.width, info.height), color, 2); + + cv::imwrite (img_name, mat); +} +#endif + +} diff --git a/modules/soft/cv_capi_feature_match.h b/modules/soft/cv_capi_feature_match.h new file mode 100644 index 0000000..67a9d4f --- /dev/null +++ b/modules/soft/cv_capi_feature_match.h @@ -0,0 +1,82 @@ +/* + * cv_capi_feature_match.h - optical flow feature match + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + * Author: Zong Wei <wei.zong@intel.com> + */ + +#ifndef CV_CAPI_FEATURE_MATCH_H +#define CV_CAPI_FEATURE_MATCH_H + +#include <xcam_std.h> +#include <video_buffer.h> +#include <interface/feature_match.h> + +#ifdef ANDROID +#include <cv.h> +#else +#include <opencv2/opencv.hpp> +#endif + +namespace XCam { + +class CVCapiFeatureMatch + : public FeatureMatch +{ +public: + explicit CVCapiFeatureMatch (); + + void optical_flow_feature_match ( + const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf, + Rect &left_img_crop, Rect &right_img_crop, int dst_width); + + void set_ocl (bool use_ocl) { + XCAM_UNUSED (use_ocl); + } + bool is_ocl_path () { + return false; + } + +protected: + bool get_crop_image (const SmartPtr<VideoBuffer> &buffer, const Rect &crop_rect, + std::vector<char> &crop_image, CvMat &img); + + void add_detected_data (CvArr* image, std::vector<CvPoint2D32f> &corners); + void get_valid_offsets (std::vector<CvPoint2D32f> &corner0, std::vector<CvPoint2D32f> &corner1, + std::vector<char> &status, std::vector<float> &error, + std::vector<float> &offsets, float &sum, int &count, + CvArr* out_image, CvSize &img0_size); + + void calc_of_match (CvArr* image0, CvArr* image1, + std::vector<CvPoint2D32f> &corner0, std::vector<CvPoint2D32f> &corner1, + std::vector<char> &status, std::vector<float> &error, + int &last_count, float &last_mean_offset, float &out_x_offset); + + void detect_and_match (CvArr* img_left, CvArr* img_right, Rect &crop_left, Rect &crop_right, + int &valid_count, float &mean_offset, float &x_offset, int dst_width); + +private: + XCAM_DEAD_COPY (CVCapiFeatureMatch); + + std::vector<char> _left_crop_image; + std::vector<char> _right_crop_image; +}; + +} + +#endif // CV_CAPI_FEATURE_MATCH_H diff --git a/modules/soft/soft_blender.cpp b/modules/soft/soft_blender.cpp new file mode 100644 index 0000000..7e0c678 --- /dev/null +++ b/modules/soft/soft_blender.cpp @@ -0,0 +1,869 @@ +/* + * soft_blender.cpp - soft blender class implementation + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "soft_blender.h" +#include "xcam_utils.h" +#include "soft_image.h" +#include "soft_worker.h" +#include "soft_blender_tasks_priv.h" +#include "image_file_handle.h" +#include "soft_video_buf_allocator.h" +#include <map> + +#define OVERLAP_POOL_SIZE 6 +#define LAP_POOL_SIZE 4 + +#define DUMP_BLENDER 0 + +namespace XCam { + +using namespace XCamSoftTasks; + +DECLARE_WORK_CALLBACK (CbGaussDownScale, SoftBlender, gauss_scale_done); +DECLARE_WORK_CALLBACK (CbBlendTask, SoftBlender, blend_task_done); +DECLARE_WORK_CALLBACK (CbReconstructTask, SoftBlender, reconstruct_done); +DECLARE_WORK_CALLBACK (CbLapTask, SoftBlender, lap_done); + +typedef std::map<void*, SmartPtr<BlendTask::Args>> MapBlendArgs; +typedef std::map<void*, SmartPtr<ReconstructTask::Args>> MapReconsArgs; + +namespace SoftBlenderPriv { + +struct PyramidResource { + SmartPtr<BufferPool> overlap_pool; + SmartPtr<GaussDownScale> scale_task[SoftBlender::BufIdxCount]; + SmartPtr<LaplaceTask> lap_task[SoftBlender::BufIdxCount]; + SmartPtr<ReconstructTask> recon_task; + SmartPtr<UcharImage> coef_mask; + MapReconsArgs recons_args; +}; + +/* Level0: G[0] = gauss(in), Lap[0] = in - upsample(G[0]) + Level1: G[1] = gauss(G[0]), Lap[1] = G[0] - upsample(G[1]) +.. + LevelN: G[N] = gauss(G[N-1]), +blend[N] = blend (Ga[N)], Gb[N)]) + Level(N-1): Reconst[N-1] = reconstruct (blend[N], LapA[N-1], LapB[N-1]) +... + Level1: reconst[1] = reconstruct (reconst[2], LapA[1], LapB[1]) + Level0: output = reconstruct (reconst[1], LapA[0], LapB[0]) + + LevelN: Pool[N].size = G[N].size + */ +class BlenderPrivConfig { +public: + PyramidResource pyr_layer[XCAM_SOFT_PYRAMID_MAX_LEVEL]; + uint32_t pyr_levels; + SmartPtr<BlendTask> last_level_blend; + SmartPtr<BufferPool> first_lap_pool; + SmartPtr<UcharImage> orig_mask; + + Mutex map_args_mutex; + MapBlendArgs blend_args; + +private: + SoftBlender *_blender; + +public: + BlenderPrivConfig (SoftBlender *blender, uint32_t level) + : pyr_levels (level) + , _blender (blender) + {} + + XCamReturn init_first_masks (uint32_t width, uint32_t height); + XCamReturn scale_down_masks (uint32_t level, uint32_t width, uint32_t height); + + XCamReturn start_scaler ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const SmartPtr<VideoBuffer> &in_buf, + const uint32_t level, const SoftBlender::BufIdx idx); + + XCamReturn start_lap_task ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const uint32_t level, const SoftBlender::BufIdx idx, + const SmartPtr<GaussDownScale::Args> &scale_args); + XCamReturn start_blend_task ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const SmartPtr<VideoBuffer> &buf, + const SoftBlender::BufIdx idx); + + XCamReturn start_reconstruct_task_by_lap ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const SmartPtr<VideoBuffer> &lap, + const uint32_t level, const SoftBlender::BufIdx idx); + XCamReturn start_reconstruct_task_by_gauss ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const SmartPtr<VideoBuffer> &gauss, + const uint32_t level); + XCamReturn start_reconstruct_task (const SmartPtr<ReconstructTask::Args> &args, const uint32_t level); + XCamReturn stop (); +}; + +}; + +#if DUMP_BLENDER +#define dump_buf dump_buf_perfix_path + +template <class SoftImageT> +static void +dump_soft (const SmartPtr<SoftImageT> &image, const char *name, int32_t level) +{ + XCAM_ASSERT (image.ptr ()); + char file_name[256]; + if (level < 0) + snprintf (file_name, 256, "%s-%dx%d.soft", name, image->get_width(), image->get_height()); + else + snprintf (file_name, 256, "%s-L%d-%dx%d.soft", name, level, image->get_width(), image->get_height()); + +#if 0 + typename SoftImageT::Type *ptr = image->get_buf_ptr (0, 0); + printf ("Print level:%d, line:0\n", level); + for (uint32_t i = 0; i < image->get_width (); ++i) { + printf ("%.1f ", (float)(ptr[i])); + } + printf ("\n"); +#endif + + SoftImageFile<SoftImageT> file(file_name, "wb"); + file.write_buf (image); + file.close (); +} + +static +void dump_level_buf (const SmartPtr<VideoBuffer> buf, const char *name, uint32_t level, uint32_t idx) +{ + char file_name[256]; + XCAM_ASSERT (name); + snprintf (file_name, 256, "%s-L%d-Idx%d", name, level, idx); + dump_buf_perfix_path (buf, file_name); +} +#else +static void dump_buf (const SmartPtr<VideoBuffer> buf, ...) { + XCAM_UNUSED (buf); +} +template <class SoftImageT> +static void dump_soft (const SmartPtr<SoftImageT> &image, ...) { + XCAM_UNUSED (image); +} +static void dump_level_buf (const SmartPtr<VideoBuffer> buf, ...) { + XCAM_UNUSED (buf); +} +#endif + +SoftBlender::SoftBlender (const char *name) + : SoftHandler (name) + , Blender (SOFT_BLENDER_ALIGNMENT_X, SOFT_BLENDER_ALIGNMENT_Y) +{ + _priv_config = new SoftBlenderPriv::BlenderPrivConfig (this, XCAM_SOFT_PYRAMID_DEFAULT_LEVEL); + XCAM_ASSERT (_priv_config.ptr ()); +} + +SoftBlender::~SoftBlender () +{ +} + +bool +SoftBlender::set_pyr_levels (uint32_t num) +{ + XCAM_ASSERT (num > 0); + XCAM_FAIL_RETURN ( + ERROR, num > 0, false, + "blender:%s set_pyr_levels failed, level(%d) must > 0", XCAM_STR (get_name ()), num); + + _priv_config->pyr_levels = num; + return true; +} + +XCamReturn +SoftBlender::terminate () +{ + _priv_config->stop (); + return SoftHandler::terminate (); +} + +XCamReturn +SoftBlender::blend ( + const SmartPtr<VideoBuffer> &in0, + const SmartPtr<VideoBuffer> &in1, + SmartPtr<VideoBuffer> &out_buf) +{ + SmartPtr<BlenderParam> param = new BlenderParam (in0, in1, out_buf); + XCamReturn ret = execute_buffer (param, true); + if (xcam_ret_is_ok(ret) && !out_buf.ptr ()) { + out_buf = param->out_buf; + } + return ret; +} + +XCamReturn +SoftBlenderPriv::BlenderPrivConfig::stop () +{ + for (uint32_t i = 0; i < pyr_levels; ++i) { + if (pyr_layer[i].scale_task[SoftBlender::Idx0].ptr ()) { + pyr_layer[i].scale_task[SoftBlender::Idx0]->stop (); + pyr_layer[i].scale_task[SoftBlender::Idx0].release (); + } + if (pyr_layer[i].scale_task[SoftBlender::Idx1].ptr ()) { + pyr_layer[i].scale_task[SoftBlender::Idx1]->stop (); + pyr_layer[i].scale_task[SoftBlender::Idx1].release (); + } + if (pyr_layer[i].lap_task[SoftBlender::Idx0].ptr ()) { + pyr_layer[i].lap_task[SoftBlender::Idx0]->stop (); + pyr_layer[i].lap_task[SoftBlender::Idx0].release (); + } + if (pyr_layer[i].lap_task[SoftBlender::Idx1].ptr ()) { + pyr_layer[i].lap_task[SoftBlender::Idx1]->stop (); + pyr_layer[i].lap_task[SoftBlender::Idx0].release (); + } + if (pyr_layer[i].recon_task.ptr ()) { + pyr_layer[i].recon_task->stop (); + pyr_layer[i].recon_task.release (); + } + + if (pyr_layer[i].overlap_pool.ptr ()) { + pyr_layer[i].overlap_pool->stop (); + } + } + + if (last_level_blend.ptr ()) { + last_level_blend->stop (); + last_level_blend.release (); + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +SoftBlenderPriv::BlenderPrivConfig::init_first_masks (uint32_t width, uint32_t height) +{ + uint32_t aligned_width = XCAM_ALIGN_UP (width, SOFT_BLENDER_ALIGNMENT_X); + + orig_mask = new UcharImage ( + width, height, aligned_width); + XCAM_ASSERT (orig_mask.ptr ()); + XCAM_ASSERT (orig_mask->is_valid ()); + std::vector<float> gauss_table; + std::vector<Uchar> mask_line; + uint32_t i = 0, j = 0; + + uint32_t quater = width / 4; + XCAM_ASSERT (quater > 1); + get_gauss_table (quater, (quater + 1) / 4.0f, gauss_table, false); + for (i = 0; i < gauss_table.size (); ++i) { + float value = ((i < quater) ? (128.0f * (2.0f - gauss_table[i])) : (128.0f * gauss_table[i])); + value = XCAM_CLAMP (value, 0.0f, 255.0f); + gauss_table[i] = value; + } + + mask_line.resize (aligned_width); + uint32_t gauss_start_pos = (width - gauss_table.size ()) / 2; + for (i = 0; i < gauss_start_pos; ++i) { + mask_line[i] = 255; + } + for (j = 0; j < gauss_table.size (); ++i, ++j) { + mask_line[i] = (Uchar)gauss_table[j]; + } + for (; i < mask_line.size (); ++i) { + mask_line[i] = 0; + } + + for (uint32_t h = 0; h < height; ++h) { + Uchar *ptr = orig_mask->get_buf_ptr (0, h); + memcpy (ptr, mask_line.data (), aligned_width); + } + + dump_soft (orig_mask, "mask_orig", -1); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +SoftBlenderPriv::BlenderPrivConfig::scale_down_masks (uint32_t level, uint32_t width, uint32_t height) +{ + XCAM_ASSERT (width % SOFT_BLENDER_ALIGNMENT_X == 0); + XCAM_ASSERT (height % SOFT_BLENDER_ALIGNMENT_Y == 0); + + pyr_layer[level].coef_mask = new UcharImage (width, height); + XCAM_ASSERT (pyr_layer[level].coef_mask.ptr ()); + + SmartPtr<GaussScaleGray::Args> args = new GaussScaleGray::Args; + if (level == 0) { + args->in_luma = orig_mask; + } else { + args->in_luma = pyr_layer[level - 1].coef_mask; + } + args->out_luma = pyr_layer[level].coef_mask; + SmartPtr<GaussScaleGray> worker = new GaussScaleGray; + WorkSize size ((args->out_luma->get_width () + 1) / 2, (args->out_luma->get_height () + 1) / 2); + worker->set_local_size (size); + worker->set_global_size (size); + XCamReturn ret = worker->work (args); + + dump_soft (pyr_layer[level].coef_mask, "mask", (int32_t)level); + return ret; +} + +XCamReturn +SoftBlenderPriv::BlenderPrivConfig::start_scaler ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const SmartPtr<VideoBuffer> &in_buf, + const uint32_t level, const SoftBlender::BufIdx idx) +{ + XCAM_ASSERT (level < pyr_levels); + XCAM_ASSERT (idx < SoftBlender::BufIdxCount); + SmartPtr<SoftWorker> worker = pyr_layer[level].scale_task[idx]; + XCAM_ASSERT (worker.ptr ()); + + XCAM_ASSERT (pyr_layer[level].overlap_pool.ptr ()); + SmartPtr<VideoBuffer> out_buf = pyr_layer[level].overlap_pool->get_buffer (); + XCAM_FAIL_RETURN ( + ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM, + "blender:(%s) start_scaler failed, level(%d),idx(%d) get output buffer empty.", + XCAM_STR (_blender->get_name ()), level, (int)idx); + + SmartPtr<GaussDownScale::Args> args = new GaussDownScale::Args (param, level, idx, in_buf, out_buf); + if (level == 0) { + Rect in_area = _blender->get_input_merge_area (idx); + const VideoBufferInfo &buf_info = in_buf->get_video_info (); + if (in_area.width == 0 || in_area.height == 0) { + in_area.width = buf_info.width; + in_area.height = buf_info.height; + } + XCAM_ASSERT (in_area.pos_x % SOFT_BLENDER_ALIGNMENT_X == 0); + XCAM_ASSERT (in_area.pos_y % SOFT_BLENDER_ALIGNMENT_Y == 0); + args->in_luma = new UcharImage ( + in_buf, in_area.width, in_area.height, buf_info.strides[0], + buf_info.offsets[0] + in_area.pos_x + in_area.pos_y * buf_info.strides[0]); + args->in_uv = new Uchar2Image ( + in_buf, in_area.width / 2, in_area.height / 2, buf_info.strides[1], + buf_info.offsets[1] + in_area.pos_x + buf_info.strides[1] * in_area.pos_y / 2); + } else { + args->in_luma = new UcharImage (in_buf, 0); + args->in_uv = new Uchar2Image (in_buf, 1); + } + args->out_luma = new UcharImage (out_buf, 0); + args->out_uv = new Uchar2Image (out_buf, 1); + + XCAM_ASSERT (out_buf->get_video_info ().width % 2 == 0 && out_buf->get_video_info ().height % 2 == 0); + + uint32_t thread_x = 2, thread_y = 2; + WorkSize work_unit = worker->get_work_uint (); + WorkSize global_size ( + xcam_ceil (args->out_luma->get_width (), work_unit.value[0]) / work_unit.value[0], + xcam_ceil (args->out_luma->get_height (), work_unit.value[1]) / work_unit.value[1]); + WorkSize local_size ( + xcam_ceil(global_size.value[0], thread_x) / thread_x , + xcam_ceil(global_size.value[1], thread_y) / thread_y); + + worker->set_local_size (local_size); + worker->set_global_size (global_size); + + return worker->work (args); +} + +XCamReturn +SoftBlenderPriv::BlenderPrivConfig::start_lap_task ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const uint32_t level, const SoftBlender::BufIdx idx, + const SmartPtr<GaussDownScale::Args> &scale_args) +{ + XCAM_ASSERT (level < pyr_levels); + XCAM_ASSERT (idx < SoftBlender::BufIdxCount); + SmartPtr<VideoBuffer> gauss = scale_args->out_buf; + + SmartPtr<VideoBuffer> out_buf; + if (level == 0) { + XCAM_ASSERT (first_lap_pool.ptr ()); + out_buf = first_lap_pool->get_buffer (); + } else { + XCAM_ASSERT (pyr_layer[level - 1].overlap_pool.ptr ()); + out_buf = pyr_layer[level - 1].overlap_pool->get_buffer (); + } + + XCAM_FAIL_RETURN ( + ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM, + "blender:(%s) start_lap_task failed, level(%d),idx(%d) get output buffer empty.", + XCAM_STR (_blender->get_name ()), level, (int)idx); + + SmartPtr<LaplaceTask::Args> args = new LaplaceTask::Args (param, level, idx, out_buf); + args->orig_luma = scale_args->in_luma;//new UcharImage (orig, 0); + args->orig_uv = scale_args->in_uv; //new Uchar2Image (orig, 1); + args->gauss_luma = new UcharImage (gauss, 0); + args->gauss_uv = new Uchar2Image (gauss, 1); + args->out_luma = new UcharImage (out_buf, 0); + args->out_uv = new Uchar2Image (out_buf, 1); + + SmartPtr<SoftWorker> worker = pyr_layer[level].lap_task[idx]; + XCAM_ASSERT (worker.ptr ()); + + uint32_t thread_x = 2, thread_y = 2; + WorkSize work_unit = worker->get_work_uint (); + WorkSize global_size ( + xcam_ceil (args->out_luma->get_width (), work_unit.value[0]) / work_unit.value[0], + xcam_ceil (args->out_luma->get_height (), work_unit.value[1]) / work_unit.value[1]); + WorkSize local_size ( + xcam_ceil(global_size.value[0], thread_x) / thread_x , + xcam_ceil(global_size.value[1], thread_y) / thread_y); + + + worker->set_local_size (local_size); + worker->set_global_size (global_size); + + return worker->work (args); +} + +XCamReturn +SoftBlenderPriv::BlenderPrivConfig::start_blend_task ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const SmartPtr<VideoBuffer> &buf, + const SoftBlender::BufIdx idx) +{ + + SmartPtr<BlendTask::Args> args; + uint32_t last_level = pyr_levels - 1; + + { + SmartLock locker (map_args_mutex); + MapBlendArgs::iterator i = blend_args.find (param.ptr ()); + if (i == blend_args.end ()) { + args = new BlendTask::Args (param, pyr_layer[last_level].coef_mask); + XCAM_ASSERT (args.ptr ()); + blend_args.insert (std::make_pair((void*)param.ptr (), args)); + XCAM_LOG_DEBUG ("soft_blender:%s init blender args", XCAM_STR (_blender->get_name ())); + } else { + args = (*i).second; + } + args->in_luma[idx] = new UcharImage (buf, 0); + args->in_uv[idx] = new Uchar2Image (buf, 1); + XCAM_ASSERT (args->in_luma[idx].ptr () && args->in_uv[idx].ptr ()); + + if (!args->in_luma[SoftBlender::Idx0].ptr () || !args->in_luma[SoftBlender::Idx1].ptr ()) + return XCAM_RETURN_BYPASS; + + blend_args.erase (i); + } + + XCAM_ASSERT (args.ptr ()); + XCAM_ASSERT (args->in_luma[SoftBlender::Idx0]->get_width () == args->in_luma[SoftBlender::Idx1]->get_width ()); + + XCAM_ASSERT (pyr_layer[last_level].overlap_pool.ptr ()); + SmartPtr<VideoBuffer> out_buf = pyr_layer[last_level].overlap_pool->get_buffer (); + XCAM_FAIL_RETURN ( + ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM, + "blender:(%s) start_blend_task failed, last level blend buffer empty.", + XCAM_STR (_blender->get_name ()), (int)idx); + args->out_luma = new UcharImage (out_buf, 0); + args->out_uv = new Uchar2Image (out_buf, 1); + args->out_buf = out_buf; + + // process 4x1 uv each loop + SmartPtr<SoftWorker> worker = last_level_blend; + XCAM_ASSERT (worker.ptr ()); + + uint32_t thread_x = 2, thread_y = 2; + WorkSize work_unit = worker->get_work_uint (); + WorkSize global_size ( + xcam_ceil (args->out_luma->get_width (), work_unit.value[0]) / work_unit.value[0], + xcam_ceil (args->out_luma->get_height (), work_unit.value[1]) / work_unit.value[1]); + WorkSize local_size ( + xcam_ceil (global_size.value[0], thread_x) / thread_x, + xcam_ceil (global_size.value[1], thread_y) / thread_y); + + worker->set_local_size (local_size); + worker->set_global_size (global_size); + + return worker->work (args); +} + +XCamReturn +SoftBlenderPriv::BlenderPrivConfig::start_reconstruct_task ( + const SmartPtr<ReconstructTask::Args> &args, const uint32_t level) +{ + XCAM_ASSERT (args.ptr ()); + XCAM_ASSERT (args->lap_luma[SoftBlender::Idx0].ptr () && args->lap_luma[SoftBlender::Idx1].ptr () && args->gauss_luma.ptr ()); + XCAM_ASSERT (args->lap_luma[SoftBlender::Idx0]->get_width () == args->lap_luma[SoftBlender::Idx1]->get_width ()); + SmartPtr<VideoBuffer> out_buf; + if (level == 0) { + out_buf = args->get_param ()->out_buf; + XCAM_ASSERT (out_buf.ptr ()); + args->mask = orig_mask; + + Rect out_area = _blender->get_merge_window (); + const VideoBufferInfo &out_info = out_buf->get_video_info (); + if (out_area.width == 0 || out_area.height == 0) { + out_area.width = out_info.width; + out_area.height = out_info.height; + } + XCAM_ASSERT (out_area.pos_x % SOFT_BLENDER_ALIGNMENT_X == 0); + XCAM_ASSERT (out_area.pos_y % SOFT_BLENDER_ALIGNMENT_Y == 0); + args->out_luma = new UcharImage ( + out_buf, out_area.width, out_area.height, out_info.strides[0], + out_info.offsets[0] + out_area.pos_x + out_area.pos_y * out_info.strides[0]); + args->out_uv = new Uchar2Image ( + out_buf, out_area.width / 2, out_area.height / 2, out_info.strides[1], + out_info.offsets[1] + out_area.pos_x + out_area.pos_y / 2 * out_info.strides[1]); + } else { + out_buf = pyr_layer[level - 1].overlap_pool->get_buffer (); + XCAM_FAIL_RETURN ( + ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM, + "blender:(%s) start_reconstruct_task failed, out buffer is empty.", XCAM_STR (_blender->get_name ())); + args->mask = pyr_layer[level - 1].coef_mask; + args->out_luma = new UcharImage (out_buf, 0); + args->out_uv = new Uchar2Image (out_buf, 1); + } + + args->out_buf = out_buf; + + SmartPtr<SoftWorker> worker = pyr_layer[level].recon_task; + XCAM_ASSERT (worker.ptr ()); + + uint32_t thread_x = 2, thread_y = 2; + WorkSize work_unit = worker->get_work_uint (); + WorkSize global_size ( + xcam_ceil (args->out_luma->get_width (), work_unit.value[0]) / work_unit.value[0], + xcam_ceil (args->out_luma->get_height (), work_unit.value[1]) / work_unit.value[1]); + WorkSize local_size ( + xcam_ceil (global_size.value[0], thread_x) / thread_x, + xcam_ceil (global_size.value[1], thread_y) / thread_y); + + worker->set_local_size (local_size); + worker->set_global_size (global_size); + + return worker->work (args); +} + +XCamReturn +SoftBlenderPriv::BlenderPrivConfig::start_reconstruct_task_by_gauss ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const SmartPtr<VideoBuffer> &gauss, + const uint32_t level) +{ + SmartPtr<ReconstructTask::Args> args; + { + SmartLock locker (map_args_mutex); + MapReconsArgs::iterator i = pyr_layer[level].recons_args.find (param.ptr ()); + if (i == pyr_layer[level].recons_args.end ()) { + args = new ReconstructTask::Args (param, level); + XCAM_ASSERT (args.ptr ()); + pyr_layer[level].recons_args.insert (std::make_pair((void*)param.ptr (), args)); + XCAM_LOG_DEBUG ("soft_blender:%s init recons_args level(%d)", XCAM_STR (_blender->get_name ()), level); + } else { + args = (*i).second; + } + args->gauss_luma = new UcharImage (gauss, 0); + args->gauss_uv = new Uchar2Image (gauss, 1); + XCAM_ASSERT (args->gauss_luma.ptr () && args->gauss_uv.ptr ()); + + if (!args->lap_luma[SoftBlender::Idx0].ptr () || !args->lap_luma[SoftBlender::Idx1].ptr ()) + return XCAM_RETURN_BYPASS; + + pyr_layer[level].recons_args.erase (i); + } + + return start_reconstruct_task (args, level); +} + +XCamReturn +SoftBlenderPriv::BlenderPrivConfig::start_reconstruct_task_by_lap ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const SmartPtr<VideoBuffer> &lap, + const uint32_t level, + const SoftBlender::BufIdx idx) +{ + SmartPtr<ReconstructTask::Args> args; + { + SmartLock locker (map_args_mutex); + MapReconsArgs::iterator i = pyr_layer[level].recons_args.find (param.ptr ()); + if (i == pyr_layer[level].recons_args.end ()) { + args = new ReconstructTask::Args (param, level); + XCAM_ASSERT (args.ptr ()); + pyr_layer[level].recons_args.insert (std::make_pair((void*)param.ptr (), args)); + XCAM_LOG_DEBUG ("soft_blender:%s init recons_args level(%d)", XCAM_STR (_blender->get_name ()), level); + } else { + args = (*i).second; + } + args->lap_luma[idx] = new UcharImage (lap, 0); + args->lap_uv[idx] = new Uchar2Image (lap, 1); + XCAM_ASSERT (args->lap_luma[idx].ptr () && args->lap_uv[idx].ptr ()); + + if (!args->gauss_luma.ptr () || !args->lap_luma[SoftBlender::Idx0].ptr () || + !args->lap_luma[SoftBlender::Idx1].ptr ()) + return XCAM_RETURN_BYPASS; + + pyr_layer[level].recons_args.erase (i); + } + + return start_reconstruct_task (args, level); +} + +XCamReturn +SoftBlender::start_work (const SmartPtr<ImageHandler::Parameters> &base) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<BlenderParam> param = base.dynamic_cast_ptr<BlenderParam> (); + + XCAM_FAIL_RETURN ( + ERROR, param.ptr () && param->in1_buf.ptr () && param->out_buf.ptr (), XCAM_RETURN_ERROR_PARAM, + "blender:%s start_work failed, params(in1/out buf) are not fully set or type not correct", + XCAM_STR (get_name ())); + + //start gauss scale level0: idx0 + ret = _priv_config->start_scaler (param, param->in_buf, 0, Idx0); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "blender:%s start_work failed on idx0", XCAM_STR (get_name ())); + + //start gauss scale level0: idx1 + ret = _priv_config->start_scaler (param, param->in1_buf, 0, Idx1); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "blender:%s start_work failed on idx1", XCAM_STR (get_name ())); + + //param->in_buf.release (); + //param->in1_buf.release (); + + return ret; +}; + +XCamReturn +SoftBlender::configure_resource (const SmartPtr<Parameters> ¶m) +{ + XCAM_ASSERT (_priv_config->pyr_levels <= XCAM_SOFT_PYRAMID_MAX_LEVEL); + const VideoBufferInfo &in0_info = param->in_buf->get_video_info (); + XCAM_FAIL_RETURN ( + ERROR, in0_info.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM, + "blender:%s only support format(NV12) but input format is %s", + XCAM_STR(get_name ()), xcam_fourcc_to_string (in0_info.format)); + + Rect in0_area, in1_area, out_area; + in0_area = get_input_merge_area (Idx0); + in1_area = get_input_merge_area (Idx1); + out_area = get_merge_window (); + XCAM_FAIL_RETURN ( + ERROR, + in0_area.width == in1_area.width && in1_area.width == out_area.width && + in0_area.height == in1_area.height && in1_area.height == out_area.height, + XCAM_RETURN_ERROR_PARAM, + "blender:%s input/output overlap area was not same. in0(w:%d,h:%d), in1(w:%d,h:%d), out(w:%d,h:%d)", + XCAM_STR(get_name ()), in0_area.width, in0_area.height, + in1_area.width, in1_area.height, out_area.width, out_area.height); + + VideoBufferInfo out_info; + uint32_t out_width(0), out_height(0); + get_output_size (out_width, out_height); + XCAM_FAIL_RETURN ( + ERROR, out_width && out_height, XCAM_RETURN_ERROR_PARAM, + "blender:%s output size was not set", XCAM_STR(get_name ())); + + out_info.init ( + in0_info.format, out_width, out_height, + XCAM_ALIGN_UP (out_width, SOFT_BLENDER_ALIGNMENT_X), XCAM_ALIGN_UP (out_height, SOFT_BLENDER_ALIGNMENT_Y)); + set_out_video_info (out_info); + + VideoBufferInfo overlap_info; + Rect merge_size = get_merge_window (); + //overlap_info.init (in0_info.format, merge_size.width, merge_size.height); + XCAM_ASSERT (merge_size.width % SOFT_BLENDER_ALIGNMENT_X == 0); + + overlap_info.init (in0_info.format, merge_size.width, merge_size.height); + _priv_config->first_lap_pool = new SoftVideoBufAllocator (overlap_info); + XCAM_FAIL_RETURN ( + ERROR, _priv_config->first_lap_pool->reserve (LAP_POOL_SIZE), XCAM_RETURN_ERROR_MEM, + "blender:%s reserve lap buffer pool(w:%d,h:%d) failed", + XCAM_STR(get_name ()), overlap_info.width, overlap_info.height); + + SmartPtr<Worker::Callback> gauss_scale_cb = new CbGaussDownScale (this); + SmartPtr<Worker::Callback> lap_cb = new CbLapTask (this); + SmartPtr<Worker::Callback> reconst_cb = new CbReconstructTask (this); + XCAM_ASSERT (gauss_scale_cb.ptr () && lap_cb.ptr () && reconst_cb.ptr ()); + + XCamReturn ret = _priv_config->init_first_masks (merge_size.width, merge_size.height); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "blender:%s init masks failed", XCAM_STR (get_name ())); + + for (uint32_t i = 0; i < _priv_config->pyr_levels; ++i) { + merge_size.width = XCAM_ALIGN_UP ((merge_size.width + 1) / 2, SOFT_BLENDER_ALIGNMENT_X); + merge_size.height = XCAM_ALIGN_UP ((merge_size.height + 1) / 2, SOFT_BLENDER_ALIGNMENT_Y); + overlap_info.init (in0_info.format, merge_size.width, merge_size.height); + + _priv_config->pyr_layer[i].overlap_pool = new SoftVideoBufAllocator (overlap_info); + XCAM_ASSERT (_priv_config->pyr_layer[i].overlap_pool.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, _priv_config->pyr_layer[i].overlap_pool->reserve (OVERLAP_POOL_SIZE), XCAM_RETURN_ERROR_MEM, + "blender:%s reserve buffer pool(w:%d,h:%d) failed", + XCAM_STR(get_name ()), overlap_info.width, overlap_info.height); + + ret = _priv_config->scale_down_masks (i, merge_size.width, merge_size.height); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "blender:(%s) first time scale coeff mask failed. level:%d", XCAM_STR (get_name ()), i); + + _priv_config->pyr_layer[i].scale_task[SoftBlender::Idx0] = new GaussDownScale (gauss_scale_cb); + XCAM_ASSERT (_priv_config->pyr_layer[i].scale_task[SoftBlender::Idx0].ptr ()); + _priv_config->pyr_layer[i].scale_task[SoftBlender::Idx1] = new GaussDownScale (gauss_scale_cb); + XCAM_ASSERT (_priv_config->pyr_layer[i].scale_task[SoftBlender::Idx1].ptr ()); + _priv_config->pyr_layer[i].lap_task[SoftBlender::Idx0] = new LaplaceTask (lap_cb); + XCAM_ASSERT (_priv_config->pyr_layer[i].lap_task[SoftBlender::Idx0].ptr ()); + _priv_config->pyr_layer[i].lap_task[SoftBlender::Idx1] = new LaplaceTask (lap_cb); + XCAM_ASSERT (_priv_config->pyr_layer[i].lap_task[SoftBlender::Idx1].ptr ()); + _priv_config->pyr_layer[i].recon_task = new ReconstructTask (reconst_cb); + XCAM_ASSERT (_priv_config->pyr_layer[i].recon_task.ptr ()); + } + + _priv_config->last_level_blend = new BlendTask (new CbBlendTask (this)); + XCAM_ASSERT (_priv_config->last_level_blend.ptr ()); + + return XCAM_RETURN_NO_ERROR; +} + +void +SoftBlender::gauss_scale_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error) +{ + XCAM_UNUSED (worker); + + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<GaussDownScale::Args> args = base.dynamic_cast_ptr<GaussDownScale::Args> (); + XCAM_ASSERT (args.ptr ()); + const SmartPtr<ImageHandler::Parameters> param = args->get_param (); + uint32_t level = args->level; + BufIdx idx = args->idx; + uint32_t next_level = level + 1; + + XCAM_ASSERT (param.ptr ()); + XCAM_ASSERT (level < _priv_config->pyr_levels); + + if (!check_work_continue (param, error)) + return; + + dump_level_buf (args->out_buf, "gauss-scale", level, idx); + + ret = _priv_config->start_lap_task (param, level, idx, args);//args->in_buf, args->out_buf); + if (!xcam_ret_is_ok (ret)) { + work_broken (param, ret); + } + + if (next_level == _priv_config->pyr_levels) { // last level + ret = _priv_config->start_blend_task (param, args->out_buf, idx); + } else { + ret = _priv_config->start_scaler (param, args->out_buf, next_level, idx); + } + + if (!xcam_ret_is_ok (ret)) { + work_broken (param, ret); + } +} + +void +SoftBlender::lap_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error) +{ + XCAM_UNUSED (worker); + + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<LaplaceTask::Args> args = base.dynamic_cast_ptr<LaplaceTask::Args> (); + XCAM_ASSERT (args.ptr ()); + const SmartPtr<ImageHandler::Parameters> param = args->get_param (); + XCAM_ASSERT (param.ptr ()); + uint32_t level = args->level; + BufIdx idx = args->idx; + XCAM_ASSERT (level < _priv_config->pyr_levels); + + if (!check_work_continue (param, error)) + return; + + dump_level_buf (args->out_buf, "lap", level, idx); + + ret = _priv_config->start_reconstruct_task_by_lap (param, args->out_buf, level, idx); + + if (!xcam_ret_is_ok (ret)) { + work_broken (param, ret); + } +} + +void +SoftBlender::blend_task_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error) +{ + XCAM_UNUSED (worker); + + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<BlendTask::Args> args = base.dynamic_cast_ptr<BlendTask::Args> (); + XCAM_ASSERT (args.ptr ()); + const SmartPtr<ImageHandler::Parameters> param = args->get_param (); + XCAM_ASSERT (param.ptr ()); + + if (!check_work_continue (param, error)) + return; + + dump_buf (args->out_buf, "blend-last"); + ret = _priv_config->start_reconstruct_task_by_gauss (param, args->out_buf, _priv_config->pyr_levels - 1); + + if (!xcam_ret_is_ok (ret)) { + work_broken (param, ret); + } +} + +void +SoftBlender::reconstruct_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error) +{ + XCAM_UNUSED (worker); + + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<ReconstructTask::Args> args = base.dynamic_cast_ptr<ReconstructTask::Args> (); + XCAM_ASSERT (args.ptr ()); + const SmartPtr<ImageHandler::Parameters> param = args->get_param (); + XCAM_ASSERT (param.ptr ()); + uint32_t level = args->level; + XCAM_ASSERT (level < _priv_config->pyr_levels); + + if (!check_work_continue (param, error)) + return; + + dump_level_buf (args->out_buf, "reconstruct", level, 0); + + if (level == 0) { + work_well_done (param, error); + return; + } + + ret = _priv_config->start_reconstruct_task_by_gauss (param, args->out_buf, level - 1); + if (!xcam_ret_is_ok (ret)) { + work_broken (param, ret); + } +} + +SmartPtr<SoftHandler> +create_soft_blender () +{ + SmartPtr<SoftBlender> blender = new SoftBlender(); + XCAM_ASSERT (blender.ptr ()); + return blender; +} + +SmartPtr<Blender> +Blender::create_soft_blender () +{ + SmartPtr<SoftHandler> handler = XCam::create_soft_blender (); + return handler.dynamic_cast_ptr<Blender> (); +} + +} diff --git a/modules/soft/soft_blender.h b/modules/soft/soft_blender.h new file mode 100644 index 0000000..b83511b --- /dev/null +++ b/modules/soft/soft_blender.h @@ -0,0 +1,98 @@ +/* + * soft_blender.h - soft blender class + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_SOFT_BLENDER_H +#define XCAM_SOFT_BLENDER_H + +#include <xcam_std.h> +#include <interface/blender.h> +#include <soft/soft_handler.h> + +#define XCAM_SOFT_PYRAMID_MAX_LEVEL 4 +#define XCAM_SOFT_PYRAMID_DEFAULT_LEVEL 3 + +namespace XCam { + +namespace SoftBlenderPriv { +class BlenderPrivConfig; +}; + +class SoftBlender + : public SoftHandler, public Blender +{ + friend class SoftBlenderPriv::BlenderPrivConfig; + friend SmartPtr<SoftHandler> create_soft_blender (); +public: + struct BlenderParam : ImageHandler::Parameters { + SmartPtr<VideoBuffer> in1_buf; + + BlenderParam ( + const SmartPtr<VideoBuffer> &in0, + const SmartPtr<VideoBuffer> &in1, + const SmartPtr<VideoBuffer> &out) + : Parameters (in0, out) + , in1_buf (in1) + {} + }; + + enum BufIdx { + Idx0 = 0, + Idx1, + BufIdxCount, + }; + +public: + ~SoftBlender (); + + bool set_pyr_levels (uint32_t num); + + //derived from SoftHandler + virtual XCamReturn terminate (); + + void gauss_scale_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &args, const XCamReturn error); + void lap_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &args, const XCamReturn error); + void blend_task_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &args, const XCamReturn error); + void reconstruct_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &args, const XCamReturn error); + +protected: + explicit SoftBlender (const char *name = "SoftBlender"); + + //derived from Blender interface + XCamReturn blend ( + const SmartPtr<VideoBuffer> &in0, + const SmartPtr<VideoBuffer> &in1, + SmartPtr<VideoBuffer> &out_buf); + + //derived from SoftHandler + XCamReturn configure_resource (const SmartPtr<Parameters> ¶m); + XCamReturn start_work (const SmartPtr<Parameters> ¶m); + +private: + SmartPtr<SoftBlenderPriv::BlenderPrivConfig> _priv_config; +}; + +extern SmartPtr<SoftHandler> create_soft_blender (); +} + +#endif //XCAM_SOFT_BLENDER_H diff --git a/modules/soft/soft_blender_tasks_priv.cpp b/modules/soft/soft_blender_tasks_priv.cpp new file mode 100644 index 0000000..76a3676 --- /dev/null +++ b/modules/soft/soft_blender_tasks_priv.cpp @@ -0,0 +1,504 @@ +/* + * soft_blender_tasks_priv.cpp - soft blender tasks private class implementation + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "soft_blender_tasks_priv.h" + +namespace XCam { + +namespace XCamSoftTasks { + +const float GaussScaleGray::coeffs[GAUSS_DOWN_SCALE_SIZE] = {0.152f, 0.222f, 0.252f, 0.222f, 0.152f}; + +void +GaussScaleGray::gauss_luma_2x2 ( + UcharImage *in_luma, UcharImage *out_luma, + uint32_t x, uint32_t y) +{ + /* + * o o o o o o o + * o o o o o o o + * o o Y(UV) o Y o o + * o o o o o o o + * o o Y o Y o o + * o o o o o o o + * o o o o o o o + */ + uint32_t in_x = x * 4, in_y = y * 4; + float line[7]; + float sum0[7] = {0.0f}; + float sum1[7] = {0.0f}; + in_luma->read_array<float, 7> (in_x - 2, in_y - 2, line); + multiply_coeff_y (sum0, line, coeffs[0]); + in_luma->read_array<float, 7> (in_x - 2, in_y - 1, line); + multiply_coeff_y (sum0, line, coeffs[1]); + in_luma->read_array<float, 7> (in_x - 2, in_y, line); + multiply_coeff_y (sum0, line, coeffs[2]); + multiply_coeff_y (sum1, line, coeffs[0]); + in_luma->read_array<float, 7> (in_x - 2, in_y + 1, line); + multiply_coeff_y (sum0, line, coeffs[3]); + multiply_coeff_y (sum1, line, coeffs[1]); + in_luma->read_array<float, 7> (in_x - 2, in_y + 2, line); + multiply_coeff_y (sum0, line, coeffs[4]); + multiply_coeff_y (sum1, line, coeffs[2]); + in_luma->read_array<float, 7> (in_x - 2, in_y + 3, line); + multiply_coeff_y (sum1, line, coeffs[3]); + in_luma->read_array<float, 7> (in_x - 2, in_y + 4, line); + multiply_coeff_y (sum1, line, coeffs[4]); + + float value[2]; + Uchar out[2]; + value[0] = gauss_sum (&sum0[0]); + value[1] = gauss_sum (&sum0[2]); + out[0] = convert_to_uchar (value[0]); + out[1] = convert_to_uchar (value[1]); + out_luma->write_array_no_check<2> (x * 2, y * 2, out); + + value[0] = gauss_sum (&sum1[0]); + value[1] = gauss_sum (&sum1[2]); + out[0] = convert_to_uchar(value[0]); + out[1] = convert_to_uchar(value[1]); + out_luma->write_array_no_check<2> (x * 2, y * 2 + 1, out); +} + +XCamReturn +GaussScaleGray::work_range (const SmartPtr<Worker::Arguments> &base, const WorkRange &range) +{ + SmartPtr<GaussScaleGray::Args> args = base.dynamic_cast_ptr<GaussScaleGray::Args> (); + XCAM_ASSERT (args.ptr ()); + UcharImage *in_luma = args->in_luma.ptr (), *out_luma = args->out_luma.ptr (); + XCAM_ASSERT (in_luma && out_luma); + + for (uint32_t y = range.pos[1]; y < range.pos[1] + range.pos_len[1]; ++y) + for (uint32_t x = range.pos[0]; x < range.pos[0] + range.pos_len[0]; ++x) + { + gauss_luma_2x2 (in_luma, out_luma, x, y); + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +GaussDownScale::work_range (const SmartPtr<Worker::Arguments> &base, const WorkRange &range) +{ + SmartPtr<GaussDownScale::Args> args = base.dynamic_cast_ptr<GaussDownScale::Args> (); + XCAM_ASSERT (args.ptr ()); + UcharImage *in_luma = args->in_luma.ptr (), *out_luma = args->out_luma.ptr (); + Uchar2Image *in_uv = args->in_uv.ptr (), *out_uv = args->out_uv.ptr (); + XCAM_ASSERT (in_luma && in_uv); + XCAM_ASSERT (out_luma && out_uv); + + for (uint32_t y = range.pos[1]; y < range.pos[1] + range.pos_len[1]; ++y) + for (uint32_t x = range.pos[0]; x < range.pos[0] + range.pos_len[0]; ++x) + { + gauss_luma_2x2 (in_luma, out_luma, x, y); + + // calculate UV + int32_t in_x = x * 2, in_y = y * 2; + Float2 uv_line[5]; + Float2 uv_sum [5]; + + in_uv->read_array<Float2, 5> (in_x - 2, in_y - 2, uv_line); + multiply_coeff_uv (uv_sum, uv_line, coeffs[0]); + in_uv->read_array<Float2, 5> (in_x - 2, in_y - 1, uv_line); + multiply_coeff_uv (uv_sum, uv_line, coeffs[1]); + in_uv->read_array<Float2, 5> (in_x - 2, in_y , uv_line); + multiply_coeff_uv (uv_sum, uv_line, coeffs[2]); + in_uv->read_array<Float2, 5> (in_x - 2, in_y + 1, uv_line); + multiply_coeff_uv (uv_sum, uv_line, coeffs[3]); + in_uv->read_array<Float2, 5> (in_x - 2, in_y + 2, uv_line); + multiply_coeff_uv (uv_sum, uv_line, coeffs[4]); + Float2 uv_value; + uv_value = gauss_sum (&uv_sum[0]); + Uchar2 uv_out(convert_to_uchar(uv_value.x), convert_to_uchar(uv_value.y)); + out_uv->write_data_no_check (x, y, uv_out); + } + + //printf ("done\n"); + XCAM_LOG_DEBUG ("GaussDownScale work on range:[x:%d, width:%d, y:%d, height:%d]", + range.pos[0], range.pos_len[0], range.pos[1], range.pos_len[1]); + + return XCAM_RETURN_NO_ERROR; +} + +static inline void +blend_luma_8 (const float *luma0, const float *luma1, const float *mask, float *out) +{ + //out[0] = luma0[0] * mask + luma1[0] * ( 1.0f - mask[0]); +#define BLEND_LUMA_8(idx) out[idx] = (luma0[idx] - luma1[idx]) * mask[idx] + luma1[idx] + BLEND_LUMA_8 (0); + BLEND_LUMA_8 (1); + BLEND_LUMA_8 (2); + BLEND_LUMA_8 (3); + BLEND_LUMA_8 (4); + BLEND_LUMA_8 (5); + BLEND_LUMA_8 (6); + BLEND_LUMA_8 (7); +} + +static inline void +normalize_8 (float *value, const float max) +{ + value[0] /= max; + value[1] /= max; + value[2] /= max; + value[3] /= max; + value[4] /= max; + value[5] /= max; + value[6] /= max; + value[7] /= max; +} + +static inline void +read_and_blend_pixel_luma_8 ( + const UcharImage *in0, const UcharImage *in1, + const UcharImage *mask, + const uint32_t in_x, const uint32_t in_y, + float *out_luma, + float *out_mask) +{ + float luma0_line[8], luma1_line[8]; + mask->read_array_no_check<float, 8> (in_x, in_y, out_mask); + in0->read_array_no_check<float, 8> (in_x, in_y, luma0_line); + in1->read_array_no_check<float, 8> (in_x, in_y, luma1_line); + normalize_8 (out_mask, 255.0f); + blend_luma_8 (luma0_line, luma1_line, out_mask, out_luma); +} + +static inline void +read_and_blend_uv_4 ( + const Uchar2Image *in_a, const Uchar2Image *in_b, + const float *mask, + const uint32_t in_x, const uint32_t in_y, + Float2 *out_uv) +{ + Float2 line_a[4], line_b[4]; + in_a->read_array_no_check<Float2, 4> (in_x, in_y, line_a); + in_b->read_array_no_check<Float2, 4> (in_x, in_y, line_b); + + //out_uv[0] = line_a[0] * mask + line_b[0] * ( 1.0f - mask[0]); +#define BLEND_UV_4(i) out_uv[i] = (line_a[i] - line_b[i]) * mask[i] + line_b[i] + BLEND_UV_4 (0); + BLEND_UV_4 (1); + BLEND_UV_4 (2); + BLEND_UV_4 (3); +} + +XCamReturn +BlendTask::work_range (const SmartPtr<Arguments> &base, const WorkRange &range) +{ + SmartPtr<BlendTask::Args> args = base.dynamic_cast_ptr<BlendTask::Args> (); + XCAM_ASSERT (args.ptr ()); + UcharImage *in0_luma = args->in_luma[0].ptr (), *in1_luma = args->in_luma[1].ptr (), *out_luma = args->out_luma.ptr (); + Uchar2Image *in0_uv = args->in_uv[0].ptr (), *in1_uv = args->in_uv[1].ptr (), *out_uv = args->out_uv.ptr (); + UcharImage *mask = args->mask.ptr (); + + XCAM_ASSERT (in0_luma && in0_uv && in1_luma && in1_uv); + XCAM_ASSERT (out_luma && out_uv); + XCAM_ASSERT (mask); + + for (uint32_t y = range.pos[1]; y < range.pos[1] + range.pos_len[1]; ++y) + for (uint32_t x = range.pos[0]; x < range.pos[0] + range.pos_len[0]; ++x) + { + // 8x2 -pixels each time for luma + uint32_t in_x = x * 8; + uint32_t in_y = y * 2; + float luma_blend[8], luma_mask[8]; + Uchar luma_uc[8]; + + // process luma (in_x, in_y) + read_and_blend_pixel_luma_8 (in0_luma, in1_luma, mask, in_x, in_y, luma_blend, luma_mask); + convert_to_uchar_N<float, 8> (luma_blend, luma_uc); + out_luma->write_array_no_check<8> (in_x, in_y, luma_uc); + + // process luma (in_x, in_y + 1) + read_and_blend_pixel_luma_8 (in0_luma, in1_luma, mask, in_x, in_y + 1, luma_blend, luma_mask); + convert_to_uchar_N<float, 8> (luma_blend, luma_uc); + out_luma->write_array_no_check<8> (in_x, in_y + 1, luma_uc); + + // process uv(4x1) (uv_x, uv_y) + uint32_t uv_x = x * 4, uv_y = y; + Float2 uv_blend[4]; + Uchar2 uv_uc[4]; + luma_mask[1] = luma_mask[2]; + luma_mask[2] = luma_mask[4]; + luma_mask[3] = luma_mask[6]; + read_and_blend_uv_4 (in0_uv, in1_uv, luma_mask, uv_x, uv_y, uv_blend); + convert_to_uchar2_N<Float2, 4> (uv_blend, uv_uc); + out_uv->write_array_no_check<4> (uv_x, uv_y, uv_uc); + } + + XCAM_LOG_DEBUG ("BlendTask work on range:[x:%d, width:%d, y:%d, height:%d]", + range.pos[0], range.pos_len[0], range.pos[1], range.pos_len[1]); + + return XCAM_RETURN_NO_ERROR; +} + +static inline void +minus_array_8 (float *orig, float *gauss, Uchar *ret) +{ +#define ORG_MINUS_GAUSS(i) ret[i] = convert_to_uchar<float> ((orig[i] - gauss[i]) * 0.5f + 128.0f) + ORG_MINUS_GAUSS(0); + ORG_MINUS_GAUSS(1); + ORG_MINUS_GAUSS(2); + ORG_MINUS_GAUSS(3); + ORG_MINUS_GAUSS(4); + ORG_MINUS_GAUSS(5); + ORG_MINUS_GAUSS(6); + ORG_MINUS_GAUSS(7); +} + +static inline void +interpolate_luma_int_row_8x1 (UcharImage* image, uint32_t fixed_x, uint32_t fixed_y, float *gauss_v, float* ret) +{ + image->read_array<float, 5> (fixed_x, fixed_y, gauss_v); + ret[0] = gauss_v[0]; + ret[1] = (gauss_v[0] + gauss_v[1]) * 0.5f; + ret[2] = gauss_v[1]; + ret[3] = (gauss_v[1] + gauss_v[2]) * 0.5f; + ret[4] = gauss_v[2]; + ret[5] = (gauss_v[2] + gauss_v[3]) * 0.5f; + ret[6] = gauss_v[3]; + ret[7] = (gauss_v[3] + gauss_v[4]) * 0.5f; +} + +static inline void +interpolate_luma_half_row_8x1 (UcharImage* image, uint32_t fixed_x, uint32_t next_y, float *last_gauss_v, float* ret) +{ + float next_gauss_v[5]; + float tmp; + image->read_array<float, 5> (fixed_x, next_y, next_gauss_v); + ret[0] = (last_gauss_v[0] + next_gauss_v[0]) / 2.0f; + ret[2] = (last_gauss_v[1] + next_gauss_v[1]) / 2.0f; + ret[4] = (last_gauss_v[2] + next_gauss_v[2]) / 2.0f; + ret[6] = (last_gauss_v[3] + next_gauss_v[3]) / 2.0f; + tmp = (last_gauss_v[4] + next_gauss_v[4]) / 2.0f; + ret[1] = (ret[0] + ret[2]) / 2.0f; + ret[3] = (ret[2] + ret[4]) / 2.0f; + ret[5] = (ret[4] + ret[6]) / 2.0f; + ret[7] = (ret[6] + tmp) / 2.0f; +} + +void +LaplaceTask::interplate_luma_8x2 ( + UcharImage *orig_luma, UcharImage *gauss_luma, UcharImage *out_luma, + uint32_t out_x, uint32_t out_y) +{ + uint32_t gauss_x = out_x / 2, first_gauss_y = out_y / 2; + float inter_value[8]; + float gauss_v[5]; + float orig_v[8]; + Uchar lap_ret[8]; + //interplate instaed of coefficient + interpolate_luma_int_row_8x1 (gauss_luma, gauss_x, first_gauss_y, gauss_v, inter_value); + orig_luma->read_array_no_check<float, 8> (out_x, out_y, orig_v); + minus_array_8 (orig_v, inter_value, lap_ret); + out_luma->write_array_no_check<8> (out_x, out_y, lap_ret); + + uint32_t next_gauss_y = first_gauss_y + 1; + interpolate_luma_half_row_8x1 (gauss_luma, gauss_x, next_gauss_y, gauss_v, inter_value); + orig_luma->read_array_no_check<float, 8> (out_x, out_y + 1, orig_v); + minus_array_8 (orig_v, inter_value, lap_ret); + out_luma->write_array_no_check<8> (out_x, out_y + 1, lap_ret); +} + +static inline void +minus_array_uv_4 (Float2 *orig, Float2 *gauss, Uchar2 *ret) +{ +#define ORG_MINUS_GAUSS_UV(i) orig[i] -= gauss[i]; orig[i] *= 0.5f; orig[i] += 128.0f + ORG_MINUS_GAUSS_UV(0); + ORG_MINUS_GAUSS_UV(1); + ORG_MINUS_GAUSS_UV(2); + ORG_MINUS_GAUSS_UV(3); + convert_to_uchar2_N<Float2, 4> (orig, ret); +} + +static inline void +interpolate_uv_int_row_4x1 (Uchar2Image *image, uint32_t x, uint32_t y, Float2 *gauss_value, Float2 *ret) +{ + image->read_array<Float2, 3> (x, y, gauss_value); + ret[0] = gauss_value[0]; + ret[1] = gauss_value[0] + gauss_value[1]; + ret[1] *= 0.5f; + ret[2] = gauss_value[1]; + ret[3] = gauss_value[1] + gauss_value[2]; + ret[3] *= 0.5f; +} + +static inline void +interpolate_uv_half_row_4x1 (Uchar2Image *image, uint32_t x, uint32_t y, Float2 *gauss_value, Float2 *ret) +{ + Float2 next_gauss_uv[3]; + image->read_array<Float2, 3> (x, y, next_gauss_uv); + ret[0] = (gauss_value[0] + next_gauss_uv[0]) * 0.5f; + ret[2] = (gauss_value[1] + next_gauss_uv[1]) * 0.5f; + Float2 tmp = (gauss_value[2] + next_gauss_uv[2]) * 0.5f; + ret[1] = (ret[0] + ret[2]) * 0.5f; + ret[3] = (ret[2] + tmp) * 0.5f; +} + +XCamReturn +LaplaceTask::work_range (const SmartPtr<Arguments> &base, const WorkRange &range) +{ + SmartPtr<LaplaceTask::Args> args = base.dynamic_cast_ptr<LaplaceTask::Args> (); + XCAM_ASSERT (args.ptr ()); + UcharImage *orig_luma = args->orig_luma.ptr (), *gauss_luma = args->gauss_luma.ptr (), *out_luma = args->out_luma.ptr (); + Uchar2Image *orig_uv = args->orig_uv.ptr (), *gauss_uv = args->gauss_uv.ptr (), *out_uv = args->out_uv.ptr (); + XCAM_ASSERT (orig_luma && orig_uv); + XCAM_ASSERT (gauss_luma && gauss_uv); + XCAM_ASSERT (out_luma && out_uv); + + for (uint32_t y = range.pos[1]; y < range.pos[1] + range.pos_len[1]; ++y) + for (uint32_t x = range.pos[0]; x < range.pos[0] + range.pos_len[0]; ++x) + { + // 8x4 -pixels each time for luma + uint32_t out_x = x * 8, out_y = y * 4; + interplate_luma_8x2 (orig_luma, gauss_luma, out_luma, out_x, out_y); + interplate_luma_8x2 (orig_luma, gauss_luma, out_luma, out_x, out_y + 2); + + // 4x2 uv + uint32_t out_uv_x = x * 4, out_uv_y = y * 2; + uint32_t gauss_uv_x = out_uv_x / 2, gauss_uv_y = out_uv_y / 2; + Float2 gauss_uv_value[3]; + Float2 orig_uv_value[4]; + Float2 inter_uv_value[4]; + Uchar2 lap_uv_ret[4]; + interpolate_uv_int_row_4x1 (gauss_uv, gauss_uv_x, gauss_uv_y, gauss_uv_value, inter_uv_value); + orig_uv->read_array_no_check<Float2, 4> (out_uv_x , out_uv_y, orig_uv_value); + minus_array_uv_4 (orig_uv_value, inter_uv_value, lap_uv_ret); + out_uv->write_array_no_check<4> (out_uv_x , out_uv_y, lap_uv_ret); + + interpolate_uv_half_row_4x1 (gauss_uv, gauss_uv_x, gauss_uv_y + 1, gauss_uv_value, inter_uv_value); + orig_uv->read_array_no_check<Float2, 4> (out_uv_x , out_uv_y + 1, orig_uv_value); + minus_array_uv_4 (orig_uv_value, inter_uv_value, lap_uv_ret); + out_uv->write_array_no_check<4> (out_uv_x, out_uv_y + 1, lap_uv_ret); + } + return XCAM_RETURN_NO_ERROR; +} + +static inline void +reconstruct_luma_8x1 (float *lap, float *up_sample, Uchar *result) +{ +#define RECONSTRUCT_UP_SAMPLE(i) result[i] = convert_to_uchar<float>(up_sample[i] + lap[i] * 2.0f - 256.0f) + RECONSTRUCT_UP_SAMPLE(0); + RECONSTRUCT_UP_SAMPLE(1); + RECONSTRUCT_UP_SAMPLE(2); + RECONSTRUCT_UP_SAMPLE(3); + RECONSTRUCT_UP_SAMPLE(4); + RECONSTRUCT_UP_SAMPLE(5); + RECONSTRUCT_UP_SAMPLE(6); + RECONSTRUCT_UP_SAMPLE(7); +} + +static inline void +reconstruct_luma_4x1 (Float2 *lap, Float2 *up_sample, Uchar2 *uv_uc) +{ +#define RECONSTRUCT_UP_SAMPLE_UV(i) \ + uv_uc[i].x = convert_to_uchar<float>(up_sample[i].x + lap[i].x * 2.0f - 256.0f); \ + uv_uc[i].y = convert_to_uchar<float>(up_sample[i].y + lap[i].y * 2.0f - 256.0f) + + RECONSTRUCT_UP_SAMPLE_UV (0); + RECONSTRUCT_UP_SAMPLE_UV (1); + RECONSTRUCT_UP_SAMPLE_UV (2); + RECONSTRUCT_UP_SAMPLE_UV (3); +} + +XCamReturn +ReconstructTask::work_range (const SmartPtr<Arguments> &base, const WorkRange &range) +{ + SmartPtr<ReconstructTask::Args> args = base.dynamic_cast_ptr<ReconstructTask::Args> (); + XCAM_ASSERT (args.ptr ()); + UcharImage *lap_luma[2] = {args->lap_luma[0].ptr (), args->lap_luma[1].ptr ()}; + UcharImage *gauss_luma = args->gauss_luma.ptr (), *out_luma = args->out_luma.ptr (); + Uchar2Image *lap_uv[2] = {args->lap_uv[0].ptr (), args->lap_uv[1].ptr ()}; + Uchar2Image *gauss_uv = args->gauss_uv.ptr (), *out_uv = args->out_uv.ptr (); + UcharImage *mask_image = args->mask.ptr (); + XCAM_ASSERT (lap_luma[0] && lap_luma[1] && lap_uv[0] && lap_uv[1]); + XCAM_ASSERT (gauss_luma && gauss_uv); + XCAM_ASSERT (out_luma && out_uv); + XCAM_ASSERT (mask_image); + + for (uint32_t y = range.pos[1]; y < range.pos[1] + range.pos_len[1]; ++y) + for (uint32_t x = range.pos[0]; x < range.pos[0] + range.pos_len[0]; ++x) + { + // 8x4 -pixels each time for luma + float luma_blend[8], luma_mask1[8], luma_mask2[8]; + float luma_sample[8]; + float gauss_data[5]; + Uchar luma_uchar[8]; + uint32_t in_x = x * 8, in_y = y * 4; + + // luma 1st - line + read_and_blend_pixel_luma_8 (lap_luma[0], lap_luma[1], mask_image, in_x, in_y, luma_blend, luma_mask1); + interpolate_luma_int_row_8x1 (gauss_luma, in_x / 2, in_y / 2, gauss_data, luma_sample); + reconstruct_luma_8x1 (luma_blend, luma_sample, luma_uchar); + out_luma->write_array_no_check<8> (in_x, in_y, luma_uchar); + + // luma 2nd -line + in_y += 1; + read_and_blend_pixel_luma_8 (lap_luma[0], lap_luma[1], mask_image, in_x, in_y, luma_blend, luma_mask1); + interpolate_luma_half_row_8x1 (gauss_luma, in_x / 2, in_y / 2 + 1, gauss_data, luma_sample); + reconstruct_luma_8x1 (luma_blend, luma_sample, luma_uchar); + out_luma->write_array_no_check<8> (in_x, in_y, luma_uchar); + + // luma 3rd -line + in_y += 1; + read_and_blend_pixel_luma_8 (lap_luma[0], lap_luma[1], mask_image, in_x, in_y, luma_blend, luma_mask2); + interpolate_luma_int_row_8x1 (gauss_luma, in_x / 2, in_y / 2, gauss_data, luma_sample); + reconstruct_luma_8x1 (luma_blend, luma_sample, luma_uchar); + out_luma->write_array_no_check<8> (in_x, in_y, luma_uchar); + + // luma 4th -line + in_y += 1; + read_and_blend_pixel_luma_8 (lap_luma[0], lap_luma[1], mask_image, in_x, in_y, luma_blend, luma_mask2); + interpolate_luma_half_row_8x1 (gauss_luma, in_x / 2, in_y / 2 + 1, gauss_data, luma_sample); + reconstruct_luma_8x1 (luma_blend, luma_sample, luma_uchar); + out_luma->write_array_no_check<8> (in_x, in_y, luma_uchar); + + // 4x2-UV process UV + uint32_t uv_x = x * 4, uv_y = y * 2; + Float2 uv_blend[4]; + Float2 gauss_uv_value[3]; + Float2 up_sample_uv[4]; + Uchar2 uv_uc[4]; + luma_mask1[1] = luma_mask1[2]; + luma_mask1[2] = luma_mask1[4]; + luma_mask1[3] = luma_mask1[6]; + luma_mask2[1] = luma_mask2[2]; + luma_mask2[2] = luma_mask2[4]; + luma_mask2[3] = luma_mask1[6]; + + //1st-line UV + read_and_blend_uv_4 (lap_uv[0], lap_uv[1], luma_mask1, uv_x, uv_y, uv_blend); + interpolate_uv_int_row_4x1 (gauss_uv, uv_x / 2, uv_y / 2, gauss_uv_value, up_sample_uv); + reconstruct_luma_4x1 (uv_blend, up_sample_uv, uv_uc); + out_uv->write_array_no_check<4> (uv_x, uv_y, uv_uc); + + //2nd-line UV + uv_y += 1; + read_and_blend_uv_4 (lap_uv[0], lap_uv[1], luma_mask2, uv_x, uv_y, uv_blend); + interpolate_uv_half_row_4x1 (gauss_uv, uv_x / 2, uv_y / 2 + 1, gauss_uv_value, up_sample_uv); + reconstruct_luma_4x1 (uv_blend, up_sample_uv, uv_uc); + out_uv->write_array_no_check<4> (uv_x, uv_y, uv_uc); + } + return XCAM_RETURN_NO_ERROR; +} + +} + +} diff --git a/modules/soft/soft_blender_tasks_priv.h b/modules/soft/soft_blender_tasks_priv.h new file mode 100644 index 0000000..a2f2ed8 --- /dev/null +++ b/modules/soft/soft_blender_tasks_priv.h @@ -0,0 +1,232 @@ +/* + * soft_blender_tasks_priv.h - soft blender tasks private class + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_SOFT_BLENDER_TASKS_PRIV_H +#define XCAM_SOFT_BLENDER_TASKS_PRIV_H + +#include <xcam_std.h> +#include <soft/soft_worker.h> +#include <soft/soft_image.h> +#include <soft/soft_blender.h> + +#define SOFT_BLENDER_ALIGNMENT_X 8 +#define SOFT_BLENDER_ALIGNMENT_Y 4 + +#define GAUSS_DOWN_SCALE_RADIUS 2 +#define GAUSS_DOWN_SCALE_SIZE ((GAUSS_DOWN_SCALE_RADIUS)*2+1) + +namespace XCam { + +namespace XCamSoftTasks { + +class GaussScaleGray + : public SoftWorker +{ +public: + struct Args : SoftArgs { + SmartPtr<UcharImage> in_luma, out_luma; + }; + +public: + explicit GaussScaleGray (const char *name = "GaussScaleGray", const SmartPtr<Worker::Callback> &cb = NULL) + : SoftWorker (name, cb) + { + set_work_uint (2, 2); + } + +private: + virtual XCamReturn work_range (const SmartPtr<Arguments> &args, const WorkRange &range); + +protected: + void gauss_luma_2x2 ( + UcharImage *in_luma, UcharImage *out_luma, uint32_t x, uint32_t y); + + inline void multiply_coeff_y (float *out, const float *in, float coef) { + out[0] += in[0] * coef; + out[1] += in[1] * coef; + out[2] += in[2] * coef; + out[3] += in[3] * coef; + out[4] += in[4] * coef; + out[5] += in[5] * coef; + out[6] += in[6] * coef; + out[7] += in[7] * coef; + } + + template<typename T> + inline T gauss_sum (const T *input) { + return (input[0] * coeffs[0] + input[1] * coeffs[1] + input[2] * coeffs[2] + + input[3] * coeffs[3] + input[4] * coeffs[4]); + } + +protected: + static const float coeffs[GAUSS_DOWN_SCALE_SIZE]; +}; + +class GaussDownScale + : public GaussScaleGray +{ +public: + struct Args : GaussScaleGray::Args { + SmartPtr<Uchar2Image> in_uv, out_uv; + const uint32_t level; + const SoftBlender::BufIdx idx; + + SmartPtr<VideoBuffer> in_buf; + SmartPtr<VideoBuffer> out_buf; + + Args ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const uint32_t l, const SoftBlender::BufIdx i, + const SmartPtr<VideoBuffer> &in, + const SmartPtr<VideoBuffer> &out) + : level (l) + , idx (i) + , in_buf (in) + , out_buf (out) + { + set_param (param); + } + }; + +public: + explicit GaussDownScale (const SmartPtr<Worker::Callback> &cb) + : GaussScaleGray ("GaussDownScale", cb) + {} + +private: + virtual XCamReturn work_range (const SmartPtr<Arguments> &args, const WorkRange &range); + + inline void multiply_coeff_uv (Float2 *out, Float2 *in, float coef) { + out[0] += in[0] * coef; + out[1] += in[1] * coef; + out[2] += in[2] * coef; + out[3] += in[3] * coef; + out[4] += in[4] * coef; + } +}; + +class BlendTask + : public SoftWorker +{ +public: + struct Args : SoftArgs { + SmartPtr<UcharImage> in_luma[2], out_luma; + SmartPtr<Uchar2Image> in_uv[2], out_uv; + SmartPtr<UcharImage> mask; + + SmartPtr<VideoBuffer> out_buf; + + Args ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const SmartPtr<UcharImage> &m, + const SmartPtr<VideoBuffer> &out = NULL) + : SoftArgs (param) + , mask (m) + , out_buf (out) + {} + }; + +public: + explicit BlendTask (const SmartPtr<Worker::Callback> &cb) + : SoftWorker ("SoftBlendTask", cb) + { + set_work_uint (8, 2); + } + +private: + virtual XCamReturn work_range (const SmartPtr<Arguments> &args, const WorkRange &range); +}; + +class LaplaceTask + : public SoftWorker +{ +public: + struct Args : SoftArgs { + SmartPtr<UcharImage> orig_luma, gauss_luma, out_luma; + SmartPtr<Uchar2Image> orig_uv, gauss_uv, out_uv; + const uint32_t level; + const SoftBlender::BufIdx idx; + + SmartPtr<VideoBuffer> out_buf; + + Args ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const uint32_t l, const SoftBlender::BufIdx i, + const SmartPtr<VideoBuffer> &out = NULL) + : SoftArgs (param) + , level(l) + , idx (i) + , out_buf (out) + {} + }; + +public: + explicit LaplaceTask (const SmartPtr<Worker::Callback> &cb) + : SoftWorker ("SoftLaplaceTask", cb) + { + set_work_uint (8, 4); + } + +private: + virtual XCamReturn work_range (const SmartPtr<Arguments> &args, const WorkRange &range); + + void interplate_luma_8x2 ( + UcharImage *orig_luma, UcharImage *gauss_luma, UcharImage *out_luma, + uint32_t out_x, uint32_t out_y); +}; + +class ReconstructTask + : public SoftWorker +{ +public: + struct Args : SoftArgs { + SmartPtr<UcharImage> gauss_luma, lap_luma[2], out_luma; + SmartPtr<Uchar2Image> gauss_uv, lap_uv[2], out_uv; + SmartPtr<UcharImage> mask; + const uint32_t level; + + SmartPtr<VideoBuffer> out_buf; + + Args ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const uint32_t l, + const SmartPtr<VideoBuffer> &out = NULL) + : SoftArgs (param) + , level(l) + , out_buf (out) + {} + }; + +public: + explicit ReconstructTask (const SmartPtr<Worker::Callback> &cb) + : SoftWorker ("SoftReconstructTask", cb) + { + set_work_uint (8, 4); + } + +private: + virtual XCamReturn work_range (const SmartPtr<Arguments> &args, const WorkRange &range); +}; + +} + +} + +#endif //XCAM_SOFT_BLENDER_TASKS_PRIV_H diff --git a/modules/soft/soft_copy_task.cpp b/modules/soft/soft_copy_task.cpp new file mode 100644 index 0000000..896d207 --- /dev/null +++ b/modules/soft/soft_copy_task.cpp @@ -0,0 +1,66 @@ +/* + * soft_copy_task.cpp - soft copy implementation + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include "soft_copy_task.h" + +namespace XCam { + +namespace XCamSoftTasks { + +template <typename ImageT> +static inline void copy_line (const ImageT *in, ImageT *out, const uint32_t y, const uint32_t size) +{ + const typename ImageT::Type *in_ptr = in->get_buf_ptr (0, y); + typename ImageT::Type *out_ptr = out->get_buf_ptr (0, y); + + memcpy (out_ptr, in_ptr, size); +} + +XCamReturn +XCamSoftTasks::CopyTask::work_range (const SmartPtr<Arguments> &base, const WorkRange &range) +{ + SmartPtr<CopyTask::Args> args = base.dynamic_cast_ptr<CopyTask::Args> (); + XCAM_ASSERT (args.ptr ()); + + UcharImage *in_luma = args->in_luma.ptr (), *out_luma = args->out_luma.ptr (); + Uchar2Image *in_uv = args->in_uv.ptr (), *out_uv = args->out_uv.ptr (); + XCAM_ASSERT (in_luma && in_uv); + XCAM_ASSERT (out_luma && out_uv); + + uint32_t luma_size = in_luma->get_width () * in_luma->pixel_size (); + uint32_t uv_size = in_uv->get_width () * in_uv->pixel_size (); + for (uint32_t y = range.pos[1]; y < range.pos[1] + range.pos_len[1]; ++y) { + uint32_t luma_y = y * 2; + copy_line<UcharImage> (in_luma, out_luma, luma_y, luma_size); + copy_line<UcharImage> (in_luma, out_luma, luma_y + 1, luma_size); + + uint32_t uv_y = y; + copy_line<Uchar2Image> (in_uv, out_uv, uv_y, uv_size); + } + + XCAM_LOG_DEBUG ("CopyTask work on range:[x:%d, width:%d, y:%d, height:%d]", + range.pos[0], range.pos_len[0], range.pos[1], range.pos_len[1]); + + return XCAM_RETURN_NO_ERROR; +} + +} + +} diff --git a/modules/soft/soft_copy_task.h b/modules/soft/soft_copy_task.h new file mode 100644 index 0000000..d02ad47 --- /dev/null +++ b/modules/soft/soft_copy_task.h @@ -0,0 +1,60 @@ +/* + * soft_copy_task.h - soft copy class + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#ifndef XCAM_SOFT_COPY_TASK_H +#define XCAM_SOFT_COPY_TASK_H + +#include <xcam_std.h> +#include <soft/soft_worker.h> +#include <soft/soft_handler.h> +#include <soft/soft_image.h> +#include <interface/stitcher.h> + +namespace XCam { + +namespace XCamSoftTasks { + +class CopyTask + : public SoftWorker +{ +public: + struct Args : SoftArgs { + SmartPtr<UcharImage> in_luma, out_luma; + SmartPtr<Uchar2Image> in_uv, out_uv; + + Args (const SmartPtr<ImageHandler::Parameters> ¶m) + : SoftArgs (param) + {} + }; + +public: + explicit CopyTask (const SmartPtr<Worker::Callback> &cb) + : SoftWorker ("CopyTask", cb) + {} + +private: + virtual XCamReturn work_range (const SmartPtr<Arguments> &args, const WorkRange &range); +}; + +} + +} + +#endif // XCAM_SOFT_COPY_TASK_H
\ No newline at end of file diff --git a/modules/soft/soft_geo_mapper.cpp b/modules/soft/soft_geo_mapper.cpp new file mode 100644 index 0000000..478b025 --- /dev/null +++ b/modules/soft/soft_geo_mapper.cpp @@ -0,0 +1,207 @@ +/* + * soft_geo_mapper.cpp - soft geometry mapper implementation + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "soft_geo_mapper.h" +#include "soft_geo_tasks_priv.h" + +#define XCAM_GEO_MAP_ALIGNMENT_X 8 +#define XCAM_GEO_MAP_ALIGNMENT_Y 2 + +namespace XCam { + +DECLARE_WORK_CALLBACK (CbGeoMapTask, SoftGeoMapper, remap_task_done); + +SoftGeoMapper::SoftGeoMapper (const char *name) + : SoftHandler (name) +{ +} + +SoftGeoMapper::~SoftGeoMapper () +{ +} + +bool +SoftGeoMapper::set_lookup_table (const PointFloat2 *data, uint32_t width, uint32_t height) +{ + XCAM_FAIL_RETURN( + ERROR, width > 1 && height > 1 && data, false, + "SoftGeoMapper(%s) set loop up table need w>1 and h>1, but width:%d, height:%d", + XCAM_STR (get_name ()), width, height); + + _lookup_table = new Float2Image (width, height); + + XCAM_FAIL_RETURN( + ERROR, _lookup_table.ptr () && _lookup_table->is_valid (), false, + "SoftGeoMapper(%s) set loop up table failed in data allocation", + XCAM_STR (get_name ())); + + for (uint32_t i = 0; i < height; ++i) { + Float2 *ret = _lookup_table->get_buf_ptr (0, i); + const PointFloat2 *line = &data[i * width]; + for (uint32_t j = 0; j < width; ++j) { + ret[j].x = line [j].x; + ret[j].y = line [j].y; + } + } + return true; +} + +XCamReturn +SoftGeoMapper::remap ( + const SmartPtr<VideoBuffer> &in, + SmartPtr<VideoBuffer> &out_buf) +{ + SmartPtr<ImageHandler::Parameters> param = new ImageHandler::Parameters (in, out_buf); + XCamReturn ret = execute_buffer (param, true); + if (xcam_ret_is_ok (ret) && !out_buf.ptr ()) { + out_buf = param->out_buf; + } + return ret; +} + +XCamReturn +SoftGeoMapper::configure_resource (const SmartPtr<Parameters> ¶m) +{ + XCAM_FAIL_RETURN( + ERROR, _lookup_table.ptr () && _lookup_table->is_valid (), XCAM_RETURN_ERROR_PARAM, + "SoftGeoMapper(%s) configure failed, look_up_table was not set correctly", + XCAM_STR (get_name ())); + + const VideoBufferInfo &in_info = param->in_buf->get_video_info (); + XCAM_FAIL_RETURN ( + ERROR, in_info.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM, + "SoftGeoMapper(:%s) only support format(NV12) but input format is %s", + XCAM_STR(get_name ()), xcam_fourcc_to_string (in_info.format)); + + Float2 factors; + get_factors (factors.x, factors.y); + if (XCAM_DOUBLE_EQUAL_AROUND (factors.x, 0.0f) || + XCAM_DOUBLE_EQUAL_AROUND (factors.y, 0.0f)) { + auto_calculate_factors (_lookup_table->get_width (), _lookup_table->get_height ()); + } + + uint32_t width, height; + get_output_size (width, height); + VideoBufferInfo out_info; + out_info.init ( + in_info.format, width, height, + XCAM_ALIGN_UP (width, XCAM_GEO_MAP_ALIGNMENT_X), + XCAM_ALIGN_UP (height, XCAM_GEO_MAP_ALIGNMENT_Y)); + set_out_video_info (out_info); + + XCAM_ASSERT (!_map_task.ptr ()); + _map_task = new XCamSoftTasks::GeoMapTask (new CbGeoMapTask(this)); + XCAM_ASSERT (_map_task.ptr ()); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +SoftGeoMapper::start_remap_task (const SmartPtr<ImageHandler::Parameters> ¶m) +{ + XCAM_ASSERT (_map_task.ptr ()); + XCAM_ASSERT (_lookup_table.ptr ()); + + Float2 factors; + get_factors (factors.x, factors.y); + + SmartPtr<VideoBuffer> in_buf = param->in_buf, out_buf = param->out_buf; + SmartPtr<XCamSoftTasks::GeoMapTask::Args> args = new XCamSoftTasks::GeoMapTask::Args (param); + args->in_luma = new UcharImage (in_buf, 0); + args->in_uv = new Uchar2Image (in_buf, 1); + args->out_luma = new UcharImage (out_buf, 0); + args->out_uv = new Uchar2Image (out_buf, 1); + args->lookup_table = _lookup_table; + args->factors = factors; + + uint32_t thread_x = 2, thread_y = 2; + WorkSize work_unit = _map_task->get_work_uint (); + WorkSize global_size ( + xcam_ceil (args->out_luma->get_width (), work_unit.value[0]) / work_unit.value[0], + xcam_ceil (args->out_luma->get_height (), work_unit.value[1]) / work_unit.value[1]); + WorkSize local_size ( + xcam_ceil(global_size.value[0], thread_x) / thread_x , + xcam_ceil(global_size.value[1], thread_y) / thread_y); + + _map_task->set_local_size (local_size); + _map_task->set_global_size (global_size); + + param->in_buf.release (); + return _map_task->work (args); +} + +XCamReturn +SoftGeoMapper::start_work (const SmartPtr<ImageHandler::Parameters> ¶m) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (param->out_buf.ptr ()); + + ret = start_remap_task (param); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "geo_mapper:%s start_work failed on idx0", XCAM_STR (get_name ())); + + param->in_buf.release (); + + return ret; +}; + +XCamReturn +SoftGeoMapper::terminate () +{ + if (_map_task.ptr ()) { + _map_task->stop (); + _map_task.release (); + } + return SoftHandler::terminate (); +} + +void +SoftGeoMapper::remap_task_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error) +{ + XCAM_UNUSED (worker); + XCAM_ASSERT (worker.ptr () == _map_task.ptr ()); + SmartPtr<XCamSoftTasks::GeoMapTask::Args> args = base.dynamic_cast_ptr<XCamSoftTasks::GeoMapTask::Args> (); + XCAM_ASSERT (args.ptr ()); + const SmartPtr<ImageHandler::Parameters> param = args->get_param (); + + if (!check_work_continue (param, error)) + return; + + work_well_done (param, error); +} + +SmartPtr<SoftHandler> create_soft_geo_mapper () +{ + SmartPtr<SoftHandler> mapper = new SoftGeoMapper (); + XCAM_ASSERT (mapper.ptr ()); + return mapper; +} + +SmartPtr<GeoMapper> +GeoMapper::create_soft_geo_mapper () +{ + SmartPtr<SoftHandler> handler = XCam::create_soft_geo_mapper (); + return handler.dynamic_cast_ptr<GeoMapper> (); +} + +} diff --git a/modules/soft/soft_geo_mapper.h b/modules/soft/soft_geo_mapper.h new file mode 100644 index 0000000..c0370d3 --- /dev/null +++ b/modules/soft/soft_geo_mapper.h @@ -0,0 +1,71 @@ +/* + * soft_geo_mapper.h - soft geometry map class + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_SOFT_GEO_MAP_H +#define XCAM_SOFT_GEO_MAP_H + +#include <xcam_std.h> +#include <interface/geo_mapper.h> +#include <soft/soft_handler.h> +#include <soft/soft_image.h> + +namespace XCam { + +namespace XCamSoftTasks { +class GeoMapTask; +}; + +class SoftGeoMapper + : public SoftHandler, public GeoMapper +{ +public: + SoftGeoMapper (const char *name = "SoftGeoMap"); + ~SoftGeoMapper (); + + bool set_lookup_table (const PointFloat2 *data, uint32_t width, uint32_t height); + + //derived from SoftHandler + virtual XCamReturn terminate (); + + void remap_task_done ( + const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &args, const XCamReturn error); + +protected: + //derived from interface + XCamReturn remap ( + const SmartPtr<VideoBuffer> &in, + SmartPtr<VideoBuffer> &out_buf); + + //derived from SoftHandler + XCamReturn configure_resource (const SmartPtr<Parameters> ¶m); + XCamReturn start_work (const SmartPtr<Parameters> ¶m); + +private: + XCamReturn start_remap_task (const SmartPtr<ImageHandler::Parameters> ¶m); + +private: + SmartPtr<XCamSoftTasks::GeoMapTask> _map_task; + SmartPtr<Float2Image> _lookup_table; +}; + +extern SmartPtr<SoftHandler> create_soft_geo_mapper (); +} + +#endif //XCAM_SOFT_GEO_MAP_H diff --git a/modules/soft/soft_geo_tasks_priv.cpp b/modules/soft/soft_geo_tasks_priv.cpp new file mode 100644 index 0000000..8079352 --- /dev/null +++ b/modules/soft/soft_geo_tasks_priv.cpp @@ -0,0 +1,116 @@ +/* + * soft_geo_tasks_priv.cpp - soft geometry map tasks + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "soft_geo_tasks_priv.h" + +namespace XCam { + +namespace XCamSoftTasks { + +XCamReturn +GeoMapTask::work_range (const SmartPtr<Arguments> &base, const WorkRange &range) +{ + static const Uchar zero_luma_byte[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + static const Uchar2 zero_uv_byte[4] = {{128, 128}, {128, 128}, {128, 128}, {128, 128}}; + SmartPtr<GeoMapTask::Args> args = base.dynamic_cast_ptr<GeoMapTask::Args> (); + XCAM_ASSERT (args.ptr ()); + UcharImage *in_luma = args->in_luma.ptr (), *out_luma = args->out_luma.ptr (); + Uchar2Image *in_uv = args->in_uv.ptr (), *out_uv = args->out_uv.ptr (); + Float2Image *lut = args->lookup_table.ptr (); + XCAM_ASSERT (in_luma && in_uv); + XCAM_ASSERT (out_luma && out_uv); + XCAM_ASSERT (lut); + + Float2 factors = args->factors; + XCAM_ASSERT ( + !XCAM_DOUBLE_EQUAL_AROUND (factors.x, 0.0f) && + !XCAM_DOUBLE_EQUAL_AROUND (factors.y, 0.0f)); + + Float2 out_center ((out_luma->get_width () - 1.0f ) / 2.0f, (out_luma->get_height () - 1.0f ) / 2.0f); + Float2 lut_center ((lut->get_width () - 1.0f) / 2.0f, (lut->get_height () - 1.0f) / 2.0f); + float x_step = 1.0f / factors.x; + float y_step = 1.0f / factors.y; + +#undef OUT_BOUND +#define OUT_BOUND(image, first, last) \ + (in_pos[first].x >= image->get_width ()) || \ + (in_pos[first].y >= image->get_height ()) || \ + (in_pos[last].x <= 0.0f) || (in_pos[last].y <= 0.0f) + + for (uint32_t y = range.pos[1]; y < range.pos[1] + range.pos_len[1]; ++y) + for (uint32_t x = range.pos[0]; x < range.pos[0] + range.pos_len[0]; ++x) + { + // calculate 8x2 luma, center aligned + Float2 in_pos[8]; + float luma_value[8]; + Uchar luma_uc[8]; + uint32_t out_x = x * 8, out_y = y * 2; + + //1st-line luma + Float2 out_pos (out_x, out_y); + out_pos -= out_center; + Float2 first = out_pos / factors; + first += lut_center; + Float2 lut_pos[8] = { + first, Float2(first.x + x_step, first.y), + Float2(first.x + x_step * 2, first.y), Float2(first.x + x_step * 3, first.y), + Float2(first.x + x_step * 4, first.y), Float2(first.x + x_step * 5, first.y), + Float2(first.x + x_step * 6, first.y), Float2(first.x + x_step * 7, first.y) + }; + lut->read_interpolate_array<Float2, 8> (lut_pos, in_pos); + in_luma->read_interpolate_array<float, 8> (in_pos, luma_value); + convert_to_uchar_N<float, 8> (luma_value, luma_uc); + if (OUT_BOUND (in_luma, 0, 7)) + out_luma->write_array_no_check<8> (out_x, out_y, zero_luma_byte); + else + out_luma->write_array_no_check<8> (out_x, out_y, luma_uc); + + //4x1 UV + Float2 uv_value[4]; + Uchar2 uv_uc[4]; + in_pos[0] /= 2.0f; + in_pos[1] = in_pos[2] / 2.0f; + in_pos[2] = in_pos[4] / 2.0f; + in_pos[3] = in_pos[6] / 2.0f; + in_uv->read_interpolate_array<Float2, 4> (in_pos, uv_value); + convert_to_uchar2_N<Float2, 4> (uv_value, uv_uc); + if (OUT_BOUND (in_uv, 0, 3)) + out_uv->write_array_no_check<4> (x * 4, y, zero_uv_byte); + else + out_uv->write_array_no_check<4> (x * 4, y, uv_uc); + + //2nd-line luma + lut_pos[0].y = lut_pos[1].y = lut_pos[2].y = lut_pos[3].y = lut_pos[4].y = lut_pos[5].y = + lut_pos[6].y = lut_pos[7].y = first.y + y_step; + lut->read_interpolate_array<Float2, 8> (lut_pos, in_pos); + in_luma->read_interpolate_array<float, 8> (in_pos, luma_value); + convert_to_uchar_N<float, 8> (luma_value, luma_uc); + if (OUT_BOUND (in_luma, 0, 7)) + out_luma->write_array_no_check<8> (out_x, out_y + 1, zero_luma_byte); + else + out_luma->write_array_no_check<8> (out_x, out_y + 1, luma_uc); + } + return XCAM_RETURN_NO_ERROR; +} + +} + +} + diff --git a/modules/soft/soft_geo_tasks_priv.h b/modules/soft/soft_geo_tasks_priv.h new file mode 100644 index 0000000..36514b2 --- /dev/null +++ b/modules/soft/soft_geo_tasks_priv.h @@ -0,0 +1,59 @@ +/* + * soft_geo_tasks_priv.h - soft geometry map tasks + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include <xcam_std.h> +#include <soft/soft_worker.h> +#include <soft/soft_image.h> +#include <soft/soft_handler.h> + +namespace XCam { + +namespace XCamSoftTasks { + +class GeoMapTask + : public SoftWorker +{ +public: + struct Args : SoftArgs { + SmartPtr<UcharImage> in_luma, out_luma; + SmartPtr<Uchar2Image> in_uv, out_uv; + SmartPtr<Float2Image> lookup_table; + Float2 factors; + + Args ( + const SmartPtr<ImageHandler::Parameters> ¶m) + : SoftArgs (param) + {} + }; + +public: + explicit GeoMapTask (const SmartPtr<Worker::Callback> &cb) + : SoftWorker ("GeoMapTask", cb) + { + set_work_uint (8, 2); + } + +private: + virtual XCamReturn work_range (const SmartPtr<Arguments> &args, const WorkRange &range); +}; + +} + +} diff --git a/modules/soft/soft_handler.cpp b/modules/soft/soft_handler.cpp new file mode 100644 index 0000000..6a81472 --- /dev/null +++ b/modules/soft/soft_handler.cpp @@ -0,0 +1,332 @@ +/* + * soft_handler.cpp - soft image handler implementation + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "soft_handler.h" +#include "soft_video_buf_allocator.h" +#include "thread_pool.h" +#include "soft_worker.h" + +#define DEFAULT_SOFT_BUF_COUNT 4 + +namespace XCam { + +class SyncMeta + : public MetaBase +{ +public: + SyncMeta () + : _done (false) + , _error (XCAM_RETURN_NO_ERROR) {} + void signal_done (XCamReturn err); + void wakeup (); + XCamReturn signal_wait_ret (); + bool is_error () const; + +private: + mutable Mutex _mutex; + Cond _cond; + bool _done; + XCamReturn _error; +}; + +void +SyncMeta::signal_done (XCamReturn err) +{ + SmartLock locker (_mutex); + _done = true; + _error = err; + _cond.broadcast (); +} + +void +SyncMeta::wakeup () +{ + SmartLock locker (_mutex); + _error = XCAM_RETURN_ERROR_UNKNOWN; + _cond.broadcast (); +} + +XCamReturn +SyncMeta::signal_wait_ret () +{ + SmartLock locker (_mutex); + if (_done) + return _error; + _cond.wait (_mutex); + return _error; +} + +bool +SyncMeta::is_error () const +{ + SmartLock locker (_mutex); + return !xcam_ret_is_ok (_error); +} + +SoftHandler::SoftHandler (const char* name) + : ImageHandler (name) + , _need_configure (true) + , _enable_allocator (true) + , _wip_buf_count (0) +{ +} + +SoftHandler::~SoftHandler () +{ +} + +bool +SoftHandler::set_threads (const SmartPtr<ThreadPool> &pool) +{ + _threads = pool; + return true; +} + +bool +SoftHandler::set_out_video_info (const VideoBufferInfo &info) +{ + XCAM_ASSERT (info.width && info.height && info.format); + _out_video_info = info; + return true; +} + +bool +SoftHandler::enable_allocator (bool enable) +{ + _enable_allocator = enable; + return true; +} + +XCamReturn +SoftHandler::confirm_configured () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (_need_configure); + if (_enable_allocator) { + XCAM_FAIL_RETURN ( + ERROR, _out_video_info.is_valid (), XCAM_RETURN_ERROR_PARAM, + "soft_hander(%s) configure resource failed before reserver buffer since out video info was not set", + XCAM_STR (get_name ())); + + set_allocator (new SoftVideoBufAllocator); + ret = reserve_buffers (_out_video_info, DEFAULT_SOFT_BUF_COUNT); + XCAM_FAIL_RETURN ( + ERROR, ret == XCAM_RETURN_NO_ERROR, ret, + "soft_hander(%s) configure resource failed in reserving buffers", XCAM_STR (get_name ())); + } + + if (_threads.ptr () && !_threads->is_running ()) { + ret = _threads->start (); + XCAM_FAIL_RETURN ( + ERROR, ret == XCAM_RETURN_NO_ERROR, ret, + "soft_hander(%s) configure resource failed when starting threads", XCAM_STR (get_name ())); + } + _need_configure = false; + + return ret; +} + +XCamReturn +SoftHandler::execute_buffer (const SmartPtr<ImageHandler::Parameters> ¶m, bool sync) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<SyncMeta> sync_meta; + + XCAM_FAIL_RETURN ( + ERROR, param.ptr (), XCAM_RETURN_ERROR_PARAM, + "soft_hander(%s) execute buffer failed, params is null", + XCAM_STR (get_name ())); + + if (_need_configure) { + ret = configure_resource (param); + XCAM_FAIL_RETURN ( + WARNING, xcam_ret_is_ok (ret), ret, + "soft_hander(%s) configure resource failed", XCAM_STR (get_name ())); + + ret = confirm_configured (); + XCAM_FAIL_RETURN ( + WARNING, xcam_ret_is_ok (ret), ret, + "soft_hander(%s) confirm configure failed", XCAM_STR (get_name ())); + } + + if (!param->out_buf.ptr () && _enable_allocator) { + param->out_buf = get_free_buf (); + XCAM_FAIL_RETURN ( + ERROR, param->out_buf.ptr (), XCAM_RETURN_ERROR_PARAM, + "soft_hander:%s execute buffer failed, output buffer failed in allocation.", + XCAM_STR (get_name ())); + } + + XCAM_ASSERT (!param->find_meta<SyncMeta> ().ptr ()); + sync_meta = new SyncMeta (); + XCAM_ASSERT (sync_meta.ptr ()); + param->add_meta (sync_meta); + +#if 0 + SmartPtr<SoftWorker> worker = get_first_worker ().dynamic_cast_ptr<SoftWorker> (); + XCAM_FAIL_RETURN ( + WARNING, worker.ptr (), XCAM_RETURN_ERROR_PARAM, + "No worder set to soft_hander(%s)", XCAM_STR (get_name ())); + + SmartPtr<Worker::Arguments> args = get_first_worker_args (worker, params); + XCAM_FAIL_RETURN ( + WARNING, args.ptr (), XCAM_RETURN_ERROR_PARAM, + "soft_hander(%s) get first worker(%s) args failed", + XCAM_STR (get_name ()), XCAM_STR (worker->get_name ())); + + _params.push (params); + ret = worker->work (args); +#else + _params.push (param); + ret = start_work (param); +#endif + + if (!xcam_ret_is_ok (ret)) { + _params.erase (param); + XCAM_LOG_WARNING ("soft_hander(%s) execute buffer failed in starting workers", XCAM_STR (get_name ())); + return ret; + } + + ++_wip_buf_count; + _cur_sync = sync_meta; + + if (sync) { + XCAM_ASSERT (sync_meta.ptr ()); + ret = sync_meta->signal_wait_ret (); + _cur_sync.release (); + } + + return ret; +} + +XCamReturn +SoftHandler::finish () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<SyncMeta> sync = _cur_sync; + if (sync.ptr ()) { + ret = sync->signal_wait_ret (); + } + XCAM_ASSERT (_params.is_empty ()); + //wait for _wip_buf_count = 0 + //if (ret == XCAM_RETURN_NO_ERROR) + // XCAM_ASSERT (_wip_buf_count == 0); + + return ret; +} + +XCamReturn +SoftHandler::terminate () +{ + SmartPtr<SyncMeta> sync = _cur_sync; + if (sync.ptr ()) { + sync->wakeup (); + sync.release (); + } + _params.clear (); + return ImageHandler::terminate (); +} + +void +SoftHandler::work_well_done (const SmartPtr<ImageHandler::Parameters> ¶m, XCamReturn err) +{ + XCAM_ASSERT (param.ptr ()); + XCAM_ASSERT (xcam_ret_is_ok (err)); + + if (!xcam_ret_is_ok (err)) { + XCAM_LOG_WARNING ("soft_hander(%s) work_well_done but errno(%d) is not ok", XCAM_STR (get_name ()), (int)err); + //continue work + } + + if (!_params.erase (param)) { + XCAM_LOG_ERROR( + "soft_hander(%s) last_work_done param already removed, who removed it?", XCAM_STR (get_name ())); + return; + } + + XCAM_LOG_DEBUG ("soft_hander(%s) work well done", XCAM_STR (get_name ())); + + param_ended (param, err); +} + +void +SoftHandler::work_broken (const SmartPtr<ImageHandler::Parameters> ¶m, XCamReturn err) +{ + XCAM_ASSERT (param.ptr ()); + XCAM_ASSERT (!xcam_ret_is_ok (err)); + + if (xcam_ret_is_ok (err)) { + XCAM_LOG_WARNING ("soft_hander(%s) work_broken but the errno(%d) is ok", XCAM_STR (get_name ()), (int)err); + //continue work + } + + if (!_params.erase (param)) { + //already removed by other handlers + return; + } + XCAM_LOG_WARNING ("soft_hander(%s) work broken", XCAM_STR (get_name ())); + + param_ended (param, err); +} + +void +SoftHandler::param_ended (SmartPtr<ImageHandler::Parameters> param, XCamReturn err) +{ + XCAM_ASSERT (param.ptr ()); + + SmartPtr<SyncMeta> sync_meta = param->find_meta<SyncMeta> (); + XCAM_ASSERT (sync_meta.ptr ()); + sync_meta->signal_done (err); + --_wip_buf_count; + execute_status_check (param, err); +} + +bool +SoftHandler::check_work_continue (const SmartPtr<ImageHandler::Parameters> ¶m, XCamReturn err) +{ + if (!xcam_ret_is_ok (err)) { + work_broken (param, err); + return false; + } + + if (is_param_error (param)) { + XCAM_LOG_WARNING ( + "soft_handler(%s) check_work_continue found param broken", XCAM_STR(get_name ())); + return false; + } + return true; +} + +bool +SoftHandler::is_param_error (const SmartPtr<ImageHandler::Parameters> ¶m) +{ + XCAM_ASSERT (param.ptr ()); + SmartPtr<SyncMeta> meta = param->find_meta<SyncMeta> (); + if (!meta.ptr ()) { // return ok if param not set + XCAM_ASSERT (meta.ptr ()); + return false; + } + + return meta->is_error (); +} + +} + diff --git a/modules/soft/soft_handler.h b/modules/soft/soft_handler.h new file mode 100644 index 0000000..e2041bf --- /dev/null +++ b/modules/soft/soft_handler.h @@ -0,0 +1,98 @@ +/* + * soft_handler.h - soft image handler class + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_SOFT_HANDLER_H +#define XCAM_SOFT_HANDLER_H + +#include <xcam_std.h> +#include <image_handler.h> +#include <video_buffer.h> +#include <worker.h> + +namespace XCam { + +class SoftHandler; +class ThreadPool; +class SyncMeta; +class SoftWorker; + +struct SoftArgs + : Worker::Arguments +{ +private: + SmartPtr<ImageHandler::Parameters> _param; +public: + explicit SoftArgs (const SmartPtr<ImageHandler::Parameters> ¶m = NULL) : _param (param) {} + inline const SmartPtr<ImageHandler::Parameters> &get_param () const { + return _param; + } + inline void set_param (const SmartPtr<ImageHandler::Parameters> ¶m) { + _param = param; + XCAM_ASSERT (param.ptr ()); + } +}; + +class SoftHandler + : public ImageHandler +{ +public: + explicit SoftHandler (const char* name); + ~SoftHandler (); + + bool set_threads (const SmartPtr<ThreadPool> &pool); + bool set_out_video_info (const VideoBufferInfo &info); + bool enable_allocator (bool enable); + + // derive from ImageHandler + virtual XCamReturn execute_buffer (const SmartPtr<Parameters> ¶m, bool sync); + virtual XCamReturn finish (); + virtual XCamReturn terminate (); + +protected: + virtual XCamReturn configure_resource (const SmartPtr<Parameters> ¶m) = 0; + virtual XCamReturn start_work (const SmartPtr<Parameters> ¶m) = 0; + //virtual SmartPtr<Worker::Arguments> get_first_worker_args (const SmartPtr<SoftWorker> &worker, SmartPtr<Parameters> ¶ms) = 0; + virtual void work_well_done (const SmartPtr<ImageHandler::Parameters> ¶m, XCamReturn err); + virtual void work_broken (const SmartPtr<ImageHandler::Parameters> ¶m, XCamReturn err); + + //directly usage + bool check_work_continue (const SmartPtr<ImageHandler::Parameters> ¶m, XCamReturn err); + +private: + XCamReturn confirm_configured (); + void param_ended (SmartPtr<ImageHandler::Parameters> param, XCamReturn err); + static bool is_param_error (const SmartPtr<ImageHandler::Parameters> ¶m); + +private: + XCAM_DEAD_COPY (SoftHandler); + +private: + SmartPtr<ThreadPool> _threads; + VideoBufferInfo _out_video_info; + SmartPtr<SyncMeta> _cur_sync; + bool _need_configure; + bool _enable_allocator; + SafeList<Parameters> _params; + mutable std::atomic<int32_t> _wip_buf_count; +}; + +} + +#endif //XCAM_SOFT_HANDLER_H diff --git a/modules/soft/soft_image.h b/modules/soft/soft_image.h new file mode 100644 index 0000000..4cbe4d9 --- /dev/null +++ b/modules/soft/soft_image.h @@ -0,0 +1,384 @@ +/* + * soft_image.h - soft image class + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_SOFT_IMAGE_H +#define XCAM_SOFT_IMAGE_H + +#include <xcam_std.h> +#include <video_buffer.h> +#include <vec_mat.h> +#include <file_handle.h> + +namespace XCam { + +typedef uint8_t Uchar; +typedef int8_t Char; +typedef Vector2<uint8_t> Uchar2; +typedef Vector2<int8_t> Char2; +typedef Vector2<float> Float2; +typedef Vector2<int> Int2; + +enum BorderType { + BorderTypeNearest, + BorderTypeConst, + BorderTypeRewind, +}; + +template <typename T> +class SoftImage +{ +public: + typedef T Type; +private: + uint8_t *_buf_ptr; + uint32_t _width; + uint32_t _height; + uint32_t _pitch; + + SmartPtr<VideoBuffer> _bind; + +public: + explicit SoftImage (const SmartPtr<VideoBuffer> &buf, const uint32_t plane); + explicit SoftImage ( + const uint32_t width, const uint32_t height, + uint32_t aligned_width = 0); + explicit SoftImage ( + const SmartPtr<VideoBuffer> &buf, + const uint32_t width, const uint32_t height, const uint32_t pictch, const uint32_t offset = 0); + + ~SoftImage () { + if (!_bind.ptr ()) { + xcam_free (_buf_ptr); + } + } + + uint32_t pixel_size () const { + return sizeof (T); + } + + uint32_t get_width () const { + return _width; + } + uint32_t get_height () const { + return _height; + } + uint32_t get_pitch () const { + return _pitch; + } + bool is_valid () const { + return (_buf_ptr && _width && _height); + } + + const SmartPtr<VideoBuffer> &get_bind_buf () const { + return _bind; + } + T *get_buf_ptr (int32_t x, int32_t y) { + return (T *)(_buf_ptr + y * _pitch) + x; + } + const T *get_buf_ptr (int32_t x, int32_t y) const { + return (const T *)(_buf_ptr + y * _pitch) + x; + } + + inline T read_data_no_check (int32_t x, int32_t y) const { + const T *t_ptr = (const T *)(_buf_ptr + y * _pitch); + return t_ptr[x]; + } + + inline T read_data (int32_t x, int32_t y) const { + border_check (x, y); + return read_data_no_check (x, y); + } + + template<typename O> + inline O read_interpolate_data (float x, float y) const; + + template<typename O, uint32_t N> + inline void read_interpolate_array (Float2 *pos, O *array) const; + + template<uint32_t N> + inline void read_array_no_check (const int32_t x, const int32_t y, T *array) const { + XCAM_ASSERT (N <= 8); + const T *t_ptr = ((const T *)(_buf_ptr + y * _pitch)) + x; + memcpy (array, t_ptr, sizeof (T) * N); + } + + template<typename O, uint32_t N> + inline void read_array_no_check (const int32_t x, const int32_t y, O *array) const { + XCAM_ASSERT (N <= 8); + const T *t_ptr = ((const T *)(_buf_ptr + y * _pitch)) + x; + for (uint32_t i = 0; i < N; ++i) { + array[i] = t_ptr[i]; + } + } + + template<uint32_t N> + inline void read_array (int32_t x, int32_t y, T *array) const { + XCAM_ASSERT (N <= 8); + border_check_y (y); + if (x + N < _width) { + read_array_no_check<N> (x, y, array); + } else { + const T *t_ptr = ((const T *)(_buf_ptr + y * _pitch)); + for (uint32_t i = 0; i < N; ++i, ++x) { + border_check_x (x); + array[i] = t_ptr[x]; + } + } + } + + template<typename O, uint32_t N> + inline void read_array (int32_t x, int32_t y, O *array) const { + XCAM_ASSERT (N <= 8); + border_check_y (y); + const T *t_ptr = ((const T *)(_buf_ptr + y * _pitch)); + for (uint32_t i = 0; i < N; ++i, ++x) { + border_check_x (x); + array[i] = t_ptr[x]; + } + } + + inline void write_data (int32_t x, int32_t y, const T &v) { + if (x < 0 || x >= (int32_t)_width) + return; + if (y < 0 || y >= (int32_t)_height) + return; + write_data_no_check (x, y, v); + } + + inline void write_data_no_check (int32_t x, int32_t y, const T &v) { + T *t_ptr = (T *)(_buf_ptr + y * _pitch); + t_ptr[x] = v; + } + + template<uint32_t N> + inline void write_array_no_check (int32_t x, int32_t y, const T *array) { + T *t_ptr = (T *)(_buf_ptr + y * _pitch); + memcpy (t_ptr + x, array, sizeof (T) * N); + } + + template<uint32_t N> + inline void write_array (int32_t x, int32_t y, const T *array) { + if (y < 0 || y >= (int32_t)_height) + return; + + if (x >= 0 && x + N <= _width) { + write_array_no_check<N> (x, y, array); + } else { + T *t_ptr = ((T *)(_buf_ptr + y * _pitch)); + for (uint32_t i = 0; i < N; ++i, ++x) { + if (x < 0 || x >= (int32_t)_width) continue; + t_ptr[x] = array[i]; + } + } + } + +private: + inline void border_check_x (int32_t &x) const { + if (x < 0) x = 0; + else if (x >= (int32_t)_width) x = (int32_t)(_width - 1); + } + + inline void border_check_y (int32_t &y) const { + if (y < 0) y = 0; + else if (y >= (int32_t)_height) y = (int32_t)(_height - 1); + } + + inline void border_check (int32_t &x, int32_t &y) const { + border_check_x (x); + border_check_y (y); + } +}; + + +template <typename T> +SoftImage<T>::SoftImage (const SmartPtr<VideoBuffer> &buf, const uint32_t plane) + : _buf_ptr (NULL) + , _width (0) , _height (0) , _pitch (0) +{ + XCAM_ASSERT (buf.ptr ()); + const VideoBufferInfo &info = buf->get_video_info (); + VideoBufferPlanarInfo planar; + if (!info.get_planar_info(planar, plane)) { + XCAM_LOG_ERROR ( + "videobuf to soft image failed. buf format:%s, plane:%d", xcam_fourcc_to_string (info.format), plane); + return; + } + _buf_ptr = buf->map () + info.offsets[plane]; + XCAM_ASSERT (_buf_ptr); + _pitch = info.strides[plane]; + _height = planar.height; + _width = planar.pixel_bytes * planar.width / sizeof (T); + XCAM_ASSERT (_width * sizeof(T) == planar.pixel_bytes * planar.width); + _bind = buf; +} + +template <typename T> +SoftImage<T>::SoftImage ( + const uint32_t width, const uint32_t height, uint32_t aligned_width) + : _buf_ptr (NULL) + , _width (0) , _height (0) , _pitch (0) +{ + if (!aligned_width) + aligned_width = width; + + XCAM_ASSERT (aligned_width >= width); + XCAM_ASSERT (width > 0 && height > 0); + _pitch = aligned_width * sizeof (T); + _buf_ptr = (uint8_t *)xcam_malloc (_pitch * height); + XCAM_ASSERT (_buf_ptr); + _width = width; + _height = height; +} + +template <typename T> +SoftImage<T>::SoftImage ( + const SmartPtr<VideoBuffer> &buf, + const uint32_t width, const uint32_t height, const uint32_t pictch, const uint32_t offset) + : _buf_ptr (NULL) + , _width (width) , _height (height) + , _pitch (pictch) + , _bind (buf) +{ + XCAM_ASSERT (buf.ptr ()); + XCAM_ASSERT (buf->map ()); + _buf_ptr = buf->map () + offset; +} + +template <typename T> +inline Uchar convert_to_uchar (const T& v) { + if (v < 0.0f) return 0; + else if (v > 255.0f) return 255; + return (Uchar)(v + 0.5f); +} + +template <typename T, uint32_t N> +inline void convert_to_uchar_N (const T *in, Uchar *out) { + for (uint32_t i = 0; i < N; ++i) { + out[i] = convert_to_uchar<T> (in[i]); + } +} + +template <typename Vec2> +inline Uchar2 convert_to_uchar2 (const Vec2& v) { + return Uchar2 (convert_to_uchar(v.x), convert_to_uchar(v.y)); +} + +template <typename Vec2, uint32_t N> +inline void convert_to_uchar2_N (const Vec2 *in, Uchar2 *out) { + for (uint32_t i = 0; i < N; ++i) { + out[i].x = convert_to_uchar (in[i].x); + out[i].y = convert_to_uchar (in[i].y); + } +} + +typedef SoftImage<Uchar> UcharImage; +typedef SoftImage<Uchar2> Uchar2Image; +typedef SoftImage<float> FloatImage; +typedef SoftImage<Float2> Float2Image; + +template <class SoftImageT> +class SoftImageFile + : public FileHandle +{ +public: + SoftImageFile () {} + explicit SoftImageFile (const char *name, const char *option) + : FileHandle (name, option) + {} + + inline XCamReturn read_buf (const SmartPtr<SoftImageT> &buf); + inline XCamReturn write_buf (const SmartPtr<SoftImageT> &buf); +}; + +template <class SoftImageT> +inline XCamReturn +SoftImageFile<SoftImageT>::read_buf (const SmartPtr<SoftImageT> &buf) +{ + XCAM_FAIL_RETURN ( + WARNING, is_valid (), XCAM_RETURN_ERROR_PARAM, + "soft image file(%s) read buf failed, file is not open", XCAM_STR (get_file_name ())); + + XCAM_FAIL_RETURN ( + WARNING, buf->is_valid (), XCAM_RETURN_ERROR_PARAM, + "soft image file(%s) read buf failed, buf is not valid", XCAM_STR (get_file_name ())); + + XCAM_ASSERT (is_valid ()); + uint32_t height = buf->get_height (); + uint32_t line_bytes = buf->get_width () * buf->pixel_size (); + + for (uint32_t index = 0; index < height; index++) { + uint8_t *line_ptr = buf->get_buf_ptr (0, index); + XCAM_FAIL_RETURN ( + WARNING, fread (line_ptr, 1, line_bytes, _fp) == line_bytes, XCAM_RETURN_ERROR_FILE, + "soft image file(%s) read buf failed, image_line:%d", XCAM_STR (get_file_name ()), index); + } + return XCAM_RETURN_NO_ERROR; +} + +template <class SoftImageT> +inline XCamReturn +SoftImageFile<SoftImageT>::write_buf (const SmartPtr<SoftImageT> &buf) +{ + XCAM_FAIL_RETURN ( + WARNING, is_valid (), XCAM_RETURN_ERROR_PARAM, + "soft image file(%s) write buf failed, file is not open", XCAM_STR (get_file_name ())); + + XCAM_FAIL_RETURN ( + WARNING, buf->is_valid (), XCAM_RETURN_ERROR_PARAM, + "soft image file(%s) write buf failed, buf is not valid", XCAM_STR (get_file_name ())); + + XCAM_ASSERT (is_valid ()); + uint32_t height = buf->get_height (); + uint32_t line_bytes = buf->get_width () * buf->pixel_size (); + + for (uint32_t index = 0; index < height; index++) { + uint8_t *line_ptr = buf->get_buf_ptr (0, index); + XCAM_FAIL_RETURN ( + WARNING, fwrite (line_ptr, 1, line_bytes, _fp) == line_bytes, XCAM_RETURN_ERROR_FILE, + "soft image file(%s) write buf failed, image_line:%d", XCAM_STR (get_file_name ()), index); + } + return XCAM_RETURN_NO_ERROR; +} + +template <typename T> template <typename O> +O +SoftImage<T>::read_interpolate_data (float x, float y) const +{ + int32_t x0 = (int32_t)(x), y0 = (int32_t)(y); + float a = x - x0, b = y - y0; + O l0[2], l1[2]; + read_array<O, 2> (x0, y0, l0); + read_array<O, 2> (x0, y0 + 1, l1); + + return l1[1] * (a * b) + l0[0] * ((1 - a) * (1 - b)) + + l1[0] * ((1 - a) * b) + l0[1] * (a * (1 - b)); +} + +template <typename T> template<typename O, uint32_t N> +void +SoftImage<T>::read_interpolate_array (Float2 *pos, O *array) const +{ + for (uint32_t i = 0; i < N; ++i) { + array[i] = read_interpolate_data<O> (pos[i].x, pos[i].y); + } +} + +} +#endif //XCAM_SOFT_IMAGE_H diff --git a/modules/soft/soft_stitcher.cpp b/modules/soft/soft_stitcher.cpp new file mode 100644 index 0000000..42f0c93 --- /dev/null +++ b/modules/soft/soft_stitcher.cpp @@ -0,0 +1,961 @@ +/* + * soft_stitcher.cpp - soft stitcher implementation + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "soft_stitcher.h" +#include "soft_blender.h" +#include "soft_geo_mapper.h" +#include "soft_video_buf_allocator.h" +#include "interface/feature_match.h" +#include "surview_fisheye_dewarp.h" +#include "soft_copy_task.h" +#include "xcam_utils.h" +#include <map> + +#define ENABLE_FEATURE_MATCH HAVE_OPENCV + +#if ENABLE_FEATURE_MATCH +#include "cv_capi_feature_match.h" +#ifndef ANDROID +#include <opencv2/core/ocl.hpp> +#endif +#endif + +#define SOFT_STITCHER_ALIGNMENT_X 8 +#define SOFT_STITCHER_ALIGNMENT_Y 4 + +#define MAP_FACTOR_X 16 +#define MAP_FACTOR_Y 16 + +#define DUMP_STITCHER 0 + +namespace XCam { + +#if DUMP_STITCHER +static void +stitcher_dump_buf (const SmartPtr<VideoBuffer> buf, uint32_t idx, const char *prefix) +{ + XCAM_ASSERT (prefix); + char name[256]; + snprintf (name, 256, "%s-%d", prefix, idx); + dump_buf_perfix_path (buf, name); +} +#else +static void stitcher_dump_buf (const SmartPtr<VideoBuffer> buf, ...) { + XCAM_UNUSED (buf); +} +#endif + + +namespace SoftSitcherPriv { + +DECLARE_HANDLER_CALLBACK (CbGeoMap, SoftStitcher, dewarp_done); +DECLARE_HANDLER_CALLBACK (CbBlender, SoftStitcher, blender_done); +DECLARE_WORK_CALLBACK (CbCopyTask, SoftStitcher, copy_task_done); + +struct BlenderParam + : SoftBlender::BlenderParam +{ + SmartPtr<SoftStitcher::StitcherParam> stitch_param; + uint32_t idx; + + BlenderParam ( + uint32_t i, + const SmartPtr<VideoBuffer> &in0, + const SmartPtr<VideoBuffer> &in1, + const SmartPtr<VideoBuffer> &out) + : SoftBlender::BlenderParam (in0, in1, out) + , idx (i) + {} +}; + +typedef std::map<void*, SmartPtr<BlenderParam>> BlenderParams; +typedef std::map<void*, int32_t> BlendCopyTaskNums; + +struct HandlerParam + : ImageHandler::Parameters +{ + SmartPtr<SoftStitcher::StitcherParam> stitch_param; + uint32_t idx; + + HandlerParam (uint32_t i) + : idx (i) + {} +}; + +struct StitcherCopyArgs + : XCamSoftTasks::CopyTask::Args +{ + uint32_t idx; + + StitcherCopyArgs ( + uint32_t i, + const SmartPtr<ImageHandler::Parameters> ¶m) + : XCamSoftTasks::CopyTask::Args (param) + , idx (i) + {} +}; + +struct Factor { + float x, y; + + Factor () : x (1.0f), y (1.0f) {} + void reset () { + x = 1.0f; + y = 1.0f; + } +}; + +struct Overlap { + SmartPtr<FeatureMatch> matcher; + SmartPtr<SoftBlender> blender; + BlenderParams param_map; + + SmartPtr<BlenderParam> find_blender_param_in_map ( + const SmartPtr<SoftStitcher::StitcherParam> &key, + const uint32_t idx); +}; + +struct FisheyeDewarp { + SmartPtr<SoftGeoMapper> dewarp; + SmartPtr<BufferPool> buf_pool; + Factor left_match_factor, right_match_factor; + + bool set_dewarp_factor (); + XCamReturn set_dewarp_geo_table ( + SmartPtr<SoftGeoMapper> mapper, + const CameraInfo &cam_info, + const Stitcher::RoundViewSlice &view_slice, + const BowlDataConfig &bowl); +}; + +struct Copier { + SmartPtr<XCamSoftTasks::CopyTask> copy_task; + Stitcher::CopyArea copy_area; + + XCamReturn start_copy_task ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const uint32_t idx, const SmartPtr<VideoBuffer> &buf); +}; +typedef std::vector<Copier> Copiers; + +class StitcherImpl { + friend class XCam::SoftStitcher; + +public: + StitcherImpl (SoftStitcher *handler) + : _stitcher (handler) + {} + + XCamReturn init_config (uint32_t count); + + bool remove_task_count (const SmartPtr<SoftStitcher::StitcherParam> ¶m); + int32_t dec_task_count (const SmartPtr<SoftStitcher::StitcherParam> ¶m); + + XCamReturn start_dewarp_works (const SmartPtr<SoftStitcher::StitcherParam> ¶m); + XCamReturn start_task_count (const SmartPtr<SoftStitcher::StitcherParam> ¶m); + XCamReturn start_overlap_tasks ( + const SmartPtr<SoftStitcher::StitcherParam> ¶m, + const uint32_t idx, const SmartPtr<VideoBuffer> &buf); + XCamReturn start_copy_tasks ( + const SmartPtr<SoftStitcher::StitcherParam> ¶m, + const uint32_t idx, const SmartPtr<VideoBuffer> &buf); + + XCamReturn start_single_blender (const uint32_t idx, const SmartPtr<BlenderParam> ¶m); + XCamReturn stop (); + + XCamReturn fisheye_dewarp_to_table (); + XCamReturn feature_match ( + const SmartPtr<VideoBuffer> &left_buf, + const SmartPtr<VideoBuffer> &right_buf, + const uint32_t idx); + + bool get_and_reset_feature_match_factors (uint32_t idx, Factor &left, Factor &right); + +private: + XCamReturn init_fisheye (uint32_t idx); + bool init_dewarp_factors (uint32_t idx); + XCamReturn create_copier (Stitcher::CopyArea area); + +private: + FisheyeDewarp _fisheye [XCAM_STITCH_MAX_CAMERAS]; + Overlap _overlaps [XCAM_STITCH_MAX_CAMERAS]; + Copiers _copiers; + SmartPtr<BufferPool> _dewarp_pool; + + Mutex _map_mutex; + BlendCopyTaskNums _task_counts; + + SoftStitcher *_stitcher; +}; + +bool +StitcherImpl::init_dewarp_factors (uint32_t idx) +{ + XCAM_FAIL_RETURN ( + ERROR, _fisheye[idx].dewarp.ptr (), false, + "FisheyeDewarp dewarp handler empty"); + + Factor match_left_factor, match_right_factor; + get_and_reset_feature_match_factors (idx, match_left_factor, match_right_factor); + + Factor unify_factor, last_left_factor, last_right_factor; + _fisheye[idx].dewarp->get_factors (unify_factor.x, unify_factor.y); + last_left_factor = last_right_factor = unify_factor; + if (XCAM_DOUBLE_EQUAL_AROUND (unify_factor.x, 0.0f) || + XCAM_DOUBLE_EQUAL_AROUND (unify_factor.y, 0.0f)) { // not started. + return true; + } + + Factor cur_left, cur_right; + cur_left.x = last_left_factor.x * match_left_factor.x; + cur_left.y = last_left_factor.y * match_left_factor.y; + cur_right.x = last_right_factor.x * match_right_factor.x; + cur_right.y = last_right_factor.y * match_right_factor.y; + + unify_factor.x = (cur_left.x + cur_right.x) / 2.0f; + unify_factor.y = (cur_left.y + cur_right.y) / 2.0f; + _fisheye[idx].dewarp->set_factors (unify_factor.x, unify_factor.y); + + return true; +} + +XCamReturn +FisheyeDewarp::set_dewarp_geo_table ( + SmartPtr<SoftGeoMapper> mapper, + const CameraInfo &cam_info, + const Stitcher::RoundViewSlice &view_slice, + const BowlDataConfig &bowl) +{ + PolyFisheyeDewarp fd; + fd.set_intrinsic_param (cam_info.calibration.intrinsic); + fd.set_extrinsic_param (cam_info.calibration.extrinsic); + + uint32_t table_width, table_height; + table_width = view_slice.width / MAP_FACTOR_X; + table_width = XCAM_ALIGN_UP (table_width, 4); + table_height = view_slice.height / MAP_FACTOR_Y; + table_height = XCAM_ALIGN_UP (table_height, 2); + SurViewFisheyeDewarp::MapTable map_table(table_width * table_height); + fd.fisheye_dewarp ( + map_table, table_width, table_height, + view_slice.width, view_slice.height, bowl); + + XCAM_FAIL_RETURN ( + ERROR, mapper->set_lookup_table (map_table.data (), table_width, table_height), + XCAM_RETURN_ERROR_UNKNOWN, "set fisheye dewarp lookup table failed"); + return XCAM_RETURN_NO_ERROR; +} + +bool +StitcherImpl::get_and_reset_feature_match_factors (uint32_t idx, Factor &left, Factor &right) +{ + uint32_t cam_num = _stitcher->get_camera_num (); + XCAM_FAIL_RETURN ( + ERROR, idx < cam_num, false, + "get dewarp factor failed, idx(%d) > camera_num(%d)", idx, cam_num); + + SmartLock locker (_map_mutex); + left = _fisheye[idx].left_match_factor; + right = _fisheye[idx].right_match_factor; + + _fisheye[idx].left_match_factor.reset (); + _fisheye[idx].right_match_factor.reset (); + return true; +} + +XCamReturn +StitcherImpl::init_fisheye (uint32_t idx) +{ + FisheyeDewarp &fisheye = _fisheye[idx]; + SmartPtr<ImageHandler::Callback> dewarp_cb = new CbGeoMap (_stitcher); + fisheye.dewarp = new SoftGeoMapper ("sitcher_remapper"); + XCAM_ASSERT (fisheye.dewarp.ptr ()); + fisheye.dewarp->set_callback (dewarp_cb); + + Stitcher::RoundViewSlice view_slice = + _stitcher->get_round_view_slice (idx); + + VideoBufferInfo buf_info; + buf_info.init ( + V4L2_PIX_FMT_NV12, view_slice.width, view_slice.height, + XCAM_ALIGN_UP (view_slice.width, SOFT_STITCHER_ALIGNMENT_X), + XCAM_ALIGN_UP (view_slice.height, SOFT_STITCHER_ALIGNMENT_Y)); + + fisheye.buf_pool = new SoftVideoBufAllocator (buf_info); + XCAM_ASSERT (fisheye.buf_pool.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, fisheye.buf_pool->reserve (2), XCAM_RETURN_ERROR_MEM, + "stitcher:%s reserve dewarp buffer pool(w:%d,h:%d) failed", + XCAM_STR (_stitcher->get_name ()), buf_info.width, buf_info.height); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::create_copier (Stitcher::CopyArea area) +{ + XCAM_FAIL_RETURN ( + ERROR, + area.in_idx != INVALID_INDEX && + area.in_area.width == area.out_area.width && area.in_area.height == area.out_area.height, + XCAM_RETURN_ERROR_PARAM, + "stitcher: copy area (idx:%d) is invalid", area.in_idx); + + SmartPtr<Worker::Callback> copy_cb = new CbCopyTask (_stitcher); + XCAM_ASSERT (copy_cb.ptr ()); + + Copier copier; + copier.copy_task = new XCamSoftTasks::CopyTask (copy_cb); + XCAM_ASSERT (copier.copy_task.ptr ()); + copier.copy_area = area; + _copiers.push_back (copier); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::init_config (uint32_t count) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + SmartPtr<ImageHandler::Callback> blender_cb = new CbBlender (_stitcher); + for (uint32_t i = 0; i < count; ++i) { + ret = init_fisheye (i); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "stitcher:%s init fisheye failed, idx:%d.", XCAM_STR (_stitcher->get_name ()), i); + +#if ENABLE_FEATURE_MATCH + _overlaps[i].matcher = new CVCapiFeatureMatch; + + CVFMConfig config; + config.sitch_min_width = 136; + config.min_corners = 4; + config.offset_factor = 0.8f; + config.delta_mean_offset = 120.0f; + config.recur_offset_error = 8.0f; + config.max_adjusted_offset = 24.0f; + config.max_valid_offset_y = 20.0f; +#ifndef ANDROID + config.max_track_error = 28.0f; +#else + config.max_track_error = 3600.0f; +#endif + _overlaps[i].matcher->set_config (config); + _overlaps[i].matcher->set_fm_index (i); +#endif + + _overlaps[i].blender = create_soft_blender ().dynamic_cast_ptr<SoftBlender>(); + XCAM_ASSERT (_overlaps[i].blender.ptr ()); + _overlaps[i].blender->set_callback (blender_cb); + _overlaps[i].param_map.clear (); + } + + Stitcher::CopyAreaArray areas = _stitcher->get_copy_area (); + uint32_t size = areas.size (); + for (uint32_t i = 0; i < size; ++i) { + XCAM_LOG_DEBUG ("soft-stitcher:copy area (idx:%d) input area(%d, %d, %d, %d) output area(%d, %d, %d, %d)", + areas[i].in_idx, + areas[i].in_area.pos_x, areas[i].in_area.pos_y, areas[i].in_area.width, areas[i].in_area.height, + areas[i].out_area.pos_x, areas[i].out_area.pos_y, areas[i].out_area.width, areas[i].out_area.height); + + XCAM_ASSERT (areas[i].in_idx < size); + ret = create_copier (areas[i]); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "soft-stitcher::%s init copier failed, idx:%d.", XCAM_STR (_stitcher->get_name ()), i); + } + + return XCAM_RETURN_NO_ERROR; +} + +bool +StitcherImpl::remove_task_count (const SmartPtr<SoftStitcher::StitcherParam> ¶m) +{ + XCAM_ASSERT (param.ptr ()); + SmartLock locker (_map_mutex); + BlendCopyTaskNums::iterator i = _task_counts.find (param.ptr ()); + if (i == _task_counts.end ()) + return false; + + _task_counts.erase (i); + return true; +} + +int32_t +StitcherImpl::dec_task_count (const SmartPtr<SoftStitcher::StitcherParam> ¶m) +{ + XCAM_ASSERT (param.ptr ()); + SmartLock locker (_map_mutex); + BlendCopyTaskNums::iterator i = _task_counts.find (param.ptr ()); + if (i == _task_counts.end ()) + return -1; + + int32_t &count = i->second; + --count; + if (count > 0) + return count; + + XCAM_ASSERT (count == 0); + _task_counts.erase (i); + return 0; +} + +XCamReturn +StitcherImpl::fisheye_dewarp_to_table () +{ + uint32_t camera_num = _stitcher->get_camera_num (); + for (uint32_t i = 0; i < camera_num; ++i) { + CameraInfo cam_info; + _stitcher->get_camera_info (i, cam_info); + Stitcher::RoundViewSlice view_slice = _stitcher->get_round_view_slice (i); + + BowlDataConfig bowl = _stitcher->get_bowl_config (); + bowl.angle_start = view_slice.hori_angle_start; + bowl.angle_end = format_angle (view_slice.hori_angle_start + view_slice.hori_angle_range); + + uint32_t out_width, out_height; + _stitcher->get_output_size (out_width, out_height); + + _fisheye[i].dewarp->set_output_size (view_slice.width, view_slice.height); + if (bowl.angle_end < bowl.angle_start) + bowl.angle_start -= 360.0f; + XCAM_LOG_INFO ( + "soft-stitcher:%s camera(idx:%d) info (angle start:%.2f, range:%.2f), bowl info (angle start%.2f, end:%.2f)", + XCAM_STR (_stitcher->get_name ()), i, + view_slice.hori_angle_start, view_slice.hori_angle_range, + bowl.angle_start, bowl.angle_end); + XCamReturn ret = _fisheye[i].set_dewarp_geo_table (_fisheye[i].dewarp, cam_info, view_slice, bowl); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "stitcher:%s set dewarp geo table failed, idx:%d.", XCAM_STR (_stitcher->get_name ()), i); + + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::start_dewarp_works (const SmartPtr<SoftStitcher::StitcherParam> ¶m) +{ + uint32_t camera_num = _stitcher->get_camera_num (); + Factor cur_left, cur_right; + + for (uint32_t i = 0; i < camera_num; ++i) { + SmartPtr<VideoBuffer> out_buf = _fisheye[i].buf_pool->get_buffer (); + SmartPtr<HandlerParam> dewarp_params = new HandlerParam (i); + dewarp_params->in_buf = param->in_bufs[i]; + dewarp_params->out_buf = out_buf; + dewarp_params->stitch_param = param; + + init_dewarp_factors (i); + XCamReturn ret = _fisheye[i].dewarp->execute_buffer (dewarp_params, false); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "soft-stitcher:%s fisheye dewarp buffer failed", XCAM_STR (_stitcher->get_name ())); + } + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<BlenderParam> +Overlap::find_blender_param_in_map ( + const SmartPtr<SoftStitcher::StitcherParam> &key, + const uint32_t idx) +{ + SmartPtr<BlenderParam> param; + BlenderParams::iterator i = param_map.find (key.ptr ()); + if (i == param_map.end ()) { + param = new BlenderParam (idx, NULL, NULL, NULL); + XCAM_ASSERT (param.ptr ()); + param->stitch_param = key; + param_map.insert (std::make_pair ((void*)key.ptr (), param)); + } else { + param = (*i).second; + } + + return param; +} + +XCamReturn +StitcherImpl::feature_match ( + const SmartPtr<VideoBuffer> &left_buf, + const SmartPtr<VideoBuffer> &right_buf, + const uint32_t idx) +{ + const Stitcher::ImageOverlapInfo overlap_info = _stitcher->get_overlap (idx); + Rect left_ovlap = overlap_info.left; + Rect right_ovlap = overlap_info.right; + const VideoBufferInfo left_buf_info = left_buf->get_video_info (); + + left_ovlap.pos_y = left_ovlap.height / 5; + left_ovlap.height = left_ovlap.height / 2; + right_ovlap.pos_y = right_ovlap.height / 5; + right_ovlap.height = right_ovlap.height / 2; + + _overlaps[idx].matcher->reset_offsets (); + _overlaps[idx].matcher->optical_flow_feature_match ( + left_buf, right_buf, left_ovlap, right_ovlap, left_buf_info.width); + float left_offsetx = _overlaps[idx].matcher->get_current_left_offset_x (); + Factor left_factor, right_factor; + + uint32_t left_idx = idx; + float center_x = (float) _stitcher->get_center (left_idx).slice_center_x; + float feature_center_x = (float)left_ovlap.pos_x + (left_ovlap.width / 2.0f); + float range = feature_center_x - center_x; + XCAM_ASSERT (range > 1.0f); + right_factor.x = (range + left_offsetx / 2.0f) / range; + right_factor.y = 1.0; + XCAM_ASSERT (right_factor.x > 0.0f && right_factor.x < 2.0f); + + uint32_t right_idx = (idx + 1) % _stitcher->get_camera_num (); + center_x = (float) _stitcher->get_center (right_idx).slice_center_x; + feature_center_x = (float)right_ovlap.pos_x + (right_ovlap.width / 2.0f); + range = center_x - feature_center_x; + XCAM_ASSERT (range > 1.0f); + left_factor.x = (range + left_offsetx / 2.0f) / range; + left_factor.y = 1.0; + XCAM_ASSERT (left_factor.x > 0.0f && left_factor.x < 2.0f); + + { + SmartLock locker (_map_mutex); + _fisheye[left_idx].right_match_factor = right_factor; + _fisheye[right_idx].left_match_factor = left_factor; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::start_single_blender ( + const uint32_t idx, + const SmartPtr<BlenderParam> ¶m) +{ + SmartPtr<SoftBlender> blender = _overlaps[idx].blender; + const Stitcher::ImageOverlapInfo &overlap_info = _stitcher->get_overlap (idx); + uint32_t out_width, out_height; + _stitcher->get_output_size (out_width, out_height); + + blender->set_output_size (out_width, out_height); + blender->set_merge_window (overlap_info.out_area); + blender->set_input_valid_area (overlap_info.left, 0); + blender->set_input_valid_area (overlap_info.right, 1); + blender->set_input_merge_area (overlap_info.left, 0); + blender->set_input_merge_area (overlap_info.right, 1); + return blender->execute_buffer (param, false); +} + +XCamReturn +StitcherImpl::start_overlap_tasks ( + const SmartPtr<SoftStitcher::StitcherParam> ¶m, + const uint32_t idx, const SmartPtr<VideoBuffer> &buf) +{ + SmartPtr<BlenderParam> cur_param, prev_param; + const uint32_t camera_num = _stitcher->get_camera_num (); + uint32_t pre_idx = (idx + camera_num - 1) % camera_num; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + { + SmartPtr<BlenderParam> param_b; + + SmartLock locker (_map_mutex); + param_b = _overlaps[idx].find_blender_param_in_map (param, idx); + param_b->in_buf = buf; + if (param_b->in_buf.ptr () && param_b->in1_buf.ptr ()) { + cur_param = param_b; + _overlaps[idx].param_map.erase (param.ptr ()); + } + + param_b = _overlaps[pre_idx].find_blender_param_in_map (param, pre_idx); + param_b->in1_buf = buf; + if (param_b->in_buf.ptr () && param_b->in1_buf.ptr ()) { + prev_param = param_b; + _overlaps[pre_idx].param_map.erase (param.ptr ()); + } + } + + if (cur_param.ptr ()) { + cur_param->out_buf = param->out_buf; + ret = start_single_blender (idx, cur_param); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "soft-stitcher:%s blend overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), idx); + } + + if (prev_param.ptr ()) { + prev_param->out_buf = param->out_buf; + ret = start_single_blender (pre_idx, prev_param); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "soft-stitcher:%s blend overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), pre_idx); + } + +#if ENABLE_FEATURE_MATCH + //start feature match + if (cur_param.ptr ()) { + ret = feature_match (cur_param->in_buf, cur_param->in1_buf, idx); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "soft-stitcher:%s feature-match overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), idx); + } + + if (prev_param.ptr ()) { + ret = feature_match (prev_param->in_buf, prev_param->in1_buf, pre_idx); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "soft-stitcher:%s feature-match overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), pre_idx); + } +#endif + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +Copier::start_copy_task ( + const SmartPtr<ImageHandler::Parameters> ¶m, + const uint32_t idx, const SmartPtr<VideoBuffer> &buf) +{ + XCAM_ASSERT (copy_task.ptr ()); + + SmartPtr<VideoBuffer> in_buf = buf, out_buf = param->out_buf; + const VideoBufferInfo &in_info = in_buf->get_video_info (); + const VideoBufferInfo &out_info = out_buf->get_video_info (); + + SmartPtr<StitcherCopyArgs> args = new StitcherCopyArgs (idx, param); + args->in_luma = new UcharImage ( + in_buf, copy_area.in_area.width, copy_area.in_area.height, in_info.strides[0], + in_info.offsets[0] + copy_area.in_area.pos_x + copy_area.in_area.pos_y * in_info.strides[0]); + args->in_uv = new Uchar2Image ( + in_buf, copy_area.in_area.width / 2, copy_area.in_area.height / 2, in_info.strides[0], + in_info.offsets[1] + copy_area.in_area.pos_x + copy_area.in_area.pos_y / 2 * in_info.strides[1]); + + args->out_luma = new UcharImage ( + out_buf, copy_area.out_area.width, copy_area.out_area.height, out_info.strides[0], + out_info.offsets[0] + copy_area.out_area.pos_x + copy_area.out_area.pos_y * out_info.strides[0]); + args->out_uv = new Uchar2Image ( + out_buf, copy_area.out_area.width / 2, copy_area.out_area.height / 2, out_info.strides[0], + out_info.offsets[1] + copy_area.out_area.pos_x + copy_area.out_area.pos_y / 2 * out_info.strides[1]); + + uint32_t thread_x = 1, thread_y = 4; + WorkSize global_size (1, xcam_ceil (copy_area.in_area.height, 2) / 2); + WorkSize local_size ( + xcam_ceil (global_size.value[0], thread_x) / thread_x, + xcam_ceil (global_size.value[1], thread_y) / thread_y); + + copy_task->set_local_size (local_size); + copy_task->set_global_size (global_size); + + return copy_task->work (args); +} + +XCamReturn +StitcherImpl::start_copy_tasks ( + const SmartPtr<SoftStitcher::StitcherParam> ¶m, + const uint32_t idx, const SmartPtr<VideoBuffer> &buf) +{ + uint32_t size = _stitcher->get_copy_area ().size (); + for (uint32_t i = 0; i < size; ++i) { + if(_copiers[i].copy_area.in_idx == idx) { + XCamReturn ret = _copiers[i].start_copy_task (param, idx, buf); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "soft-stitcher:%s start copy task failed, idx:%d", XCAM_STR (_stitcher->get_name ()), idx); + } + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +StitcherImpl::stop () +{ + uint32_t cam_num = _stitcher->get_camera_num (); + for (uint32_t i = 0; i < cam_num; ++i) { + if (_fisheye[i].dewarp.ptr ()) { + _fisheye[i].dewarp->terminate (); + _fisheye[i].dewarp.release (); + } + if (_fisheye[i].buf_pool.ptr ()) { + _fisheye[i].buf_pool->stop (); + } + + if (_overlaps[i].blender.ptr ()) { + _overlaps[i].blender->terminate (); + _overlaps[i].blender.release (); + } + } + + for (Copiers::iterator i_copy = _copiers.begin (); i_copy != _copiers.end (); ++i_copy) { + Copier © = *i_copy; + if (copy.copy_task.ptr ()) { + copy.copy_task->stop (); + copy.copy_task.release (); + } + } + + if (_dewarp_pool.ptr ()) { + _dewarp_pool->stop (); + } + return XCAM_RETURN_NO_ERROR; +} + +}; + +SoftStitcher::SoftStitcher (const char *name) + : SoftHandler (name) + , Stitcher (SOFT_STITCHER_ALIGNMENT_X, SOFT_STITCHER_ALIGNMENT_Y) +{ + _impl = new SoftSitcherPriv::StitcherImpl (this); + XCAM_ASSERT (_impl.ptr ()); +#if ENABLE_FEATURE_MATCH +#ifndef ANDROID + cv::ocl::setUseOpenCL (false); +#endif +#endif +} + +SoftStitcher::~SoftStitcher () +{ +} + +XCamReturn +SoftStitcher::stitch_buffers (const VideoBufferList &in_bufs, SmartPtr<VideoBuffer> &out_buf) +{ + XCAM_FAIL_RETURN ( + ERROR, !in_bufs.empty (), XCAM_RETURN_ERROR_PARAM, + "soft-stitcher:%s stitch buffer failed, in_bufs is empty", XCAM_STR (get_name ())); + + SmartPtr<StitcherParam> param = new StitcherParam; + param->out_buf = out_buf; + uint32_t count = 0; + for (VideoBufferList::const_iterator i = in_bufs.begin(); i != in_bufs.end (); ++i) { + SmartPtr<VideoBuffer> buf = *i; + XCAM_ASSERT (buf.ptr ()); + param->in_bufs[count++] = buf; + } + param->in_buf_num = count; + XCamReturn ret = execute_buffer (param, true); + if (!out_buf.ptr () && xcam_ret_is_ok (ret)) { + out_buf = param->out_buf; + } + return ret; +} + +XCamReturn +SoftStitcher::terminate () +{ + _impl->stop (); + return SoftHandler::terminate (); +} + +XCamReturn +SoftStitcher::start_task_count (const SmartPtr<SoftStitcher::StitcherParam> ¶m) +{ + XCAM_ASSERT (param.ptr ()); + XCAM_ASSERT (_impl.ptr ()); + + SmartLock locker (_impl->_map_mutex); + + XCAM_FAIL_RETURN ( + ERROR, check_work_continue (param, XCAM_RETURN_NO_ERROR), XCAM_RETURN_ERROR_PARAM, + "soft-stitcher:%s start task count failed in work check", XCAM_STR (get_name ())); + + if (_impl->_task_counts.find (param.ptr ()) != _impl->_task_counts.end ()) { + XCAM_LOG_ERROR ("tasks already started, this should never happen."); + return XCAM_RETURN_ERROR_UNKNOWN; + } + + int32_t count = get_camera_num (); + count += get_copy_area ().size (); + + XCAM_LOG_DEBUG ("stitcher :%s start task count :%d", XCAM_STR(get_name ()), count); + _impl->_task_counts.insert (std::make_pair((void*)param.ptr(), count)); + return XCAM_RETURN_NO_ERROR; +} + +void +SoftStitcher::dewarp_done ( + const SmartPtr<ImageHandler> &handler, + const SmartPtr<ImageHandler::Parameters> &base, + const XCamReturn error) +{ + SmartPtr<SoftSitcherPriv::HandlerParam> dewarp_param = base.dynamic_cast_ptr<SoftSitcherPriv::HandlerParam> (); + XCAM_ASSERT (dewarp_param.ptr ()); + SmartPtr<SoftStitcher::StitcherParam> param = dewarp_param->stitch_param; + XCAM_ASSERT (param.ptr ()); + XCAM_UNUSED (handler); + + if (!check_work_continue (param, error)) + return; + + XCAM_LOG_INFO ("soft-stitcher:%s camera(idx:%d) dewarp done", XCAM_STR (get_name ()), dewarp_param->idx); + stitcher_dump_buf (dewarp_param->out_buf, dewarp_param->idx, "stitcher-dewarp"); + + //start both blender and feature match + XCamReturn ret = _impl->start_overlap_tasks (param, dewarp_param->idx, dewarp_param->out_buf); + if (!xcam_ret_is_ok (ret)) { + work_broken (param, ret); + } + + ret = _impl->start_copy_tasks (param, dewarp_param->idx, dewarp_param->out_buf); + if (!xcam_ret_is_ok (ret)) { + work_broken (param, ret); + } +} + +void +SoftStitcher::blender_done ( + const SmartPtr<ImageHandler> &handler, + const SmartPtr<ImageHandler::Parameters> &base, + const XCamReturn error) +{ + SmartPtr<SoftSitcherPriv::BlenderParam> blender_param = base.dynamic_cast_ptr<SoftSitcherPriv::BlenderParam> (); + XCAM_ASSERT (blender_param.ptr ()); + SmartPtr<SoftStitcher::StitcherParam> param = blender_param->stitch_param; + XCAM_ASSERT (param.ptr ()); + XCAM_UNUSED (handler); + + if (!check_work_continue (param, error)) { + _impl->remove_task_count (param); + return; + } + + stitcher_dump_buf (blender_param->out_buf, blender_param->idx, "stitcher-blend"); + XCAM_LOG_INFO ("blender:(%s) overlap:%d done", XCAM_STR (handler->get_name ()), blender_param->idx); + + if (_impl->dec_task_count (param) == 0) { + work_well_done (param, error); + } +} + +void +SoftStitcher::copy_task_done ( + const SmartPtr<Worker> &worker, + const SmartPtr<Worker::Arguments> &base, + const XCamReturn error) +{ + XCAM_UNUSED (worker); + XCAM_ASSERT (worker.ptr ()); + SmartPtr<SoftSitcherPriv::StitcherCopyArgs> args = base.dynamic_cast_ptr<SoftSitcherPriv::StitcherCopyArgs> (); + XCAM_ASSERT (args.ptr ()); + const SmartPtr<SoftStitcher::StitcherParam> param = + args->get_param ().dynamic_cast_ptr<SoftStitcher::StitcherParam> (); + XCAM_ASSERT (param.ptr ()); + + if (!check_work_continue (param, error)) { + _impl->remove_task_count (param); + return; + } + XCAM_LOG_INFO ("soft-stitcher:%s camera(idx:%d) copy done", XCAM_STR (get_name ()), args->idx); + + if (_impl->dec_task_count (param) == 0) { + work_well_done (param, error); + } +} + +XCamReturn +SoftStitcher::configure_resource (const SmartPtr<Parameters> ¶m) +{ + XCAM_UNUSED (param); + XCAM_ASSERT (_impl.ptr ()); + + XCamReturn ret = estimate_round_slices (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "soft-stitcher:%s estimate round view slices failed", XCAM_STR (get_name ())); + + ret = estimate_coarse_crops (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "soft-stitcher:%s estimate coarse crops failed", XCAM_STR (get_name ())); + + ret = mark_centers (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "soft-stitcher:%s mark centers failed", XCAM_STR (get_name ())); + + ret = estimate_overlap (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "soft-stitcher:%s estimake coarse overlap failed", XCAM_STR (get_name ())); + + ret = update_copy_areas (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "soft-stitcher:%s update copy areas failed", XCAM_STR (get_name ())); + + uint32_t camera_count = get_camera_num (); + ret = _impl->init_config (camera_count); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "soft-stitcher:%s initialize private config failed", XCAM_STR (get_name ())); + + ret = _impl->fisheye_dewarp_to_table (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "soft-stitcher:%s fisheye_dewarp_to_table failed", XCAM_STR (get_name ())); + + VideoBufferInfo out_info; + uint32_t out_width, out_height; + get_output_size (out_width, out_height); + XCAM_FAIL_RETURN ( + ERROR, out_width && out_height, XCAM_RETURN_ERROR_PARAM, + "soft-stitcher:%s output size was not set", XCAM_STR(get_name ())); + + out_info.init ( + V4L2_PIX_FMT_NV12, out_width, out_height, + XCAM_ALIGN_UP (out_width, SOFT_STITCHER_ALIGNMENT_X), + XCAM_ALIGN_UP (out_height, SOFT_STITCHER_ALIGNMENT_Y)); + set_out_video_info (out_info); + + return ret; +} + +XCamReturn +SoftStitcher::start_work (const SmartPtr<Parameters> &base) +{ + SmartPtr<StitcherParam> param = base.dynamic_cast_ptr<StitcherParam> (); + + XCAM_FAIL_RETURN ( + ERROR, param.ptr () && param->in_buf_num > 0 && param->in_bufs[0].ptr (), XCAM_RETURN_ERROR_PARAM, + "soft_stitcher:%s start_work failed, params(in_buf_num) in_bufs are set", + XCAM_STR (get_name ())); + + XCamReturn ret = start_task_count (param); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), XCAM_RETURN_ERROR_PARAM, + "soft_stitcher:%s start blender count failed", XCAM_STR (get_name ())); + + ret = _impl->start_dewarp_works (param); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), XCAM_RETURN_ERROR_PARAM, + "soft_stitcher:%s start dewarp works failed", XCAM_STR (get_name ())); + + //for (uint32_t i = 0; i < param->in_buf_num; ++i) { + // param->in_bufs[i].release (); + //} + + return ret; +} + +SmartPtr<Stitcher> +Stitcher::create_soft_stitcher () +{ + return new SoftStitcher; +} + +} + diff --git a/modules/soft/soft_stitcher.h b/modules/soft/soft_stitcher.h new file mode 100644 index 0000000..fd5b4a5 --- /dev/null +++ b/modules/soft/soft_stitcher.h @@ -0,0 +1,94 @@ +/* + * soft_stitcher.h - soft stitcher class + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_SOFT_STITCHER_H +#define XCAM_SOFT_STITCHER_H + +#include <xcam_std.h> +#include <interface/stitcher.h> +#include <soft/soft_handler.h> + +namespace XCam { + +namespace SoftSitcherPriv { +class StitcherImpl; +class CbGeoMap; +class CbBlender; +class CbCopyTask; +}; + +class SoftStitcher + : public SoftHandler + , public Stitcher +{ + friend class SoftSitcherPriv::StitcherImpl; + friend class SoftSitcherPriv::CbGeoMap; + friend class SoftSitcherPriv::CbBlender; + friend class SoftSitcherPriv::CbCopyTask; + +public: + struct StitcherParam + : ImageHandler::Parameters + { + uint32_t in_buf_num; + SmartPtr<VideoBuffer> in_bufs[XCAM_STITCH_MAX_CAMERAS]; + + StitcherParam () + : Parameters (NULL, NULL) + , in_buf_num (0) + {} + }; + +public: + explicit SoftStitcher (const char *name = "SoftStitcher"); + ~SoftStitcher (); + + //derived from SoftHandler + virtual XCamReturn terminate (); + +protected: + // interface derive from Stitcher + XCamReturn stitch_buffers (const VideoBufferList &in_bufs, SmartPtr<VideoBuffer> &out_buf); + + //derived from SoftHandler + XCamReturn configure_resource (const SmartPtr<Parameters> ¶m); + XCamReturn start_work (const SmartPtr<Parameters> ¶m); + +private: + // handler done, call back functions + XCamReturn start_task_count ( + const SmartPtr<SoftStitcher::StitcherParam> ¶m); + void dewarp_done ( + const SmartPtr<ImageHandler> &handler, + const SmartPtr<ImageHandler::Parameters> ¶m, const XCamReturn error); + void blender_done ( + const SmartPtr<ImageHandler> &handler, + const SmartPtr<ImageHandler::Parameters> ¶m, const XCamReturn error); + void copy_task_done ( + const SmartPtr<Worker> &worker, + const SmartPtr<Worker::Arguments> &base, const XCamReturn error); + +private: + SmartPtr<SoftSitcherPriv::StitcherImpl> _impl; +}; + +} + +#endif //XCAM_SOFT_STITCHER_H diff --git a/modules/soft/soft_video_buf_allocator.cpp b/modules/soft/soft_video_buf_allocator.cpp new file mode 100644 index 0000000..79cc869 --- /dev/null +++ b/modules/soft/soft_video_buf_allocator.cpp @@ -0,0 +1,101 @@ +/* + * soft_video_buf_allocator.cpp - soft video buffer allocator implementation + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "soft_video_buf_allocator.h" + +namespace XCam { + +class VideoMemData + : public BufferData +{ +public: + explicit VideoMemData (uint32_t size); + virtual ~VideoMemData (); + bool is_valid () const { + return (_mem_ptr ? true : false); + } + + //derive from BufferData + virtual uint8_t *map (); + virtual bool unmap (); + +private: + uint8_t *_mem_ptr; + uint32_t _mem_size; +}; + +VideoMemData::VideoMemData (uint32_t size) + : _mem_ptr (NULL) + , _mem_size (0) +{ + XCAM_ASSERT (size > 0); + _mem_ptr = xcam_malloc_type_array (uint8_t, size); + if (_mem_ptr) + _mem_size = size; +} + +VideoMemData::~VideoMemData () +{ + xcam_free (_mem_ptr); +} + +uint8_t * +VideoMemData::map () +{ + XCAM_ASSERT (_mem_ptr); + return _mem_ptr; +} + +bool +VideoMemData::unmap () +{ + return true; +} + +SoftVideoBufAllocator::SoftVideoBufAllocator () +{ +} + +SoftVideoBufAllocator::SoftVideoBufAllocator (const VideoBufferInfo &info) +{ + set_video_info (info); +} + +SoftVideoBufAllocator::~SoftVideoBufAllocator () +{ +} + +SmartPtr<BufferData> +SoftVideoBufAllocator::allocate_data (const VideoBufferInfo &buffer_info) +{ + XCAM_FAIL_RETURN ( + ERROR, buffer_info.size, NULL, + "SoftVideoBufAllocator allocate data failed. buf_size is zero"); + + SmartPtr<VideoMemData> data = new VideoMemData (buffer_info.size); + XCAM_FAIL_RETURN ( + ERROR, data.ptr () && data->is_valid (), NULL, + "SoftVideoBufAllocator allocate data failed. buf_size:%d", buffer_info.size); + + return data; +} + +} + diff --git a/modules/soft/soft_video_buf_allocator.h b/modules/soft/soft_video_buf_allocator.h new file mode 100644 index 0000000..ecf0d4a --- /dev/null +++ b/modules/soft/soft_video_buf_allocator.h @@ -0,0 +1,57 @@ +/* + * soft_video_buf_allocator.h - soft video buffer allocator class + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_SOFT_VIDEO_BUF_ALLOCATOR_H +#define XCAM_SOFT_VIDEO_BUF_ALLOCATOR_H + +#include <xcam_std.h> +#include <buffer_pool.h> + +namespace XCam { + +class SoftVideoBufAllocator + : public BufferPool +{ +public: + explicit SoftVideoBufAllocator (); + explicit SoftVideoBufAllocator (const VideoBufferInfo &info); + virtual ~SoftVideoBufAllocator (); + +private: + //derive from BufferPool + virtual SmartPtr<BufferData> allocate_data (const VideoBufferInfo &buffer_info); +}; + +#if 0 +class AllocatorPool { +public: + explicit AllocatorPool (); + virtual ~AllocatorPool (); + + SmartPtr<VideoBuffer> allocate_video_buf (const VideoBufferInfo &info); + +private: + SafeList<BufferPool> _pools; +}; +#endif + +} + +#endif //XCAM_SOFT_VIDEO_BUF_ALLOCATOR_H diff --git a/modules/soft/soft_worker.cpp b/modules/soft/soft_worker.cpp new file mode 100644 index 0000000..3a76345 --- /dev/null +++ b/modules/soft/soft_worker.cpp @@ -0,0 +1,284 @@ +/* + * soft_worker.cpp - soft worker implementation + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "soft_worker.h" +#include "thread_pool.h" +#include "xcam_mutex.h" + +namespace XCam { + +class ItemSynch { +private: + mutable std::atomic<uint32_t> _remain_items; + Mutex _mutex; + XCamReturn _error; + +public: + ItemSynch (uint32_t items) + : _remain_items(items), _error (XCAM_RETURN_NO_ERROR) + {} + void update_error (XCamReturn err) { + SmartLock locker(_mutex); + _error = err; + } + XCamReturn get_error () { + SmartLock locker(_mutex); + return _error; + } + uint32_t dec() { + return --_remain_items; + } + +private: + XCAM_DEAD_COPY (ItemSynch); +}; + +class WorkItem + : public ThreadPool::UserData +{ +public: + WorkItem ( + const SmartPtr<SoftWorker> &worker, + const SmartPtr<Worker::Arguments> &args, + const WorkSize &item, + SmartPtr<ItemSynch> &sync) + : _worker (worker) + , _args (args) + , _item (item) + , _sync (sync) + { + } + virtual XCamReturn run (); + virtual void done (XCamReturn err); + + +private: + SmartPtr<SoftWorker> _worker; + SmartPtr<Worker::Arguments> _args; + WorkSize _item; + SmartPtr<ItemSynch> _sync; +}; + +XCamReturn +WorkItem::run () +{ + XCamReturn ret = _sync->get_error(); + if (!xcam_ret_is_ok (ret)) + return ret; + + ret = _worker->work_impl (_args, _item); + if (!xcam_ret_is_ok (ret)) + _sync->update_error (ret); + + return ret; +} + +void +WorkItem::done (XCamReturn err) +{ + if (_sync->dec () == 0) { + XCamReturn ret = _sync->get_error (); + if (xcam_ret_is_ok (ret)) + ret = err; + _worker->all_items_done (_args, ret); + } +} + +SoftWorker::SoftWorker (const char *name, const SmartPtr<Callback> &cb) + : Worker (name, cb) + , _global (1, 1, 1) + , _local (1, 1, 1) + , _work_unit (1, 1, 1) +{ +} + +SoftWorker::~SoftWorker () +{ +} + +bool +SoftWorker::set_work_uint (uint32_t x, uint32_t y, uint32_t z) +{ + XCAM_FAIL_RETURN ( + ERROR, x && y && z, false, + "SoftWorker(%s) set work unit failed(x:%d, y:%d, z:%d)", + XCAM_STR (get_name ()), x, y, z); + _work_unit.value[0] = x; + _work_unit.value[1] = y; + _work_unit.value[2] = z; + return true; +} + +bool +SoftWorker::set_threads (const SmartPtr<ThreadPool> &threads) +{ + XCAM_FAIL_RETURN ( + ERROR, !_threads.ptr (), false, + "SoftWorker(%s) set threads failed, it's already set before.", XCAM_STR (get_name ())); + _threads = threads; + return true; +} + +bool +SoftWorker::set_global_size (const WorkSize &size) +{ + XCAM_FAIL_RETURN ( + ERROR, size.value[0] && size.value[1] && size.value[2], false, + "SoftWorker(%s) set global size(x:%d, y:%d, z:%d) failed.", + XCAM_STR (get_name ()), size.value[0], size.value[1], size.value[2]); + + _global = size; + return true; +} + +bool +SoftWorker::set_local_size (const WorkSize &size) +{ + XCAM_FAIL_RETURN ( + ERROR, size.value[0] && size.value[1] && size.value[2], false, + "SoftWorker(%s) set local size(x:%d, y:%d, z:%d) failed.", + XCAM_STR (get_name ()), size.value[0], size.value[1], size.value[2]); + + _local = size; + return true; +} + +XCamReturn +SoftWorker::stop () +{ + _threads->stop (); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +SoftWorker::work (const SmartPtr<Worker::Arguments> &args) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (_local.value[0] * _local.value[1] * _local.value[2]); + XCAM_ASSERT (_global.value[0] * _global.value[1] * _global.value[2]); + + WorkSize items; + uint32_t max_items = 1; + + for (uint32_t i = 0; i < SOFT_MAX_DIM; ++i) { + items.value[i] = xcam_ceil (_global.value[i], _local.value[i]) / _local.value[i]; + max_items *= items.value[i]; + } + + XCAM_FAIL_RETURN ( + ERROR, max_items, XCAM_RETURN_ERROR_PARAM, + "SoftWorker(%s) max item is zero. work failed.", XCAM_STR (get_name ())); + + if (max_items == 1) { + ret = work_impl (args, WorkSize(0, 0, 0)); + status_check (args, ret); + return ret; + } + + if (!_threads.ptr ()) { + char thr_name [XCAM_MAX_STR_SIZE]; + snprintf (thr_name, XCAM_MAX_STR_SIZE, "%s-thrs", XCAM_STR(get_name ())); + _threads = new ThreadPool (thr_name); + XCAM_ASSERT (_threads.ptr ()); + _threads->set_threads (max_items, max_items + 1); //extra thread to process all_items_done + ret = _threads->start (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "SoftWorker(%s) work failed when starting threads", XCAM_STR(get_name())); + } + + SmartPtr<ItemSynch> sync = new ItemSynch (max_items); + for (uint32_t z = 0; z < items.value[2]; ++z) + for (uint32_t y = 0; y < items.value[1]; ++y) + for (uint32_t x = 0; x < items.value[0]; ++x) + { + SmartPtr<WorkItem> item = new WorkItem (this, args, WorkSize(x, y, z), sync); + ret = _threads->queue (item); + if (!xcam_ret_is_ok (ret)) { + //consider half queued but half failed + sync->update_error (ret); + //status_check (args, ret); // need it here? + XCAM_LOG_ERROR ( + "SoftWorker(%s) queue work item(x:%d y: %d z:%d) failed", + XCAM_STR(get_name()), x, y, z); + return ret; + } + } + + return XCAM_RETURN_NO_ERROR; +} + +void +SoftWorker::all_items_done (const SmartPtr<Arguments> &args, XCamReturn error) +{ + status_check (args, error); +} + +WorkRange +SoftWorker::get_range (const WorkSize &item) +{ + WorkRange range; + for (uint32_t i = 0; i < SOFT_MAX_DIM; ++i) { + range.pos[i] = item.value[i] * _local.value[i]; + XCAM_ASSERT (range.pos[i] < _global.value[i]); + if (range.pos[i] + _local.value[i] > _global.value[i]) + range.pos_len[i] = _global.value[i] - range.pos[i]; + else + range.pos_len[i] = _local.value[i]; + } + return range; +} + +XCamReturn +SoftWorker::work_impl (const SmartPtr<Arguments> &args, const WorkSize &item) +{ + WorkRange range = get_range (item); + return work_range (args, range); +} + +XCamReturn +SoftWorker::work_range (const SmartPtr<Arguments> &args, const WorkRange &range) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + WorkSize unit; + memcpy(unit.value, range.pos, sizeof (unit.value)); + + for (unit.value[2] = range.pos[2]; unit.value[2] < range.pos[2] + range.pos_len[2]; ++unit.value[2]) + for (unit.value[1] = range.pos[1]; unit.value[1] < range.pos[1] + range.pos_len[1]; ++unit.value[1]) + for (unit.value[0] = range.pos[0]; unit.value[0] < range.pos[0] + range.pos_len[0]; ++unit.value[0]) { + ret = work_unit (args, unit); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "SoftWorker(%s) work on pixel(x:%d y: %d z:%d) failed", + get_name (), unit.value[0], unit.value[1], unit.value[2]); + } + + return ret; +} + +XCamReturn +SoftWorker::work_unit (const SmartPtr<Arguments> &, const WorkSize &) +{ + XCAM_LOG_ERROR ("SoftWorker(%s) work_pixel was not derived. check code"); + return XCAM_RETURN_ERROR_PARAM; +} + +}; diff --git a/modules/soft/soft_worker.h b/modules/soft/soft_worker.h new file mode 100644 index 0000000..a851893 --- /dev/null +++ b/modules/soft/soft_worker.h @@ -0,0 +1,100 @@ +/* + * soft_worker.h - soft worker class + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_SOFT_WORKER_H +#define XCAM_SOFT_WORKER_H + +#include <xcam_std.h> +#include <worker.h> + +#define SOFT_MAX_DIM 3 + +namespace XCam { + +class ThreadPool; + +struct WorkRange { + uint32_t pos[SOFT_MAX_DIM]; + uint32_t pos_len[SOFT_MAX_DIM]; + + WorkRange () { + xcam_mem_clear (pos); + xcam_mem_clear (pos_len); + } +}; + +struct WorkSize { + uint32_t value[SOFT_MAX_DIM]; + WorkSize (uint32_t x = 1, uint32_t y = 1, uint32_t z = 1) { + value[0] = x; + value[1] = y; + value[2] = z; + } +}; + +//multi-thread worker +class SoftWorker + : public Worker +{ + friend class WorkItem; + +public: + explicit SoftWorker (const char *name, const SmartPtr<Callback> &cb = NULL); + virtual ~SoftWorker (); + + bool set_work_uint (uint32_t x, uint32_t y, uint32_t z = 1); + const WorkSize &get_work_uint () const { + return _work_unit; + } + + bool set_threads (const SmartPtr<ThreadPool> &threads); + bool set_global_size (const WorkSize &size); + const WorkSize &get_global_size () const { + return _global; + } + bool set_local_size (const WorkSize &size); + const WorkSize &get_local_size () const { + return _local; + } + + // derived from Worker + virtual XCamReturn work (const SmartPtr<Arguments> &args); + virtual XCamReturn stop (); + +private: + //new virtual functions + virtual XCamReturn work_range (const SmartPtr<Arguments> &args, const WorkRange &range); + virtual WorkRange get_range (const WorkSize &item); + virtual XCamReturn work_unit (const SmartPtr<Arguments> &args, const WorkSize &unit); + + XCamReturn work_impl (const SmartPtr<Arguments> &args, const WorkSize &item); + void all_items_done (const SmartPtr<Arguments> &args, XCamReturn error); + + XCAM_DEAD_COPY (SoftWorker); + +private: + SmartPtr<ThreadPool> _threads; + WorkSize _global; + WorkSize _local; + WorkSize _work_unit; +}; + +} +#endif //XCAM_SOFT_WORKER_H diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am new file mode 100644 index 0000000..ef2b28e --- /dev/null +++ b/pkgconfig/Makefile.am @@ -0,0 +1,12 @@ +pcverfiles = libxcam.pc + +all-local: $(pcverfiles) + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = $(pcverfiles) + +CLEANFILES = $(pcverfiles) +pcinfiles = libxcam.pc.in + +DISTCLEANFILES = $(pcinfiles:.in=) +EXTRA_DIST = $(pcinfiles) diff --git a/pkgconfig/libxcam.pc.in b/pkgconfig/libxcam.pc.in new file mode 100644 index 0000000..1729b0a --- /dev/null +++ b/pkgconfig/libxcam.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libxcam +Description: extended camera features +Requires: +Version: @XCAM_VERSION@ +Libs: -L${libdir} -lxcam_capi -lxcam_ocl -lxcam_core +Cflags: -I${includedir}/xcam -I${includedir} + diff --git a/plugins/3a/Makefile.am b/plugins/3a/Makefile.am new file mode 100644 index 0000000..63c148a --- /dev/null +++ b/plugins/3a/Makefile.am @@ -0,0 +1,15 @@ +if ENABLE_IA_AIQ +AIQ_DIR = aiq +else +AIQ_DIR = +endif + +if ENABLE_IA_AIQ +if HAVE_LIBCL +HYBRID_DIR = hybrid +else +HYBRID_DIR = +endif +endif + +SUBDIRS = $(AIQ_DIR) $(HYBRID_DIR) diff --git a/plugins/3a/aiq/Makefile.am b/plugins/3a/aiq/Makefile.am new file mode 100644 index 0000000..c1ca926 --- /dev/null +++ b/plugins/3a/aiq/Makefile.am @@ -0,0 +1,43 @@ +plugin_LTLIBRARIES = libxcam_3a_aiq.la + +XCAMAIQ_CXXFLAGS = $(XCAM_CXXFLAGS) +XCAMAIQ_LIBS = \ + $(NULL) + +if HAVE_LIBDRM +XCAMAIQ_CXXFLAGS += $(LIBDRM_CFLAGS) +XCAMAIQ_LIBS += $(LIBDRM_LIBS) +endif + +if USE_LOCAL_ATOMISP +XCAMAIQ_CXXFLAGS += \ + -I$(top_srcdir)/ext/atomisp \ + $(NULL) +endif + +plugindir="$(libdir)/xcam/plugins/3a" + +libxcam_3a_aiq_la_SOURCES = \ + aiq_wrapper.cpp \ + $(NULL) + +libxcam_3a_aiq_la_CXXFLAGS = \ + $(GST_CFLAGS) $(XCAMAIQ_CXXFLAGS) \ + -I$(top_srcdir)/xcore \ + -I$(top_srcdir)/modules/isp \ + -I$(top_srcdir)/plugins/3a/aiq \ + $(NULL) + +libxcam_3a_aiq_la_LIBADD = \ + $(XCAMAIQ_LIBS) \ + $(top_builddir)/modules/isp/libxcam_isp.la \ + $(top_builddir)/xcore/libxcam_core.la \ + $(NULL) + +libxcam_3a_aiq_la_LDFLAGS = \ + -module -avoid-version \ + $(top_builddir)/xcore/libxcam_core.la \ + $(PTHREAD_LDFLAGS) \ + $(NULL) + +libxcam_3a_aiq_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/plugins/3a/aiq/aiq_wrapper.cpp b/plugins/3a/aiq/aiq_wrapper.cpp new file mode 100644 index 0000000..e6feb20 --- /dev/null +++ b/plugins/3a/aiq/aiq_wrapper.cpp @@ -0,0 +1,453 @@ +/* + * aiq_wrapper.cpp - aiq wrapper: + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include <base/xcam_3a_description.h> +#include <xcam_std.h> +#include "x3a_analyzer_aiq.h" +#include "x3a_statistics_queue.h" +#include "aiq3a_utils.h" +#include "x3a_result_factory.h" +#include "x3a_analyze_tuner.h" + +#define DEFAULT_AIQ_CPF_FILE "/etc/atomisp/imx185.cpf" + + +using namespace XCam; + +#define AIQ_CONTEXT_CAST(context) ((XCam3AAiqContext*)(context)) + +class XCam3AAiqContext + : public AnalyzerCallback +{ +public: + XCam3AAiqContext (); + ~XCam3AAiqContext (); + bool setup_analyzer (struct atomisp_sensor_mode_data &sensor_mode_data, const char *cpf); + void set_size (uint32_t width, uint32_t height); + bool setup_stats_pool (uint32_t bit_depth = 8); + bool is_stats_pool_ready () const { + return (_stats_pool.ptr () ? true : false); + } + SmartPtr<X3aAnalyzeTuner> &get_analyzer () { + return _analyzer; + } + + SmartPtr<X3aIspStatistics> get_stats_buffer (); + uint32_t get_results (X3aResultList &results); + + // derive from AnalyzerCallback + virtual void x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results); + void update_brightness_result(XCamCommonParam *params); + +private: + XCAM_DEAD_COPY (XCam3AAiqContext); + +private: +// members + SmartPtr<X3aAnalyzeTuner> _analyzer; + SmartPtr<X3aStatisticsQueue> _stats_pool; + uint32_t _video_width; + uint32_t _video_height; + + Mutex _result_mutex; + X3aResultList _results; + double _brightness_level; +}; + +XCam3AAiqContext::XCam3AAiqContext () + : _video_width (0) + , _video_height (0) + , _brightness_level(0) +{ +} + +XCam3AAiqContext::~XCam3AAiqContext () +{ + _analyzer->stop (); + _analyzer->deinit (); +} + +bool +XCam3AAiqContext::setup_analyzer (struct atomisp_sensor_mode_data &sensor_mode_data, const char *cpf) +{ + XCAM_ASSERT (!_analyzer.ptr ()); + SmartPtr<X3aAnalyzer> aiq_analyzer = new X3aAnalyzerAiq (sensor_mode_data, cpf); + XCAM_ASSERT (aiq_analyzer.ptr ()); + + _analyzer = new X3aAnalyzeTuner (); + XCAM_ASSERT (_analyzer.ptr ()); + + _analyzer->set_analyzer (aiq_analyzer); + _analyzer->set_results_callback (this); + return true; +} + +void +XCam3AAiqContext::set_size (uint32_t width, uint32_t height) +{ + _video_width = width; + _video_height = height; +} + +bool +XCam3AAiqContext::setup_stats_pool (uint32_t bit_depth) +{ + VideoBufferInfo info; + info.init (XCAM_PIX_FMT_SGRBG16, _video_width, _video_height); + + _stats_pool = new X3aStatisticsQueue; + XCAM_ASSERT (_stats_pool.ptr ()); + + _stats_pool->set_bit_depth (bit_depth); + XCAM_FAIL_RETURN ( + WARNING, + _stats_pool->set_video_info (info), + false, + "3a stats set video info failed"); + + + if (!_stats_pool->reserve (6)) { + XCAM_LOG_WARNING ("init_3a_stats_pool failed to reserve stats buffer."); + return false; + } + + return true; +} + +SmartPtr<X3aIspStatistics> +XCam3AAiqContext::get_stats_buffer () +{ + SmartPtr<X3aIspStatistics> new_stats = + _stats_pool->get_buffer (_stats_pool).dynamic_cast_ptr<X3aIspStatistics> (); + + XCAM_FAIL_RETURN ( + WARNING, + new_stats.ptr (), + NULL, + "get isp stats buffer failed"); + + return new_stats; +} + + +void +XCam3AAiqContext::x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results) +{ + XCAM_UNUSED (analyzer); + SmartLock locker (_result_mutex); + _results.insert (_results.end (), results.begin (), results.end ()); +} + +void +XCam3AAiqContext::update_brightness_result(XCamCommonParam *params) +{ + if( params->brightness == _brightness_level) + return; + _brightness_level = params->brightness; + + XCam3aResultBrightness xcam3a_brightness_result; + xcam_mem_clear (xcam3a_brightness_result); + xcam3a_brightness_result.head.type = XCAM_3A_RESULT_BRIGHTNESS; + xcam3a_brightness_result.head.process_type = XCAM_IMAGE_PROCESS_ALWAYS; + xcam3a_brightness_result.head.version = XCAM_VERSION; + xcam3a_brightness_result.brightness_level = _brightness_level; + + SmartPtr<X3aResult> brightness_result = + X3aResultFactory::instance ()->create_3a_result ((XCam3aResultHead*)&xcam3a_brightness_result); + _results.push_back(brightness_result); +} + +uint32_t +XCam3AAiqContext::get_results (X3aResultList &results) +{ + uint32_t size = 0; + + SmartLock locker (_result_mutex); + + results.assign (_results.begin (), _results.end ()); + size = _results.size (); + _results.clear (); + + return size; +} + +static SmartPtr<X3aAnalyzeTuner> +get_analyzer (XCam3AContext *context) +{ + XCam3AAiqContext *aiq_context = AIQ_CONTEXT_CAST (context); + if (!aiq_context) + return NULL; + + return aiq_context->get_analyzer (); +} + +static XCamReturn +xcam_create_context (XCam3AContext **context) +{ + XCAM_ASSERT (context); + XCam3AAiqContext *aiq_context = new XCam3AAiqContext (); + *context = ((XCam3AContext*)(aiq_context)); + return XCAM_RETURN_NO_ERROR; +} + +static XCamReturn +xcam_destroy_context (XCam3AContext *context) +{ + XCam3AAiqContext *aiq_context = AIQ_CONTEXT_CAST (context); + delete aiq_context; + return XCAM_RETURN_NO_ERROR; +} + +static XCamReturn +xcam_configure_3a (XCam3AContext *context, uint32_t width, uint32_t height, double framerate) +{ + XCam3AAiqContext *aiq_context = AIQ_CONTEXT_CAST (context); + XCamReturn ret = XCAM_RETURN_NO_ERROR; + struct atomisp_sensor_mode_data sensor_mode_data; + + switch ((int)framerate) { + case 30: + sensor_mode_data.coarse_integration_time_min = 1; + sensor_mode_data.coarse_integration_time_max_margin = 1; + sensor_mode_data.fine_integration_time_min = 0; + sensor_mode_data.fine_integration_time_max_margin = 0; + sensor_mode_data.fine_integration_time_def = 0; + sensor_mode_data.frame_length_lines = 1125; + sensor_mode_data.line_length_pck = 1100; + sensor_mode_data.read_mode = 0; + sensor_mode_data.vt_pix_clk_freq_mhz = 37125000; + sensor_mode_data.crop_horizontal_start = 0; + sensor_mode_data.crop_vertical_start = 0; + sensor_mode_data.crop_horizontal_end = 1920; + sensor_mode_data.crop_vertical_end = 1080; + sensor_mode_data.output_width = 1920; + sensor_mode_data.output_height = 1080; + sensor_mode_data.binning_factor_x = 1; + sensor_mode_data.binning_factor_y = 1; + break; + default: + sensor_mode_data.coarse_integration_time_min = 1; + sensor_mode_data.coarse_integration_time_max_margin = 1; + sensor_mode_data.fine_integration_time_min = 0; + sensor_mode_data.fine_integration_time_max_margin = 0; + sensor_mode_data.fine_integration_time_def = 0; + sensor_mode_data.frame_length_lines = 1125; + sensor_mode_data.line_length_pck = 1320; + sensor_mode_data.read_mode = 0; + sensor_mode_data.vt_pix_clk_freq_mhz = 37125000; + sensor_mode_data.crop_horizontal_start = 0; + sensor_mode_data.crop_vertical_start = 0; + sensor_mode_data.crop_horizontal_end = 1920; + sensor_mode_data.crop_vertical_end = 1080; + sensor_mode_data.output_width = 1920; + sensor_mode_data.output_height = 1080; + sensor_mode_data.binning_factor_x = 1; + sensor_mode_data.binning_factor_y = 1; + break; + } + + XCAM_ASSERT (aiq_context); + const char *path_cpf = getenv ("AIQ_CPF_PATH"); + XCAM_FAIL_RETURN ( + WARNING, + aiq_context->setup_analyzer (sensor_mode_data, path_cpf == NULL ? DEFAULT_AIQ_CPF_FILE : path_cpf), + XCAM_RETURN_ERROR_UNKNOWN, + "setup aiq 3a analyzer failed"); + + SmartPtr<X3aAnalyzeTuner> analyzer = aiq_context->get_analyzer (); + + ret = analyzer->prepare_handlers (); + XCAM_FAIL_RETURN ( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "analyzer(aiq3alib) prepare handlers failed"); + + ret = analyzer->init (width, height, framerate); + XCAM_FAIL_RETURN ( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "configure aiq 3a failed"); + + ret = analyzer->start (); + XCAM_FAIL_RETURN ( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "start aiq 3a failed"); + + aiq_context->set_size (width, height); + + return XCAM_RETURN_NO_ERROR; +} + +static XCamReturn +xcam_set_3a_stats (XCam3AContext *context, XCam3AStats *stats, int64_t timestamp) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + XCam3AAiqContext *aiq_context = AIQ_CONTEXT_CAST (context); + XCAM_ASSERT (aiq_context); + + SmartPtr<X3aAnalyzeTuner> analyzer = aiq_context->get_analyzer (); + XCAM_ASSERT (analyzer.ptr ()); + XCAM_ASSERT (stats); + + if (!aiq_context->is_stats_pool_ready ()) { + // init statistics queue + XCAM_FAIL_RETURN ( + WARNING, + aiq_context->setup_stats_pool (stats->info.bit_depth), + XCAM_RETURN_ERROR_UNKNOWN, + "aiq configure 3a failed on stats pool setup"); + } + + // Convert stats to atomisp_3a_stats; + SmartPtr<X3aIspStatistics> isp_stats = aiq_context->get_stats_buffer (); + if (!isp_stats.ptr ()) { + XCAM_LOG_WARNING ("get stats bufffer failed or stopped"); + return XCAM_RETURN_ERROR_MEM; + } + + struct atomisp_3a_statistics *raw_stats = isp_stats->get_isp_stats (); + XCAM_ASSERT (raw_stats); + + translate_3a_stats (stats, raw_stats); + isp_stats->set_timestamp (timestamp); + + ret = analyzer->push_3a_stats (isp_stats); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("set 3a stats failed"); + } + + return ret; +} + +static XCamReturn +xcam_update_common_params (XCam3AContext *context, XCamCommonParam *params) +{ + if (params) { + SmartPtr<X3aAnalyzeTuner> analyzer = get_analyzer (context); + XCAM_ASSERT (analyzer.ptr ()); + + analyzer->update_common_parameters (*params); + } +#if 0 + XCam3AAiqContext *aiq_context = AIQ_CONTEXT_CAST (context); + aiq_context->update_brightness_result(params); +#endif + return XCAM_RETURN_NO_ERROR; +} + +static XCamReturn +xcam_analyze_awb (XCam3AContext *context, XCamAwbParam *params) +{ + if (params) { + SmartPtr<X3aAnalyzeTuner> analyzer = get_analyzer (context); + XCAM_ASSERT (analyzer.ptr ()); + + analyzer->update_awb_parameters (*params); + } + return XCAM_RETURN_NO_ERROR; +} + +static XCamReturn +xcam_analyze_ae (XCam3AContext *context, XCamAeParam *params) +{ + if (params) { + SmartPtr<X3aAnalyzeTuner> analyzer = get_analyzer (context); + XCAM_ASSERT (analyzer.ptr ()); + + analyzer->update_ae_parameters (*params); + } + return XCAM_RETURN_NO_ERROR; +} + +static XCamReturn +xcam_analyze_af (XCam3AContext *context, XCamAfParam *params) +{ + if (params) { + SmartPtr<X3aAnalyzeTuner> analyzer = get_analyzer (context); + XCAM_ASSERT (analyzer.ptr ()); + + analyzer->update_af_parameters (*params); + } + return XCAM_RETURN_NO_ERROR; +} + +static XCamReturn +xcam_combine_analyze_results (XCam3AContext *context, XCam3aResultHead *results[], uint32_t *res_count) +{ + XCam3AAiqContext *aiq_context = AIQ_CONTEXT_CAST (context); + XCAM_ASSERT (aiq_context); + X3aResultList aiq_results; + uint32_t result_count = aiq_context->get_results (aiq_results); + + if (!result_count) { + *res_count = 0; + XCAM_LOG_DEBUG ("aiq wrapper combine with no result out"); + return XCAM_RETURN_NO_ERROR; + } + + // mark as static + static XCam3aResultHead *res_array[XCAM_3A_MAX_RESULT_COUNT]; + xcam_mem_clear (res_array); + XCAM_ASSERT (result_count < XCAM_3A_MAX_RESULT_COUNT); + + // result_count may changed + result_count = translate_3a_results_to_xcam (aiq_results, res_array, XCAM_3A_MAX_RESULT_COUNT); + + for (uint32_t i = 0; i < result_count; ++i) { + results[i] = res_array[i]; + } + *res_count = result_count; + XCAM_ASSERT (result_count > 0); + + return XCAM_RETURN_NO_ERROR; +} + +static void +xcam_free_results (XCam3aResultHead *results[], uint32_t res_count) +{ + for (uint32_t i = 0; i < res_count; ++i) { + if (results[i]) + free_3a_result (results[i]); + } +} + +XCAM_BEGIN_DECLARE + +XCam3ADescription xcam_3a_desciption = { + XCAM_VERSION, + sizeof (XCam3ADescription), + xcam_create_context, + xcam_destroy_context, + xcam_configure_3a, + xcam_set_3a_stats, + xcam_update_common_params, + xcam_analyze_awb, + xcam_analyze_ae, + xcam_analyze_af, + xcam_combine_analyze_results, + xcam_free_results +}; + +XCAM_END_DECLARE + diff --git a/plugins/3a/hybrid/Makefile.am b/plugins/3a/hybrid/Makefile.am new file mode 100644 index 0000000..df23f61 --- /dev/null +++ b/plugins/3a/hybrid/Makefile.am @@ -0,0 +1,30 @@ +plugin_LTLIBRARIES = libxcam_3a_hybrid.la + +XCAMSRC_CXXFLAGS = $(XCAM_CXXFLAGS) +XCAMSRC_LIBS = \ + $(NULL) + +plugindir="$(libdir)/xcam/plugins/3a" + +libxcam_3a_hybrid_la_SOURCES = \ + sample.cpp \ + $(NULL) + +libxcam_3a_hybrid_la_CXXFLAGS = \ + $(GST_CFLAGS) $(XCAMSRC_CXXFLAGS) \ + -I$(top_srcdir)/xcore \ + -I$(top_srcdir)/plugins/3a/hybrid \ + $(NULL) + +libxcam_3a_hybrid_la_LIBADD = \ + $(XCAMSRC_LIBS) \ + $(top_builddir)/xcore/libxcam_core.la \ + $(NULL) + +libxcam_3a_hybrid_la_LDFLAGS = \ + -module -avoid-version \ + $(top_builddir)/xcore/libxcam_core.la \ + $(PTHREAD_LDFLAGS) \ + $(NULL) + +libxcam_3a_hybrid_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/plugins/3a/hybrid/sample.cpp b/plugins/3a/hybrid/sample.cpp new file mode 100644 index 0000000..2c45269 --- /dev/null +++ b/plugins/3a/hybrid/sample.cpp @@ -0,0 +1,206 @@ +/* + * aiq_wrapper.cpp - aiq wrapper: + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Jia Meng <jia.meng@intel.com> + */ + +#include <base/xcam_3a_description.h> +#include <xcam_std.h> + +using namespace XCam; + +#define CONTEXT_CAST(context) ((XCam3AHybridContext*)(context)) + +class XCam3AHybridContext +{ +public: + XCam3AHybridContext (); + ~XCam3AHybridContext (); + +private: + XCAM_DEAD_COPY (XCam3AHybridContext); + +}; + +XCam3AHybridContext::XCam3AHybridContext () +{ +} + +XCam3AHybridContext::~XCam3AHybridContext () +{ +} + +static XCamReturn +xcam_create_context (XCam3AContext **context) +{ + XCAM_ASSERT (context); + XCam3AHybridContext *ctx = new XCam3AHybridContext (); + *context = ((XCam3AContext*)(ctx)); + return XCAM_RETURN_NO_ERROR; +} + +static XCamReturn +xcam_destroy_context (XCam3AContext *context) +{ + XCam3AHybridContext *ctx = CONTEXT_CAST (context); + delete ctx; + return XCAM_RETURN_NO_ERROR; +} + +// configure customized 3a analyzer with width/height/framerate +static XCamReturn +xcam_configure_3a (XCam3AContext *context, uint32_t width, uint32_t height, double framerate) +{ + XCAM_UNUSED (context); + XCAM_UNUSED (width); + XCAM_UNUSED (height); + XCAM_UNUSED (framerate); + + return XCAM_RETURN_NO_ERROR; +} + +// set 3a stats to customized 3a analyzer for subsequent usage +static XCamReturn +xcam_set_3a_stats (XCam3AContext *context, XCam3AStats *stats, int64_t timestamp) +{ + XCAM_UNUSED (context); + XCAM_UNUSED (timestamp); + + XCam3AStatsInfo info = stats->info; + for (uint32_t i = 0; i < info.height; ++i) + for (uint32_t j = 0; j < info.width; ++j) { + XCAM_LOG_DEBUG ("%d %d %d %d %d %d %d %d", + stats->stats[i * info.aligned_width + j].avg_y, + stats->stats[i * info.aligned_width + j].avg_gr, + stats->stats[i * info.aligned_width + j].avg_r, + stats->stats[i * info.aligned_width + j].avg_b, + stats->stats[i * info.aligned_width + j].avg_gb, + stats->stats[i * info.aligned_width + j].valid_wb_count, + stats->stats[i * info.aligned_width + j].f_value1, + stats->stats[i * info.aligned_width + j].f_value2); + } + + return XCAM_RETURN_NO_ERROR; +} + +// refer to xcam_params.h for common parameters +static XCamReturn +xcam_update_common_params (XCam3AContext *context, XCamCommonParam *params) +{ + XCAM_UNUSED (context); + XCAM_UNUSED (params); + + return XCAM_RETURN_NO_ERROR; +} + +// customized awb algorithm should be added here +static XCamReturn +xcam_analyze_awb (XCam3AContext *context, XCamAwbParam *params) +{ + XCAM_UNUSED (context); + XCAM_UNUSED (params); + + return XCAM_RETURN_NO_ERROR; +} + +// customized ae algorithm should be added here +static XCamReturn +xcam_analyze_ae (XCam3AContext *context, XCamAeParam *params) +{ + XCAM_UNUSED (context); + XCAM_UNUSED (params); + + return XCAM_RETURN_NO_ERROR; +} + +// customized af is unsupported now +static XCamReturn +xcam_analyze_af (XCam3AContext *context, XCamAfParam *params) +{ + XCAM_UNUSED (context); + XCAM_UNUSED (params); + + return XCAM_RETURN_NO_ERROR; +} + +// combine ae/awb analyze results and set to framework +// only support XCam3aResultExposure and XCam3aResultWhiteBalance now +static XCamReturn +xcam_combine_analyze_results (XCam3AContext *context, XCam3aResultHead *results[], uint32_t *res_count) +{ + XCAM_UNUSED (context); + + uint32_t result_count = 2; + static XCam3aResultHead *res_array[XCAM_3A_MAX_RESULT_COUNT]; + xcam_mem_clear (res_array); + + for (uint32_t i = 0; i < result_count; ++i) { + results[i] = res_array[i]; + } + *res_count = result_count; + + XCam3aResultExposure *exposure = xcam_malloc0_type (XCam3aResultExposure); + XCAM_ASSERT (exposure); + exposure->head.type = XCAM_3A_RESULT_EXPOSURE; + exposure->head.process_type = XCAM_IMAGE_PROCESS_ALWAYS; + exposure->head.version = XCAM_VERSION; + exposure->exposure_time = 9986; // 9.986ms + exposure->analog_gain = 10; + results[0] = (XCam3aResultHead *)exposure; + + XCam3aResultWhiteBalance *wb = xcam_malloc0_type (XCam3aResultWhiteBalance); + XCAM_ASSERT (wb); + wb->head.type = XCAM_3A_RESULT_WHITE_BALANCE; + wb->head.process_type = XCAM_IMAGE_PROCESS_ALWAYS; + wb->head.version = XCAM_VERSION; + wb->gr_gain = 1.0; + wb->r_gain = 1.6453; + wb->b_gain = 2.0645; + wb->gb_gain = 1.0; + results[1] = (XCam3aResultHead *)wb; + + return XCAM_RETURN_NO_ERROR; +} + +static void +xcam_free_results (XCam3aResultHead *results[], uint32_t res_count) +{ + for (uint32_t i = 0; i < res_count; ++i) { + if (results[i]) + xcam_free (results[i]); + } +} + +XCAM_BEGIN_DECLARE + +XCam3ADescription xcam_3a_desciption = { + XCAM_VERSION, + sizeof (XCam3ADescription), + xcam_create_context, + xcam_destroy_context, + xcam_configure_3a, + xcam_set_3a_stats, + xcam_update_common_params, + xcam_analyze_awb, + xcam_analyze_ae, + xcam_analyze_af, + xcam_combine_analyze_results, + xcam_free_results +}; + +XCAM_END_DECLARE + diff --git a/plugins/Makefile.am b/plugins/Makefile.am new file mode 100644 index 0000000..e3e20f4 --- /dev/null +++ b/plugins/Makefile.am @@ -0,0 +1,13 @@ +if ENABLE_3ALIB +X3ALIB_DIR = 3a +else +X3ALIB_DIR = +endif + +if ENABLE_SMART_LIB +SMARTLIB_DIR = smart +else +SMARTLIB_DIR = +endif + +SUBDIRS = $(X3ALIB_DIR) $(SMARTLIB_DIR) diff --git a/plugins/smart/Makefile.am b/plugins/smart/Makefile.am new file mode 100644 index 0000000..49cf033 --- /dev/null +++ b/plugins/smart/Makefile.am @@ -0,0 +1,13 @@ + +if ENABLE_DVS +if HAVE_LIBCL +DVS_DIR = dvs +else +DVS_DIR = +endif +else +DVS_DIR = +endif + +SUBDIRS = $(DVS_DIR) sample + diff --git a/plugins/smart/dvs/Makefile.am b/plugins/smart/dvs/Makefile.am new file mode 100644 index 0000000..2675621 --- /dev/null +++ b/plugins/smart/dvs/Makefile.am @@ -0,0 +1,47 @@ +SUBDIRS = libdvs + +noinst_LTLIBRARIES = libxcam_plugin_dvs.la + +XCAM_PLUGIN_DVS_CXXFLAGS = $(XCAM_CXXFLAGS) \ + -I$(top_srcdir)/xcore \ + -I$(top_srcdir)/modules \ + -I$(top_srcdir)/plugins/smart/dvs/libdvs \ + $(NULL) + +if HAVE_LIBDRM +XCAM_PLUGIN_DVS_CXXFLAGS += $(LIBDRM_CFLAGS) +endif + +XCAM_PLUGIN_DVS_LIBS = \ + $(top_builddir)/plugins/smart/dvs/libdvs/libxcam_dvs.a \ + $(NULL) + +if HAVE_LIBDRM +XCAM_PLUGIN_DVS_LIBS += $(LIBDRM_LIBS) +endif + +plugindir="$(libdir)/xcam/plugins/smart" + +libxcam_plugin_dvs_la_SOURCES = \ + xcam_plugin_dvs.cpp \ + $(NULL) + +libxcam_plugin_dvs_la_CXXFLAGS = \ + $(GST_CFLAGS) $(XCAM_PLUGIN_DVS_CXXFLAGS) \ + $(NULL) + +libxcam_plugin_dvs_la_LIBADD = \ + $(XCAM_PLUGIN_DVS_LIBS) \ + $(top_builddir)/modules/ocl/libxcam_ocl.la \ + $(top_builddir)/xcore/libxcam_core.la \ + $(OPENCV_LIBS) \ + $(NULL) + +libxcam_plugin_dvs_la_LDFLAGS = \ + -module -avoid-version \ + $(top_builddir)/xcore/libxcam_core.la \ + $(PTHREAD_LDFLAGS) \ + $(OPENCV_LIBS) \ + $(NULL) + +libxcam_plugin_dvs_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/plugins/smart/dvs/libdvs/.gitignore b/plugins/smart/dvs/libdvs/.gitignore new file mode 100644 index 0000000..468c13e --- /dev/null +++ b/plugins/smart/dvs/libdvs/.gitignore @@ -0,0 +1,2 @@ +*.a +test_image_stabilization diff --git a/plugins/smart/dvs/libdvs/Makefile.am b/plugins/smart/dvs/libdvs/Makefile.am new file mode 100644 index 0000000..6fba743 --- /dev/null +++ b/plugins/smart/dvs/libdvs/Makefile.am @@ -0,0 +1,45 @@ +noinst_LIBRARIES = \ + libxcam_dvs.a \ + $(NULL) + +XCAM_DVS_LIB_CXXFLAGS = \ + $(XCAM_CXXFLAGS) \ + $(OPENCV_CFLAGS) \ + $(NULL) + +XCAM_DVS_LIBS = \ + $(OPENCV_LIBS) \ + $(NULL) + +libxcam_dvs_a_SOURCES = \ + libdvs.cpp \ + stabilizer.cpp \ + $(NULL) + +libxcam_dvs_a_CXXFLAGS = \ + $(GST_CFLAGS) $(XCAM_DVS_LIB_CXXFLAGS) \ + -I$(top_srcdir)/xcore \ + $(NULL) + +libxcam_dvs_a_LIBADD = \ + $(top_builddir)/xcore/libxcam_core.la \ + $(NULL) + +noinst_PROGRAMS = \ + test_image_stabilization \ + $(NULL) + +test_image_stabilization_SOURCES = \ + test-image-stabilization.cpp \ + $(NULL) + +test_image_stabilization_CXXFLAGS = \ + $(XCAM_CXXFLAGS) \ + -I$(top_srcdir)/xcore \ + $(NULL) + +test_image_stabilization_LDADD = \ + libxcam_dvs.a \ + $(OPENCV_LIBS) \ + $(NULL) + diff --git a/plugins/smart/dvs/libdvs/libdvs.cpp b/plugins/smart/dvs/libdvs/libdvs.cpp new file mode 100644 index 0000000..2c984ae --- /dev/null +++ b/plugins/smart/dvs/libdvs/libdvs.cpp @@ -0,0 +1,138 @@ +/* + * libdvs.cpp - abstract for DVS (Digital Video Stabilizer) + * + * Copyright (c) 2014-2016 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include <opencv2/core.hpp> +#include <opencv2/core/ocl.hpp> +#include <opencv2/core/utility.hpp> + +#include "libdvs.h" +#include "stabilizer.h" + +struct DigitalVideoStabilizer : DvsInterface +{ + virtual ~DigitalVideoStabilizer() {} + + int init(int width, int height, bool twoPass); + + void setConfig(DvsConfig* config); + + void release(); + + void nextStabilizedMotion(DvsData* frame, DvsResult* result); + + + VideoStabilizer* _videoStab; + + DigitalVideoStabilizer () { + _videoStab = NULL; + } +}; + +int DigitalVideoStabilizer::init(int width, int height, bool twoPass) +{ + cv::Size frameSize; + frameSize.width = width; + frameSize.height = height; + + if (_videoStab != NULL) { + delete _videoStab; + _videoStab = NULL; + } + _videoStab = new VideoStabilizer(twoPass, false, false, false); + if (_videoStab == NULL) { + return -1; + } + + // stabilizer configuration + _videoStab->setFrameSize(frameSize); + _videoStab->configFeatureDetector(1000, 15); + + return 0; +} + +void DigitalVideoStabilizer::setConfig(DvsConfig* config) +{ + if (NULL == _videoStab) { + return; + } + // stabilizer configuration + _videoStab->setFrameSize(cv::Size(config->frame_width, config->frame_height)); + _videoStab->configMotionFilter(config->radius, config->stdev); + _videoStab->configFeatureDetector(config->features, config->minDistance); +} + +void DigitalVideoStabilizer::release() +{ + if (_videoStab != NULL) { + delete _videoStab; + } +} + +void DigitalVideoStabilizer::nextStabilizedMotion(DvsData* frame, DvsResult* result) +{ + if ((NULL == _videoStab) || (NULL == result)) { + return; + } + result->frame_id = -1; + result->frame_width = _videoStab->getFrameSize().width; + result->frame_height = _videoStab->getFrameSize().height; + + cv::Mat HMatrix = _videoStab->nextStabilizedMotion(frame, result->frame_id); + + if (HMatrix.empty()) { + result->valid = false; + result->proj_mat[0][0] = 1.0f; + result->proj_mat[0][1] = 0.0f; + result->proj_mat[0][2] = 0.0f; + result->proj_mat[1][0] = 0.0f; + result->proj_mat[1][1] = 1.0f; + result->proj_mat[1][2] = 0.0f; + result->proj_mat[2][0] = 0.0f; + result->proj_mat[2][1] = 0.0f; + result->proj_mat[2][2] = 1.0f; + return; + } + + cv::Mat invHMat = HMatrix.inv(); + result->valid = true; + + for( int i = 0; i < 3; i++ ) { + for( int j = 0; j < 3; j++ ) { + result->proj_mat[i][j] = invHMat.at<float>(i, j); + } + } +#if 0 + printf ("proj_mat(%d, :)={%f, %f, %f, %f, %f, %f, %f, %f, %f}; \n", result->frame_id + 1, + result->proj_mat[0][0], result->proj_mat[0][1], result->proj_mat[0][2], + result->proj_mat[1][0], result->proj_mat[1][1], result->proj_mat[1][2], + result->proj_mat[2][0], result->proj_mat[2][1], result->proj_mat[2][2]); + + printf ("amplitude(%d, :)={%f, %f}; \n", result->frame_id + 1, + result->proj_mat[0][2], result->proj_mat[1][2]); +#endif +} + +DvsInterface* getDigitalVideoStabilizer(void) +{ + return new DigitalVideoStabilizer(); +} + + + diff --git a/plugins/smart/dvs/libdvs/libdvs.h b/plugins/smart/dvs/libdvs/libdvs.h new file mode 100644 index 0000000..d580d99 --- /dev/null +++ b/plugins/smart/dvs/libdvs/libdvs.h @@ -0,0 +1,96 @@ +/* + * libdvs.h - abstract header for DVS (Digital Video Stabilizer) + * + * Copyright (c) 2014-2016 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#ifndef _LIB_DVS_HPP +#define _LIB_DVS_HPP + +#include <stdio.h> + +#if (defined __linux__) +#define DVSAPI __attribute__((visibility("default"))) +#endif + +typedef struct DvsData +{ + cv::UMat data; + + virtual ~DvsData () {}; +} DvsData; + + +typedef struct DvsResult +{ + int frame_id; + bool valid; + int frame_width; + int frame_height; + double proj_mat[3][3]; + + DvsResult(): frame_id(-1), valid(false) + {}; +} DvsResult; + + +typedef struct DvsConfig +{ + bool use_ocl; //ture:ocl path; false:cpu path; + int frame_width; + int frame_height; + int radius; + float stdev; + int features; + double minDistance; + + DvsConfig() + { + use_ocl = true; + frame_width = 1; + frame_height = 1; + radius = 15; + stdev = 10.0f; + features = 1000; + minDistance = 15.0f; + } +} DvsConfig; + +typedef struct DvsInterface +{ + virtual ~DvsInterface() {} + /// initialize model from memory + virtual int init(int width, int height, bool twoPass) = 0; + + /// set detection parameters, if config = NULL, default parameters will be used + virtual void setConfig(DvsConfig* config) = 0; + + /// release memory + virtual void release() = 0; + + /// apply homography estimation to an input image + /// @param frame input 8-bit single channel UMAT image (color image must be transferred to gray-scale) + /// @param result output homography estimation result of the input image + virtual void nextStabilizedMotion(DvsData* frame, DvsResult* result) = 0; + +} DvsInterface; + +extern "C" DVSAPI DvsInterface* getDigitalVideoStabilizer(void); + +#endif + + diff --git a/plugins/smart/dvs/libdvs/stabilizer.cpp b/plugins/smart/dvs/libdvs/stabilizer.cpp new file mode 100644 index 0000000..1dd4f66 --- /dev/null +++ b/plugins/smart/dvs/libdvs/stabilizer.cpp @@ -0,0 +1,431 @@ +/* + * stablizer.cpp - abstract for DVS (Digital Video Stabilizer) + * + * Copyright (c) 2014-2016 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include "stabilizer.h" + +using namespace cv; +using namespace cv::videostab; +using namespace std; + +Mat +OnePassVideoStabilizer::nextStabilizedMotion(DvsData* frame, int& stablizedPos) +{ + if (!(frame->data.empty())) + { + Mat image; + frame->data.getMat(ACCESS_READ).copyTo(image); + + curPos_++; + + if (curPos_ > 0) + { + at(curPos_, frames_) = image; + + if (doDeblurring_) + at(curPos_, blurrinessRates_) = calcBlurriness(image); + + at(curPos_ - 1, motions_) = estimateMotion(); + + if (curPos_ >= radius_) + { + curStabilizedPos_ = curPos_ - radius_; + Mat stabilizationMotion = estimateStabilizationMotion(); + if (doCorrectionForInclusion_) + stabilizationMotion = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_); + + at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion; + stablizedPos = curStabilizedPos_; + + return stabilizationMotion; + } + } + else + setUpFrame(image); + + log_->print("."); + return Mat(); + } + + if (curStabilizedPos_ < curPos_) + { + curStabilizedPos_++; + stablizedPos = curStabilizedPos_; + at(curStabilizedPos_ + radius_, frames_) = at(curPos_, frames_); + at(curStabilizedPos_ + radius_ - 1, motions_) = Mat::eye(3, 3, CV_32F); + + Mat stabilizationMotion = estimateStabilizationMotion(); + if (doCorrectionForInclusion_) + stabilizationMotion = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_); + + at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion; + + log_->print("."); + + return stabilizationMotion; + } + + return Mat(); +} + + +Mat +OnePassVideoStabilizer::estimateMotion() +{ +#if ENABLE_DVS_CL_PATH + cv::UMat frame0 = at(curPos_ - 1, frames_).getUMat(ACCESS_READ); + cv::UMat frame1 = at(curPos_, frames_).getUMat(ACCESS_READ); + + cv::UMat ugrayImage0; + cv::UMat ugrayImage1; + if ( frame0.type() != CV_8U ) + { + cvtColor( frame0, ugrayImage0, COLOR_BGR2GRAY ); + } + else + { + ugrayImage0 = frame0; + } + + if ( frame1.type() != CV_8U ) + { + cvtColor( frame1, ugrayImage1, COLOR_BGR2GRAY ); + } + else + { + ugrayImage1 = frame1; + } + + return motionEstimator_.dynamicCast<KeypointBasedMotionEstimator>()->estimate(ugrayImage0, ugrayImage1); +#else + return motionEstimator_.dynamicCast<KeypointBasedMotionEstimator>()->estimate(at(curPos_ - 1, frames_), at(curPos_, frames_)); +#endif +} + +void +OnePassVideoStabilizer::setUpFrame(const Mat &firstFrame) +{ + frameSize_ = firstFrame.size(); + frameMask_.create(frameSize_, CV_8U); + frameMask_.setTo(255); + + int cacheSize = 2 * radius_ + 1; + frames_.resize(2); + motions_.resize(cacheSize); + stabilizationMotions_.resize(cacheSize); + + for (int i = -radius_; i < 0; ++i) + { + at(i, motions_) = Mat::eye(3, 3, CV_32F); + at(i, frames_) = firstFrame; + } + + at(0, frames_) = firstFrame; + + StabilizerBase::setUp(firstFrame); +} + + +Mat +TwoPassVideoStabilizer::nextStabilizedMotion(DvsData* frame, int& stablizedPos) +{ + if (!(frame->data.empty())) + { + Mat image; + frame->data.getMat(ACCESS_READ).copyTo(image); + + curPos_++; + + if (curPos_ > 0) + { + at(curPos_, frames_) = image; + + if (doDeblurring_) + at(curPos_, blurrinessRates_) = calcBlurriness(image); + + at(curPos_ - 1, motions_) = estimateMotion(); + + if (curPos_ >= radius_) + { + curStabilizedPos_ = curPos_ - radius_; + Mat stabilizationMotion = estimateStabilizationMotion(); + if (doCorrectionForInclusion_) + stabilizationMotion = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_); + + at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion; + stablizedPos = curStabilizedPos_; + + return stabilizationMotion; + } + } + else + setUpFrame(image); + + log_->print("."); + return Mat(); + } + + if (curStabilizedPos_ < curPos_) + { + curStabilizedPos_++; + stablizedPos = curStabilizedPos_; + at(curStabilizedPos_ + radius_, frames_) = at(curPos_, frames_); + at(curStabilizedPos_ + radius_ - 1, motions_) = Mat::eye(3, 3, CV_32F); + + Mat stabilizationMotion = estimateStabilizationMotion(); + if (doCorrectionForInclusion_) + stabilizationMotion = ensureInclusionConstraint(stabilizationMotion, frameSize_, trimRatio_); + + at(curStabilizedPos_, stabilizationMotions_) = stabilizationMotion; + + log_->print("."); + + return stabilizationMotion; + } + + return Mat(); +} + + +Mat +TwoPassVideoStabilizer::estimateMotion() +{ +#if ENABLE_DVS_CL_PATH + cv::UMat frame0 = at(curPos_ - 1, frames_).getUMat(ACCESS_READ); + cv::UMat frame1 = at(curPos_, frames_).getUMat(ACCESS_READ); + + cv::UMat ugrayImage0; + cv::UMat ugrayImage1; + if ( frame0.type() != CV_8U ) + { + cvtColor( frame0, ugrayImage0, COLOR_BGR2GRAY ); + } + else + { + ugrayImage0 = frame0; + } + + if ( frame1.type() != CV_8U ) + { + cvtColor( frame1, ugrayImage1, COLOR_BGR2GRAY ); + } + else + { + ugrayImage1 = frame1; + } + + return motionEstimator_.dynamicCast<KeypointBasedMotionEstimator>()->estimate(ugrayImage0, ugrayImage1); +#else + return motionEstimator_.dynamicCast<KeypointBasedMotionEstimator>()->estimate(at(curPos_ - 1, frames_), at(curPos_, frames_)); +#endif +} + +void +TwoPassVideoStabilizer::setUpFrame(const Mat &firstFrame) +{ + //int cacheSize = 2*radius_ + 1; + frames_.resize(2); + stabilizedFrames_.resize(2); + stabilizedMasks_.resize(2); + + for (int i = -1; i <= 0; ++i) + at(i, frames_) = firstFrame; + + StabilizerBase::setUp(firstFrame); +} + +VideoStabilizer::VideoStabilizer( + bool isTwoPass, + bool wobbleSuppress, + bool deblur, + bool inpainter) + : isTwoPass_ (isTwoPass) + , trimRatio_ (0.05f) +{ + Ptr<MotionEstimatorRansacL2> est = makePtr<MotionEstimatorRansacL2>(MM_HOMOGRAPHY); + Ptr<IOutlierRejector> outlierRejector = makePtr<TranslationBasedLocalOutlierRejector>(); + Ptr<KeypointBasedMotionEstimator> kbest = makePtr<KeypointBasedMotionEstimator>(est); + kbest->setDetector(GFTTDetector::create(1000, 0.01, 15)); + kbest->setOutlierRejector(outlierRejector); + + if (isTwoPass) + { + Ptr<TwoPassVideoStabilizer> twoPassStabilizer = makePtr<TwoPassVideoStabilizer>(); + stabilizer_ = twoPassStabilizer; + twoPassStabilizer->setEstimateTrimRatio(false); + twoPassStabilizer->setMotionStabilizer(makePtr<GaussianMotionFilter>(15, 10)); + + if (wobbleSuppress) { + Ptr<MoreAccurateMotionWobbleSuppressorBase> ws = makePtr<MoreAccurateMotionWobbleSuppressor>(); + + ws->setMotionEstimator(kbest); + ws->setPeriod(30); + twoPassStabilizer->setWobbleSuppressor(ws); + } + } else { + Ptr<OnePassVideoStabilizer> onePassStabilizer = makePtr<OnePassVideoStabilizer>(); + stabilizer_ = onePassStabilizer; + onePassStabilizer->setMotionFilter(makePtr<GaussianMotionFilter>(15, 10)); + } + + stabilizer_->setMotionEstimator(kbest); + + stabilizer_->setRadius(15); + + if (deblur) + { + Ptr<WeightingDeblurer> deblurrer = makePtr<WeightingDeblurer>(); + deblurrer->setRadius(3); + deblurrer->setSensitivity(0.001f); + stabilizer_->setDeblurer(deblurrer); + } + + if (inpainter) + { + bool inpaintMosaic = true; + bool inpaintColorAverage = true; + bool inpaintColorNs = false; + bool inpaintColorTelea = false; + + // init inpainter + InpaintingPipeline *inpainters = new InpaintingPipeline(); + Ptr<InpainterBase> inpainters_(inpainters); + if (true == inpaintMosaic) + { + Ptr<ConsistentMosaicInpainter> inp = makePtr<ConsistentMosaicInpainter>(); + inp->setStdevThresh(10.0f); + inpainters->pushBack(inp); + } + if (true == inpaintColorAverage) + inpainters->pushBack(makePtr<ColorAverageInpainter>()); + else if (true == inpaintColorNs) + inpainters->pushBack(makePtr<ColorInpainter>(0, 2)); + else if (true == inpaintColorTelea) + inpainters->pushBack(makePtr<ColorInpainter>(1, 2)); + if (!inpainters->empty()) + { + inpainters->setRadius(2); + stabilizer_->setInpainter(inpainters_); + } + } +} + +VideoStabilizer::~VideoStabilizer() {} + +void +VideoStabilizer::configFeatureDetector(int features, double minDistance) +{ + Ptr<ImageMotionEstimatorBase> estimator = stabilizer_->motionEstimator(); + Ptr<FeatureDetector> detector = estimator.dynamicCast<KeypointBasedMotionEstimator>()->detector(); + if (NULL == detector) { + return; + } + + detector.dynamicCast<GFTTDetector>()->setMaxFeatures(features); + detector.dynamicCast<GFTTDetector>()->setMinDistance(minDistance); +} + +void +VideoStabilizer::configMotionFilter(int radius, float stdev) +{ + if (isTwoPass_) { + Ptr<TwoPassVideoStabilizer> stab = stabilizer_.dynamicCast<TwoPassVideoStabilizer>(); + Ptr<IMotionStabilizer> motionStabilizer = stab->motionStabilizer(); + motionStabilizer.dynamicCast<GaussianMotionFilter>()->setParams(radius, stdev); + } else { + Ptr<OnePassVideoStabilizer> stab = stabilizer_.dynamicCast<OnePassVideoStabilizer>(); + Ptr<MotionFilterBase> motionFilter = stab->motionFilter(); + motionFilter.dynamicCast<GaussianMotionFilter>()->setParams(radius, stdev); + } + stabilizer_->setRadius(radius); +} + +void +VideoStabilizer::configDeblurrer(int radius, double sensitivity) +{ + Ptr<DeblurerBase> deblurrer = stabilizer_->deblurrer(); + if (NULL == deblurrer) { + return; + } + + deblurrer->setRadius(radius); + deblurrer.dynamicCast<WeightingDeblurer>()->setSensitivity(sensitivity); +} + +void +VideoStabilizer::setFrameSize(Size frameSize) +{ + frameSize_ = frameSize; +} + +Mat +VideoStabilizer::nextFrame() +{ + if (isTwoPass_) { + Ptr<TwoPassVideoStabilizer> stab = stabilizer_.dynamicCast<TwoPassVideoStabilizer>(); + return stab->nextFrame(); + } else { + Ptr<OnePassVideoStabilizer> stab = stabilizer_.dynamicCast<OnePassVideoStabilizer>(); + return stab->nextFrame(); + } +} + +Mat +VideoStabilizer::nextStabilizedMotion(DvsData* frame, int& stablizedPos) +{ + Mat HMatrix; + + if (isTwoPass_) { + Ptr<TwoPassVideoStabilizer> stab = stabilizer_.dynamicCast<TwoPassVideoStabilizer>(); + HMatrix = stab->nextStabilizedMotion(frame, stablizedPos); + } else { + Ptr<OnePassVideoStabilizer> stab = stabilizer_.dynamicCast<OnePassVideoStabilizer>(); + HMatrix = stab->nextStabilizedMotion(frame, stablizedPos); + } + + return HMatrix; +} + +Size +VideoStabilizer::trimedVideoSize(Size frameSize) +{ + Size outputFrameSize; + outputFrameSize.width = ((int)((float)frameSize.width * (1 - 2 * trimRatio_)) >> 3) << 3; + outputFrameSize.height = ((int)((float)frameSize.height * (1 - 2 * trimRatio_)) >> 3) << 3; + + return (outputFrameSize); +} + +Mat +VideoStabilizer::cropVideoFrame(Mat& frame) +{ + Rect cropROI; + Size inputFrameSize = frame.size(); + Size outputFrameSize = trimedVideoSize(inputFrameSize); + + cropROI.x = (inputFrameSize.width - outputFrameSize.width) >> 1; + cropROI.y = (inputFrameSize.height - outputFrameSize.height) >> 1; + cropROI.width = outputFrameSize.width; + cropROI.height = outputFrameSize.height; + + Mat croppedFrame = frame(cropROI).clone(); + + return croppedFrame; +} + diff --git a/plugins/smart/dvs/libdvs/stabilizer.h b/plugins/smart/dvs/libdvs/stabilizer.h new file mode 100644 index 0000000..ffa701e --- /dev/null +++ b/plugins/smart/dvs/libdvs/stabilizer.h @@ -0,0 +1,100 @@ +/* + * stablizer.h - abstract header for DVS (Digital Video Stabilizer) + * + * Copyright (c) 2014-2016 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#ifndef _STABILIZER_H_ +#define _STABILIZER_H_ + +#include <vector> +#include <opencv2/core.hpp> +#include <opencv2/opencv.hpp> +#include <opencv2/videostab.hpp> + +#include "libdvs.h" + +class OnePassVideoStabilizer : public cv::videostab::OnePassStabilizer +{ +public: + virtual ~OnePassVideoStabilizer() {}; + + virtual cv::Mat nextStabilizedMotion(DvsData* frame, int& stablizedPos); + +protected: + virtual cv::Mat estimateMotion(); + virtual void setUpFrame(const cv::Mat &firstFrame); + +private: + +}; + +class TwoPassVideoStabilizer : public cv::videostab::TwoPassStabilizer +{ +public: + virtual ~TwoPassVideoStabilizer() {}; + + virtual cv::Mat nextStabilizedMotion(DvsData* frame, int& stablizedPos); + +protected: + virtual cv::Mat estimateMotion(); + virtual void setUpFrame(const cv::Mat &firstFrame); + +private: + +}; + +class VideoStabilizer +{ +public: + VideoStabilizer(bool isTwoPass = false, + bool wobbleSuppress = false, + bool deblur = false, + bool inpainter = false); + virtual ~VideoStabilizer(); + + cv::Ptr<cv::videostab::StabilizerBase> stabilizer() const { + return stabilizer_; + } + + cv::Mat nextFrame(); + cv::Mat nextStabilizedMotion(DvsData* frame, int& stablizedPos); + + cv::Size trimedVideoSize(cv::Size frameSize); + cv::Mat cropVideoFrame(cv::Mat& frame); + + void setFrameSize(cv::Size frameSize); + cv::Size getFrameSize() const { + return frameSize_; + } + + void configFeatureDetector(int features, double minDistance); + void configMotionFilter(int radius, float stdev); + void configDeblurrer(int radius, double sensitivity); + +public: + cv::VideoWriter writer_; + +private: + bool isTwoPass_; + float trimRatio_; + cv::Size frameSize_; + cv::Ptr<cv::videostab::StabilizerBase> stabilizer_; +}; + + +#endif diff --git a/plugins/smart/dvs/libdvs/test-image-stabilization.cpp b/plugins/smart/dvs/libdvs/test-image-stabilization.cpp new file mode 100644 index 0000000..944ef12 --- /dev/null +++ b/plugins/smart/dvs/libdvs/test-image-stabilization.cpp @@ -0,0 +1,157 @@ +/* + * test-image-stabilization.cpp - test image stabilization + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + + +#include <unistd.h> +#include <getopt.h> +#include <string> +#include <base/xcam_defs.h> +#include "stabilizer.h" + +using namespace std; +using namespace cv; +using namespace cv::videostab; + +void usage(const char* arg0) +{ + printf ("Usage:\n" + "%s --input file --output file\n" + "\t--input input video\n" + "\t--output output video\n" + "\t--enable-twopass two pass stabilization\n" + "\t--enable-deblur do deblur on output video\n" + "\t--wobble-suppress do wobble suppress\n" + "\t--save save file or not, default: true\n" + "\t--help usage\n", + arg0); +} + +int main(int argc, char *argv[]) +{ + char inputPath[XCAM_MAX_STR_SIZE] = {0}; + char outputPath[XCAM_MAX_STR_SIZE] = {0}; + bool enableTwoPass = false; + bool enableDeblur = false; + bool wobbleSuppress = false; + bool saveOutput = true; + + const struct option long_opts[] = { + {"input", required_argument, NULL, 'i'}, + {"output", required_argument, NULL, 'o'}, + {"enable-twopass", required_argument, NULL, 'p'}, + {"enable-deblur", required_argument, NULL, 'd'}, + {"wobble-suppress", required_argument, NULL, 'w'}, + {"save", required_argument, NULL, 's'}, + {"help", no_argument, NULL, 'e'}, + {NULL, 0, NULL, 0}, + }; + + int opt = -1; + while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { + switch (opt) { + case 'i': + strncpy (inputPath, optarg, XCAM_MAX_STR_SIZE); + break; + case 'o': + strncpy (outputPath, optarg, XCAM_MAX_STR_SIZE); + break; + case 'p': + enableTwoPass = (strcasecmp (optarg, "false") == 0 ? false : true);; + break; + case 'd': + enableDeblur = (strcasecmp (optarg, "false") == 0 ? false : true); + break; + case 'w': + wobbleSuppress = (strcasecmp (optarg, "false") == 0 ? false : true); + break; + case 's': + saveOutput = (strcasecmp (optarg, "false") == 0 ? false : true); + break; + case 'e': + usage (argv[0]); + return -1; + default: + printf ("getopt_long return unknown value:%c \n", opt); + usage (argv[0]); + return -1; + } + } + + if (optind < argc || argc < 2) { + printf ("unknown option %s \n", argv[optind]); + usage (argv[0]); + return -1; + } + + printf ("Description----------------\n"); + printf ("input file:\t%s\n", inputPath); + printf ("output file:\t%s\n", outputPath); + printf ("enable two pass stabilizer:\t%s\n", enableTwoPass ? "true" : "false"); + printf ("enable deblur:\t%s\n", enableDeblur ? "true" : "false"); + printf ("enable wobble suppress:\t%s\n", wobbleSuppress ? "true" : "false"); + printf ("save file:\t%s\n", saveOutput ? "true" : "false"); + printf ("---------------------------\n"); + + Ptr<VideoStabilizer> dvs = makePtr<VideoStabilizer>(enableTwoPass, wobbleSuppress, enableDeblur); + Ptr<StabilizerBase> stabilizer = dvs->stabilizer(); + + Ptr<VideoFileSource> source = makePtr<VideoFileSource>(inputPath); + stabilizer->setFrameSource(source); + + int outputFps = source->fps(); + Size frameSize = Size(source->width(), source->height()); + cout << "frame count (rough): " << source->count() << endl; + cout << "output FPS: " << outputFps << endl; + cout << "frame size: " << source->width() << "x" << source->height() << endl; + + // stabilizer configuration + dvs->configFeatureDetector(1000, 15.0f); + dvs->configMotionFilter(15, 10.0f); + + // start to run + Mat stabilizedFrame, croppedStabilizedFrame; + int nframes = 0; + + while (!(stabilizedFrame = dvs->nextFrame()).empty()) + { + nframes++; + cout << nframes << endl; + + // doing cropping here + croppedStabilizedFrame = dvs->cropVideoFrame(stabilizedFrame); + + if (saveOutput) { + if (!dvs->writer_.isOpened()) { + dvs->writer_.open(outputPath, VideoWriter::fourcc('X', '2', '6', '4'), + outputFps, dvs->trimedVideoSize(frameSize)); + } + dvs->writer_.write(croppedStabilizedFrame); + } + + imshow("stabilizedFrame", croppedStabilizedFrame); + char key = static_cast<char>(waitKey(3)); + if (key == 27) { + cout << endl; + break; + } + } + + return 0; +} diff --git a/plugins/smart/dvs/xcam_plugin_dvs.cpp b/plugins/smart/dvs/xcam_plugin_dvs.cpp new file mode 100644 index 0000000..d8e2365 --- /dev/null +++ b/plugins/smart/dvs/xcam_plugin_dvs.cpp @@ -0,0 +1,204 @@ +/* + * xcam_plugin_dvs.cpp - Digital Video Stabilizer plugin + * + * Copyright (c) 2014-2016 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ +#include <base/xcam_common.h> +#include <base/xcam_smart_description.h> +#include <base/xcam_smart_result.h> +#include <base/xcam_3a_result.h> +#include <base/xcam_buffer.h> + +#include <smartptr.h> +#if HAVE_LIBDRM +#include <drm_display.h> +#endif +#include <dma_video_buffer.h> + +#include <ocl/cl_utils.h> +#include <ocl/cl_context.h> +#include <ocl/cl_device.h> +#include <ocl/cl_memory.h> + +#include <opencv2/core/ocl.hpp> + +#include "libdvs/libdvs.h" + +#define DVS_MOTION_FILTER_RADIUS 15 + +struct DvsBuffer : public DvsData +{ + XCamVideoBuffer* buffer; + + DvsBuffer () { } + + DvsBuffer (XCamVideoBuffer* buf, cv::UMat& frame) + : buffer (buf) + { + buffer->ref(buffer); + data = frame; + } + + ~DvsBuffer () { + buffer->unref(buffer); + } +}; + +XCamReturn dvs_create_context(XCamSmartAnalysisContext **context, uint32_t *async_mode, XcamPostResultsFunc post_func) +{ + XCAM_UNUSED (async_mode); + XCAM_UNUSED (post_func); + + DvsInterface* theDVS = NULL; + + theDVS = getDigitalVideoStabilizer(); + if (theDVS == NULL) { + return XCAM_RETURN_ERROR_MEM; + } + theDVS->init(640, 480, false); + + *context = (XCamSmartAnalysisContext *)theDVS; + + cl_platform_id platform_id = XCam::CLDevice::instance()->get_platform_id(); + char* platform_name = XCam::CLDevice::instance()->get_platform_name (); + cl_device_id device_id = XCam::CLDevice::instance()->get_device_id(); + cl_context cl_context_id = XCam::CLDevice::instance()->get_context()->get_context_id(); + + clRetainContext (cl_context_id); + cv::ocl::attachContext (platform_name, platform_id, cl_context_id, device_id); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn dvs_destroy_context(XCamSmartAnalysisContext *context) +{ + DvsInterface *theDVS = (DvsInterface *)context; + + theDVS->release (); + + delete (theDVS); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn dvs_update_params(XCamSmartAnalysisContext *context, const XCamSmartAnalysisParam *params) +{ + XCAM_UNUSED (context); + XCAM_UNUSED (params); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn dvs_analyze(XCamSmartAnalysisContext *context, XCamVideoBuffer *buffer, XCam3aResultHead *results[], uint32_t *res_count) +{ + DvsInterface *theDVS = (DvsInterface *)context; + DvsResult dvsResult; + + if (buffer->info.format != V4L2_PIX_FMT_NV12 || buffer->mem_type != XCAM_MEM_TYPE_PRIVATE_BO) + return XCAM_RETURN_ERROR_PARAM; + + int buffer_fd = xcam_video_buffer_get_fd(buffer); + XCam::VideoBufferInfo buffer_info; + buffer_info.init (buffer->info.format, buffer->info.width, buffer->info.height, + buffer->info.aligned_width, buffer->info.aligned_height, buffer->info.size); + XCam::SmartPtr<XCam::VideoBuffer> new_buffer = new XCam::DmaVideoBuffer(buffer_info, buffer_fd); + + XCam::SmartPtr<XCam::VideoBuffer> video_buffer; +#if HAVE_LIBDRM + XCam::SmartPtr<XCam::DrmDisplay> display = XCam::DrmDisplay::instance (); + video_buffer = display->convert_to_drm_bo_buf (display, new_buffer); +#else + video_buffer = new_buffer; +#endif + + XCam::SmartPtr<XCam::CLContext> cl_Context = XCam::CLDevice::instance()->get_context(); + XCam::SmartPtr<XCam::CLBuffer> cl_buffer = XCam::convert_to_clbuffer (cl_Context, video_buffer); + cl_mem cl_mem_id = cl_buffer->get_mem_id(); + + clRetainMemObject(cl_mem_id); + cv::UMat frame; + cv::ocl::convertFromBuffer(cl_mem_id, buffer->info.strides[0], buffer->info.height, buffer->info.width, CV_8U, frame); + + DvsBuffer* dvs_buf = new DvsBuffer(buffer, frame); + //set default config + DvsConfig config; + memset(&config, 0, sizeof(DvsConfig)); + config.use_ocl = true; + config.frame_width = buffer->info.width; + config.frame_height = buffer->info.height; + config.radius = DVS_MOTION_FILTER_RADIUS; + config.stdev = 10.0f; + config.features = 1000; + config.minDistance = 20.0f; + + theDVS->setConfig(&config); + + theDVS->nextStabilizedMotion(dvs_buf, &dvsResult); + + delete(dvs_buf); + + if ((dvsResult.frame_id < 0) && (dvsResult.valid == false)) + { + results[0] = NULL; + *res_count = 0; + XCAM_LOG_WARNING ("dvs_analyze not ready! "); + } else { + XCamDVSResult *dvs_result = (XCamDVSResult *)malloc(sizeof(XCamDVSResult)); + memset(dvs_result, 0, sizeof(XCamDVSResult)); + + dvs_result->head.type = XCAM_3A_RESULT_DVS; + dvs_result->head.process_type = XCAM_IMAGE_PROCESS_POST; + dvs_result->head.version = 0x080; + dvs_result->frame_id = dvsResult.frame_id; + dvs_result->frame_width = dvsResult.frame_width; + dvs_result->frame_height = dvsResult.frame_height; + memcpy(dvs_result->proj_mat, dvsResult.proj_mat, sizeof(DvsResult::proj_mat)); + + results[0] = (XCam3aResultHead *)dvs_result; + *res_count = 1; + } + + return XCAM_RETURN_NO_ERROR; +} + +void dvs_free_results(XCamSmartAnalysisContext *context, XCam3aResultHead *results[], uint32_t res_count) +{ + XCAM_UNUSED (context); + for (uint32_t i = 0; i < res_count; ++i) { + if (results[i]) { + free (results[i]); + } + } +} + +XCAM_BEGIN_DECLARE + +XCamSmartAnalysisDescription xcam_smart_analysis_desciption = +{ + 0x080, + sizeof (XCamSmartAnalysisDescription), + 10, + "digital_video_stabilizer", + dvs_create_context, + dvs_destroy_context, + dvs_update_params, + dvs_analyze, + dvs_free_results, +}; + +XCAM_END_DECLARE + diff --git a/plugins/smart/sample/Makefile.am b/plugins/smart/sample/Makefile.am new file mode 100644 index 0000000..407d2dd3 --- /dev/null +++ b/plugins/smart/sample/Makefile.am @@ -0,0 +1,46 @@ +noinst_LTLIBRARIES = \ + $(NULL) + +if ENABLE_IA_AIQ +noinst_LTLIBRARIES += \ + libxcam_sample_smart.la \ + $(NULL) +endif + +XCAMSMART_CXXFLAGS = $(XCAM_CXXFLAGS) +XCAMSMART_LIBS = \ + $(NULL) + +if USE_LOCAL_ATOMISP +XCAMSMART_CXXFLAGS += \ + -I$(top_srcdir)/ext/atomisp \ + $(NULL) +endif + +plugindir="$(libdir)/xcam/plugins/smart" + +if ENABLE_IA_AIQ +libxcam_sample_smart_la_SOURCES = \ + sample_smart_analysis.cpp \ + $(NULL) + +libxcam_sample_smart_la_CXXFLAGS = \ + $(GST_CFLAGS) $(XCAMSMART_CXXFLAGS) \ + -I$(top_srcdir)/xcore \ + -I$(top_srcdir)/modules/isp \ + -I$(top_srcdir)/plugins/smart \ + $(NULL) + +libxcam_sample_smart_la_LIBADD = \ + $(XCAMSMART_LIBS) \ + $(top_builddir)/xcore/libxcam_core.la \ + $(NULL) + +libxcam_sample_smart_la_LDFLAGS = \ + -module -avoid-version \ + $(top_builddir)/xcore/libxcam_core.la \ + $(PTHREAD_LDFLAGS) \ + $(NULL) +endif + +libxcam_sample_smart_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/plugins/smart/sample/sample_smart_analysis.cpp b/plugins/smart/sample/sample_smart_analysis.cpp new file mode 100644 index 0000000..a144946 --- /dev/null +++ b/plugins/smart/sample/sample_smart_analysis.cpp @@ -0,0 +1,450 @@ +/* + * sample_smart_analysis.cpp - smart analysis sample code + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include <base/xcam_smart_description.h> +#include <base/xcam_buffer.h> +#include <xcam_std.h> +#include "aiq3a_utils.h" +#include "x3a_result_factory.h" +#include "smart_analyzer.h" + +using namespace XCam; + +#define DEFAULT_SAVE_FRAME_NAME "frame_buffer" +#define XSMART_ANALYSIS_CONTEXT_CAST(context) ((XCamSmartAnalyerContext*)(context)) + +class FrameSaver +{ +public: + explicit FrameSaver (bool save, uint32_t interval, uint32_t count); + ~FrameSaver (); + + void save_frame (XCamVideoBuffer *buffer); + + void enable_save_file (bool enable) { + _save_file = enable; + } + void set_interval (uint32_t inteval) { + _interval = inteval; + } + void set_frame_save (uint32_t frame_save) { + _frame_save = frame_save; + } + +private: + XCAM_DEAD_COPY (FrameSaver); + void open_file (); + void close_file (); + +private: + FILE *_file; + bool _save_file; + uint32_t _interval; + uint32_t _frame_save; + uint32_t _frame_count; + uint32_t _skip_frame_count; + +}; + +FrameSaver::FrameSaver (bool save, uint32_t interval, uint32_t count) + : _file (NULL) + , _save_file (save) + , _interval (interval) + , _frame_save (count) + , _frame_count (0) + , _skip_frame_count (300) +{ +} + +FrameSaver::~FrameSaver () +{ + close_file (); +} + +void +FrameSaver::save_frame (XCamVideoBuffer *buffer) +{ + if (NULL == buffer) { + return; + } + if (!_save_file) + return ; + + if ((_frame_count++ % _interval) != 0) + return; + + if (_frame_count < _skip_frame_count) + return; + + if (_frame_count > (_frame_save * _interval + _skip_frame_count)) { + return; + } + + open_file (); + + if (!_file) { + XCAM_LOG_ERROR ("open file failed"); + return; + } + + uint8_t *memory = xcam_video_buffer_map (buffer); + XCamVideoBufferPlanarInfo planar; + for (uint32_t index = 0; index < buffer->info.components; index++) { + xcam_video_buffer_get_planar_info (&buffer->info, &planar, index); + uint32_t line_bytes = planar.width * planar.pixel_bytes; + + for (uint32_t i = 0; i < planar.height; i++) { + if (fwrite (memory + buffer->info.offsets [index] + i * buffer->info.strides [index], + 1, line_bytes, _file) != line_bytes) { + XCAM_LOG_ERROR ("write file failed, size doesn't match"); + return; + } + } + } + xcam_video_buffer_unmap (buffer); + close_file (); +} + +void +FrameSaver::open_file () +{ + if ((_file) && (_frame_save == 0)) + return; + + char file_name[512]; + if (_frame_save != 0) { + snprintf (file_name, sizeof(file_name), "%s%d%s", DEFAULT_SAVE_FRAME_NAME, _frame_count, ".yuv"); + } + + _file = fopen(file_name, "wb"); +} + +void +FrameSaver::close_file () +{ + if (_file) + fclose (_file); + _file = NULL; +} + +class SampleHandler +{ +public: + explicit SampleHandler (const char *name = NULL); + virtual ~SampleHandler (); + + XCamReturn init (uint32_t width, uint32_t height, double framerate); + XCamReturn deinit (); + bool set_results_callback (AnalyzerCallback *callback); + + XCamReturn update_params (const XCamSmartAnalysisParam *params); + XCamReturn analyze (XCamVideoBuffer *buffer); + +private: + XCAM_DEAD_COPY (SampleHandler); + +private: + char *_name; + uint32_t _width; + uint32_t _height; + double _framerate; + AnalyzerCallback *_callback; + SmartPtr<FrameSaver> _frameSaver; +}; + +SampleHandler::SampleHandler (const char *name) + : _name (NULL) + , _width (0) + , _height (0) + , _framerate (30.0) + , _callback (NULL) +{ + if (name) + _name = strndup (name, XCAM_MAX_STR_SIZE); + + if (!_frameSaver.ptr ()) { + _frameSaver = new FrameSaver (true, 2, 16); + } +} + +SampleHandler::~SampleHandler () +{ + if (_name) + xcam_free (_name); +} + +XCamReturn +SampleHandler::init (uint32_t width, uint32_t height, double framerate) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + _width = width; + _height = height; + _framerate = framerate; + + return ret; +} + +XCamReturn +SampleHandler::deinit () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + return ret; +} + +bool +SampleHandler::set_results_callback (AnalyzerCallback *callback) +{ + XCAM_ASSERT (!_callback); + _callback = callback; + return true; +} + +XCamReturn +SampleHandler::update_params (const XCamSmartAnalysisParam *params) +{ + XCAM_UNUSED (params); + + XCamReturn ret = XCAM_RETURN_NO_ERROR; + return ret; +} + +XCamReturn +SampleHandler::analyze (XCamVideoBuffer *buffer) +{ + XCAM_LOG_DEBUG ("Smart SampleHandler::analyze on ts:" XCAM_TIMESTAMP_FORMAT, XCAM_TIMESTAMP_ARGS (buffer->timestamp)); + if (NULL == buffer) { + return XCAM_RETURN_ERROR_PARAM; + } + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_LOG_DEBUG ("format(0x%x), color_bits(%d)", buffer->info.format, buffer->info.color_bits); + XCAM_LOG_DEBUG ("size(%d), components(%d)", buffer->info.size, buffer->info.components); + XCAM_LOG_DEBUG ("width(%d), heitht(%d)", buffer->info.width, buffer->info.height); + XCAM_LOG_DEBUG ("aligned_width(%d), aligned_height(%d)", buffer->info.aligned_width, buffer->info.aligned_height); + + _frameSaver->save_frame (buffer); + + X3aResultList results; + XCam3aResultBrightness xcam3a_brightness_result; + xcam_mem_clear (xcam3a_brightness_result); + xcam3a_brightness_result.head.type = XCAM_3A_RESULT_BRIGHTNESS; + xcam3a_brightness_result.head.process_type = XCAM_IMAGE_PROCESS_ALWAYS; + xcam3a_brightness_result.head.version = XCAM_VERSION; + xcam3a_brightness_result.brightness_level = 9.9; + + SmartPtr<X3aResult> brightness_result = + X3aResultFactory::instance ()->create_3a_result ((XCam3aResultHead*)&xcam3a_brightness_result); + results.push_back(brightness_result); + + if (_callback) { + if (XCAM_RETURN_NO_ERROR == ret) { + _callback->x3a_calculation_done (NULL, results); + } else { + _callback->x3a_calculation_failed (NULL, buffer->timestamp, "pre 3a analyze failed"); + } + } + + return ret; +} + +class XCamSmartAnalyerContext + : public AnalyzerCallback +{ +public: + XCamSmartAnalyerContext (); + ~XCamSmartAnalyerContext (); + bool setup_handler (); + SmartPtr<SampleHandler> &get_handler () { + return _handler; + } + + uint32_t get_results (X3aResultList &results); + + // derive from AnalyzerCallback + virtual void x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results); + +private: + XCAM_DEAD_COPY (XCamSmartAnalyerContext); + +private: +// members + SmartPtr<SampleHandler> _handler; + Mutex _result_mutex; + X3aResultList _results; +}; + +XCamSmartAnalyerContext::XCamSmartAnalyerContext () +{ + setup_handler (); +} + +XCamSmartAnalyerContext::~XCamSmartAnalyerContext () +{ + _handler->deinit (); +} + +bool +XCamSmartAnalyerContext::setup_handler () +{ + XCAM_ASSERT (!_handler.ptr ()); + _handler = new SampleHandler (); + XCAM_ASSERT (_handler.ptr ()); + _handler->set_results_callback (this); + return true; +} + +void +XCamSmartAnalyerContext::x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results) +{ + XCAM_UNUSED (analyzer); + SmartLock locker (_result_mutex); + _results.insert (_results.end (), results.begin (), results.end ()); +} + +uint32_t +XCamSmartAnalyerContext::get_results (X3aResultList &results) +{ + uint32_t size = 0; + SmartLock locker (_result_mutex); + + results.assign (_results.begin (), _results.end ()); + size = _results.size (); + _results.clear (); + + return size; +} + +static XCamReturn +xcam_create_context (XCamSmartAnalysisContext **context, uint32_t *async_mode, XcamPostResultsFunc post_func) +{ + XCAM_ASSERT (context); + XCAM_UNUSED (post_func); + XCamSmartAnalyerContext *analysis_context = new XCamSmartAnalyerContext (); + *context = ((XCamSmartAnalysisContext*)(analysis_context)); + *async_mode = false; + + return XCAM_RETURN_NO_ERROR; +} + +static XCamReturn +xcam_destroy_context (XCamSmartAnalysisContext *context) +{ + XCamSmartAnalyerContext *analysis_context = XSMART_ANALYSIS_CONTEXT_CAST (context); + delete analysis_context; + return XCAM_RETURN_NO_ERROR; +} + +static XCamReturn +xcam_update_params (XCamSmartAnalysisContext *context, const XCamSmartAnalysisParam *params) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + XCamSmartAnalyerContext *analysis_context = XSMART_ANALYSIS_CONTEXT_CAST (context); + XCAM_ASSERT (analysis_context); + + SmartPtr<SampleHandler> handler = analysis_context->get_handler (); + XCAM_ASSERT (handler.ptr ()); + XCAM_ASSERT (params); + + ret = handler->update_params (params); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("update params failed"); + } + + return ret; +} + +static XCamReturn +xcam_get_results (XCamSmartAnalysisContext *context, XCam3aResultHead *results[], uint32_t *res_count) +{ + XCamSmartAnalyerContext *analysis_context = XSMART_ANALYSIS_CONTEXT_CAST (context); + XCAM_ASSERT (analysis_context); + X3aResultList analysis_results; + uint32_t result_count = analysis_context->get_results (analysis_results); + + if (!result_count) { + *res_count = 0; + XCAM_LOG_DEBUG ("Smart Analysis return no result"); + return XCAM_RETURN_NO_ERROR; + } + + // mark as static + static XCam3aResultHead *res_array[XCAM_3A_MAX_RESULT_COUNT]; + XCAM_ASSERT (result_count < XCAM_3A_MAX_RESULT_COUNT); + result_count = translate_3a_results_to_xcam (analysis_results, res_array, XCAM_3A_MAX_RESULT_COUNT); + + for (uint32_t i = 0; i < result_count; ++i) { + results[i] = res_array[i]; + } + *res_count = result_count; + XCAM_ASSERT (result_count > 0); + + return XCAM_RETURN_NO_ERROR; +} + + +static XCamReturn +xcam_analyze (XCamSmartAnalysisContext *context, XCamVideoBuffer *buffer, XCam3aResultHead *results[], uint32_t *res_count) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + if (!buffer) { + return XCAM_RETURN_ERROR_PARAM; + } + + XCamSmartAnalyerContext *analysis_context = XSMART_ANALYSIS_CONTEXT_CAST (context); + XCAM_ASSERT (analysis_context); + + SmartPtr<SampleHandler> handler = analysis_context->get_handler (); + XCAM_ASSERT (handler.ptr ()); + + ret = handler->analyze(buffer); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("buffer analyze failed"); + } + + xcam_get_results (context, results, res_count); + return ret; +} + +static void +xcam_free_results (XCamSmartAnalysisContext *context, XCam3aResultHead *results[], uint32_t res_count) +{ + XCAM_UNUSED (context); + for (uint32_t i = 0; i < res_count; ++i) { + if (results[i]) + free_3a_result (results[i]); + } +} + +XCAM_BEGIN_DECLARE + +XCamSmartAnalysisDescription xcam_smart_analysis_desciption = { + XCAM_VERSION, + sizeof (XCamSmartAnalysisDescription), + XCAM_SMART_PLUGIN_PRIORITY_DEFAULT, + "sample test", + xcam_create_context, + xcam_destroy_context, + xcam_update_params, + xcam_analyze, + xcam_free_results +}; + +XCAM_END_DECLARE + diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..61440c7 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,9 @@ +test-binary-kernel +test-cl-image +test-device-manager +test-image-blend +test-image-deblurring +test-image-stitching +test-pipe-manager +test-video-stabilization +test-soft-image diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 0000000..6e68880 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,126 @@ +XCORE_DIR = $(top_srcdir)/xcore +MODULES_DIR = $(top_srcdir)/modules + +TEST_BASE_CXXFLAGS = $(XCAM_CXXFLAGS) +if HAVE_LIBDRM +TEST_BASE_CXXFLAGS += $(LIBDRM_CFLAGS) $(LIBDRM_LIBS) +endif + +if USE_LOCAL_ATOMISP +TEST_BASE_CXXFLAGS += -I$(top_srcdir)/ext/atomisp +endif + +TEST_BASE_CXXFLAGS += \ + -I$(XCORE_DIR) \ + -I$(MODULES_DIR) \ + $(NULL) + +TEST_BASE_LA = \ + $(NULL) + +noinst_PROGRAMS = \ + test-device-manager \ + test-soft-image \ + $(NULL) + +if ENABLE_IA_AIQ +noinst_PROGRAMS += \ + test-poll-thread \ + $(NULL) +endif + +if HAVE_LIBCL +noinst_PROGRAMS += \ + test-cl-image \ + test-binary-kernel \ + test-pipe-manager \ + test-image-blend \ + test-image-stitching \ + test-video-stabilization \ + $(NULL) + +TEST_BASE_LA += $(top_builddir)/modules/ocl/libxcam_ocl.la + +if HAVE_OPENCV +noinst_PROGRAMS += \ + test-image-deblurring \ + $(NULL) + +TEST_BASE_CXXFLAGS += $(OPENCV_CFLAGS) +TEST_BASE_LA += $(OPENCV_LIBS) +endif +endif + +TEST_BASE_LA += \ + $(top_builddir)/xcore/libxcam_core.la \ + $(NULL) + +test_device_manager_SOURCES = test-device-manager.cpp +test_device_manager_CXXFLAGS = $(TEST_BASE_CXXFLAGS) +test_device_manager_LDADD = $(TEST_BASE_LA) + +if ENABLE_IA_AIQ +ISP_LA = $(top_builddir)/modules/isp/libxcam_isp.la + +test_device_manager_LDADD += $(ISP_LA) + +test_poll_thread_SOURCES = test-poll-thread.cpp +test_poll_thread_CXXFLAGS = $(TEST_BASE_CXXFLAGS) +test_poll_thread_LDADD = \ + $(TEST_BASE_LA) $(ISP_LA) \ + $(NULL) +endif + +if HAVE_LIBCL +test_cl_image_SOURCES = test-cl-image.cpp +test_cl_image_CXXFLAGS = $(TEST_BASE_CXXFLAGS) +test_cl_image_LDADD = \ + $(TEST_BASE_LA) \ + $(NULL) + +test_binary_kernel_SOURCES = test-binary-kernel.cpp +test_binary_kernel_CXXFLAGS = $(TEST_BASE_CXXFLAGS) +test_binary_kernel_LDADD = \ + $(TEST_BASE_LA) \ + $(NULL) + +test_pipe_manager_SOURCES = test-pipe-manager.cpp +test_pipe_manager_CXXFLAGS = $(TEST_BASE_CXXFLAGS) +test_pipe_manager_LDADD = \ + $(TEST_BASE_LA) \ + $(NULL) + +test_image_blend_SOURCES = test-image-blend.cpp +test_image_blend_CXXFLAGS = $(TEST_BASE_CXXFLAGS) +test_image_blend_LDADD = \ + $(TEST_BASE_LA) \ + $(NULL) + +test_image_stitching_SOURCES = test-image-stitching.cpp +test_image_stitching_CXXFLAGS = $(TEST_BASE_CXXFLAGS) +test_image_stitching_LDADD = \ + $(TEST_BASE_LA) \ + $(NULL) + +test_video_stabilization_SOURCES = test-video-stabilization.cpp +test_video_stabilization_CXXFLAGS = $(TEST_BASE_CXXFLAGS) +test_video_stabilization_LDADD = \ + $(TEST_BASE_LA) \ + $(NULL) + +if HAVE_OPENCV +test_image_deblurring_SOURCES = test-image-deblurring.cpp +test_image_deblurring_CXXFLAGS = $(TEST_BASE_CXXFLAGS) + $(NULL) +test_image_deblurring_LDADD = \ + $(TEST_BASE_LA) \ + $(NULL) +endif +endif + +test_soft_image_SOURCES = test-soft-image.cpp +test_soft_image_CXXFLAGS = $(TEST_BASE_CXXFLAGS) +test_soft_image_LDADD = \ + $(top_builddir)/modules/soft/libxcam_soft.la \ + $(TEST_BASE_LA) \ + $(NULL) diff --git a/tests/test-binary-kernel.cpp b/tests/test-binary-kernel.cpp new file mode 100644 index 0000000..127b982 --- /dev/null +++ b/tests/test-binary-kernel.cpp @@ -0,0 +1,126 @@ +/* + * test-binary-kernel.cpp - Compile the source kernel into binary kernel + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include "test_common.h" +#include "test_inline.h" +#include "file_handle.h" +#include "ocl/cl_device.h" +#include "ocl/cl_context.h" +#include "ocl/cl_kernel.h" +#include <getopt.h> + +using namespace XCam; + +static void +print_help (const char *arg0) +{ + printf ("Usage: %s --src-kernel <source-kernel> --bin-kernel <binary-kernel> --kernel-name <kernel-name>\n" + "\t --src-kernel specify source kernel path\n" + "\t --bin-kernel specify binary kernel path\n" + "\t --kernel-name specify kernel name\n" + "\t --help help\n" + , arg0); +} + +#define FAILED_STATEMENT { \ + if (kernel_body) xcam_free (kernel_body); \ + if (kernel_name) xcam_free (kernel_name); \ + if (program_binaries) xcam_free (program_binaries); \ + return -1; } + +int main (int argc, char *argv[]) +{ + char *src_path = NULL, *bin_path = NULL; + size_t src_size = 0; + size_t bin_size = 0; + char *kernel_name = NULL; + char *kernel_body = NULL; + uint8_t *program_binaries = NULL; + FileHandle src_file, bin_file; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + const struct option long_opts [] = { + {"src-kernel", required_argument, NULL, 's'}, + {"bin-kernel", required_argument, NULL, 'b'}, + {"kernel-name", required_argument, NULL, 'n'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + int opt = 0; + while ((opt = getopt_long (argc, argv, "", long_opts, NULL)) != -1) { + switch (opt) { + case 's': + src_path = optarg; + break; + case 'b': + bin_path = optarg; + break; + case 'n': + kernel_name = strndup (optarg, 1024); + break; + case 'h': + print_help (argv[0]); + return 0; + + default: + print_help (argv[0]); + return -1; + } + } + + if (!src_path || !bin_path) { + XCAM_LOG_ERROR ("path of source/binary kernel is null"); + return -1; + } + if (!kernel_name) { + XCAM_LOG_ERROR ("kernel name is null"); + return -1; + } + + if (src_file.open (src_path, "r") != XCAM_RETURN_NO_ERROR || + bin_file.open (bin_path, "wb") != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("open source/binary kernel failed"); + return -1; + } + + ret = src_file.get_file_size (src_size); + CHECK_STATEMENT (ret, FAILED_STATEMENT, "get source sizes from %s failed", src_path); + + kernel_body = (char *) xcam_malloc0 (sizeof (char) * (src_size + 1)); + XCAM_ASSERT(kernel_body); + + src_file.read_file (kernel_body, src_size); + CHECK_STATEMENT (ret, FAILED_STATEMENT, "read source from %s failed", src_path); + kernel_body[src_size] = '\0'; + + SmartPtr<CLContext> context; + context = CLDevice::instance ()->get_context (); + SmartPtr<CLKernel> kernel = new CLKernel (context, kernel_name); + kernel->load_from_source (kernel_body, strlen (kernel_body), &program_binaries, &bin_size); + + ret = bin_file.write_file (program_binaries, bin_size); + CHECK_STATEMENT (ret, FAILED_STATEMENT, "write binary to %s failed", bin_path); + + xcam_free (kernel_name); + xcam_free (kernel_body); + xcam_free (program_binaries); + return 0; +} diff --git a/tests/test-cl-image.cpp b/tests/test-cl-image.cpp new file mode 100644 index 0000000..19000b5 --- /dev/null +++ b/tests/test-cl-image.cpp @@ -0,0 +1,589 @@ +/* + * test_cl_image.cpp - test cl image + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + * Author: Wei Zong <wei.zong@intel.com> + */ + +#include "test_common.h" +#include "test_inline.h" +#include "image_file_handle.h" +#include "ocl/cl_device.h" +#include "ocl/cl_context.h" +#include "ocl/cl_demo_handler.h" +#include "ocl/cl_csc_handler.h" +#include "ocl/cl_bayer_pipe_handler.h" +#include "ocl/cl_yuv_pipe_handler.h" +#include "ocl/cl_tonemapping_handler.h" +#include "ocl/cl_retinex_handler.h" +#include "ocl/cl_gauss_handler.h" +#include "ocl/cl_wavelet_denoise_handler.h" +#include "ocl/cl_newwavelet_denoise_handler.h" +#include "ocl/cl_defog_dcp_handler.h" +#include "ocl/cl_3d_denoise_handler.h" +#include "ocl/cl_image_warp_handler.h" +#include "ocl/cl_fisheye_handler.h" +#include "ocl/cl_utils.h" + +using namespace XCam; + +enum TestHandlerType { + TestHandlerUnknown = 0, + TestHandlerDemo, + TestHandlerColorConversion, + TestHandlerBayerPipe, + TestHandlerYuvPipe, + TestHandlerTonemapping, + TestHandlerRetinex, + TestHandlerGauss, + TestHandlerHatWavelet, + TestHandlerHaarWavelet, + TestHandlerDefogDcp, + TestHandler3DDenoise, + TestHandlerImageWarp, + TestHandlerFisheye, +}; + +enum PsnrType { + PSNRY = 0, + PSNRR, + PSNRG, + PSNRB, +}; + +static XCamReturn +calculate_psnr (SmartPtr<VideoBuffer> &psnr_cur, SmartPtr<VideoBuffer> &psnr_ref, PsnrType psnr_type, float &psnr) +{ + const VideoBufferInfo info = psnr_cur->get_video_info (); + VideoBufferPlanarInfo planar; + uint8_t *cur_mem = NULL, *ref_mem = NULL; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + int8_t interval = 1, index = 0; + if (PSNRY == psnr_type) { + interval = 1; + index = 0; + } else if (PSNRR == psnr_type) { + interval = 4; + index = 0; + } else if (PSNRG == psnr_type) { + interval = 4; + index = 1; + } else if (PSNRB == psnr_type) { + interval = 4; + index = 2; + } + + cur_mem = psnr_cur->map (); + ref_mem = psnr_ref->map (); + if (!cur_mem || !ref_mem) { + XCAM_LOG_ERROR ("calculate_psnr map buffer failed"); + return XCAM_RETURN_ERROR_MEM; + } + + uint32_t sum = 0, pos = 0; + info.get_planar_info (planar, 0); + for (uint32_t i = 0; i < planar.height; i++) { + for (uint32_t j = 0; j < planar.width / interval; j++) { + pos = i * planar.width + j * interval + index; + sum += (cur_mem [pos] - ref_mem [pos]) * (cur_mem [pos] - ref_mem [pos]); + } + } + float mse = (float) sum / (planar.height * planar.width / interval) + 0.000001f; + psnr = 10 * log10 (255 * 255 / mse); + + psnr_cur->unmap (); + psnr_ref->unmap (); + + return ret; +} + +static XCamReturn +kernel_loop(SmartPtr<CLImageHandler> &image_handler, SmartPtr<VideoBuffer> &input_buf, SmartPtr<VideoBuffer> &output_buf, uint32_t kernel_loop_count) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + for (uint32_t i = 0; i < kernel_loop_count; i++) { + PROFILING_START(cl_kernel); + ret = image_handler->execute (input_buf, output_buf); + PROFILING_END(cl_kernel, kernel_loop_count) + } + return ret; +} + +static void +print_help (const char *bin_name) +{ + printf ("Usage: %s [-f format] -i input -o output\n" + "\t -t type specify image handler type\n" + "\t select from [demo, blacklevel, defect, demosaic, tonemapping, csc, hdr, wb, denoise," + " gamma, snr, bnr, macc, ee, bayerpipe, yuvpipe, retinex, gauss, wavelet-hat, wavelet-haar, dcp, fisheye]\n" + "\t -f input_format specify a input format\n" + "\t -W image_width specify input image width\n" + "\t -H image_height specify input image height\n" + "\t -g output_format specify a output format\n" + "\t select from [NV12, BA10, RGBA, RGBA64]\n" + "\t -i input specify input file path\n" + "\t -o output specify output file path\n" + "\t -r refer specify reference file path\n" + "\t -k binary_kernel specify binary kernel path\n" + "\t -p count specify cl kernel loop count\n" + "\t -c csc_type specify csc type, default:rgba2nv12\n" + "\t select from [rgbatonv12, rgbatolab, rgba64torgba, yuyvtorgba, nv12torgba]\n" + "\t -b enable bayer-nr, default: disable\n" + "\t -P enable psnr calculation, default: disable\n" + "\t -h help\n" + , bin_name); + + printf ("Note:\n" + "Usage of binary kernel:\n" + "1. generate binary kernel:\n" + " $ test-binary-kernel --src-kernel kernel_demo.cl --bin-kernel kernel_demo.cl.bin" + " --kernel-name kernel_demo\n" + "2. execute binary kernel:\n" + " $ test-cl-image -t demo -f BA10 -i input.raw -o output.raw -k kernel_demo.cl.bin\n"); +} + +int main (int argc, char *argv[]) +{ + uint32_t input_format = 0; + uint32_t output_format = V4L2_PIX_FMT_RGBA32; + uint32_t width = 1920; + uint32_t height = 1080; + uint32_t buf_count = 0; + int32_t kernel_loop_count = 0; + const char *input_file = NULL, *output_file = NULL, *refer_file = NULL; + const char *bin_kernel_path = NULL; + ImageFileHandle input_fp, output_fp, refer_fp; + const char *bin_name = argv[0]; + TestHandlerType handler_type = TestHandlerUnknown; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<CLImageHandler> image_handler; + VideoBufferInfo input_buf_info; + SmartPtr<CLContext> context; + SmartPtr<BufferPool> buf_pool; + int opt = 0; + CLCscType csc_type = CL_CSC_TYPE_RGBATONV12; + bool enable_bnr = false; + bool enable_psnr = false; + + while ((opt = getopt(argc, argv, "f:W:H:i:o:r:t:k:p:c:g:bPh")) != -1) { + switch (opt) { + case 'i': + input_file = optarg; + break; + case 'o': + output_file = optarg; + break; + case 'r': + refer_file = optarg; + break; + + case 'f': { + if (!strcasecmp (optarg, "nv12")) + input_format = V4L2_PIX_FMT_NV12; + else if (!strcasecmp (optarg, "ba10")) + input_format = V4L2_PIX_FMT_SGRBG10; + else if (! strcasecmp (optarg, "rgba")) + input_format = V4L2_PIX_FMT_RGBA32; + else if (! strcasecmp (optarg, "rgba64")) + input_format = XCAM_PIX_FMT_RGBA64; + else if (!strcasecmp (optarg, "ba12")) + input_format = V4L2_PIX_FMT_SGRBG12; + else + print_help (bin_name); + break; + } + case 'W': { + width = atoi (optarg); + break; + } + case 'H': { + height = atoi (optarg); + break; + } + case 'g': { + if (!strcasecmp (optarg, "nv12")) + output_format = V4L2_PIX_FMT_NV12; + else if (!strcasecmp (optarg, "ba10")) + output_format = V4L2_PIX_FMT_SGRBG10; + else if (! strcasecmp (optarg, "rgba")) + output_format = V4L2_PIX_FMT_RGBA32; + else if (! strcasecmp (optarg, "rgba64")) + output_format = XCAM_PIX_FMT_RGBA64; + + else + print_help (bin_name); + break; + } + case 't': { + if (!strcasecmp (optarg, "demo")) + handler_type = TestHandlerDemo; + else if (!strcasecmp (optarg, "csc")) + handler_type = TestHandlerColorConversion; + else if (!strcasecmp (optarg, "bayerpipe")) + handler_type = TestHandlerBayerPipe; + else if (!strcasecmp (optarg, "yuvpipe")) + handler_type = TestHandlerYuvPipe; + else if (!strcasecmp (optarg, "tonemapping")) + handler_type = TestHandlerTonemapping; + else if (!strcasecmp (optarg, "retinex")) + handler_type = TestHandlerRetinex; + else if (!strcasecmp (optarg, "gauss")) + handler_type = TestHandlerGauss; + else if (!strcasecmp (optarg, "wavelet-hat")) + handler_type = TestHandlerHatWavelet; + else if (!strcasecmp (optarg, "wavelet-haar")) + handler_type = TestHandlerHaarWavelet; + else if (!strcasecmp (optarg, "dcp")) + handler_type = TestHandlerDefogDcp; + else if (!strcasecmp (optarg, "3d-denoise")) + handler_type = TestHandler3DDenoise; + else if (!strcasecmp (optarg, "warp")) + handler_type = TestHandlerImageWarp; + else if (!strcasecmp (optarg, "fisheye")) + handler_type = TestHandlerFisheye; + else + print_help (bin_name); + break; + } + case 'k': + bin_kernel_path = optarg; + break; + case 'p': + kernel_loop_count = atoi (optarg); + XCAM_ASSERT (kernel_loop_count >= 0 && kernel_loop_count < INT32_MAX); + break; + case 'c': + if (!strcasecmp (optarg, "rgbatonv12")) + csc_type = CL_CSC_TYPE_RGBATONV12; + else if (!strcasecmp (optarg, "rgbatolab")) + csc_type = CL_CSC_TYPE_RGBATOLAB; + else if (!strcasecmp (optarg, "rgba64torgba")) + csc_type = CL_CSC_TYPE_RGBA64TORGBA; + else if (!strcasecmp (optarg, "yuyvtorgba")) + csc_type = CL_CSC_TYPE_YUYVTORGBA; + else if (!strcasecmp (optarg, "nv12torgba")) + csc_type = CL_CSC_TYPE_NV12TORGBA; + else + print_help (bin_name); + break; + + case 'b': + enable_bnr = true; + break; + + case 'P': + enable_psnr = true; + break; + + case 'h': + print_help (bin_name); + return 0; + + default: + print_help (bin_name); + return -1; + } + } + + if (!input_format || !input_file || !output_file || (enable_psnr && !refer_file) || handler_type == TestHandlerUnknown) { + print_help (bin_name); + return -1; + } + + ret = input_fp.open (input_file, "rb"); + CHECK (ret, "open input file(%s) failed", XCAM_STR (input_file)); + ret = output_fp.open (output_file, "wb"); + CHECK (ret, "open output file(%s) failed", XCAM_STR (output_file)); + if (enable_psnr) { + refer_fp.open (refer_file, "rb"); + CHECK (ret, "open reference file(%s) failed", XCAM_STR (refer_file)); + } + + context = CLDevice::instance ()->get_context (); + + switch (handler_type) { + case TestHandlerDemo: + if (!bin_kernel_path) + image_handler = create_cl_demo_image_handler (context); + else { + FileHandle file; + if (file.open (bin_kernel_path, "r") != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("open binary kernel failed"); + return -1; + } + + size_t size; + if (file.get_file_size (size) != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("get binary kernel size failed"); + return -1; + } + + uint8_t *binary = (uint8_t *) xcam_malloc0 (sizeof (uint8_t) * (size)); + XCAM_ASSERT (binary); + + if (file.read_file (binary, size) != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("read binary kernel failed"); + xcam_free (binary); + return -1; + } + + image_handler = create_cl_binary_demo_image_handler (context, binary, size); + xcam_free (binary); + } + break; + case TestHandlerColorConversion: { + SmartPtr<CLCscImageHandler> csc_handler; + XCam3aResultColorMatrix color_matrix; + xcam_mem_clear (color_matrix); + double matrix_table[XCAM_COLOR_MATRIX_SIZE] = {0.299, 0.587, 0.114, -0.14713, -0.28886, 0.436, 0.615, -0.51499, -0.10001}; + memcpy (color_matrix.matrix, matrix_table, sizeof(double)*XCAM_COLOR_MATRIX_SIZE); + image_handler = create_cl_csc_image_handler (context, csc_type); + csc_handler = image_handler.dynamic_cast_ptr<CLCscImageHandler> (); + XCAM_ASSERT (csc_handler.ptr ()); + csc_handler->set_matrix(color_matrix); + break; + } + case TestHandlerBayerPipe: { + image_handler = create_cl_bayer_pipe_image_handler (context); + SmartPtr<CLBayerPipeImageHandler> bayer_pipe = image_handler.dynamic_cast_ptr<CLBayerPipeImageHandler> (); + XCAM_ASSERT (bayer_pipe.ptr ()); + bayer_pipe->set_output_format (output_format); + bayer_pipe->enable_denoise (enable_bnr); + break; + } + case TestHandlerYuvPipe: { + image_handler = create_cl_yuv_pipe_image_handler (context); + SmartPtr<CLYuvPipeImageHandler> yuv_pipe = image_handler.dynamic_cast_ptr<CLYuvPipeImageHandler> (); + XCAM_ASSERT (yuv_pipe.ptr ()); + break; + } + case TestHandlerTonemapping: { + image_handler = create_cl_tonemapping_image_handler (context); + SmartPtr<CLTonemappingImageHandler> tonemapping_pipe = image_handler.dynamic_cast_ptr<CLTonemappingImageHandler> (); + XCAM_ASSERT (tonemapping_pipe.ptr ()); + break; + } + case TestHandlerRetinex: { + image_handler = create_cl_retinex_image_handler (context); + SmartPtr<CLRetinexImageHandler> retinex = image_handler.dynamic_cast_ptr<CLRetinexImageHandler> (); + XCAM_ASSERT (retinex.ptr ()); + break; + } + case TestHandlerGauss: { + image_handler = create_cl_gauss_image_handler (context); + SmartPtr<CLGaussImageHandler> gauss = image_handler.dynamic_cast_ptr<CLGaussImageHandler> (); + XCAM_ASSERT (gauss.ptr ()); + break; + } + case TestHandlerHatWavelet: { + image_handler = create_cl_wavelet_denoise_image_handler (context, CL_IMAGE_CHANNEL_UV); + SmartPtr<CLWaveletDenoiseImageHandler> wavelet = image_handler.dynamic_cast_ptr<CLWaveletDenoiseImageHandler> (); + XCAM_ASSERT (wavelet.ptr ()); + XCam3aResultWaveletNoiseReduction wavelet_config; + xcam_mem_clear (wavelet_config); + wavelet_config.threshold[0] = 0.2; + wavelet_config.threshold[1] = 0.5; + wavelet_config.decomposition_levels = 4; + wavelet_config.analog_gain = 0.001; + wavelet->set_denoise_config (wavelet_config); + break; + } + case TestHandlerHaarWavelet: { + image_handler = create_cl_newwavelet_denoise_image_handler (context, CL_IMAGE_CHANNEL_UV | CL_IMAGE_CHANNEL_Y, false); + SmartPtr<CLNewWaveletDenoiseImageHandler> wavelet = image_handler.dynamic_cast_ptr<CLNewWaveletDenoiseImageHandler> (); + XCAM_ASSERT (wavelet.ptr ()); + XCam3aResultWaveletNoiseReduction wavelet_config; + wavelet_config.threshold[0] = 0.2; + wavelet_config.threshold[1] = 0.5; + wavelet_config.decomposition_levels = 4; + wavelet_config.analog_gain = 0.001; + wavelet->set_denoise_config (wavelet_config); + break; + } + case TestHandlerDefogDcp: { + image_handler = create_cl_defog_dcp_image_handler (context); + XCAM_ASSERT (image_handler.ptr ()); + break; + } + case TestHandler3DDenoise: { + uint8_t ref_count = 2; + image_handler = create_cl_3d_denoise_image_handler (context, CL_IMAGE_CHANNEL_Y | CL_IMAGE_CHANNEL_UV, ref_count); + SmartPtr<CL3DDenoiseImageHandler> denoise = image_handler.dynamic_cast_ptr<CL3DDenoiseImageHandler> (); + XCAM_ASSERT (denoise.ptr ()); + XCam3aResultTemporalNoiseReduction denoise_config; + xcam_mem_clear (denoise_config); + denoise_config.threshold[0] = 0.05; + denoise_config.threshold[1] = 0.05; + denoise_config.gain = 0.6; + denoise->set_denoise_config (denoise_config); + break; + } + case TestHandlerImageWarp: { + image_handler = create_cl_image_warp_handler (context); + SmartPtr<CLImageWarpHandler> warp = image_handler.dynamic_cast_ptr<CLImageWarpHandler> (); + XCAM_ASSERT (warp.ptr ()); + XCamDVSResult warp_config; + xcam_mem_clear (warp_config); + warp_config.frame_id = 1; + warp_config.frame_width = width; + warp_config.frame_height = height; + + float theta = -10.0f; + float phi = 10.0f; + + float shift_x = -0.2f * width; + float shift_y = 0.2f * height; + float scale_x = 2.0f; + float scale_y = 0.5f; + float shear_x = tan(theta * 3.1415926 / 180.0f); + float shear_y = tan(phi * 3.1415926 / 180.0f); + float project_x = 2.0f / width; + float project_y = -1.0f / height; + + warp_config.proj_mat[0] = scale_x; + warp_config.proj_mat[1] = shear_x; + warp_config.proj_mat[2] = shift_x; + warp_config.proj_mat[3] = shear_y; + warp_config.proj_mat[4] = scale_y; + warp_config.proj_mat[5] = shift_y; + warp_config.proj_mat[6] = project_x; + warp_config.proj_mat[7] = project_y; + warp_config.proj_mat[8] = 1.0f; + + warp->set_warp_config (warp_config); + break; + } + case TestHandlerFisheye: { + image_handler = create_fisheye_handler (context); + SmartPtr<CLFisheyeHandler> fisheye = image_handler.dynamic_cast_ptr<CLFisheyeHandler> (); + XCAM_ASSERT (fisheye.ptr ()); + FisheyeInfo fisheye_info; + //fisheye0 {480.0f, 480.0f, 190.0f, 480.0f, -90.0f}, + //fisheye1 {1440.0f, 480.0f, 190.0f, 480.0f, 90.0f} + fisheye_info.center_x = 480.0f; + fisheye_info.center_y = 480.0f; + fisheye_info.wide_angle = 190.0f; + fisheye_info.radius = 480.0f; + fisheye_info.rotate_angle = -90.0f; + fisheye->set_fisheye_info (fisheye_info); + fisheye->set_dst_range (210.0f, 180.0f); + fisheye->set_output_size (1120, 960); + break; + } + default: + XCAM_LOG_ERROR ("unsupported image handler type:%d", handler_type); + return -1; + } + if (!image_handler.ptr ()) { + XCAM_LOG_ERROR ("create image_handler failed"); + return -1; + } + + input_buf_info.init (input_format, width, height); + + buf_pool = new CLVideoBufferPool (); + image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); + buf_pool->set_video_info (input_buf_info); + if (!buf_pool->reserve (6)) { + XCAM_LOG_ERROR ("init buffer pool failed"); + return -1; + } + + SmartPtr<VideoBuffer> input_buf, output_buf, psnr_cur, psnr_ref; + while (true) { + input_buf = buf_pool->get_buffer (buf_pool); + XCAM_ASSERT (input_buf.ptr ()); + + ret = input_fp.read_buf (input_buf); + if (ret == XCAM_RETURN_BYPASS) + break; + if (ret == XCAM_RETURN_ERROR_FILE) { + XCAM_LOG_ERROR ("read buffer from %s failed", XCAM_STR (input_file)); + return -1; + } + + if (kernel_loop_count != 0) + { + kernel_loop (image_handler, input_buf, output_buf, kernel_loop_count); + CHECK (ret, "execute kernels failed"); + return 0; + } + + ret = image_handler->execute (input_buf, output_buf); + CHECK_EXP ((ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS), "execute kernels failed"); + if (ret == XCAM_RETURN_BYPASS) + continue; + context->finish (); + XCAM_ASSERT (output_buf.ptr ()); + ret = output_fp.write_buf (output_buf); + CHECK (ret, "write buffer to %s failed", XCAM_STR (output_file)); + psnr_cur = output_buf; + + ++buf_count; + } + + XCAM_LOG_INFO ("processed %d buffers successfully", buf_count); + + if (enable_psnr) { + buf_pool = new CLVideoBufferPool (); + XCAM_ASSERT (buf_pool.ptr ()); + buf_pool->set_video_info (input_buf_info); + if (!buf_pool->reserve (6)) { + XCAM_LOG_ERROR ("init buffer pool failed"); + return -1; + } + + psnr_ref = buf_pool->get_buffer (buf_pool); + XCAM_ASSERT (psnr_ref.ptr ()); + + ret = refer_fp.read_buf (psnr_ref); + CHECK (ret, "read buffer from %s failed", refer_file); + + float psnr = 0.0f; + ret = calculate_psnr (psnr_cur, psnr_ref, PSNRY, psnr); + CHECK (ret, "calculate PSNR_Y failed"); + XCAM_LOG_INFO ("PSNR_Y: %.2f", psnr); + + image_handler = create_cl_csc_image_handler (context, CL_CSC_TYPE_NV12TORGBA); + XCAM_ASSERT (image_handler.ptr ()); + + SmartPtr<VideoBuffer> psnr_cur_output, psnr_ref_output; + ret = image_handler->execute (psnr_cur, psnr_cur_output); + CHECK (ret, "execute kernels failed"); + XCAM_ASSERT (psnr_cur_output.ptr ()); + + ret = image_handler->execute (psnr_ref, psnr_ref_output); + CHECK (ret, "execute kernels failed"); + XCAM_ASSERT (psnr_ref_output.ptr ()); + + ret = calculate_psnr (psnr_cur_output, psnr_ref_output, PSNRR, psnr); + CHECK (ret, "calculate PSNR_R failed"); + XCAM_LOG_INFO ("PSNR_R: %.2f", psnr); + + ret = calculate_psnr (psnr_cur_output, psnr_ref_output, PSNRG, psnr); + CHECK (ret, "calculate PSNR_G failed"); + XCAM_LOG_INFO ("PSNR_G: %.2f", psnr); + + ret = calculate_psnr (psnr_cur_output, psnr_ref_output, PSNRB, psnr); + CHECK (ret, "calculate PSNR_B failed"); + XCAM_LOG_INFO ("PSNR_B: %.2f", psnr); + } + + return 0; +} diff --git a/tests/test-device-manager.cpp b/tests/test-device-manager.cpp new file mode 100644 index 0000000..f299d46 --- /dev/null +++ b/tests/test-device-manager.cpp @@ -0,0 +1,923 @@ +/* + * main.cpp - test + * + * Copyright (c) 2014 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + * Author: Wei Zong <wei.zong@intel.com> + */ + +#include "device_manager.h" +#include "uvc_device.h" +#include "fake_v4l2_device.h" +#include "x3a_analyzer_simple.h" +#include "analyzer_loader.h" +#include "smart_analyzer_loader.h" +#if HAVE_IA_AIQ +#include "isp/atomisp_device.h" +#include "isp/isp_controller.h" +#include "isp/isp_image_processor.h" +#include "isp/isp_poll_thread.h" +#include "isp/x3a_analyzer_aiq.h" +#include "x3a_analyze_tuner.h" +#include "dynamic_analyzer_loader.h" +#include "isp/hybrid_analyzer_loader.h" +#endif +#if HAVE_LIBCL +#include "ocl/cl_3a_image_processor.h" +#include "ocl/cl_post_image_processor.h" +#include "ocl/cl_csc_image_processor.h" +#include "ocl/cl_tnr_handler.h" +#endif +#if HAVE_LIBDRM +#include "drm_display.h" +#endif +#include "fake_poll_thread.h" +#include "image_file_handle.h" +#include <base/xcam_3a_types.h> +#include <unistd.h> +#include <signal.h> +#include <stdlib.h> +#include <string> +#include <getopt.h> +#include "test_common.h" + +using namespace XCam; + +#define IMX185_WDR_CPF "/etc/atomisp/imx185_wdr.cpf" + +static Mutex g_mutex; +static Cond g_cond; +static bool g_stop = false; + +class MainDeviceManager + : public DeviceManager +{ +public: + MainDeviceManager () + : _save_file (false) + , _interval (1) + , _frame_width (0) + , _frame_height (0) + , _frame_count (0) + , _frame_save (0) + , _enable_display (false) + { +#if HAVE_LIBDRM + _display = DrmDisplay::instance (); +#endif + XCAM_OBJ_PROFILING_INIT; + } + + ~MainDeviceManager () { + _file_handle.close (); + } + + void enable_save_file (bool enable) { + _save_file = enable; + } + + void set_interval (uint32_t inteval) { + _interval = inteval; + } + + void set_frame_width (uint32_t frame_width) { + _frame_width = frame_width; + } + + void set_frame_height (uint32_t frame_height) { + _frame_height = frame_height; + } + + void set_frame_save (uint32_t frame_save) { + _frame_save = frame_save; + } + + void enable_display(bool value) { + _enable_display = value; + } + +#if HAVE_LIBDRM + void set_display_mode(DrmDisplayMode mode) { + _display->set_display_mode (mode); + } +#endif + +protected: + virtual void handle_message (const SmartPtr<XCamMessage> &msg); + virtual void handle_buffer (const SmartPtr<VideoBuffer> &buf); + + int display_buf (const SmartPtr<VideoBuffer> &buf); + +private: + void open_file (); + +private: + bool _save_file; + uint32_t _interval; + uint32_t _frame_width; + uint32_t _frame_height; + uint32_t _frame_count; + uint32_t _frame_save; + bool _enable_display; + ImageFileHandle _file_handle; +#if HAVE_LIBDRM + SmartPtr<DrmDisplay> _display; +#endif + XCAM_OBJ_PROFILING_DEFINES; +}; + +void +MainDeviceManager::handle_message (const SmartPtr<XCamMessage> &msg) +{ + XCAM_UNUSED (msg); +} + +void +MainDeviceManager::handle_buffer (const SmartPtr<VideoBuffer> &buf) +{ + if (!buf.ptr ()) { + XCAM_LOG_WARNING ("video buffer is null, handle buffer failed."); + return; + } + + FPS_CALCULATION (fps_buf, 30); + XCAM_OBJ_PROFILING_START; + + if (_enable_display) + display_buf (buf); + + XCAM_OBJ_PROFILING_END("main_dev_manager_display", XCAM_OBJ_DUR_FRAME_NUM); + + if (!_save_file) + return ; + + if ((_frame_count++ % _interval) != 0) + return; + + if ((_frame_save != 0) && (_frame_count > _frame_save)) { + SmartLock locker (g_mutex); + g_stop = true; + g_cond.broadcast (); + return; + } + + open_file (); + + if (!_file_handle.is_valid ()) { + XCAM_LOG_ERROR ("open file failed"); + return; + } + _file_handle.write_buf (buf); +} + +int +MainDeviceManager::display_buf (const SmartPtr<VideoBuffer> &data) +{ +#if HAVE_LIBDRM + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<VideoBuffer> buf = data; + const VideoBufferInfo & frame_info = buf->get_video_info (); + struct v4l2_rect rect = { 0, 0, frame_info.width, frame_info.height}; + + if (!_display->is_render_inited ()) { + ret = _display->render_init (0, 0, this->_frame_width, this->_frame_height, + frame_info.format, &rect); + CHECK (ret, "display failed on render_init"); + } + ret = _display->render_setup_frame_buffer (buf); + CHECK (ret, "display failed on framebuf set"); + ret = _display->render_buffer (buf); + CHECK (ret, "display failed on rendering"); +#else + XCAM_UNUSED (data); +#endif + + return 0; +} + + +void +MainDeviceManager::open_file () +{ + if (_file_handle.is_valid () && (_frame_save == 0)) + return; + + std::string file_name = DEFAULT_SAVE_FILE_NAME; + + if (_frame_save != 0) { + file_name += std::to_string(_frame_count); + } + file_name += ".raw"; + + if (_file_handle.open (file_name.c_str (), "wb") != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("create file(%s) failed", file_name.c_str ()); + } +} + +#define V4L2_CAPTURE_MODE_STILL 0x2000 +#define V4L2_CAPTURE_MODE_VIDEO 0x4000 +#define V4L2_CAPTURE_MODE_PREVIEW 0x8000 + +typedef enum { + AnalyzerTypeSimple = 0, + AnalyzerTypeAiqTuner, + AnalyzerTypeDynamic, + AnalyzerTypeHybrid, +} AnalyzerType; + +void dev_stop_handler(int sig) +{ + XCAM_UNUSED (sig); + + SmartLock locker (g_mutex); + g_stop = true; + g_cond.broadcast (); + + //exit(0); +} + +void print_help (const char *bin_name) +{ + printf ("Usage: %s [-a analyzer]\n" + "Configurations:\n" + "\t -a analyzer specify a analyzer\n" + "\t select from [simple" +#if HAVE_IA_AIQ + ", aiq" +#if HAVE_LIBCL + ", dynamic, hybrid" +#endif +#endif + "], default is [simple]\n" + "\t -m mem_type specify video memory type\n" + "\t mem_type select from [dma, mmap], default is [mmap]\n" + "\t -s save file to %s\n" + "\t -n interval save file on every [interval] frame\n" + "\t -f pixel_fmt specify output pixel format\n" + "\t pixel_fmt select from [NV12, YUYV, BA10, BA12], default is [NV12]\n" + "\t -W image_width specify image width, default is [1920]\n" + "\t -H image_height specify image height, default is [1080]\n" + "\t -d cap_mode specify capture mode\n" + "\t cap_mode select from [video, still], default is [video]\n" + "\t -i frame_save specify the frame count to save, default is 0 which means endless\n" + "\t -p preview on enable local display, need root privilege\n" + "\t --usb specify node for usb camera device, enables capture path through USB camera \n" + "\t specify [/dev/video4, /dev/video5] depending on which node USB camera is attached\n" + "\t -e display_mode preview mode\n" + "\t select from [primary, overlay], default is [primary]\n" + "\t --sync set analyzer in sync mode\n" + "\t -r raw_input specify the path of raw image as fake source instead of live camera\n" + "\t -h help\n" +#if HAVE_LIBCL + "CL features:\n" + "\t -c process image with cl kernel\n" +#if HAVE_IA_AIQ + "\t -b brightness specify brightness level\n" + "\t brightness level select from [0, 256], default is [128]\n" +#endif + "\t --capture specify the capture stage of image\n" + "\t capture_stage select from [bayer, tonemapping], default is [tonemapping]\n" + "\t --tnr specify temporal noise reduction type, default is tnr off\n" + "\t only support [yuv]\n" + "\t --tnr-level specify tnr level\n" + "\t --wdr-mode specify wdr mode. select from [gaussian, haleq]\n" + "\t --enable-bnr enable bayer noise reduction\n" + "\t --defog-mode specify defog mode\n" + "\t select from [disabled, retinex, dcp], default is [disabled]\n" + "\t --wavelet-mode specify wavelet denoise mode, default is off\n" + "\t select from [0:disable, 1:Hat Y, 2:Hat UV, 3:Haar Y, 4:Haar UV, 5:Haar YUV, 6:Haar Bayes Shrink]\n" + "\t --3d-denoise specify 3D Denoise mode\n" + "\t select from [disabled, yuv, uv], default is [disabled]\n" + "\t --enable-wireframe enable wire frame\n" + "\t --pipeline specify pipe mode\n" + "\t select from [basic, advance, extreme], default is [basic]\n" + "\t --disable-post disable cl post image processor\n" +#endif + , bin_name + , DEFAULT_SAVE_FILE_NAME); +} + +int main (int argc, char *argv[]) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<V4l2Device> device; +#if HAVE_IA_AIQ + SmartPtr<V4l2SubDevice> event_device; + SmartPtr<IspController> isp_controller; + SmartPtr<ImageProcessor> isp_processor; +#endif + SmartPtr<X3aAnalyzer> analyzer; + SmartPtr<AnalyzerLoader> loader; + AnalyzerType analyzer_type = AnalyzerTypeSimple; + +#if HAVE_LIBCL + bool have_cl_processor = false; + SmartPtr<SmartAnalyzer> smart_analyzer; + bool have_cl_post_processor = true; + SmartPtr<CL3aImageProcessor> cl_processor; + SmartPtr<CLPostImageProcessor> cl_post_processor; + uint32_t tnr_type = CL_TNR_DISABLE; + uint32_t denoise_type = 0; + uint8_t tnr_level = 0; + CL3aImageProcessor::PipelineProfile pipeline_mode = CL3aImageProcessor::BasicPipelineProfile; + CL3aImageProcessor::CaptureStage capture_stage = CL3aImageProcessor::TonemappingStage; + CL3aImageProcessor::CLTonemappingMode wdr_mode = CL3aImageProcessor::WDRdisabled; + +#if HAVE_IA_AIQ + int32_t brightness_level = 128; +#endif + uint32_t defog_type = 0; + CLWaveletBasis wavelet_mode = CL_WAVELET_DISABLED; + uint32_t wavelet_channel = CL_IMAGE_CHANNEL_UV; + bool wavelet_bayes_shrink = false; + uint32_t denoise_3d_mode = 0; + uint8_t denoise_3d_ref_count = 3; + bool wireframe_type = false; + bool image_warp_type = false; +#endif + + bool need_display = false; +#if HAVE_LIBDRM + DrmDisplayMode display_mode = DRM_DISPLAY_MODE_PRIMARY; +#endif + enum v4l2_memory v4l2_mem_type = V4L2_MEMORY_MMAP; + const char *bin_name = argv[0]; + uint32_t capture_mode = V4L2_CAPTURE_MODE_VIDEO; + uint32_t pixel_format = V4L2_PIX_FMT_NV12; + + bool have_usbcam = 0; + std::string usb_device_name; + bool sync_mode = false; + bool save_file = false; + uint32_t interval_frames = 1; + uint32_t save_frames = 0; + uint32_t frame_rate; + uint32_t frame_width = 1920; + uint32_t frame_height = 1080; + std::string path_to_fake; + + int opt; + const char *short_opts = "sca:n:m:f:W:H:d:b:pi:e:r:h"; + const struct option long_opts[] = { + {"tnr", required_argument, NULL, 'T'}, + {"tnr-level", required_argument, NULL, 'L'}, + {"wdr-mode", required_argument, NULL, 'w'}, + {"enable-bnr", no_argument, NULL, 'B'}, + {"defog-mode", required_argument, NULL, 'X'}, + {"wavelet-mode", required_argument, NULL, 'V'}, + {"3d-denoise", required_argument, NULL, 'N'}, + {"enable-wireframe", no_argument, NULL, 'F'}, + {"enable-warp", no_argument, NULL, 'A'}, + {"usb", required_argument, NULL, 'U'}, + {"sync", no_argument, NULL, 'Y'}, + {"capture", required_argument, NULL, 'C'}, + {"pipeline", required_argument, NULL, 'P'}, + {"disable-post", no_argument, NULL, 'O'}, + {0, 0, 0, 0}, + }; + + while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { + switch (opt) { + case 'a': { + XCAM_ASSERT (optarg); + if (!strcmp (optarg, "simple")) + analyzer_type = AnalyzerTypeSimple; +#if HAVE_IA_AIQ + else if (!strcmp (optarg, "aiq")) + analyzer_type = AnalyzerTypeAiqTuner; +#if HAVE_LIBCL + else if (!strcmp (optarg, "dynamic")) + analyzer_type = AnalyzerTypeDynamic; + else if (!strcmp (optarg, "hybrid")) + analyzer_type = AnalyzerTypeHybrid; +#endif +#endif + else { + print_help (bin_name); + return -1; + } + break; + } + + case 'm': { + XCAM_ASSERT (optarg); + if (!strcmp (optarg, "dma")) + v4l2_mem_type = V4L2_MEMORY_DMABUF; + else if (!strcmp (optarg, "mmap")) + v4l2_mem_type = V4L2_MEMORY_MMAP; + else + print_help (bin_name); + break; + } + + case 's': + save_file = true; + break; + case 'n': + XCAM_ASSERT (optarg); + interval_frames = atoi(optarg); + break; + case 'i': + XCAM_ASSERT (optarg); + save_frames = atoi(optarg); + break; + case 'f': + XCAM_ASSERT (optarg); + CHECK_EXP ((strlen(optarg) == 4), "invalid pixel format\n"); + pixel_format = v4l2_fourcc ((unsigned)optarg[0], + (unsigned)optarg[1], + (unsigned)optarg[2], + (unsigned)optarg[3]); + break; + case 'd': + XCAM_ASSERT (optarg); + if (!strcmp (optarg, "still")) + capture_mode = V4L2_CAPTURE_MODE_STILL; + else if (!strcmp (optarg, "video")) + capture_mode = V4L2_CAPTURE_MODE_VIDEO; + else { + print_help (bin_name); + return -1; + } + break; + case 'U': + XCAM_ASSERT (optarg); + have_usbcam = true; + usb_device_name = optarg; + XCAM_LOG_DEBUG("using USB camera plugged in at node: %s", XCAM_STR(usb_device_name.c_str())); + break; + case 'W': + XCAM_ASSERT (optarg); + frame_width = atoi(optarg); + break; + case 'H': + XCAM_ASSERT (optarg); + frame_height = atoi(optarg); + break; + case 'e': { +#if HAVE_LIBDRM + XCAM_ASSERT (optarg); + if (!strcmp (optarg, "primary")) + display_mode = DRM_DISPLAY_MODE_PRIMARY; + else if (!strcmp (optarg, "overlay")) + display_mode = DRM_DISPLAY_MODE_OVERLAY; + else { + print_help (bin_name); + return -1; + } +#else + XCAM_LOG_WARNING ("preview is not supported"); +#endif + break; + } + + case 'Y': + sync_mode = true; + break; +#if HAVE_LIBCL + case 'c': + have_cl_processor = true; + break; +#if HAVE_IA_AIQ + case 'b': + XCAM_ASSERT (optarg); + brightness_level = atoi(optarg); + if(brightness_level < 0 || brightness_level > 256) { + print_help (bin_name); + return -1; + } + break; +#endif + + case 'B': { + denoise_type |= XCAM_DENOISE_TYPE_BNR; + break; + } + case 'X': { + XCAM_ASSERT (optarg); + defog_type = true; + if (!strcmp (optarg, "disabled")) + defog_type = CLPostImageProcessor::DefogDisabled; + else if (!strcmp (optarg, "retinex")) + defog_type = CLPostImageProcessor::DefogRetinex; + else if (!strcmp (optarg, "dcp")) + defog_type = CLPostImageProcessor::DefogDarkChannelPrior; + else { + print_help (bin_name); + return -1; + } + break; + } + case 'V': { + XCAM_ASSERT (optarg); + if (atoi(optarg) < 0 || atoi(optarg) > 255) { + print_help (bin_name); + return -1; + } + if (atoi(optarg) == 1) { + wavelet_mode = CL_WAVELET_HAT; + wavelet_channel = CL_IMAGE_CHANNEL_Y; + } else if (atoi(optarg) == 2) { + wavelet_mode = CL_WAVELET_HAT; + wavelet_channel = CL_IMAGE_CHANNEL_UV; + } else if (atoi(optarg) == 3) { + wavelet_mode = CL_WAVELET_HAAR; + wavelet_channel = CL_IMAGE_CHANNEL_Y; + } else if (atoi(optarg) == 4) { + wavelet_mode = CL_WAVELET_HAAR; + wavelet_channel = CL_IMAGE_CHANNEL_UV; + } else if (atoi(optarg) == 5) { + wavelet_mode = CL_WAVELET_HAAR; + wavelet_channel = CL_IMAGE_CHANNEL_UV | CL_IMAGE_CHANNEL_Y; + } else if (atoi(optarg) == 6) { + wavelet_mode = CL_WAVELET_HAAR; + wavelet_channel = CL_IMAGE_CHANNEL_UV | CL_IMAGE_CHANNEL_Y; + wavelet_bayes_shrink = true; + } else { + wavelet_mode = CL_WAVELET_DISABLED; + } + break; + } + case 'N': { + XCAM_ASSERT (optarg); + denoise_3d_mode = true; + if (!strcmp (optarg, "disabled")) + denoise_3d_mode = CLPostImageProcessor::Denoise3DDisabled; + else if (!strcmp (optarg, "yuv")) + denoise_3d_mode = CLPostImageProcessor::Denoise3DYuv; + else if (!strcmp (optarg, "uv")) + denoise_3d_mode = CLPostImageProcessor::Denoise3DUV; + else { + print_help (bin_name); + return -1; + } + break; + } + case 'F': { + wireframe_type = true; + break; + } + case 'A': { + image_warp_type = true; + break; + } + case 'T': { + XCAM_ASSERT (optarg); + if (!strcasecmp (optarg, "yuv")) + tnr_type = CL_TNR_TYPE_YUV; + else { + printf ("--tnr only support <yuv>, <%s> is not supported\n", optarg); + print_help (bin_name); + return -1; + } + break; + } + case 'L': { + XCAM_ASSERT (optarg); + if (atoi(optarg) < 0 || atoi(optarg) > 255) { + print_help (bin_name); + return -1; + } + tnr_level = atoi(optarg); + break; + } + case 'w': { + XCAM_ASSERT (optarg); + if (!strcasecmp (optarg, "gaussian")) + wdr_mode = CL3aImageProcessor::Gaussian; + else if (!strcasecmp (optarg, "haleq")) + wdr_mode = CL3aImageProcessor::Haleq; + + pixel_format = V4L2_PIX_FMT_SGRBG12; + setenv ("AIQ_CPF_PATH", IMX185_WDR_CPF, 1); + break; + } + case 'P': { + XCAM_ASSERT (optarg); + if (!strcasecmp (optarg, "basic")) + pipeline_mode = CL3aImageProcessor::BasicPipelineProfile; + else if (!strcasecmp (optarg, "advance")) + pipeline_mode = CL3aImageProcessor::AdvancedPipelineProfile; + else if (!strcasecmp (optarg, "extreme")) + pipeline_mode = CL3aImageProcessor::ExtremePipelineProfile; + else { + print_help (bin_name); + return -1; + } + break; + } + case 'C': { + XCAM_ASSERT (optarg); + if (!strcmp (optarg, "bayer")) + capture_stage = CL3aImageProcessor::BasicbayerStage; + break; + } + case 'O': { + have_cl_post_processor = false; + break; + } +#endif + case 'r': { + XCAM_ASSERT (optarg); + XCAM_LOG_INFO ("use raw image %s as input source", optarg); + path_to_fake = optarg; + break; + } + case 'p': { +#if HAVE_LIBDRM + need_display = true; +#else + XCAM_LOG_WARNING ("preview is not supported, disable preview now"); + need_display = false; +#endif + break; + } + case 'h': + print_help (bin_name); + return 0; + + default: + print_help (bin_name); + return -1; + } + } + + SmartPtr<MainDeviceManager> device_manager = new MainDeviceManager (); + device_manager->enable_save_file (save_file); + device_manager->set_interval (interval_frames); + device_manager->set_frame_save (save_frames); + device_manager->set_frame_width (frame_width); + device_manager->set_frame_height (frame_height); + + if (!device.ptr ()) { + if (path_to_fake.c_str ()) { + device = new FakeV4l2Device (); + } else if (have_usbcam) { + device = new UVCDevice (usb_device_name.c_str ()); + } +#if HAVE_IA_AIQ + else { + if (capture_mode == V4L2_CAPTURE_MODE_STILL) + device = new AtomispDevice (CAPTURE_DEVICE_STILL); + else if (capture_mode == V4L2_CAPTURE_MODE_VIDEO) + device = new AtomispDevice (CAPTURE_DEVICE_VIDEO); + else + device = new AtomispDevice (DEFAULT_CAPTURE_DEVICE); + } +#endif + } + +#if HAVE_IA_AIQ + if (!isp_controller.ptr ()) + isp_controller = new IspController (device); +#endif + + switch (analyzer_type) { + case AnalyzerTypeSimple: + analyzer = new X3aAnalyzerSimple (); + break; +#if HAVE_IA_AIQ + case AnalyzerTypeAiqTuner: { + SmartPtr<X3aAnalyzer> aiq_analyzer = new X3aAnalyzerAiq (isp_controller, DEFAULT_CPF_FILE); + SmartPtr<X3aAnalyzeTuner> tuner_analyzer = new X3aAnalyzeTuner (); + XCAM_ASSERT (aiq_analyzer.ptr () && tuner_analyzer.ptr ()); + tuner_analyzer->set_analyzer (aiq_analyzer); + analyzer = tuner_analyzer; + break; + } +#if HAVE_LIBCL + case AnalyzerTypeDynamic: { + const char *path_of_3a = DEFAULT_DYNAMIC_3A_LIB; + SmartPtr<DynamicAnalyzerLoader> dynamic_loader = new DynamicAnalyzerLoader (path_of_3a); + loader = dynamic_loader.dynamic_cast_ptr<AnalyzerLoader> (); + analyzer = dynamic_loader->load_analyzer (loader); + CHECK_EXP (analyzer.ptr (), "load dynamic 3a lib(%s) failed", path_of_3a); + break; + } + case AnalyzerTypeHybrid: { + const char *path_of_3a = DEFAULT_HYBRID_3A_LIB; + SmartPtr<HybridAnalyzerLoader> hybrid_loader = new HybridAnalyzerLoader (path_of_3a); + hybrid_loader->set_cpf_path (DEFAULT_CPF_FILE); + hybrid_loader->set_isp_controller (isp_controller); + loader = hybrid_loader.dynamic_cast_ptr<AnalyzerLoader> (); + analyzer = hybrid_loader->load_analyzer (loader); + CHECK_EXP (analyzer.ptr (), "load hybrid 3a lib(%s) failed", path_of_3a); + break; + } +#endif +#endif + default: + print_help (bin_name); + return -1; + } + XCAM_ASSERT (analyzer.ptr ()); + analyzer->set_sync_mode (sync_mode); + +#if HAVE_LIBCL + SmartHandlerList smart_handlers = SmartAnalyzerLoader::load_smart_handlers (DEFAULT_SMART_ANALYSIS_LIB_DIR); + if (!smart_handlers.empty ()) { + smart_analyzer = new SmartAnalyzer (); + if (smart_analyzer.ptr ()) { + SmartHandlerList::iterator i_handler = smart_handlers.begin (); + for (; i_handler != smart_handlers.end (); ++i_handler) + { + XCAM_ASSERT ((*i_handler).ptr ()); + smart_analyzer->add_handler (*i_handler); + } + } else { + XCAM_LOG_WARNING ("load smart analyzer(%s) failed, please check.", DEFAULT_SMART_ANALYSIS_LIB_DIR); + } + } + + if (smart_analyzer.ptr ()) { + if (smart_analyzer->prepare_handlers () != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("analyzer(%s) prepare handlers failed", smart_analyzer->get_name ()); + } + device_manager->set_smart_analyzer (smart_analyzer); + } +#endif + + signal(SIGINT, dev_stop_handler); + + device->set_sensor_id (0); + device->set_capture_mode (capture_mode); + //device->set_mem_type (V4L2_MEMORY_DMABUF); + device->set_mem_type (v4l2_mem_type); + device->set_buffer_count (8); + if (pixel_format == V4L2_PIX_FMT_SGRBG12) { + frame_rate = 30; + device->set_framerate (frame_rate, 1); + } +#if HAVE_LIBCL + else { + frame_rate = 25; + device->set_framerate (frame_rate, 1); + if(wdr_mode != CL3aImageProcessor::WDRdisabled) { + XCAM_LOG_WARNING("Tonemapping is only applicable under BA12 format. Disable tonemapping automatically."); + wdr_mode = CL3aImageProcessor::WDRdisabled; + } + } +#endif + ret = device->open (); + CHECK (ret, "device(%s) open failed", device->get_device_name()); + ret = device->set_format (frame_width, frame_height, pixel_format, V4L2_FIELD_NONE, frame_width * 2); + CHECK (ret, "device(%s) set format failed", device->get_device_name()); + +#if HAVE_IA_AIQ + if (!event_device.ptr ()) + event_device = new V4l2SubDevice (DEFAULT_EVENT_DEVICE); + ret = event_device->open (); + if (ret == XCAM_RETURN_NO_ERROR) { + CHECK (ret, "event device(%s) open failed", event_device->get_device_name()); + int event = V4L2_EVENT_ATOMISP_3A_STATS_READY; + ret = event_device->subscribe_event (event); + CHECK_CONTINUE ( + ret, + "device(%s) subscribe event(%d) failed", + event_device->get_device_name(), event); + event = V4L2_EVENT_FRAME_SYNC; + ret = event_device->subscribe_event (event); + CHECK_CONTINUE ( + ret, + "device(%s) subscribe event(%d) failed", + event_device->get_device_name(), event); + + device_manager->set_event_device (event_device); + } +#endif + + device_manager->set_capture_device (device); + if (analyzer.ptr()) + device_manager->set_3a_analyzer (analyzer); + +#if HAVE_IA_AIQ +#if HAVE_LIBCL + if (have_cl_processor) + isp_processor = new IspExposureImageProcessor (isp_controller); + else +#endif + isp_processor = new IspImageProcessor (isp_controller); + + XCAM_ASSERT (isp_processor.ptr ()); + device_manager->add_image_processor (isp_processor); +#endif +#if HAVE_LIBCL + if (have_cl_processor) { + cl_processor = new CL3aImageProcessor (); + cl_processor->set_stats_callback(device_manager); + cl_processor->set_denoise (denoise_type); + cl_processor->set_capture_stage (capture_stage); + + cl_processor->set_tonemapping (wdr_mode); + if (wdr_mode != CL3aImageProcessor::WDRdisabled) { + cl_processor->set_gamma (false); + cl_processor->set_3a_stats_bits (12); + } + + cl_processor->set_tnr (tnr_type, tnr_level); + cl_processor->set_profile (pipeline_mode); +#if HAVE_IA_AIQ + analyzer->set_parameter_brightness((brightness_level - 128) / 128.0); +#endif + device_manager->add_image_processor (cl_processor); + } + + if (have_cl_post_processor) { + cl_post_processor = new CLPostImageProcessor (); + + cl_post_processor->set_stats_callback (device_manager); + cl_post_processor->set_defog_mode ((CLPostImageProcessor::CLDefogMode)defog_type); + cl_post_processor->set_wavelet (wavelet_mode, wavelet_channel, wavelet_bayes_shrink); + cl_post_processor->set_3ddenoise_mode ((CLPostImageProcessor::CL3DDenoiseMode) denoise_3d_mode, denoise_3d_ref_count); + + cl_post_processor->set_wireframe (wireframe_type); + cl_post_processor->set_image_warp (image_warp_type); + if (smart_analyzer.ptr () && (wireframe_type || image_warp_type)) { + cl_post_processor->set_scaler (true); + cl_post_processor->set_scaler_factor (640.0 / frame_width); + } + + if (need_display) { + need_display = false; + XCAM_LOG_WARNING ("CLVideoBuffer doesn't support local preview, disable local preview now"); + } + + if (need_display) { +#if HAVE_LIBDRM + if (DrmDisplay::set_preview (need_display)) { + device_manager->set_display_mode (display_mode); + cl_post_processor->set_output_format (V4L2_PIX_FMT_XBGR32); + } else { + need_display = false; + XCAM_LOG_WARNING ("set preview failed, disable local preview now"); + } +#else + XCAM_LOG_WARNING ("preview is not supported, disable preview now"); + need_display = false; +#endif + } + device_manager->enable_display (need_display); + + device_manager->add_image_processor (cl_post_processor); + } +#endif + + SmartPtr<PollThread> poll_thread; + if (have_usbcam) { + poll_thread = new PollThread (); + } else if (path_to_fake.c_str ()) { + poll_thread = new FakePollThread (path_to_fake.c_str ()); + } +#if HAVE_IA_AIQ + else { + SmartPtr<IspPollThread> isp_poll_thread = new IspPollThread (); + isp_poll_thread->set_isp_controller (isp_controller); + poll_thread = isp_poll_thread; + } +#endif + device_manager->set_poll_thread (poll_thread); + + ret = device_manager->start (); + CHECK (ret, "device manager start failed"); + +#if HAVE_LIBCL + // hard code exposure range and max gain for imx185 WDR + if (wdr_mode != CL3aImageProcessor::WDRdisabled) { + if (frame_rate == 30) + analyzer->set_ae_exposure_time_range (80 * 1110 * 1000 / 37125, 1120 * 1110 * 1000 / 37125); + else + analyzer->set_ae_exposure_time_range (80 * 1320 * 1000 / 37125, 1120 * 1320 * 1000 / 37125); + analyzer->set_ae_max_analog_gain (3.98); // 12dB + } +#endif + + // wait for interruption + { + SmartLock locker (g_mutex); + while (!g_stop) + g_cond.wait (g_mutex); + } + + ret = device_manager->stop(); + CHECK_CONTINUE (ret, "device manager stop failed"); + device->close (); +#if HAVE_IA_AIQ + event_device->close (); +#endif + + return 0; +} diff --git a/tests/test-image-blend.cpp b/tests/test-image-blend.cpp new file mode 100644 index 0000000..a00236f --- /dev/null +++ b/tests/test-image-blend.cpp @@ -0,0 +1,445 @@ +/* + * test-image-blend.cpp - test cl image + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "test_common.h" +#include "test_inline.h" +#include <unistd.h> +#include <getopt.h> +#include <ocl/cl_device.h> +#include <ocl/cl_context.h> +#include <ocl/cl_blender.h> +#include <image_file_handle.h> +#include <ocl/cl_geo_map_handler.h> +#if HAVE_LIBDRM +#include <drm_display.h> +#endif +#include <dma_video_buffer.h> + +using namespace XCam; + +#define ENABLE_DMA_TEST 0 + +static uint32_t input_format = V4L2_PIX_FMT_NV12; +//static uint32_t output_format = V4L2_PIX_FMT_NV12; +static uint32_t input_width0 = 1280, input_width1 = 1280; +static uint32_t input_height = 960; +static uint32_t output_width = 1920; +static uint32_t output_height; +static bool need_save_output = true; +static bool enable_geo = false; +static bool enable_seam = false; + +static int loop = 0; +static uint32_t map_width = 51, map_height = 43; +static const char *map0 = "fisheye0.csv"; +static const char *map1 = "fisheye1.csv"; +static char file_in0_name[XCAM_MAX_STR_SIZE], file_in1_name[XCAM_MAX_STR_SIZE], file_out_name[XCAM_MAX_STR_SIZE]; + +static int read_map_data (const char* file, GeoPos *map, int width, int height); + +static void +usage(const char* arg0) +{ + printf ("Usage:\n" + "%s --input0 file --input1 file --output file" + " [--input-w0 width] [--input-w1 width] [--input-h height] [--output-w width] \n" + "\t--input0, first image(NV12)\n" + "\t--input1, second image(NV12)\n" + "\t--output, output image(NV12) PREFIX\n" + "\t--input-w0, optional, input width; default:1280\n" + "\t--input-w1, optional, input width; default:1280\n" + "\t--input-h, optional, input height; default:960\n" + "\t--output-w, optional, output width; default:1920, output height is same as input height.\n" + "\t--loop, optional, how many loops need to run for performance test, default 0; \n" + "\t--save, optional, save file or not, default true; select from [true/false]\n" + "\t--enable-geo, optional, enable geo map image frist. default: no\n" + "\t--enable-seam, optional, enable seam finder in blending area. default: no\n" + "\t--help, usage\n", + arg0); +} + +static int +geo_correct_image ( + SmartPtr<CLGeoMapHandler> geo_map_handler, SmartPtr<VideoBuffer> &in_out, + GeoPos *geo_map0, uint32_t map_width, uint32_t map_height, + char *file_name, bool need_save_output) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<VideoBuffer> geo_out; + geo_map_handler->set_map_data (geo_map0, map_width, map_height); + ret = geo_map_handler->execute (in_out, geo_out); + CHECK (ret, "geo map handler execute inpu0 failed"); + XCAM_ASSERT (geo_out.ptr ()); + in_out = geo_out; + + if (need_save_output) { + char gdc_dump_name[1024]; + snprintf (gdc_dump_name, 1024, "gdc-%s", file_name); + ImageFileHandle file_out; + file_out.open (gdc_dump_name, "wb"); + file_out.write_buf (geo_out); + file_out.close (); + printf ("write gdc output buffer to: %s done\n", gdc_dump_name); + } + return 0; +} + +#if (ENABLE_DMA_TEST) && (HAVE_LIBDRM) +static SmartPtr<VideoBuffer> +dma_buf_to_xcam_buf ( + SmartPtr<DrmDisplay> display, int dma_fd, + uint32_t width, uint32_t height, uint32_t size, + uint32_t aligned_width = 0, uint32_t aligned_height = 0) +{ + /* + * + * XCAM_ASSERT (native_handle_t.numFds == 1); + * XCAM_ASSERT (native_handle_t.data[0] > 0); + * dma_fd = native_handle_t.data[0] ; + */; + VideoBufferInfo info; + SmartPtr<VideoBuffer> dma_buf; + SmartPtr<VideoBuffer> output; + + XCAM_ASSERT (dma_fd > 0); + + if (aligned_width == 0) + aligned_width = XCAM_ALIGN_UP(width, 16); + if (aligned_height == 0) + aligned_height = XCAM_ALIGN_UP(height, 16); + + info.init (V4L2_PIX_FMT_NV12, width, height, aligned_width, aligned_height, size); + dma_buf = new DmaVideoBuffer (info, dma_fd); + output = display->convert_to_drm_bo_buf (display, dma_buf); + if (!output.ptr ()) { + XCAM_LOG_ERROR ("dma_buf(%d) convert to xcam_buf failed", dma_fd); + } + + return output; +} + +static SmartPtr<VideoBuffer> +create_dma_buffer (SmartPtr<DrmDisplay> &display, const VideoBufferInfo &info) +{ + SmartPtr<BufferPool> buf_pool = new DrmBoBufferPool (display); + buf_pool->set_video_info (info); + buf_pool->reserve (1); + return buf_pool->get_buffer (buf_pool); +} +#endif + +static XCamReturn +blend_images ( + SmartPtr<VideoBuffer> input0, SmartPtr<VideoBuffer> input1, + SmartPtr<VideoBuffer> &output_buf, + SmartPtr<CLBlender> blender) +{ + blender->set_output_size (output_width, output_height); + input0->attach_buffer (input1); + return blender->execute (input0, output_buf); +} + +int main (int argc, char *argv[]) +{ + GeoPos *geo_map0 = NULL, *geo_map1 = NULL; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<CLImageHandler> image_handler; + SmartPtr<CLGeoMapHandler> geo_map_handler; + SmartPtr<CLBlender> blender; + VideoBufferInfo input_buf_info0, input_buf_info1, output_buf_info; + SmartPtr<CLContext> context; + SmartPtr<BufferPool> buf_pool0, buf_pool1; + ImageFileHandle file_in0, file_in1, file_out; + SmartPtr<VideoBuffer> input0, input1; + SmartPtr<VideoBuffer> output_buf; + SmartPtr<VideoBuffer> read_buf; + +#define FAILED_GEO_FREE { delete [] geo_map0; delete [] geo_map1; return -1; } + + const struct option long_opts[] = { + {"input0", required_argument, NULL, 'i'}, + {"input1", required_argument, NULL, 'I'}, + {"output", required_argument, NULL, 'o'}, + {"input-w0", required_argument, NULL, 'w'}, + {"input-w1", required_argument, NULL, 'W'}, + {"input-h", required_argument, NULL, 'H'}, + {"output-w", required_argument, NULL, 'x'}, + {"loop", required_argument, NULL, 'l'}, + {"save", required_argument, NULL, 's'}, + {"enable-geo", no_argument, NULL, 'g'}, + {"enable-seam", no_argument, NULL, 'm'}, + {"help", no_argument, NULL, 'h'}, + {0, 0, 0, 0}, + }; + + int opt = -1; + while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { + switch (opt) { + case 'i': + strncpy (file_in0_name, optarg, XCAM_MAX_STR_SIZE); + break; + case 'I': + strncpy (file_in1_name, optarg, XCAM_MAX_STR_SIZE); + break; + case 'o': + strncpy (file_out_name, optarg, XCAM_MAX_STR_SIZE); + break; + case 'w': + input_width0 = atoi(optarg); + break; + case 'W': + input_width1 = atoi(optarg); + break; + case 'H': + input_height = atoi(optarg); + break; + case 'x': + output_width = atoi(optarg); + break; + case 'l': + loop = atoi(optarg); + break; + case 's': + need_save_output = (strcasecmp (optarg, "false") == 0 ? false : true); + break; + case 'g': + enable_geo = true; + break; + case 'm': + enable_seam = true; + break; + case 'h': + usage (argv[0]); + return -1; + default: + printf ("getopt_long return unknown value:%c\n", opt); + usage (argv[0]); + return -1; + + } + } + + if (optind < argc || argc < 2) { + printf("unknown option %s\n", argv[optind]); + usage (argv[0]); + return -1; + } + + printf ("Description-----------\n"); + printf ("input0 file:%s\n", file_in0_name); + printf ("input1 file:%s\n", file_in1_name); + printf ("output file PREFIX:%s\n", file_out_name); + printf ("input0 width:%d\n", input_width0); + printf ("input1 width:%d\n", input_width1); + printf ("input/output height:%d\n", input_height); + printf ("output width:%d\n", output_width); + printf ("loop count:%d\n", loop); + printf ("need save file:%s\n", need_save_output ? "true" : "false"); + printf ("enable seam mask:%s\n", (enable_seam ? "true" : "false")); + printf ("----------------------\n"); + + output_height = input_height; + input_buf_info0.init (input_format, input_width0, input_height); + input_buf_info1.init (input_format, input_width1, input_height); + output_buf_info.init (input_format, output_width, output_height); +#if (ENABLE_DMA_TEST) && (HAVE_LIBDRM) + SmartPtr<DrmDisplay> display = DrmDisplay::instance (); + buf_pool0 = new DrmBoBufferPool (display); + buf_pool1 = new DrmBoBufferPool (display); +#else + buf_pool0 = new CLVideoBufferPool (); + buf_pool1 = new CLVideoBufferPool (); +#endif + XCAM_ASSERT (buf_pool0.ptr () && buf_pool1.ptr ()); + buf_pool0->set_video_info (input_buf_info0); + buf_pool1->set_video_info (input_buf_info1); + if (!buf_pool0->reserve (2)) { + XCAM_LOG_ERROR ("init buffer pool failed"); + return -1; + } + if (!buf_pool1->reserve (2)) { + XCAM_LOG_ERROR ("init buffer pool failed"); + return -1; + } + + context = CLDevice::instance ()->get_context (); + blender = create_pyramid_blender (context, 2, true, enable_seam).dynamic_cast_ptr<CLBlender> (); + XCAM_ASSERT (blender.ptr ()); + +#if (ENABLE_DMA_TEST) && (HAVE_LIBDRM) + int dma_fd0 = 30, dma_fd1 = 31, dma_fd_out = 32; + input_buf_info0.init ( + input_format, input_width0, input_height, XCAM_ALIGN_UP (input_width0, 16), XCAM_ALIGN_UP(input_height, 16)); + input_buf_info1.init ( + input_format, input_width1, input_height, XCAM_ALIGN_UP (input_width1, 16), XCAM_ALIGN_UP(input_height, 16)); + output_buf_info.init ( + input_format, output_width, output_height, XCAM_ALIGN_UP (output_width, 16), XCAM_ALIGN_UP(output_height, 16)); + uint32_t in_size = input_buf_info0.aligned_width * input_buf_info0.aligned_height * 3 / 2; + uint32_t out_size = output_buf_info.aligned_width * output_buf_info.aligned_height * 3 / 2; + /* create dma fd, for buffer_handle_t just skip this segment, directly goto dma_buf_to_xcam_buf */ + SmartPtr<VideoBuffer> dma_buf0, dma_buf1, dma_buf_out; + dma_buf0 = create_dma_buffer (display, input_buf_info0); //unit test + dma_buf1 = create_dma_buffer (display, input_buf_info1); //unit test + dma_buf_out = create_dma_buffer (display, output_buf_info); //unit test + dma_fd0 = dma_buf0->get_fd (); //unit test + dma_fd1 = dma_buf1->get_fd (); //unit test + dma_fd_out = dma_buf_out->get_fd (); //unit test + /* + buffer_handle_t just go to here, + dma_fd0 = native_handle_t.data[0]; + dma_fd1 = native_handle_t.data[0]; + dma_fd_out = native_handle_t.data[0]; + */ + printf ("DMA handles, buf0:%d, buf1:%d, buf_out:%d\n", dma_fd0, dma_fd1, dma_fd_out); + input0 = dma_buf_to_xcam_buf ( + display, dma_fd0, input_width0, input_height, in_size, + input_buf_info0.aligned_width, input_buf_info0.aligned_height); + input1 = dma_buf_to_xcam_buf ( + display, dma_fd1, input_width0, input_height, in_size, + input_buf_info1.aligned_width, input_buf_info1.aligned_height); + output_buf = dma_buf_to_xcam_buf ( + display, dma_fd_out, output_width, output_height, out_size, + output_buf_info.aligned_width, output_buf_info.aligned_height); + blender->disable_buf_pool (true); +#else + input0 = buf_pool0->get_buffer (buf_pool0); + input1 = buf_pool1->get_buffer (buf_pool1); + XCAM_ASSERT (input0.ptr () && input1.ptr ()); +#endif + // + ret = file_in0.open (file_in0_name, "rb"); + CHECK_STATEMENT (ret, FAILED_GEO_FREE, "open input file(%s) failed", file_in0_name); + read_buf = input0; + ret = file_in0.read_buf (read_buf); + CHECK_STATEMENT (ret, FAILED_GEO_FREE, "read buffer0 from (%s) failed", file_in0_name); + + ret = file_in1.open (file_in1_name, "rb"); + CHECK_STATEMENT (ret, FAILED_GEO_FREE, "open input file(%s) failed", file_in1_name); + read_buf = input1; + ret = file_in1.read_buf (read_buf); + CHECK_STATEMENT (ret, FAILED_GEO_FREE, "read buffer1 from (%s) failed", file_in1_name); + + if (enable_geo) { + geo_map_handler = create_geo_map_handler (context).dynamic_cast_ptr<CLGeoMapHandler> (); + XCAM_ASSERT (geo_map_handler.ptr ()); + + geo_map0 = new GeoPos[map_width * map_height]; + geo_map1 = new GeoPos[map_width * map_height]; + XCAM_ASSERT (geo_map0 && geo_map1); + if (read_map_data (map0, geo_map0, map_width, map_height) <= 0 || + read_map_data (map1, geo_map1, map_width, map_height) <= 0) { + delete [] geo_map0; + delete [] geo_map1; + return -1; + } + + geo_map_handler->set_map_uint (28.0f, 28.0f); + } + + int i = 0; + do { + input0->clear_attached_buffers (); + input1->clear_attached_buffers (); + + if (enable_geo) { + geo_correct_image (geo_map_handler, input0, geo_map0, map_width, map_height, file_in0_name, need_save_output); + geo_correct_image (geo_map_handler, input1, geo_map1, map_width, map_height, file_in1_name, need_save_output); + } + + ret = blend_images (input0, input1, output_buf, blender); + CHECK_STATEMENT (ret, FAILED_GEO_FREE, "blend_images execute failed"); + //printf ("DMA handles, output_buf:%d\n", output_buf->get_fd ()); + + if (need_save_output) { + char out_name[1024]; + snprintf (out_name, 1023, "%s.%02d", file_out_name, i); + + ret = file_out.open (out_name, "wb"); + CHECK_STATEMENT (ret, FAILED_GEO_FREE, "open output file(%s) failed", out_name); + ret = file_out.write_buf (output_buf); + CHECK_STATEMENT (ret, FAILED_GEO_FREE, "write buffer to (%s) failed", out_name); + printf ("write output buffer to: %s done\n", out_name); + } else { + // check info + ensure_gpu_buffer_done (output_buf); + } + + FPS_CALCULATION (image_blend, XCAM_OBJ_DUR_FRAME_NUM); + ++i; + } while (i < loop); + + delete [] geo_map0; + delete [] geo_map1; + + return ret; +} + +//return count +int read_map_data (const char* file, GeoPos *map, int width, int height) +{ + char *ptr = NULL; + FILE *p_f = fopen (file, "rb"); + CHECK_EXP (p_f, "open geo-map file(%s) failed", file); + +#define FAILED_READ_MAP { if (p_f) fclose(p_f); if (ptr) xcam_free (ptr); return -1; } + + CHECK_DECLARE (ERROR, fseek(p_f, 0L, SEEK_END) == 0, FAILED_READ_MAP, "seek to file(%s) end failed", file); + size_t size = ftell (p_f); + XCAM_ASSERT ((int)size != -1); + fseek (p_f, 0L, SEEK_SET); + + ptr = (char*)xcam_malloc (size + 1); + XCAM_ASSERT (ptr); + CHECK_DECLARE (ERROR, fread (ptr, 1, size, p_f) == size, FAILED_READ_MAP, "read map file(%s)failed", file); + ptr[size] = 0; + fclose (p_f); + p_f = NULL; + + char *str_num = NULL; + char tokens[] = "\t ,\r\n"; + str_num = strtok (ptr, tokens); + int count = 0; + int x = 0, y = 0; + while (str_num != NULL) { + float num = strtof (str_num, NULL); + //printf ("%.3f\n", num); + + x = count % width; + y = count / (width * 2); // x,y + if (y >= height) + break; + + if (count % (width * 2) >= width) + map[y * width + x].y = num; + else + map[y * width + x].x = num; + + ++count; + str_num = strtok (NULL, tokens); + } + xcam_free (ptr); + ptr = NULL; + CHECK_EXP (y < height, "map data(%s) count larger than expected(%dx%dx2)", file, width, height); + CHECK_EXP (count >= width * height * 2, "map data(%s) count less than expected(%dx%dx2)", file, width, height); + + printf ("read map(%s) x/y data count:%d\n", file, count); + return count; +} + diff --git a/tests/test-image-deblurring.cpp b/tests/test-image-deblurring.cpp new file mode 100644 index 0000000..bc681b2 --- /dev/null +++ b/tests/test-image-deblurring.cpp @@ -0,0 +1,170 @@ +/* + * test-image-deblurring.cpp - test image deblurring + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Andrey Parfenov <a1994ndrey@gmail.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "test_common.h" +#include "test_inline.h" + +#include <unistd.h> +#include <getopt.h> +#include <image_file_handle.h> +#include <ocl/cv_image_sharp.h> +#include <ocl/cv_wiener_filter.h> +#include <ocl/cv_image_deblurring.h> + +#include <opencv2/opencv.hpp> +#include <opencv2/core/ocl.hpp> + +using namespace XCam; + +static void +usage (const char* arg0) +{ + printf ("Usage: %s --input file --output file\n" + "\t--input, input image(RGB)\n" + "\t--output, output image(RGB) PREFIX\n" + "\t--blind, optional, blind or non-blind deblurring, default true; select from [true/false]\n" + "\t--save, optional, save file or not, default true; select from [true/false]\n" + "\t--help, usage\n", + arg0); +} + +static void +blind_deblurring (cv::Mat &input_image, cv::Mat &output_image) +{ + SmartPtr<CVImageDeblurring> image_deblurring = new CVImageDeblurring (); + cv::Mat kernel; + image_deblurring->blind_deblurring (input_image, output_image, kernel, -1, -1, false); +} + +static void +non_blind_deblurring (cv::Mat &input_image, cv::Mat &output_image) +{ + SmartPtr<CVWienerFilter> wiener_filter = new CVWienerFilter (); + cv::cvtColor (input_image, input_image, CV_BGR2GRAY); + // use simple motion blur kernel + int kernel_size = 13; + cv::Mat kernel = cv::Mat::zeros (kernel_size, kernel_size, CV_32FC1); + for (int i = 0; i < kernel_size; i++) + { + kernel.at<float> ((kernel_size - 1) / 2, i) = 1.0; + } + kernel /= kernel_size; + //flip kernel to perform convolution + cv::Mat conv_kernel; + cv::flip (kernel, conv_kernel, -1); + cv::Mat blurred; + cv::filter2D (input_image, blurred, CV_32FC1, conv_kernel, cv::Point(-1, -1), 0, cv::BORDER_CONSTANT); + // restore the image + cv::Mat median_blurred; + medianBlur (blurred, median_blurred, 3); + SmartPtr<CVImageProcessHelper> helpers = new CVImageProcessHelper (); + float noise_power = 1.0f / helpers->get_snr (blurred, median_blurred); + wiener_filter->wiener_filter (blurred, kernel, output_image, noise_power); +} + +int main (int argc, char *argv[]) +{ + const char *file_in_name = NULL; + const char *file_out_name = NULL; + + bool need_save_output = true; + bool blind = true; + + const struct option long_opts[] = { + {"input", required_argument, NULL, 'i'}, + {"output", required_argument, NULL, 'o'}, + {"blind", required_argument, NULL, 'b'}, + {"save", required_argument, NULL, 's'}, + {"help", no_argument, NULL, 'H'}, + {0, 0, 0, 0}, + }; + + int opt = -1; + while ((opt = getopt_long (argc, argv, "", long_opts, NULL)) != -1) + { + switch (opt) { + case 'i': + file_in_name = optarg; + break; + case 'o': + file_out_name = optarg; + break; + case 'b': + blind = (strcasecmp (optarg, "false") == 0 ? false : true); + break; + case 's': + need_save_output = (strcasecmp (optarg, "false") == 0 ? false : true); + break; + case 'H': + usage (argv[0]); + return -1; + default: + printf ("getopt_long return unknown value:%c\n", opt); + usage (argv[0]); + return -1; + } + } + + if (optind < argc || argc < 2) + { + printf ("unknown option %s\n", argv[optind]); + usage (argv[0]); + return -1; + } + + if (!file_in_name || !file_out_name) + { + XCAM_LOG_ERROR ("input/output path is NULL"); + return -1; + } + + printf ("Description-----------\n"); + printf ("input image file:%s\n", file_in_name); + printf ("output file :%s\n", file_out_name); + printf ("blind deblurring:%s\n", blind ? "true" : "false"); + printf ("need save file:%s\n", need_save_output ? "true" : "false"); + printf ("----------------------\n"); + + SmartPtr<CVImageSharp> sharp = new CVImageSharp (); + cv::Mat input_image = cv::imread (file_in_name, CV_LOAD_IMAGE_COLOR); + cv::Mat output_image; + if (input_image.empty ()) + { + XCAM_LOG_ERROR ("input file read error"); + return 0; + } + if (blind) + { + blind_deblurring (input_image, output_image); + } + else + { + non_blind_deblurring (input_image, output_image); + } + float input_sharp = sharp->measure_sharp (input_image); + float output_sharp = sharp->measure_sharp (output_image); + if (need_save_output) + { + cv::imwrite (file_out_name, output_image); + } + XCAM_ASSERT (output_sharp > input_sharp); +} + diff --git a/tests/test-image-stitching.cpp b/tests/test-image-stitching.cpp new file mode 100644 index 0000000..ddd765f --- /dev/null +++ b/tests/test-image-stitching.cpp @@ -0,0 +1,614 @@ +/* + * test-image-stitching.cpp - test image stitching + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "test_common.h" +#include "test_inline.h" +#include <unistd.h> +#include <getopt.h> +#include <image_file_handle.h> +#include <calibration_parser.h> +#include <ocl/cl_device.h> +#include <ocl/cl_context.h> +#include <ocl/cl_fisheye_handler.h> +#include <ocl/cl_image_360_stitch.h> +#include <ocl/cl_utils.h> +#if HAVE_OPENCV +#include <ocl/cv_base_class.h> +#endif + +#define XCAM_TEST_STITCH_DEBUG 0 +#define XCAM_ALIGNED_WIDTH 16 + +#define CHECK_ACCESS(fliename) \ + if (access (fliename, F_OK) != 0) { \ + XCAM_LOG_ERROR ("%s not found", fliename); \ + return false; \ + } + +using namespace XCam; + +#if XCAM_TEST_STITCH_DEBUG +static void dbg_write_image ( + SmartPtr<CLContext> context, SmartPtr<CLImage360Stitch> image_360, + SmartPtr<VideoBuffer> input_bufs[], SmartPtr<VideoBuffer> output_buf, + SmartPtr<VideoBuffer> top_view_buf, SmartPtr<VideoBuffer> rectified_view_buf, + bool all_in_one, int fisheye_num, int input_count); +#endif + +static bool +parse_calibration_params ( + IntrinsicParameter intrinsic_param[], + ExtrinsicParameter extrinsic_param[], + int fisheye_num) +{ + CalibrationParser calib_parser; + + char intrinsic_path[1024], extrinsic_path[1024]; + for(int index = 0; index < fisheye_num; index++) { + switch (index) { + case 0: + strncpy (intrinsic_path, "./calib_params/intrinsic_camera_front.txt", 1023); + strncpy (extrinsic_path, "./calib_params/extrinsic_camera_front.txt", 1023); + break; + case 1: + strncpy (intrinsic_path, "./calib_params/intrinsic_camera_right.txt", 1023); + strncpy (extrinsic_path, "./calib_params/extrinsic_camera_right.txt", 1023); + break; + case 2: + strncpy (intrinsic_path, "./calib_params/intrinsic_camera_rear.txt", 1023); + strncpy (extrinsic_path, "./calib_params/extrinsic_camera_rear.txt", 1023); + break; + case 3: + strncpy (intrinsic_path, "./calib_params/intrinsic_camera_left.txt", 1023); + strncpy (extrinsic_path, "./calib_params/extrinsic_camera_left.txt", 1023); + break; + default: + XCAM_LOG_ERROR ("bowl view only support 4-camera mode"); + return false; + } + + CHECK_ACCESS (intrinsic_path); + CHECK_ACCESS (extrinsic_path); + + if (!xcam_ret_is_ok ( + calib_parser.parse_intrinsic_file (intrinsic_path, intrinsic_param[index]))) { + XCAM_LOG_ERROR ("parse fisheye:%d intrinsic file:%s failed.", index, intrinsic_path); + return false; + } + if (!xcam_ret_is_ok ( + calib_parser.parse_extrinsic_file (extrinsic_path, extrinsic_param[index]))) { + XCAM_LOG_ERROR ("parse fisheye:%d extrinsic file:%s failed.", index, extrinsic_path); + return false; + } + + extrinsic_param[index].trans_x += TEST_CAMERA_POSITION_OFFSET_X; + } + + return true; +} + +XCamReturn +read_file_to_video_buffer ( + ImageFileHandle &file, + uint32_t width, + uint32_t height, + uint32_t row_pitch, + SmartPtr<VideoBuffer> &buf) +{ + size_t size = row_pitch * height / 2 * 3; + uint8_t *nv12_mem = (uint8_t *) xcam_malloc0 (sizeof (uint8_t) * size); + XCAM_ASSERT (nv12_mem); + + XCamReturn ret = file.read_file (nv12_mem, size); + if (ret != XCAM_RETURN_NO_ERROR) { + xcam_free (nv12_mem); + return ret; + } + + uint32_t offset_uv = row_pitch * height; + convert_nv12_mem_to_video_buffer (nv12_mem, width, height, row_pitch, offset_uv, buf); + XCAM_ASSERT (buf.ptr ()); + + xcam_free (nv12_mem); + return XCAM_RETURN_NO_ERROR; +} + +void usage(const char* arg0) +{ + printf ("Usage:\n" + "%s --input file --output file\n" + "\t--input input image(NV12)\n" + "\t--output output image(NV12)\n" + "\t--input-w optional, input width, default: 1920\n" + "\t--input-h optional, input height, default: 1080\n" + "\t--output-w optional, output width, default: 1920\n" + "\t--output-h optional, output width, default: 960\n" + "\t--res-mode optional, image resolution mode, select from [1080p/1080p4/4k], default: 1080p\n" + "\t--surround-mode optional, stitching surround mode, select from [sphere, bowl], default: sphere\n" + "\t--scale-mode optional, image scaling mode, select from [local/global], default: local\n" + "\t--enable-seam optional, enable seam finder in blending area, default: no\n" + "\t--enable-fisheyemap optional, enable fisheye map, default: no\n" + "\t--enable-lsc optional, enable lens shading correction, default: no\n" +#if HAVE_OPENCV + "\t--fm-ocl optional, enable ocl for feature match, select from [true/false], default: false\n" +#endif + "\t--fisheye-num optional, the number of fisheye lens, default: 2\n" + "\t--all-in-one optional, all fisheye in one image, select from [true/false], default: true\n" + "\t--save optional, save file or not, select from [true/false], default: true\n" + "\t--framerate optional, framerate of saved video, default: 30.0\n" + "\t--loop optional, how many loops need to run for performance test, default: 1\n" + "\t--help usage\n", + arg0); +} + +int main (int argc, char *argv[]) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<CLContext> context; + SmartPtr<BufferPool> buf_pool[XCAM_STITCH_FISHEYE_MAX_NUM]; + ImageFileHandle file_in[XCAM_STITCH_FISHEYE_MAX_NUM]; + ImageFileHandle file_out; + SmartPtr<VideoBuffer> input_buf, output_buf, top_view_buf, rectified_view_buf; + VideoBufferInfo input_buf_info, output_buf_info, top_view_buf_info, rectified_view_buf_info; + SmartPtr<CLImage360Stitch> image_360; + + uint32_t input_format = V4L2_PIX_FMT_NV12; + uint32_t input_width = 1920; + uint32_t input_height = 1080; + uint32_t output_height = 960; + uint32_t output_width = output_height * 2; + + uint32_t top_view_width = 1920; + uint32_t top_view_height = 1080; + + uint32_t rectified_view_width = 1920; + uint32_t rectified_view_height = 1080; + + int loop = 1; + bool enable_seam = false; + bool enable_fisheye_map = false; + bool enable_lsc = false; + CLBlenderScaleMode scale_mode = CLBlenderScaleLocal; + StitchResMode res_mode = StitchRes1080P; + SurroundMode surround_mode = BowlView; + + IntrinsicParameter intrinsic_param[XCAM_STITCH_FISHEYE_MAX_NUM]; + ExtrinsicParameter extrinsic_param[XCAM_STITCH_FISHEYE_MAX_NUM]; + +#if HAVE_OPENCV + bool fm_ocl = false; +#endif + int fisheye_num = 2; + bool all_in_one = true; + bool need_save_output = true; + double framerate = 30.0; + + const char *file_in_name[XCAM_STITCH_FISHEYE_MAX_NUM] = {NULL}; + const char *file_out_name = NULL; + const char *top_view_filename = "top_view.mp4"; + const char *rectified_view_filename = "rectified_view.mp4"; + + int input_count = 0; + + const struct option long_opts[] = { + {"input", required_argument, NULL, 'i'}, + {"output", required_argument, NULL, 'o'}, + {"input-w", required_argument, NULL, 'w'}, + {"input-h", required_argument, NULL, 'h'}, + {"output-w", required_argument, NULL, 'W'}, + {"output-h", required_argument, NULL, 'H'}, + {"res-mode", required_argument, NULL, 'R'}, + {"surround-mode", required_argument, NULL, 'r'}, + {"scale-mode", required_argument, NULL, 'c'}, + {"enable-seam", no_argument, NULL, 'S'}, + {"enable-fisheyemap", no_argument, NULL, 'F'}, + {"enable-lsc", no_argument, NULL, 'L'}, +#if HAVE_OPENCV + {"fm-ocl", required_argument, NULL, 'O'}, +#endif + {"fisheye-num", required_argument, NULL, 'N'}, + {"all-in-one", required_argument, NULL, 'A'}, + {"save", required_argument, NULL, 's'}, + {"framerate", required_argument, NULL, 'f'}, + {"loop", required_argument, NULL, 'l'}, + {"help", no_argument, NULL, 'e'}, + {NULL, 0, NULL, 0}, + }; + + int opt = -1; + while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { + switch (opt) { + case 'i': + XCAM_ASSERT (optarg); + file_in_name[input_count] = optarg; + input_count++; + break; + case 'o': + XCAM_ASSERT (optarg); + file_out_name = optarg; + break; + case 'w': + input_width = atoi(optarg); + break; + case 'h': + input_height = atoi(optarg); + break; + case 'W': + output_width = atoi(optarg); + break; + case 'H': + output_height = atoi(optarg); + break; + case 'R': + if (!strcasecmp (optarg, "1080p")) + res_mode = StitchRes1080P; + else if (!strcasecmp (optarg, "1080p4")) + res_mode = StitchRes1080P4; + else if (!strcasecmp (optarg, "4k")) + res_mode = StitchRes4K; + else { + XCAM_LOG_ERROR ("incorrect resolution mode"); + return -1; + } + break; + case 'r': + if (!strcasecmp (optarg, "sphere")) + surround_mode = SphereView; + else if(!strcasecmp (optarg, "bowl")) + surround_mode = BowlView; + else { + XCAM_LOG_ERROR ("incorrect surround mode"); + return -1; + } + break; + case 'c': + if (!strcasecmp (optarg, "local")) + scale_mode = CLBlenderScaleLocal; + else if (!strcasecmp (optarg, "global")) + scale_mode = CLBlenderScaleGlobal; + else { + XCAM_LOG_ERROR ("incorrect scaling mode"); + return -1; + } + break; + case 'S': + enable_seam = true; + break; + case 'F': + enable_fisheye_map = true; + break; + case 'L': + enable_lsc = true; + break; +#if HAVE_OPENCV + case 'O': + fm_ocl = (strcasecmp (optarg, "true") == 0 ? true : false); + break; +#endif + case 'N': + fisheye_num = atoi(optarg); + if (fisheye_num > XCAM_STITCH_FISHEYE_MAX_NUM) { + XCAM_LOG_ERROR ("fisheye number should not be greater than %d\n", XCAM_STITCH_FISHEYE_MAX_NUM); + return -1; + } + break; + case 'A': + all_in_one = (strcasecmp (optarg, "false") == 0 ? false : true); + break; + case 's': + need_save_output = (strcasecmp (optarg, "false") == 0 ? false : true); + break; + case 'f': + framerate = atof(optarg); + break; + case 'l': + loop = atoi(optarg); + break; + case 'e': + usage (argv[0]); + return -1; + default: + XCAM_LOG_ERROR ("getopt_long return unknown value:%c", opt); + usage (argv[0]); + return -1; + } + } + + if (optind < argc || argc < 2) { + XCAM_LOG_ERROR ("unknown option %s", argv[optind]); + usage (argv[0]); + return -1; + } + + if (!all_in_one && input_count != fisheye_num) { + XCAM_LOG_ERROR ("multiple-input mode: conflicting input number(%d) and fisheye number(%d)", + input_count, fisheye_num); + return -1; + } + + for (int i = 0; i < input_count; i++) { + if (!file_in_name[i]) { + XCAM_LOG_ERROR ("input[%d] path is NULL", i); + return -1; + } + } + + if (!file_out_name) { + XCAM_LOG_ERROR ("output path is NULL"); + return -1; + } + + output_width = XCAM_ALIGN_UP (output_width, XCAM_ALIGNED_WIDTH); + output_height = XCAM_ALIGN_UP (output_height, XCAM_ALIGNED_WIDTH); + // if (output_width != output_height * 2) { + // XCAM_LOG_ERROR ("incorrect output size width:%d height:%d", output_width, output_height); + // return -1; + // } + +#if !HAVE_OPENCV + if (need_save_output) { + XCAM_LOG_WARNING ("non-OpenCV mode, can't save video"); + need_save_output = false; + } +#endif + + printf ("Description------------------------\n"); + if (all_in_one) + printf ("input file:\t\t%s\n", file_in_name[0]); + else { + for (int i = 0; i < input_count; i++) + printf ("input file %d:\t\t%s\n", i, file_in_name[i]); + } + printf ("output file:\t\t%s\n", file_out_name); + printf ("input width:\t\t%d\n", input_width); + printf ("input height:\t\t%d\n", input_height); + printf ("output width:\t\t%d\n", output_width); + printf ("output height:\t\t%d\n", output_height); + printf ("resolution mode:\t%s\n", + res_mode == StitchRes1080P ? "1080P" : (res_mode == StitchRes1080P4 ? "1080P4" : "4K")); + printf ("surround mode: \t\t%s\n", + surround_mode == SphereView ? "sphere view" : "bowl view"); + printf ("scale mode:\t\t%s\n", scale_mode == CLBlenderScaleLocal ? "local" : "global"); + printf ("seam mask:\t\t%s\n", enable_seam ? "true" : "false"); + printf ("fisheye map:\t\t%s\n", enable_fisheye_map ? "true" : "false"); + printf ("shading correction:\t%s\n", enable_lsc ? "true" : "false"); +#if HAVE_OPENCV + printf ("feature match ocl:\t%s\n", fm_ocl ? "true" : "false"); +#endif + printf ("fisheye number:\t\t%d\n", fisheye_num); + printf ("all in one:\t\t%s\n", all_in_one ? "true" : "false"); + printf ("save file:\t\t%s\n", need_save_output ? "true" : "false"); + printf ("framerate:\t\t%.3lf\n", framerate); + printf ("loop count:\t\t%d\n", loop); + printf ("-----------------------------------\n"); + + context = CLDevice::instance ()->get_context (); + image_360 = + create_image_360_stitch ( + context, enable_seam, scale_mode, enable_fisheye_map, enable_lsc, surround_mode, + res_mode, fisheye_num, all_in_one).dynamic_cast_ptr<CLImage360Stitch> (); + XCAM_ASSERT (image_360.ptr ()); + image_360->set_output_size (output_width, output_height); +#if HAVE_OPENCV + image_360->set_feature_match_ocl (fm_ocl); +#endif + image_360->set_pool_type (CLImageHandler::CLVideoPoolType); + + if (surround_mode == BowlView) { + parse_calibration_params (intrinsic_param, extrinsic_param, fisheye_num); + + for (int i = 0; i < fisheye_num; i++) { + image_360->set_fisheye_intrinsic (intrinsic_param[i], i); + image_360->set_fisheye_extrinsic (extrinsic_param[i], i); + } + } + + input_buf_info.init (input_format, input_width, input_height); + output_buf_info.init (input_format, output_width, output_height); + top_view_buf_info.init (input_format, top_view_width, top_view_height); + rectified_view_buf_info.init (input_format, rectified_view_width, rectified_view_height); + for (int i = 0; i < input_count; i++) { + buf_pool[i] = new CLVideoBufferPool (); + XCAM_ASSERT (buf_pool[i].ptr ()); + buf_pool[i]->set_video_info (input_buf_info); + if (!buf_pool[i]->reserve (6)) { + XCAM_LOG_ERROR ("init buffer pool failed"); + return -1; + } + } + + SmartPtr<BufferPool> top_view_pool = new CLVideoBufferPool (); + XCAM_ASSERT (top_view_pool.ptr ()); + top_view_pool->set_video_info (top_view_buf_info); + if (!top_view_pool->reserve (6)) { + XCAM_LOG_ERROR ("top-view-buffer pool reserve failed"); + return -1; + } + top_view_buf = top_view_pool->get_buffer (top_view_pool); + + SmartPtr<BufferPool> rectified_view_pool = new CLVideoBufferPool (); + XCAM_ASSERT (rectified_view_pool.ptr ()); + rectified_view_pool->set_video_info (rectified_view_buf_info); + if (!rectified_view_pool->reserve (6)) { + XCAM_LOG_ERROR ("top-view-buffer pool reserve failed"); + return -1; + } + rectified_view_buf = rectified_view_pool->get_buffer (rectified_view_pool); + + for (int i = 0; i < input_count; i++) { + ret = file_in[i].open (file_in_name[i], "rb"); + CHECK (ret, "open %s failed", file_in_name[i]); + } + +#if HAVE_OPENCV + cv::VideoWriter writer; + cv::VideoWriter top_view_writer; + cv::VideoWriter rectified_view_writer; + if (need_save_output) { + cv::Size dst_size = cv::Size (output_width, output_height); + if (!writer.open (file_out_name, CV_FOURCC('X', '2', '6', '4'), framerate, dst_size)) { + XCAM_LOG_ERROR ("open file %s failed", file_out_name); + return -1; + } + + dst_size = cv::Size (top_view_width, top_view_height); + if (!top_view_writer.open (top_view_filename, CV_FOURCC('X', '2', '6', '4'), framerate, dst_size)) { + XCAM_LOG_ERROR ("open file %s failed", top_view_filename); + return -1; + } + + dst_size = cv::Size (rectified_view_width, rectified_view_height); + if (!rectified_view_writer.open (rectified_view_filename, CV_FOURCC('X', '2', '6', '4'), framerate, dst_size)) { + XCAM_LOG_ERROR ("open file %s failed", rectified_view_filename); + return -1; + } + } +#endif + + SmartPtr<VideoBuffer> pre_buf, cur_buf; +#if (HAVE_OPENCV) && (XCAM_TEST_STITCH_DEBUG) + SmartPtr<VideoBuffer> input_bufs[XCAM_STITCH_FISHEYE_MAX_NUM]; +#endif + int frame_id = 0; + std::vector<PointFloat2> top_view_map_table; + std::vector<PointFloat2> rectified_view_map_table; + float rectified_start_angle = -45.0f, rectified_end_angle = 45.0f; + + while (loop--) { + for (int i = 0; i < input_count; i++) { + ret = file_in[i].rewind (); + CHECK (ret, "image_360 stitch rewind file(%s) failed", file_in_name[i]); + } + + do { + for (int i = 0; i < input_count; i++) { + cur_buf = buf_pool[i]->get_buffer (buf_pool[i]); + XCAM_ASSERT (cur_buf.ptr ()); + ret = file_in[i].read_buf (cur_buf); + // ret = read_file_to_video_buffer (file_in[i], input_width, input_height, input_width, cur_buf); + if (ret == XCAM_RETURN_BYPASS) + break; + if (ret == XCAM_RETURN_ERROR_FILE) { + XCAM_LOG_ERROR ("read buffer from %s failed", file_in_name[i]); + return -1; + } + + if (i == 0) + input_buf = cur_buf; + else + pre_buf->attach_buffer (cur_buf); + + pre_buf = cur_buf; +#if (HAVE_OPENCV) && (XCAM_TEST_STITCH_DEBUG) + input_bufs[i] = cur_buf; +#endif + } + if (ret == XCAM_RETURN_BYPASS) + break; + + ret = image_360->execute (input_buf, output_buf); + CHECK (ret, "image_360 stitch execute failed"); + +#if HAVE_OPENCV + if (need_save_output) { + cv::Mat out_mat; + convert_to_mat (output_buf, out_mat); + writer.write (out_mat); + + BowlDataConfig config = image_360->get_fisheye_bowl_config (); + cv::Mat top_view_mat; + sample_generate_top_view (output_buf, top_view_buf, config, top_view_map_table); + convert_to_mat (top_view_buf, top_view_mat); + top_view_writer.write (top_view_mat); + + cv::Mat rectified_view_mat; + sample_generate_rectified_view (output_buf, rectified_view_buf, config, rectified_start_angle, + rectified_end_angle, rectified_view_map_table); + convert_to_mat (rectified_view_buf, rectified_view_mat); + rectified_view_writer.write (rectified_view_mat); + +#if XCAM_TEST_STITCH_DEBUG + dbg_write_image (context, image_360, input_bufs, output_buf, top_view_buf, rectified_view_buf, + all_in_one, fisheye_num, input_count); +#endif + } else +#endif + ensure_gpu_buffer_done (output_buf); + + frame_id++; + FPS_CALCULATION (image_stitching, XCAM_OBJ_DUR_FRAME_NUM); + } while (true); + } + + return 0; +} + +#if (HAVE_OPENCV) && (XCAM_TEST_STITCH_DEBUG) +static void dbg_write_image ( + SmartPtr<CLContext> context, SmartPtr<CLImage360Stitch> image_360, + SmartPtr<VideoBuffer> input_bufs[], SmartPtr<VideoBuffer> output_buf, + SmartPtr<VideoBuffer> top_view_buf, SmartPtr<VideoBuffer> rectified_view_buf, + bool all_in_one, int fisheye_num, int input_count) +{ + cv::Mat mat; + static int frame_count = 0; + char file_name [1024]; + StitchInfo stitch_info = image_360->get_stitch_info (); + + std::snprintf (file_name, 1023, "orig_fisheye_%d.jpg", frame_count); + for (int i = 0; i < input_count; i++) { + if (!all_in_one) + std::snprintf (file_name, 1023, "orig_fisheye_%d_%d.jpg", frame_count, i); + + convert_to_mat (input_bufs[i], mat); + int fisheye_per_frame = all_in_one ? fisheye_num : 1; + for (int i = 0; i < fisheye_per_frame; i++) { + cv::circle (mat, cv::Point(stitch_info.fisheye_info[i].center_x, stitch_info.fisheye_info[i].center_y), + stitch_info.fisheye_info[i].radius, cv::Scalar(0, 0, 255), 2); + } + cv::imwrite (file_name, mat); + } + + char frame_str[1024]; + std::snprintf (frame_str, 1023, "%d", frame_count); + + convert_to_mat (output_buf, mat); + cv::putText (mat, frame_str, cv::Point(120, 120), cv::FONT_HERSHEY_COMPLEX, 2.0, + cv::Scalar(0, 0, 255), 2, 8, false); + std::snprintf (file_name, 1023, "stitched_img_%d.jpg", frame_count); + cv::imwrite (file_name, mat); + + convert_to_mat (top_view_buf, mat); + cv::putText (mat, frame_str, cv::Point(120, 120), cv::FONT_HERSHEY_COMPLEX, 2.0, + cv::Scalar(0, 0, 255), 2, 8, false); + std::snprintf (file_name, 1023, "top_view_img_%d.jpg", frame_count); + cv::imwrite (file_name, mat); + + convert_to_mat (rectified_view_buf, mat); + cv::putText (mat, frame_str, cv::Point(120, 120), cv::FONT_HERSHEY_COMPLEX, 2.0, + cv::Scalar(0, 0, 255), 2, 8, false); + std::snprintf (file_name, 1023, "rectified_view_img_%d.jpg", frame_count); + cv::imwrite (file_name, mat); + + frame_count++; +} +#endif + diff --git a/tests/test-pipe-manager.cpp b/tests/test-pipe-manager.cpp new file mode 100644 index 0000000..280bfdc --- /dev/null +++ b/tests/test-pipe-manager.cpp @@ -0,0 +1,467 @@ +/* + * test-pipe-manager.cpp -test pipe manager + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include <pipe_manager.h> +#include <smart_analyzer_loader.h> +#include <ocl/cl_post_image_processor.h> +#if HAVE_LIBDRM +#include <drm_display.h> +#endif +#include <getopt.h> +#include <test_common.h> +#include <signal.h> +#include <stdio.h> + +#define DEFAULT_FPT_BUF_COUNT 32 + +using namespace XCam; + +static bool is_stop = false; + +struct FileFP { + FILE *fp; + FileFP () + : fp (NULL) + {} + ~FileFP () + { + if (fp) + fclose (fp); + fp = NULL; + } +}; + +class MainPipeManager + : public PipeManager +{ +public: + MainPipeManager () + : _image_width (0) + , _image_height (0) + , _enable_display (false) + { +#if HAVE_LIBDRM + _display = DrmDisplay::instance (); +#endif + XCAM_OBJ_PROFILING_INIT; + } + + void set_image_width (uint32_t image_width) { + _image_width = image_width; + } + + void set_image_height (uint32_t image_height) { + _image_height = image_height; + } + + void enable_display (bool value) { + _enable_display = value; + } + +#if HAVE_LIBDRM + void set_display_mode (DrmDisplayMode mode) { + _display->set_display_mode (mode); + } +#endif + +protected: + virtual void post_buffer (const SmartPtr<VideoBuffer> &buf); + int display_buf (const SmartPtr<VideoBuffer> &buf); + +private: + uint32_t _image_width; + uint32_t _image_height; + bool _enable_display; +#if HAVE_LIBDRM + SmartPtr<DrmDisplay> _display; +#endif + XCAM_OBJ_PROFILING_DEFINES; +}; + +void +MainPipeManager::post_buffer (const SmartPtr<VideoBuffer> &buf) +{ + FPS_CALCULATION (fps_buf, XCAM_OBJ_DUR_FRAME_NUM); + + XCAM_OBJ_PROFILING_START; + + if (_enable_display) + display_buf (buf); + + XCAM_OBJ_PROFILING_END("main_pipe_manager_display", XCAM_OBJ_DUR_FRAME_NUM); +} + +int +MainPipeManager::display_buf (const SmartPtr<VideoBuffer> &data) +{ +#if HAVE_LIBDRM + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<VideoBuffer> buf = data; + const VideoBufferInfo & frame_info = buf->get_video_info (); + struct v4l2_rect rect = { 0, 0, frame_info.width, frame_info.height}; + + if (!_display->is_render_inited ()) { + ret = _display->render_init (0, 0, this->_image_width, this->_image_height, + frame_info.format, &rect); + CHECK (ret, "display failed on render_init"); + } + ret = _display->render_setup_frame_buffer (buf); + CHECK (ret, "display failed on framebuf set"); + ret = _display->render_buffer (buf); + CHECK (ret, "display failed on rendering"); +#else + XCAM_UNUSED (data); +#endif + + return 0; +} + +XCamReturn +read_buf (SmartPtr<VideoBuffer> &buf, FileFP &file) +{ + const VideoBufferInfo info = buf->get_video_info (); + VideoBufferPlanarInfo planar; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + uint8_t *memory = buf->map (); + for (uint32_t index = 0; index < info.components; index++) { + info.get_planar_info (planar, index); + uint32_t line_bytes = planar.width * planar.pixel_bytes; + + for (uint32_t i = 0; i < planar.height; i++) { + if (fread (memory + info.offsets [index] + i * info.strides [index], 1, line_bytes, file.fp) != line_bytes) { + if (feof (file.fp)) { + fseek (file.fp, 0, SEEK_SET); + ret = XCAM_RETURN_BYPASS; + } else { + XCAM_LOG_ERROR ("read file failed, size doesn't match"); + ret = XCAM_RETURN_ERROR_FILE; + } + goto done; + } + } + } +done: + buf->unmap (); + return ret; +} + +void pipe_stop_handler(int sig) +{ + XCAM_UNUSED (sig); + is_stop = true; +} + +void print_help (const char *bin_name) +{ + printf ("Usage: %s [--format=NV12] [--width=1920] ...\n" + "\t --format specify output pixel format, default is NV12\n" + "\t --width specify input image width, default is 1920\n" + "\t --height specify input image height, default is 1080\n" + "\t --fake-input specify the path of image as fake source\n" + "\t --defog-mode specify defog mode\n" + "\t select from [disabled, retinex, dcp], default is [disabled]\n" + "\t --wavelet-mode specify wavelet denoise mode, default is disable\n" + "\t select from [0:disable, 1:Hat Y, 2:Hat UV, 3:Haar Y, 4:Haar UV, 5:Haar YUV, 6:Haar Bayes Shrink]\n" + "\t --3d-denoise specify 3D Denoise mode\n" + "\t select from [disabled, yuv, uv], default is [disabled]\n" + "\t --enable-wireframe enable wire frame\n" + "\t --enable-warp enable image warp\n" + "\t --display-mode display mode\n" + "\t select from [primary, overlay], default is [primary]\n" + "\t -p enable local display, need root privilege\n" + "\t -h help\n" + , bin_name); +} + +int main (int argc, char *argv[]) +{ + const char *bin_name = argv[0]; + + XCamReturn ret = XCAM_RETURN_NO_ERROR; + VideoBufferInfo buf_info; + SmartPtr<VideoBuffer> video_buf; + SmartPtr<SmartAnalyzer> smart_analyzer; + SmartPtr<CLPostImageProcessor> cl_post_processor; + SmartPtr<BufferPool> buf_pool; + + uint32_t pixel_format = V4L2_PIX_FMT_NV12; + uint32_t image_width = 1920; + uint32_t image_height = 1080; + bool need_display = false; +#if HAVE_LIBDRM + DrmDisplayMode display_mode = DRM_DISPLAY_MODE_PRIMARY; +#endif + const char *input_path = NULL; + FileFP input_fp; + + uint32_t defog_mode = 0; + CLWaveletBasis wavelet_mode = CL_WAVELET_DISABLED; + uint32_t wavelet_channel = CL_IMAGE_CHANNEL_UV; + bool wavelet_bayes_shrink = false; + uint32_t denoise_3d_mode = 0; + uint8_t denoise_3d_ref_count = 3; + bool enable_wireframe = false; + bool enable_image_warp = false; + + int opt; + const char *short_opts = "ph"; + const struct option long_opts [] = { + {"format", required_argument, NULL, 'F'}, + {"width", required_argument, NULL, 'W'}, + {"height", required_argument, NULL, 'H'}, + {"fake-input", required_argument, NULL, 'A'}, + {"defog-mode", required_argument, NULL, 'D'}, + {"wavelet-mode", required_argument, NULL, 'V'}, + {"3d-denoise", required_argument, NULL, 'N'}, + {"enable-wireframe", no_argument, NULL, 'I'}, + {"enable-warp", no_argument, NULL, 'S'}, + {"display-mode", required_argument, NULL, 'P'}, + {NULL, 0, NULL, 0} + }; + + while ((opt = getopt_long (argc, argv, short_opts, long_opts, NULL)) != -1) { + switch (opt) { + case 'F': { + XCAM_ASSERT (optarg); + CHECK_EXP ((strlen (optarg) == 4), "invalid pixel format\n"); + pixel_format = v4l2_fourcc ((unsigned) optarg[0], + (unsigned) optarg[1], + (unsigned) optarg[2], + (unsigned) optarg[3]); + break; + } + case 'W': { + XCAM_ASSERT (optarg); + image_width = atoi (optarg); + break; + } + case 'H': { + XCAM_ASSERT (optarg); + image_height = atoi (optarg); + break; + } + case 'A': { + XCAM_ASSERT (optarg); + XCAM_LOG_INFO ("use image %s as input source", optarg); + input_path = optarg; + break; + } + case 'D': { + XCAM_ASSERT (optarg); + if (!strcmp (optarg, "disabled")) + defog_mode = CLPostImageProcessor::DefogDisabled; + else if (!strcmp (optarg, "retinex")) + defog_mode = CLPostImageProcessor::DefogRetinex; + else if (!strcmp (optarg, "dcp")) + defog_mode = CLPostImageProcessor::DefogDarkChannelPrior; + else { + print_help (bin_name); + return -1; + } + break; + } + case 'V': { + XCAM_ASSERT (optarg); + if (atoi(optarg) < 0 || atoi(optarg) > 255) { + print_help (bin_name); + return -1; + } + if (atoi(optarg) == 1) { + wavelet_mode = CL_WAVELET_HAT; + wavelet_channel = CL_IMAGE_CHANNEL_Y; + } else if (atoi(optarg) == 2) { + wavelet_mode = CL_WAVELET_HAT; + wavelet_channel = CL_IMAGE_CHANNEL_UV; + } else if (atoi(optarg) == 3) { + wavelet_mode = CL_WAVELET_HAAR; + wavelet_channel = CL_IMAGE_CHANNEL_Y; + } else if (atoi(optarg) == 4) { + wavelet_mode = CL_WAVELET_HAAR; + wavelet_channel = CL_IMAGE_CHANNEL_UV; + } else if (atoi(optarg) == 5) { + wavelet_mode = CL_WAVELET_HAAR; + wavelet_channel = CL_IMAGE_CHANNEL_UV | CL_IMAGE_CHANNEL_Y; + } else if (atoi(optarg) == 6) { + wavelet_mode = CL_WAVELET_HAAR; + wavelet_channel = CL_IMAGE_CHANNEL_UV | CL_IMAGE_CHANNEL_Y; + wavelet_bayes_shrink = true; + } else { + wavelet_mode = CL_WAVELET_DISABLED; + } + break; + } + case 'N': { + XCAM_ASSERT (optarg); + if (!strcmp (optarg, "disabled")) + denoise_3d_mode = CLPostImageProcessor::Denoise3DDisabled; + else if (!strcmp (optarg, "yuv")) + denoise_3d_mode = CLPostImageProcessor::Denoise3DYuv; + else if (!strcmp (optarg, "uv")) + denoise_3d_mode = CLPostImageProcessor::Denoise3DUV; + else { + print_help (bin_name); + return -1; + } + break; + } + case 'I': { + enable_wireframe = true; + break; + } + case 'S': { + enable_image_warp = true; + break; + } + case 'P': { +#if HAVE_LIBDRM + XCAM_ASSERT (optarg); + if (!strcmp (optarg, "primary")) + display_mode = DRM_DISPLAY_MODE_PRIMARY; + else if (!strcmp (optarg, "overlay")) + display_mode = DRM_DISPLAY_MODE_OVERLAY; + else { + print_help (bin_name); + return -1; + } +#else + XCAM_LOG_WARNING ("preview is not supported"); +#endif + break; + } + case 'p': { +#if HAVE_LIBDRM + need_display = true; +#else + XCAM_LOG_WARNING ("preview is not supported, disable preview now"); + need_display = false; +#endif + break; + } + case 'h': + print_help (bin_name); + return 0; + default: + print_help (bin_name); + return -1; + } + } + + signal (SIGINT, pipe_stop_handler); + + if (!input_path) { + XCAM_LOG_ERROR ("path of image is NULL"); + return -1; + } + input_fp.fp = fopen (input_path, "rb"); + if (!input_fp.fp) { + XCAM_LOG_ERROR ("failed to open file: %s", XCAM_STR (input_path)); + return -1; + } + + SmartPtr<MainPipeManager> pipe_manager = new MainPipeManager (); + pipe_manager->set_image_width (image_width); + pipe_manager->set_image_height (image_height); + + SmartHandlerList smart_handlers = SmartAnalyzerLoader::load_smart_handlers (DEFAULT_SMART_ANALYSIS_LIB_DIR); + if (!smart_handlers.empty () ) { + smart_analyzer = new SmartAnalyzer (); + if (smart_analyzer.ptr ()) { + SmartHandlerList::iterator i_handler = smart_handlers.begin (); + for (; i_handler != smart_handlers.end (); ++i_handler) { + XCAM_ASSERT ((*i_handler).ptr ()); + smart_analyzer->add_handler (*i_handler); + } + } else { + XCAM_LOG_INFO ("load smart analyzer(%s) failed", DEFAULT_SMART_ANALYSIS_LIB_DIR); + } + } + if (smart_analyzer.ptr ()) { + if (smart_analyzer->prepare_handlers () != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("analyzer(%s) prepare handlers failed", smart_analyzer->get_name ()); + } + pipe_manager->set_smart_analyzer (smart_analyzer); + } + + cl_post_processor = new CLPostImageProcessor (); + cl_post_processor->set_stats_callback (pipe_manager); + cl_post_processor->set_defog_mode ((CLPostImageProcessor::CLDefogMode) defog_mode); + cl_post_processor->set_wavelet (wavelet_mode, wavelet_channel, wavelet_bayes_shrink); + cl_post_processor->set_3ddenoise_mode ((CLPostImageProcessor::CL3DDenoiseMode) denoise_3d_mode, denoise_3d_ref_count); + + cl_post_processor->set_wireframe (enable_wireframe); + cl_post_processor->set_image_warp (enable_image_warp); + if (smart_analyzer.ptr () && (enable_wireframe || enable_image_warp)) { + cl_post_processor->set_scaler (true); + cl_post_processor->set_scaler_factor (640.0 / image_width); + } + + pipe_manager->add_image_processor (cl_post_processor); + + buf_info.init (pixel_format, image_width, image_height); + buf_pool = new CLVideoBufferPool (); + XCAM_ASSERT (buf_pool.ptr ()); + if (!buf_pool->set_video_info (buf_info) || !buf_pool->reserve (DEFAULT_FPT_BUF_COUNT)) { + XCAM_LOG_ERROR ("init buffer pool failed"); + return -1; + } + + if (need_display) { + need_display = false; + XCAM_LOG_WARNING ("CLVideoBuffer doesn't support local preview, disable local preview now"); + } + + if (need_display) { +#if HAVE_LIBDRM + if (DrmDisplay::set_preview (need_display)) { + pipe_manager->set_display_mode (display_mode); + cl_post_processor->set_output_format (V4L2_PIX_FMT_XBGR32); + } else { + need_display = false; + XCAM_LOG_WARNING ("set preview failed, disable local preview now"); + } +#else + XCAM_LOG_WARNING ("preview is not supported, disable preview now"); + need_display = false; +#endif + } + pipe_manager->enable_display (need_display); + + ret = pipe_manager->start (); + CHECK (ret, "pipe manager start failed"); + + while (!is_stop) { + video_buf = buf_pool->get_buffer (buf_pool); + XCAM_ASSERT (video_buf.ptr ()); + + ret = read_buf (video_buf, input_fp); + if (ret == XCAM_RETURN_BYPASS) { + ret = read_buf (video_buf, input_fp); + } + + if (ret == XCAM_RETURN_NO_ERROR) + pipe_manager->push_buffer (video_buf); + } + + ret = pipe_manager->stop(); + CHECK (ret, "pipe manager stop failed"); + + return 0; +} diff --git a/tests/test-poll-thread.cpp b/tests/test-poll-thread.cpp new file mode 100644 index 0000000..98b84c8 --- /dev/null +++ b/tests/test-poll-thread.cpp @@ -0,0 +1,247 @@ +/* + * main.cpp - test + * + * Copyright (c) 2014 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: John Ye <john.ye@intel.com> + */ + +#include "device_manager.h" +#include "isp/atomisp_device.h" +#include "isp/x3a_analyzer_aiq.h" +#include "isp/isp_controller.h" +#include "isp/isp_image_processor.h" +#include <unistd.h> +#include <signal.h> +#include "test_common.h" + +#if HAVE_LIBDRM +#include "drm_display.h" +#endif + +using namespace XCam; + +class PollCB: public PollCallback { +public: + +#if HAVE_LIBDRM + PollCB(SmartPtr<DrmDisplay> &drm_dev, struct v4l2_format &format) + : _file (NULL) + , _format(format) + , _drm_dev(drm_dev) + + { + open_file(); + }; +#else + PollCB(struct v4l2_format &format) + : _file (NULL), + _format(format) + { + open_file(); + }; +#endif + + ~PollCB() { + close_file (); + }; + XCamReturn poll_buffer_ready (SmartPtr<VideoBuffer> &buf); + XCamReturn poll_buffer_failed (int64_t timestamp, const char *msg) + { + XCAM_UNUSED(timestamp); + XCAM_UNUSED(msg); + XCAM_LOG_DEBUG("%s", __FUNCTION__); + return XCAM_RETURN_NO_ERROR; + } + XCamReturn x3a_stats_ready (const SmartPtr<X3aStats> &stats) { + XCAM_UNUSED(stats); + XCAM_LOG_DEBUG("%s", __FUNCTION__); + return XCAM_RETURN_NO_ERROR; + } + XCamReturn dvs_stats_ready() { + XCAM_LOG_DEBUG("%s", __FUNCTION__); + return XCAM_RETURN_NO_ERROR; + } + +private: + void open_file (); + void close_file (); + size_t dump_to_file(const void *buf, size_t nbyte); + + FILE *_file; + struct v4l2_format _format; +#if HAVE_LIBDRM + SmartPtr<DrmDisplay> _drm_dev; +#endif +}; + +XCamReturn +PollCB::poll_buffer_ready (SmartPtr<VideoBuffer> &buf) { + + SmartPtr<VideoBuffer> base = buf; + XCAM_LOG_DEBUG("%s", __FUNCTION__); + FPS_CALCULATION (fps_buf, XCAM_OBJ_DUR_FRAME_NUM); + + // dump_to_file( (void*) buf->get_v4l2_userptr(), + // buf->get_v4l2_buf_length() + // ); + +#if HAVE_LIBDRM + //if (!_drm_dev->has_frame_buffer (base)) + _drm_dev->render_setup_frame_buffer (base); + + _drm_dev->render_buffer (base); +#endif + + return XCAM_RETURN_NO_ERROR; +} + + +void +PollCB::open_file () +{ + if (_file) + return; + _file = fopen ("capture_buffer.nv12", "wb"); +} + +void +PollCB::close_file () +{ + if (_file) + fclose (_file); + _file = NULL; +} + +size_t +PollCB::dump_to_file (const void *buf, size_t nbyte) +{ + if (!_file) + return 0; + return fwrite(buf, nbyte, 1, _file); +} + + +#define V4L2_CAPTURE_MODE_STILL 0x2000 +#define V4L2_CAPTURE_MODE_VIDEO 0x4000 +#define V4L2_CAPTURE_MODE_PREVIEW 0x8000 + +static Mutex g_mutex; +static Cond g_cond; +static bool g_stop = false; + +void dev_stop_handler(int sig) +{ + XCAM_UNUSED (sig); + + SmartLock locker (g_mutex); + g_stop = true; + g_cond.broadcast (); + + // exit(0); +} + +int main (int argc, const char *argv[]) +{ + (void)argv; + (void)argc; // suppress unused variable warning + + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<V4l2Device> device = new AtomispDevice (DEFAULT_CAPTURE_DEVICE); + SmartPtr<V4l2SubDevice> event_device = new V4l2SubDevice (DEFAULT_EVENT_DEVICE); + SmartPtr<IspController> isp_controller = new IspController (device); + SmartPtr<ImageProcessor> processor = new IspImageProcessor (isp_controller); + + device->set_sensor_id (0); + device->set_capture_mode (V4L2_CAPTURE_MODE_VIDEO); + //device->set_mem_type (V4L2_MEMORY_MMAP); + device->set_mem_type (V4L2_MEMORY_DMABUF); + device->set_buffer_count (8); + device->set_framerate (25, 1); + ret = device->open (); + CHECK (ret, "device(%s) open failed", device->get_device_name()); + //ret = device->set_format (1920, 1080, V4L2_PIX_FMT_NV12, V4L2_FIELD_NONE, 1920 * 2); + ret = device->set_format (1920, 1080, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, 1920 * 2); + CHECK (ret, "device(%s) set format failed", device->get_device_name()); + + + ret = event_device->open (); + CHECK (ret, "event device(%s) open failed", event_device->get_device_name()); + int event = V4L2_EVENT_ATOMISP_3A_STATS_READY; + ret = event_device->subscribe_event (event); + CHECK_CONTINUE ( + ret, + "device(%s) subscribe event(%d) failed", + event_device->get_device_name(), event); + event = V4L2_EVENT_FRAME_SYNC; + ret = event_device->subscribe_event (event); + CHECK_CONTINUE ( + ret, + "device(%s) subscribe event(%d) failed", + event_device->get_device_name(), event); + ret = event_device->start(); + CHECK (ret, "event device start failed"); + + struct v4l2_format format; + device->get_format(format); + +#if HAVE_LIBDRM + AtomispDevice* atom_isp_dev = (AtomispDevice*)device.ptr(); + SmartPtr<DrmDisplay> drmdisp = DrmDisplay::instance(); + struct v4l2_rect rect = { 0, 0, format.fmt.pix.width, format.fmt.pix.height }; + drmdisp->render_init( + 0, + 0, + 1920, + 1080, + format.fmt.pix.pixelformat, + &rect); + atom_isp_dev->set_drm_display(drmdisp); + + ret = device->start(); + CHECK (ret, "capture device start failed"); + SmartPtr<PollThread> poll_thread = new PollThread(); + PollCB* poll_cb = new PollCB(drmdisp, format); +#else + ret = device->start(); + CHECK(ret, "capture device start failed"); + SmartPtr<PollThread> poll_thread = new PollThread(); + PollCB* poll_cb = new PollCB(format); +#endif + + poll_thread->set_capture_device(device); + poll_thread->set_event_device(event_device); + poll_thread->set_poll_callback(poll_cb); + + signal(SIGINT, dev_stop_handler); + + poll_thread->start(); + CHECK (ret, "poll thread start failed"); + + // wait for interruption + { + SmartLock locker (g_mutex); + while (!g_stop) + g_cond.wait (g_mutex); + } + + ret = poll_thread->stop(); + CHECK_CONTINUE (ret, "poll thread stop failed"); + device->close (); + event_device->close (); + + return 0; +} diff --git a/tests/test-soft-image.cpp b/tests/test-soft-image.cpp new file mode 100644 index 0000000..578de8e --- /dev/null +++ b/tests/test-soft-image.cpp @@ -0,0 +1,795 @@ +/* + * test-soft-image.cpp - test soft image + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "test_common.h" +#include "test_inline.h" +#include <buffer_pool.h> +#include <image_handler.h> +#include <image_file_handle.h> +#include <soft/soft_video_buf_allocator.h> +#include <interface/blender.h> +#include <interface/geo_mapper.h> +#include <interface/stitcher.h> +#include <calibration_parser.h> +#include <string> + +#if (!defined(ANDROID) && (HAVE_OPENCV)) +#include <ocl/cv_base_class.h> +#endif + +#define XCAM_TEST_SOFT_IMAGE_DEBUG 0 + +#if (!defined(ANDROID) && (HAVE_OPENCV)) +#define XCAM_TEST_OPENCV 1 +#else +#define XCAM_TEST_OPENCV 0 +#endif + +#define XCAM_TEST_MAX_STR_SIZE 1024 + +#define FISHEYE_CONFIG_PATH "./" + +#define MAP_WIDTH 3 +#define MAP_HEIGHT 4 + +static PointFloat2 map_table[MAP_HEIGHT * MAP_WIDTH] = { + {160.0f, 120.0f}, {480.0f, 120.0f}, {796.0f, 120.0f}, + {60.0f, 240.0f}, {480.0f, 240.0f}, {900.0f, 240.0f}, + {16.0f, 360.0f}, {480.0f, 360.0f}, {944.0f, 360.0f}, + {0.0f, 480.0f}, {480.0f, 480.0f}, {960.0f, 480.0f}, +}; + +using namespace XCam; + +enum SoftType { + SoftTypeNone = 0, + SoftTypeBlender, + SoftTypeRemap, + SoftTypeStitch, +}; + +#define RUN_N(statement, loop, msg, ...) \ + for (int i = 0; i < loop; ++i) { \ + CHECK (statement, msg, ## __VA_ARGS__); \ + FPS_CALCULATION (soft-image, XCAM_OBJ_DUR_FRAME_NUM); \ + } + +#define ADD_ENELEMT(elements, file_name) \ + { \ + SmartPtr<SoftElement> element = new SoftElement (file_name); \ + elements.push_back (element); \ + } + +#if XCAM_TEST_OPENCV +const static cv::Scalar color = cv::Scalar (0, 0, 255); +const static int fontFace = cv::FONT_HERSHEY_COMPLEX; +#endif + +class SoftElement { +public: + explicit SoftElement (const char *file_name = NULL, uint32_t width = 0, uint32_t height = 0); + ~SoftElement (); + + void set_buf_size (uint32_t width, uint32_t height); + uint32_t get_width () const { + return _width; + } + uint32_t get_height () const { + return _height; + } + + const char *get_file_name () const { + return _file_name; + } + + SmartPtr<VideoBuffer> &get_buf () { + return _buf; + } + + XCamReturn open_file (const char *option); + XCamReturn close_file (); + XCamReturn rewind_file (); + + XCamReturn read_buf (); + XCamReturn write_buf (); + + XCamReturn create_buf_pool (const VideoBufferInfo &info, uint32_t count); + +#if XCAM_TEST_OPENCV + XCamReturn cv_open_writer (); + void cv_write_image (char *img_name, char *frame_str, char *idx_str = NULL); +#endif + +private: + char *_file_name; + uint32_t _width; + uint32_t _height; + SmartPtr<VideoBuffer> _buf; + + ImageFileHandle _file; + SmartPtr<BufferPool> _pool; +#if XCAM_TEST_OPENCV + cv::VideoWriter _writer; +#endif +}; + +typedef std::vector<SmartPtr<SoftElement>> SoftElements; + +SoftElement::SoftElement (const char *file_name, uint32_t width, uint32_t height) + : _file_name (NULL) + , _width (width) + , _height (height) +{ + if (file_name) + _file_name = strndup (file_name, XCAM_TEST_MAX_STR_SIZE); +} + +SoftElement::~SoftElement () +{ + _file.close (); + + if (_file_name) + xcam_free (_file_name); +} + +void +SoftElement::set_buf_size (uint32_t width, uint32_t height) +{ + _width = width; + _height = height; +} + +XCamReturn +SoftElement::open_file (const char *option) +{ + if (_file.open (_file_name, option) != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("open %s failed.", _file_name); + return XCAM_RETURN_ERROR_FILE; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +SoftElement::close_file () +{ + return _file.close (); +} + +XCamReturn +SoftElement::rewind_file () +{ + return _file.rewind (); +} + +XCamReturn +SoftElement::create_buf_pool (const VideoBufferInfo &info, uint32_t count) +{ + _pool = new SoftVideoBufAllocator (); + _pool->set_video_info (info); + if (!_pool->reserve (count)) { + XCAM_LOG_ERROR ("create buffer pool failed"); + return XCAM_RETURN_ERROR_MEM; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +SoftElement::read_buf () +{ + _buf = _pool->get_buffer (_pool); + XCAM_ASSERT (_buf.ptr ()); + + return _file.read_buf (_buf); +} + +XCamReturn +SoftElement::write_buf () { + return _file.write_buf (_buf); +} + +#if XCAM_TEST_OPENCV +XCamReturn +SoftElement::cv_open_writer () +{ + XCAM_FAIL_RETURN ( + ERROR, + _width && _height, + XCAM_RETURN_ERROR_PARAM, + "invalid size width:%d height:%d", _width, _height); + + cv::Size frame_size = cv::Size (_width, _height); + if (!_writer.open (_file_name, CV_FOURCC('X', '2', '6', '4'), 30, frame_size)) { + XCAM_LOG_ERROR ("open file %s failed", _file_name); + return XCAM_RETURN_ERROR_FILE; + } + + return XCAM_RETURN_NO_ERROR; +} + +void +SoftElement::cv_write_image (char *img_name, char *frame_str, char *idx_str) +{ + cv::Mat mat; + +#if XCAM_TEST_SOFT_IMAGE_DEBUG + convert_to_mat (_buf, mat); + + cv::putText (mat, frame_str, cv::Point(20, 50), fontFace, 2.0, color, 2, 8, false); + if(idx_str) + cv::putText (mat, idx_str, cv::Point(20, 110), fontFace, 2.0, color, 2, 8, false); + + cv::imwrite (img_name, mat); +#else + XCAM_UNUSED (img_name); + XCAM_UNUSED (frame_str); + XCAM_UNUSED (idx_str); +#endif + + if (_writer.isOpened ()) { + if (mat.empty()) + convert_to_mat (_buf, mat); + + _writer.write (mat); + } +} +#endif + +static int +parse_camera_info (const char *path, uint32_t idx, CameraInfo &info, uint32_t camera_count) +{ + static const char *instrinsic_names[] = { + "intrinsic_camera_front.txt", "intrinsic_camera_right.txt", + "intrinsic_camera_rear.txt", "intrinsic_camera_left.txt" + }; + static const char *exstrinsic_names[] = { + "extrinsic_camera_front.txt", "extrinsic_camera_right.txt", + "extrinsic_camera_rear.txt", "extrinsic_camera_left.txt" + }; + static const float viewpoints_range[] = {64.0f, 160.0f, 64.0f, 160.0f}; + + char intrinsic_path[XCAM_TEST_MAX_STR_SIZE] = {'\0'}; + char extrinsic_path[XCAM_TEST_MAX_STR_SIZE] = {'\0'}; + snprintf (intrinsic_path, XCAM_TEST_MAX_STR_SIZE, "%s/%s", path, instrinsic_names[idx]); + snprintf (extrinsic_path, XCAM_TEST_MAX_STR_SIZE, "%s/%s", path, exstrinsic_names[idx]); + + CalibrationParser parser; + CHECK ( + parser.parse_intrinsic_file (intrinsic_path, info.calibration.intrinsic), + "parse intrinsic params (%s)failed.", intrinsic_path); + + CHECK ( + parser.parse_extrinsic_file (extrinsic_path, info.calibration.extrinsic), + "parse extrinsic params (%s)failed.", extrinsic_path); + info.calibration.extrinsic.trans_x += TEST_CAMERA_POSITION_OFFSET_X; + + info.angle_range = viewpoints_range[idx]; + info.round_angle_start = (idx * 360.0f / camera_count) - info.angle_range / 2.0f; + return 0; +} + +static void +combine_name (const char *orig_name, const char *embedded_str, char *new_name) +{ + const char *dir_delimiter = std::strrchr (orig_name, '/'); + + if (dir_delimiter) { + std::string path (orig_name, dir_delimiter - orig_name + 1); + XCAM_ASSERT (path.c_str ()); + snprintf (new_name, XCAM_TEST_MAX_STR_SIZE, "%s%s_%s", path.c_str (), embedded_str, dir_delimiter + 1); + } else { + snprintf (new_name, XCAM_TEST_MAX_STR_SIZE, "%s_%s", embedded_str, orig_name); + } +} + +static void +add_element (SoftElements &elements, const char *element_name, uint32_t width, uint32_t height) +{ + char file_name[XCAM_TEST_MAX_STR_SIZE] = {'\0'}; + combine_name (elements[0]->get_file_name (), element_name, file_name); + + SmartPtr<SoftElement> element = new SoftElement (file_name, width, height); + elements.push_back (element); +} + +static XCamReturn +elements_open_file (const SoftElements &elements, const char *option, const bool &nv12_output) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + for (uint32_t i = 0; i < elements.size (); ++i) { + if (nv12_output) + ret = elements[i]->open_file (option); +#if XCAM_TEST_OPENCV + else + ret = elements[i]->cv_open_writer (); +#endif + + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("open file(%s) failed", elements[i]->get_file_name ()); + break; + } + } + + return ret; +} + +static XCamReturn +remap_topview_buf ( + BowlModel &model, + const SmartPtr<VideoBuffer> &buf, + SmartPtr<VideoBuffer> &topview_buf, + uint32_t topview_width, uint32_t topview_height) +{ + BowlModel::PointMap points; + + uint32_t lut_w = topview_width / 4, lut_h = topview_height / 4; + float length_mm = 0.0f, width_mm = 0.0f; + + model.get_max_topview_area_mm (length_mm, width_mm); + XCAM_LOG_INFO ("Max Topview Area (L%.2fmm, W%.2fmm)", length_mm, width_mm); + + model.get_topview_rect_map (points, lut_w, lut_h); + SmartPtr<GeoMapper> mapper = GeoMapper::create_soft_geo_mapper (); + XCAM_ASSERT (mapper.ptr ()); + mapper->set_output_size (topview_width, topview_height); + mapper->set_lookup_table (points.data (), lut_w, lut_h); + + XCamReturn ret = mapper->remap (buf, topview_buf); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("remap stitched image to topview failed."); + return ret; + } + +#if 0 + BowlModel::VertexMap bowl_vertices; + BowlModel::PointMap bowl_points; + uint32_t bowl_lut_w = 15, bowl_lut_h = 10; + model.get_bowlview_vertex_map (bowl_vertices, bowl_points, bowl_lut_w, bowl_lut_h); + for (uint32_t i = 0; i < bowl_lut_h; ++i) { + for (uint32_t j = 0; j < bowl_lut_w; ++j) + { + PointFloat3 &vetex = bowl_vertices[i * bowl_lut_w + j]; + printf ("(%4.0f, %4.0f, %4.0f), ", vetex.x, vetex.y, vetex.z ); + } + printf ("\n"); + } +#endif + + return XCAM_RETURN_NO_ERROR; +} + +static void +write_image (const SoftElements &ins, const SoftElements &outs, const bool &nv12_output) { + if (nv12_output) { + for (uint32_t i = 0; i < outs.size (); ++i) + outs[i]->write_buf (); + } +#if XCAM_TEST_OPENCV + else { + static uint32_t frame_num = 0; + char img_name[XCAM_TEST_MAX_STR_SIZE] = {'\0'}; + char frame_str[XCAM_TEST_MAX_STR_SIZE] = {'\0'}; + std::snprintf (frame_str, XCAM_TEST_MAX_STR_SIZE, "frame:%d", frame_num); + + char idx_str[XCAM_TEST_MAX_STR_SIZE] = {'\0'}; + for (uint32_t i = 0; i < ins.size (); ++i) { + std::snprintf (idx_str, XCAM_TEST_MAX_STR_SIZE, "idx:%d", i); + std::snprintf (img_name, XCAM_TEST_MAX_STR_SIZE, "orig_fisheye_%d_%d.jpg", frame_num, i); + ins[i]->cv_write_image (img_name, frame_str, idx_str); + } + + for (uint32_t i = 0; i < outs.size (); ++i) { + std::snprintf (img_name, XCAM_TEST_MAX_STR_SIZE, "%s_%d.jpg", outs[i]->get_file_name (), frame_num); + outs[i]->cv_write_image (img_name, frame_str); + } + frame_num++; + } +#endif +} + +static XCamReturn +ensure_output_format (const char *file_name, const SoftType &type, bool &nv12_output) +{ + char suffix[XCAM_TEST_MAX_STR_SIZE] = {'\0'}; + const char *ptr = std::strrchr (file_name, '.'); + std::snprintf (suffix, XCAM_TEST_MAX_STR_SIZE, "%s", ptr + 1); + if (!strcasecmp (suffix, "mp4")) { +#if XCAM_TEST_OPENCV + if (type != SoftTypeStitch) { + XCAM_LOG_ERROR ("only stitch type supports MP4 output format"); + return XCAM_RETURN_ERROR_PARAM; + } + nv12_output = false; +#else + XCAM_LOG_ERROR ("only supports NV12 output format"); + return XCAM_RETURN_ERROR_PARAM; +#endif + } + + return XCAM_RETURN_NO_ERROR; +} + +static bool +check_element (const SoftElements &elements, const uint32_t &idx) +{ + if (idx >= elements.size ()) + return false; + + if (!elements[idx].ptr()) { + XCAM_LOG_ERROR ("SoftElement(idx:%d) ptr is NULL", idx); + return false; + } + + XCAM_FAIL_RETURN ( + ERROR, + elements[idx]->get_width () && elements[idx]->get_height (), + false, + "SoftElement(idx:%d): invalid parameters width:%d height:%d", + idx, elements[idx]->get_width (), elements[idx]->get_height ()); + + return true; +} + +static XCamReturn +check_elements (const SoftElements &elements) +{ + for (uint32_t i = 0; i < elements.size (); ++i) { + XCAM_FAIL_RETURN ( + ERROR, + check_element (elements, i), + XCAM_RETURN_ERROR_PARAM, + "invalid SoftElement index:%d\n", i); + } + + return XCAM_RETURN_NO_ERROR; +} + +static XCamReturn +run_topview (const SmartPtr<Stitcher> &stitcher, const SoftElements &outs) +{ + BowlModel bowl_model (stitcher->get_bowl_config (), outs[0]->get_width (), outs[0]->get_height ()); + return remap_topview_buf (bowl_model, outs[0]->get_buf (), outs[1]->get_buf (), + outs[1]->get_width (), outs[1]->get_height ()); +} + +static int +run_stitcher ( + const SmartPtr<Stitcher> &stitcher, + const SoftElements &ins, const SoftElements &outs, + bool nv12_output, bool save_output, int loop) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + CHECK (check_elements (ins), "invalid input elements"); + CHECK (check_elements (outs), "invalid output elements"); + + VideoBufferList in_buffers; + while (loop--) { + for (uint32_t i = 0; i < ins.size (); ++i) { + CHECK (ins[i]->rewind_file (), "rewind buffer from file(%s) failed", ins[i]->get_file_name ()); + } + + do { + in_buffers.clear (); + + for (uint32_t i = 0; i < ins.size (); ++i) { + ret = ins[i]->read_buf(); + if (ret == XCAM_RETURN_BYPASS) + break; + CHECK (ret, "read buffer from file(%s) failed.", ins[i]->get_file_name ()); + + in_buffers.push_back (ins[i]->get_buf ()); + } + if (ret == XCAM_RETURN_BYPASS) + break; + + CHECK ( + stitcher->stitch_buffers (in_buffers, outs[0]->get_buf ()), + "stitch buffer failed."); + + if (save_output) { + if (check_element (outs, 1)) { + CHECK (run_topview (stitcher, outs), "run topview failed"); + } + + write_image (ins, outs, nv12_output); + } + + FPS_CALCULATION (soft - stitcher, XCAM_OBJ_DUR_FRAME_NUM); + } while (true); + } + + return 0; +} + +static void usage(const char* arg0) +{ + printf ("Usage:\n" + "%s --type TYPE--input0 file0 --input1 file1 --output file\n" + "\t--type processing type, selected from: blend, remap, stitch, ...\n" + "\t-- [stitch]: read calibration files from exported path $FISHEYE_CONFIG_PATH\n" + "\t--input0 input image(NV12)\n" + "\t--input1 input image(NV12)\n" + "\t--input2 input image(NV12)\n" + "\t--input3 input image(NV12)\n" + "\t--output output image(NV12)\n" + "\t--in-w optional, input width, default: 1920\n" + "\t--in-h optional, input height, default: 1080\n" + "\t--out-w optional, output width, default: 1920\n" + "\t--out-h optional, output height, default: 960\n" + "\t--topview-w optional, output width, default: 1280\n" + "\t--topview-h optional, output height, default: 720\n" + "\t--save optional, save file or not, select from [true/false], default: true\n" + "\t--loop optional, how many loops need to run, default: 1\n" + "\t--help usage\n", + arg0); +} + +int main (int argc, char *argv[]) +{ + uint32_t input_width = 1920; + uint32_t input_height = 1080; + uint32_t output_width = 1920; //output_height * 2; + uint32_t output_height = 960; //960; + uint32_t topview_width = 1280; + uint32_t topview_height = 720; + SoftType type = SoftTypeNone; + + SoftElements ins; + SoftElements outs; + + int loop = 1; + bool save_output = true; + bool nv12_output = true; + + const struct option long_opts[] = { + {"type", required_argument, NULL, 't'}, + {"input0", required_argument, NULL, 'i'}, + {"input1", required_argument, NULL, 'j'}, + {"input2", required_argument, NULL, 'k'}, + {"input3", required_argument, NULL, 'l'}, + {"output", required_argument, NULL, 'o'}, + {"in-w", required_argument, NULL, 'w'}, + {"in-h", required_argument, NULL, 'h'}, + {"out-w", required_argument, NULL, 'W'}, + {"out-h", required_argument, NULL, 'H'}, + {"topview-w", required_argument, NULL, 'P'}, + {"topview-h", required_argument, NULL, 'V'}, + {"save", required_argument, NULL, 's'}, + {"loop", required_argument, NULL, 'L'}, + {"help", no_argument, NULL, 'e'}, + {NULL, 0, NULL, 0}, + }; + + int opt = -1; + while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { + switch (opt) { + case 't': + XCAM_ASSERT (optarg); + if (!strcasecmp (optarg, "blend")) + type = SoftTypeBlender; + else if (!strcasecmp (optarg, "remap")) + type = SoftTypeRemap; + else if (!strcasecmp (optarg, "stitch")) + type = SoftTypeStitch; + else { + XCAM_LOG_ERROR ("unknown type:%s", optarg); + usage (argv[0]); + return -1; + } + break; + + case 'i': + XCAM_ASSERT (optarg); + ADD_ENELEMT(ins, optarg); + break; + case 'j': + XCAM_ASSERT (optarg); + ADD_ENELEMT(ins, optarg); + break; + case 'k': + XCAM_ASSERT (optarg); + ADD_ENELEMT(ins, optarg); + break; + case 'l': + XCAM_ASSERT (optarg); + ADD_ENELEMT(ins, optarg); + break; + case 'o': + XCAM_ASSERT (optarg); + ADD_ENELEMT(outs, optarg); + break; + case 'w': + input_width = atoi(optarg); + break; + case 'h': + input_height = atoi(optarg); + break; + case 'W': + output_width = atoi(optarg); + break; + case 'H': + output_height = atoi(optarg); + break; + case 'P': + topview_width = atoi(optarg); + break; + case 'V': + topview_height = atoi(optarg); + break; + case 's': + save_output = (strcasecmp (optarg, "false") == 0 ? false : true); + break; + case 'L': + loop = atoi(optarg); + break; + default: + XCAM_LOG_ERROR ("getopt_long return unknown value:%c", opt); + usage (argv[0]); + return -1; + } + } + + if (optind < argc || argc < 2) { + XCAM_LOG_ERROR ("unknown option %s", argv[optind]); + usage (argv[0]); + return -1; + } + + if (SoftTypeNone == type) { + XCAM_LOG_ERROR ("Type was not set"); + usage (argv[0]); + return -1; + } + + if (ins.empty () || outs.empty () || + !strlen (ins[0]->get_file_name ()) || !strlen (outs[0]->get_file_name ())) { + XCAM_LOG_ERROR ("input or output file name was not set"); + usage (argv[0]); + return -1; + } + + for (uint32_t i = 0; i < ins.size (); ++i) { + printf ("input%d file:\t\t%s\n", i, ins[i]->get_file_name ()); + } + printf ("output file:\t\t%s\n", outs[0]->get_file_name ()); + printf ("input width:\t\t%d\n", input_width); + printf ("input height:\t\t%d\n", input_height); + printf ("output width:\t\t%d\n", output_width); + printf ("output height:\t\t%d\n", output_height); + printf ("topview width:\t\t%d\n", topview_width); + printf ("topview height:\t\t%d\n", topview_height); + printf ("save output:\t\t%s\n", save_output ? "true" : "false"); + printf ("loop count:\t\t%d\n", loop); + + VideoBufferInfo in_info, out_info; + in_info.init (V4L2_PIX_FMT_NV12, input_width, input_height); + out_info.init (V4L2_PIX_FMT_NV12, output_width, output_height); + + for (uint32_t i = 0; i < ins.size (); ++i) { + ins[i]->set_buf_size (input_width, input_height); + CHECK (ins[i]->create_buf_pool (in_info, 6), "create buffer pool failed"); + CHECK (ins[i]->open_file ("rb"), "open file(%s) failed", ins[i]->get_file_name ()); + } + + outs[0]->set_buf_size (output_width, output_height); + if (save_output) { + CHECK (ensure_output_format (outs[0]->get_file_name (), type, nv12_output), "unsupported output format"); + if (nv12_output) { + CHECK (outs[0]->open_file ("wb"), "open file(%s) failed", outs[0]->get_file_name ()); + } + } + + switch (type) { + case SoftTypeBlender: { + CHECK_EXP (ins.size () >= 2, "blender need 2 input files."); + SmartPtr<Blender> blender = Blender::create_soft_blender (); + XCAM_ASSERT (blender.ptr ()); + blender->set_output_size (output_width, output_height); + Rect merge_window; + merge_window.pos_x = 0; + merge_window.pos_y = 0; + merge_window.width = out_info.width; + merge_window.height = out_info.height; + blender->set_merge_window (merge_window); + + CHECK (ins[0]->read_buf(), "read buffer from file(%s) failed.", ins[0]->get_file_name ()); + CHECK (ins[1]->read_buf(), "read buffer from file(%s) failed.", ins[1]->get_file_name ()); + RUN_N (blender->blend (ins[0]->get_buf (), ins[1]->get_buf (), outs[0]->get_buf ()), loop, "blend buffer failed."); + if (save_output) + outs[0]->write_buf (); + break; + } + case SoftTypeRemap: { + SmartPtr<GeoMapper> mapper = GeoMapper::create_soft_geo_mapper (); + XCAM_ASSERT (mapper.ptr ()); + mapper->set_output_size (output_width, output_height); + mapper->set_lookup_table (map_table, MAP_WIDTH, MAP_HEIGHT); + //mapper->set_factors ((output_width - 1.0f) / (MAP_WIDTH - 1.0f), (output_height - 1.0f) / (MAP_HEIGHT - 1.0f)); + + CHECK (ins[0]->read_buf(), "read buffer from file(%s) failed.", ins[0]->get_file_name ()); + RUN_N (mapper->remap (ins[0]->get_buf (), outs[0]->get_buf ()), loop, "remap buffer failed."); + if (save_output) + outs[0]->write_buf (); + break; + } + case SoftTypeStitch: { + CHECK_EXP (ins.size () >= 2 && ins.size () <= 4, "stitcher need at 2~4 input files."); + + uint32_t camera_count = ins.size (); + SmartPtr<Stitcher> stitcher = Stitcher::create_soft_stitcher (); + XCAM_ASSERT (stitcher.ptr ()); + + CameraInfo cam_info[4]; + const char *fisheye_config_path = getenv ("FISHEYE_CONFIG_PATH"); + if (!fisheye_config_path) + fisheye_config_path = FISHEYE_CONFIG_PATH; + + for (uint32_t i = 0; i < camera_count; ++i) { + if (parse_camera_info (fisheye_config_path, i, cam_info[i], camera_count) != 0) { + XCAM_LOG_ERROR ("parse fisheye dewarp info(idx:%d) failed.", i); + return -1; + } + } + + PointFloat3 bowl_coord_offset; + if (camera_count == 4) { + centralize_bowl_coord_from_cameras ( + cam_info[0].calibration.extrinsic, cam_info[1].calibration.extrinsic, + cam_info[2].calibration.extrinsic, cam_info[3].calibration.extrinsic, + bowl_coord_offset); + } + + stitcher->set_camera_num (camera_count); + for (uint32_t i = 0; i < camera_count; ++i) { + stitcher->set_camera_info (i, cam_info[i]); + } + + BowlDataConfig bowl; + bowl.wall_height = 3000.0f; + bowl.ground_length = 2000.0f; + //bowl.a = 5000.0f; + //bowl.b = 3600.0f; + //bowl.c = 3000.0f; + bowl.angle_start = 0.0f; + bowl.angle_end = 360.0f; + stitcher->set_bowl_config (bowl); + stitcher->set_output_size (output_width, output_height); + + if (save_output) { + add_element (outs, "topview", topview_width, topview_height); + elements_open_file (outs, "wb", nv12_output); + } + CHECK_EXP ( + run_stitcher (stitcher, ins, outs, nv12_output, save_output, loop) == 0, + "run stitcher failed."); + break; + } + + default: { + XCAM_LOG_ERROR ("unsupported type:%d", type); + usage (argv[0]); + return -1; + } + } + + return 0; +} diff --git a/tests/test-video-stabilization.cpp b/tests/test-video-stabilization.cpp new file mode 100644 index 0000000..5280467 --- /dev/null +++ b/tests/test-video-stabilization.cpp @@ -0,0 +1,353 @@ +/* + * test-video-stabilization.cpp - test video stabilization using Gyroscope + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include "test_common.h" +#include "test_inline.h" +#include <unistd.h> +#include <getopt.h> +#include <ocl/cl_utils.h> +#include <ocl/cl_device.h> +#include <ocl/cl_context.h> +#include <ocl/cl_blender.h> +#include <image_file_handle.h> +#include <ocl/cl_video_stabilizer.h> +#include <dma_video_buffer.h> + +#if HAVE_OPENCV +#include <opencv2/opencv.hpp> +#include <opencv2/core/ocl.hpp> +#include <ocl/cv_base_class.h> +#endif + +using namespace XCam; + +static int read_device_pose (const char *file, DevicePoseList &pose, uint32_t pose_size); + +static void +usage(const char* arg0) +{ + printf ("Usage:\n" + "%s --input file --output file" + " [--input-w width] [--input-h height] \n" + "\t--input, input image(NV12)\n" + "\t--gyro, input gyro pose data;\n" + "\t--output, output image(NV12) PREFIX\n" + "\t--input-w, optional, input width; default:1920\n" + "\t--input-h, optional, input height; default:1080\n" + "\t--save, optional, save file or not, default true; select from [true/false]\n" + "\t--loop optional, how many loops need to run for performance test, default: 1\n" + "\t--help, usage\n", + arg0); +} + +int main (int argc, char *argv[]) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + SmartPtr<CLVideoStabilizer> video_stab; + + SmartPtr<CLContext> context; + SmartPtr<BufferPool> buf_pool; + + VideoBufferInfo input_buf_info; + VideoBufferInfo output_buf_info; + SmartPtr<VideoBuffer> input_buf; + SmartPtr<VideoBuffer> output_buf; + + uint32_t input_format = V4L2_PIX_FMT_NV12; + uint32_t input_width = 1920; + uint32_t input_height = 1080; + uint32_t output_width = 1920; + uint32_t output_height = 1080; + + ImageFileHandle file_in, file_out; + const char *file_in_name = NULL; + const char *file_out_name = NULL; + + const char *gyro_data = "gyro_data.csv"; + + bool need_save_output = true; + double framerate = 30.0; + int loop = 1; + + const struct option long_opts[] = { + {"input", required_argument, NULL, 'i'}, + {"gyro", required_argument, NULL, 'g'}, + {"output", required_argument, NULL, 'o'}, + {"input-w", required_argument, NULL, 'w'}, + {"input-h", required_argument, NULL, 'h'}, + {"save", required_argument, NULL, 's'}, + {"loop", required_argument, NULL, 'l'}, + {"help", no_argument, NULL, 'H'}, + {0, 0, 0, 0}, + }; + + int opt = -1; + while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { + switch (opt) { + case 'i': + file_in_name = optarg; + break; + case 'g': + gyro_data = optarg; + break; + case 'o': + file_out_name = optarg; + break; + case 'w': + input_width = atoi(optarg); + output_width = input_width; + break; + case 'h': + input_height = atoi(optarg); + output_height = input_height; + break; + case 's': + need_save_output = (strcasecmp (optarg, "false") == 0 ? false : true); + break; + case 'l': + loop = atoi(optarg); + break; + case 'H': + usage (argv[0]); + return -1; + default: + printf ("getopt_long return unknown value:%c\n", opt); + usage (argv[0]); + return -1; + } + } + + if (optind < argc || argc < 2) { + printf("unknown option %s\n", argv[optind]); + usage (argv[0]); + return -1; + } + + if (!file_in_name || !file_out_name) { + XCAM_LOG_ERROR ("input/output path is NULL"); + return -1; + } + + printf ("Description-----------\n"); + printf ("input video file:%s\n", file_in_name); + printf ("gyro pose file:%s\n", gyro_data); + printf ("output file PREFIX:%s\n", file_out_name); + printf ("input width:%d\n", input_width); + printf ("input height:%d\n", input_height); + printf ("need save file:%s\n", need_save_output ? "true" : "false"); + printf ("loop count:\t\t%d\n", loop); + printf ("----------------------\n"); + + DevicePoseList device_pose; + + const int pose_size = sizeof(DevicePose::orientation) / sizeof(double) + + sizeof(DevicePose::translation) / sizeof(double) + + sizeof(DevicePose::timestamp) / sizeof(int64_t); + + const int count = read_device_pose (gyro_data, device_pose, pose_size); + if (count <= 0 || device_pose.size () <= 0) { + XCAM_LOG_ERROR ("read gyro file(%s) failed.", gyro_data); + return -1; + } + + context = CLDevice::instance ()->get_context (); + video_stab = create_cl_video_stab_handler (context).dynamic_cast_ptr<CLVideoStabilizer> (); + XCAM_ASSERT (video_stab.ptr ()); + video_stab->set_pool_type (CLImageHandler::CLVideoPoolType); + + /* + Color CameraIntrinsics: + image_width: 1920, image_height :1080, + fx: 1707.799171, fy: 1710.337510, + cx: 940.413257, cy: 540.198348, + image_plane_distance: 1.778957. + + Color Camera Frame with respect to IMU Frame: + Position: 0.045699, -0.008592, -0.006434 + Orientation: -0.013859, -0.999889, 0.002361, 0.005021 + */ + double focal_x = 1707.799171; + double focal_y = 1710.337510; + double offset_x = 940.413257; + double offset_y = 540.198348; + double skew = 0; + video_stab->set_camera_intrinsics (focal_x, focal_y, offset_x, offset_y, skew); + + CoordinateSystemConv world_to_device (AXIS_X, AXIS_MINUS_Z, AXIS_NONE); + CoordinateSystemConv device_to_image (AXIS_X, AXIS_Y, AXIS_Y); + video_stab->align_coordinate_system (world_to_device, device_to_image); + + uint32_t radius = 15; + float stdev = 10; + video_stab->set_motion_filter (radius, stdev); + + input_buf_info.init (input_format, input_width, input_height); + output_buf_info.init (input_format, output_width, output_height); + buf_pool = new CLVideoBufferPool (); + XCAM_ASSERT (buf_pool.ptr ()); + buf_pool->set_video_info (input_buf_info); + if (!buf_pool->reserve (36)) { + XCAM_LOG_ERROR ("init buffer pool failed"); + return -1; + } + + ret = file_in.open (file_in_name, "rb"); + CHECK (ret, "open %s failed", file_in_name); + +#if HAVE_OPENCV + cv::VideoWriter writer; + if (need_save_output) { + cv::Size dst_size = cv::Size (output_width, output_height); + if (!writer.open (file_out_name, CV_FOURCC('X', '2', '6', '4'), framerate, dst_size)) { + XCAM_LOG_ERROR ("open file %s failed", file_out_name); + return -1; + } + } +#endif + + int i = 0; + while (loop--) { + ret = file_in.rewind (); + CHECK (ret, "video stabilization stitch rewind file(%s) failed", file_in_name); + + video_stab->reset_counter (); + + DevicePoseList::iterator pose_iterator = device_pose.begin (); + do { + input_buf = buf_pool->get_buffer (buf_pool); + XCAM_ASSERT (input_buf.ptr ()); + ret = file_in.read_buf (input_buf); + if (ret == XCAM_RETURN_BYPASS) + break; + if (ret == XCAM_RETURN_ERROR_FILE) { + XCAM_LOG_ERROR ("read buffer from %s failed", file_in_name); + return -1; + } + + SmartPtr<MetaData> pose_data = *(pose_iterator); + SmartPtr<DevicePose> data = *(pose_iterator); + input_buf->add_metadata (pose_data); + input_buf->set_timestamp (pose_data->timestamp); + + ret = video_stab->execute (input_buf, output_buf); + if (++pose_iterator == device_pose.end ()) { + break; + } + if (ret == XCAM_RETURN_BYPASS) { + continue; + } + +#if HAVE_OPENCV + if (need_save_output) { + cv::Mat out_mat; + convert_to_mat (output_buf, out_mat); + writer.write (out_mat); + } else +#endif + ensure_gpu_buffer_done (output_buf); + + FPS_CALCULATION (video_stabilizer, XCAM_OBJ_DUR_FRAME_NUM); + ++i; + + } while (true); + } + + return ret; +} + +//return count + +#define RELEASE_FILE_MEM { \ + xcam_free (ptr); \ + if (p_f) fclose (p_f); \ + return -1; \ + } + +int read_device_pose (const char* file, DevicePoseList &pose_list, uint32_t members) +{ + char *ptr = NULL; + SmartPtr<DevicePose> data; + + FILE *p_f = fopen (file, "rb"); + CHECK_EXP (p_f, "open gyro pos data(%s) failed", file); + + CHECK_DECLARE ( + ERROR, + !fseek (p_f, 0L, SEEK_END), + RELEASE_FILE_MEM, "seek to file(%s) end failed", file); + + size_t size = ftell(p_f); + int entries = size / members; + + fseek (p_f, 0L, SEEK_SET); + + ptr = (char*) xcam_malloc0 (size + 1); + CHECK_DECLARE (ERROR, ptr, RELEASE_FILE_MEM, "malloc file buffer failed"); + + CHECK_DECLARE ( + ERROR, + fread (ptr, 1, size, p_f) == size, + RELEASE_FILE_MEM, "read pose file(%s)failed", file); + ptr[size] = 0; + fclose (p_f); + p_f = NULL; + + char *str_num = NULL; + char tokens[] = "\t ,\r\n"; + str_num = strtok (ptr, tokens); + int count = 0; + int x = 0, y = 0; + const int orient_size = sizeof(DevicePose::orientation) / sizeof(double); + const int trans_size = sizeof(DevicePose::translation) / sizeof(double); + + while (str_num != NULL) { + float num = strtof (str_num, NULL); + + x = count % members; + y = count / members; + if (y >= entries) { + break; + } + if (x == 0) { + data = new DevicePose (); + } + + CHECK_DECLARE (ERROR, data.ptr (), RELEASE_FILE_MEM, "invalid buffer pointer(device pose is null)"); + if (x < orient_size) { + data->orientation[x] = num; + } else if (x < orient_size + trans_size) { + data->translation[x - orient_size] = num; + } else if (x == orient_size + trans_size) { + data->timestamp = num * 1000000; + pose_list.push_back (data); + } else { + CHECK_DECLARE (ERROR, false, RELEASE_FILE_MEM, "unknow branch"); + } + + ++count; + str_num = strtok (NULL, tokens); + } + free (ptr); + ptr = NULL; + + return count / members; +} + diff --git a/tests/test-xcamsrc-camera.sh b/tests/test-xcamsrc-camera.sh new file mode 100755 index 0000000..4cec805 --- /dev/null +++ b/tests/test-xcamsrc-camera.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +gst-launch-1.0 xcamsrc sensor-id=3 capture-mode=1 io-mode=4 ! video/x-raw, format=NV12, width=1920, height=1080, framerate=30/1 ! queue ! vaapiencode_h264 ! fakesink diff --git a/tests/test_common.h b/tests/test_common.h new file mode 100644 index 0000000..9ca75e3 --- /dev/null +++ b/tests/test_common.h @@ -0,0 +1,69 @@ +/* + * test_common.h - test common + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: John Ye <john.ye@intel.com> + */ + +#ifndef XCAM_TEST_COMMON_H +#define XCAM_TEST_COMMON_H + +#include <unistd.h> +#include <getopt.h> + +#define TEST_CAMERA_POSITION_OFFSET_X 2000 + +#undef CHECK_DECLARE +#undef CHECK +#undef CHECK_CONTINUE + +#define CHECK_DECLARE(level, exp, statement, msg, ...) \ + if (!(exp)) { \ + XCAM_LOG_##level (msg, ## __VA_ARGS__); \ + statement; \ + } + +#define CHECK(ret, msg, ...) \ + CHECK_DECLARE(ERROR, (ret) == XCAM_RETURN_NO_ERROR, return -1, msg, ## __VA_ARGS__) + +#define CHECK_STATEMENT(ret, statement, msg, ...) \ + CHECK_DECLARE(ERROR, (ret) == XCAM_RETURN_NO_ERROR, statement, msg, ## __VA_ARGS__) + +#define CHECK_CONTINUE(ret, msg, ...) \ + CHECK_DECLARE(WARNING, (ret) == XCAM_RETURN_NO_ERROR, , msg, ## __VA_ARGS__) + +#define CHECK_EXP(exp, msg, ...) \ + CHECK_DECLARE(ERROR, exp, return -1, msg, ## __VA_ARGS__) + +#define CAPTURE_DEVICE_VIDEO "/dev/video3" +#define CAPTURE_DEVICE_STILL "/dev/video0" +#define DEFAULT_CAPTURE_DEVICE CAPTURE_DEVICE_VIDEO + +#define DEFAULT_EVENT_DEVICE "/dev/v4l-subdev6" +#define DEFAULT_CPF_FILE "/etc/atomisp/imx185.cpf" +#define DEFAULT_SAVE_FILE_NAME "capture_buffer" +#define DEFAULT_DYNAMIC_3A_LIB "/usr/lib/xcam/plugins/3a/libxcam_3a_aiq.so" +#define DEFAULT_HYBRID_3A_LIB "/usr/lib/xcam/plugins/3a/libxcam_3a_hybrid.so" +#define DEFAULT_SMART_ANALYSIS_LIB_DIR "/usr/lib/xcam/plugins/smart" + + +#define FPS_CALCULATION(objname, count) XCAM_STATIC_FPS_CALCULATION(objname, count) + +#define PROFILING_START(name) XCAM_STATIC_PROFILING_START(name) +#define PROFILING_END(name, times_of_print) XCAM_STATIC_PROFILING_END(name, times_of_print) + +#endif // XCAM_TEST_COMMON_H diff --git a/tests/test_inline.h b/tests/test_inline.h new file mode 100644 index 0000000..de8a064 --- /dev/null +++ b/tests/test_inline.h @@ -0,0 +1,51 @@ +/* + * test_inline.h - test inline header + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Yinhang Liu <yinhangx.liu@intel.com> + */ + +#ifndef XCAM_TEST_INLINE_H +#define XCAM_TEST_INLINE_H + +#include <video_buffer.h> + +using namespace XCam; + +inline static void +ensure_gpu_buffer_done (SmartPtr<VideoBuffer> buf) +{ + const VideoBufferInfo info = buf->get_video_info (); + VideoBufferPlanarInfo planar; + uint8_t *memory = NULL; + + memory = buf->map (); + for (uint32_t index = 0; index < info.components; index++) { + info.get_planar_info (planar, index); + uint32_t line_bytes = planar.width * planar.pixel_bytes; + + for (uint32_t i = 0; i < planar.height; i++) { + int mem_idx = info.offsets [index] + i * info.strides [index] + line_bytes - 1; + if (memory[mem_idx] == 1) { + memory[mem_idx] = 1; + } + } + } + buf->unmap (); +} + +#endif // XCAM_TEST_INLINE_H diff --git a/tools/cl-double-quotation.sh b/tools/cl-double-quotation.sh new file mode 100755 index 0000000..5a77a67 --- /dev/null +++ b/tools/cl-double-quotation.sh @@ -0,0 +1,46 @@ +#! /bin/sh +# Add double quotation marks on cl file, this script will +# be called in top_srcdir/clx_kernel/Makefile.am + +CL_FILE=$1 +CLX_FILE=$2 + +if [ $# -ne 2 ]; then + echo "Usage: $0 <cl_file> <clx_file>" + exit 1 +fi + +gawk ' + BEGIN { FS = "" } + { + if ($0~/^[\t " "]*[\/]+/ || $0~/^[\t " "]*[\*]/) + print $0 + else + { + if ($0~/^[ ]*$/) + print + else + { + $0 = gensub (/\\$/, "\\\\\\\\", "g") + $0 = gensub (/\"/, "\\\\\\\"", "g") + $0 = gensub (/%/, "\\\\%", "g") + $0 = gensub (/\\n/, "\\\\\\\\n", "g") + $0 = gensub (/\\t/, "\\\\\\\\t", "g") + $0 = gensub (/^#/, "\\\\n#", "g") + + print "\""$0"\\n\"" + } + } + } + ' $CL_FILE > $CLX_FILE.tmp + +ret=$? +if [ $ret != 0 ]; then + rm -rf $CLX_FILE.tmp + echo "Add double quotation marks on $CL_FILE failed" + exit 1 +fi + +mv $CLX_FILE.tmp $CLX_FILE + +echo "Add double quotation marks on $CL_FILE done" diff --git a/tools/convert-binary-to-text.sh b/tools/convert-binary-to-text.sh new file mode 100755 index 0000000..9e533ea --- /dev/null +++ b/tools/convert-binary-to-text.sh @@ -0,0 +1,46 @@ +#! /bin/sh +# Convert binary to binary-text. +# Command line: +# convert-binary-to-text.sh xxx.cl.bin xxx.clx.bin +# +# Usage of binary-text file (if needed): +# 1. generate binary file, related script: libxcam/tests/test-binary-kernel +# $ test-binary-kernel --src-kernel kernel_demo.cl --bin-kernel kernel_demo.cl.bin --kernel-name kernel_demo +# +# 2. generate binary-text file, related script: libxcam/tools/convert-binary-to-text.sh +# $ convert-binary-to-text.sh kernel_demo.cl.bin kernel_demo.clx.bin +# +# 3. include binary-text file when create image handler, please refer to demo handler: +# SmartPtr<CLImageHandler> create_cl_binary_demo_image_handler (SmartPtr<CLContext> &context) + + +BINARY_FILE=$1 +TEXT_FILE=$2 + +if [ $# -ne 2 ]; then + echo "Usage: $0 <binary_file> <text_file>" + exit 1 +fi + +od -A n -t x1 -v $BINARY_FILE | \ + gawk ' + BEGIN { print "{" } + { + printf " " + for (i = 1; i < NF; i++) + { printf " 0x" $i "," } + print " 0x" $i "," + } + END { print "};" } + ' > $TEXT_FILE.tmp + +ret=$? +if [ $ret != 0 ]; then + echo "Convert $BINARY_FILE to $TEXT_FILE faild" + rm -f $TEXT_FILE.tmp + exit 1 +fi + +mv $TEXT_FILE.tmp $TEXT_FILE + +echo "Convert $BINARY_FILE to $TEXT_FILE done" diff --git a/tools/pre-commit-code-style.sh b/tools/pre-commit-code-style.sh new file mode 100755 index 0000000..a310cb4 --- /dev/null +++ b/tools/pre-commit-code-style.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# checking code style before commit + +ASTYLE=astyle +ASTYLE_PARAMS="--indent=spaces=4 --convert-tabs --pad-oper --suffix=none" + +DOS2UNIX=dos2unix +DOS2UNIX_PARAMS="-ascii --safe --keepdate --quiet" + +command -v $ASTYLE > /dev/null 2>&1 || echo "warning: $ASTYLE is not installed" +command -v $DOS2UNIX > /dev/null 2>&1 || echo "warning: $DOS2UNIX is not installed" + +echo "---- checking code style (dos2unix / astyle)----" +for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR | grep -E "\.c$|\.cpp$|\.h$|\.cl$|\.hpp$" ` ; do + $DOS2UNIX ${DOS2UNIX_PARAMS} ${file} + $ASTYLE ${ASTYLE_PARAMS} ${file} + ret=$? + if [ $ret != 0 ] ; then + echo "code style failed on $file" + exit 1 + fi + git add $file +done +echo "---- checking code style done----" diff --git a/wrapper/Makefile.am b/wrapper/Makefile.am new file mode 100644 index 0000000..63dbffd --- /dev/null +++ b/wrapper/Makefile.am @@ -0,0 +1,8 @@ + +if ENABLE_GST +GST_DIR = gstreamer +else +GST_DIR = +endif + +SUBDIRS = $(GST_DIR) diff --git a/wrapper/gstreamer/Makefile.am b/wrapper/gstreamer/Makefile.am new file mode 100644 index 0000000..8a47a6f --- /dev/null +++ b/wrapper/gstreamer/Makefile.am @@ -0,0 +1,136 @@ +if ENABLE_IA_AIQ +SUBDIRS = interface +endif + +plugin_LTLIBRARIES = \ + libgstxcamsrc.la \ + $(NULL) + +if HAVE_LIBCL +plugin_LTLIBRARIES += \ + libgstxcamfilter.la \ + $(NULL) +endif + +XCORE_DIR = $(top_srcdir)/xcore +MODULES_DIR = $(top_srcdir)/modules + +XCORE_LA = $(top_builddir)/xcore/libxcam_core.la + +if ENABLE_IA_AIQ +XCAM_INTERFACE_DIR = -I$(top_srcdir)/wrapper/gstreamer/interface +XCAM_INTERFACE_LA = $(top_builddir)/wrapper/gstreamer/interface/libgstxcaminterface.la +else +XCAM_INTERFACE_DIR = +XCAM_INTERFACE_LA = +endif + +XCAMGST_CXXFLAGS = $(XCAM_CXXFLAGS) +XCAMGST_LIBS = \ + $(NULL) + +if HAVE_LIBDRM +XCAMGST_CXXFLAGS += $(LIBDRM_CFLAGS) +XCAMGST_LIBS += $(LIBDRM_LIBS) +endif + +if USE_LOCAL_ATOMISP +XCAMGST_CXXFLAGS += -I$(top_srcdir)/ext/atomisp +endif + +XCAMGST_CXXFLAGS += \ + -I$(XCORE_DIR) \ + -I$(MODULES_DIR) \ + $(NULL) + +# Note: plugindir is set in configure +plugindir="$(libdir)/gstreamer-1.0" + +# sources used to compile this plug-in +libgstxcamsrc_la_SOURCES = \ + gstxcambuffermeta.cpp \ + gstxcambufferpool.cpp \ + main_dev_manager.cpp \ + gstxcamsrc.cpp \ + $(NULL) + +# compiler and linker flags used to compile this plugin, set in configure.ac +libgstxcamsrc_la_CXXFLAGS = \ + $(GST_CFLAGS) $(XCAMGST_CXXFLAGS) \ + -I$(top_srcdir)/wrapper/gstreamer \ + $(XCAM_INTERFACE_DIR) \ + $(NULL) + +libgstxcamsrc_la_LIBADD = $(XCAMGST_LIBS) \ + $(XCAM_INTERFACE_LA) \ + $(XCORE_LA) $(GST_ALLOCATOR_LIBS) \ + $(GST_VIDEO_LIBS) $(GST_LIBS) \ + $(NULL) + +libgstxcamsrc_la_LDFLAGS = \ + -module -avoid-version \ + $(PTHREAD_LDFLAGS) $(XCORE_LA) \ + $(NULL) + +libgstxcamsrc_la_LIBTOOLFLAGS = --tag=disable-static + +if ENABLE_IA_AIQ +ISP_LA = $(top_builddir)/modules/isp/libxcam_isp.la +libgstxcamsrc_la_LIBADD += $(ISP_LA) +libgstxcamsrc_la_LDFLAGS += $(ISP_LA) +endif + +if HAVE_LIBCL +OCL_LA = $(top_builddir)/modules/ocl/libxcam_ocl.la + +libgstxcamsrc_la_LIBADD += $(OCL_LA) +libgstxcamsrc_la_LDFLAGS += $(OCL_LA) + +libgstxcamfilter_la_SOURCES = \ + gstxcambuffermeta.cpp \ + main_pipe_manager.cpp \ + gstxcamfilter.cpp \ + $(NULL) + +libgstxcamfilter_la_CXXFLAGS = \ + $(GST_CFLAGS) $(XCAMGST_CXXFLAGS) \ + -I$(top_srcdir)/wrapper/gstreamer \ + $(NULL) + +libgstxcamfilter_la_LIBADD = \ + $(XCAMGST_LIBS) \ + $(XCORE_LA) $(OCL_LA) \ + $(GST_ALLOCATOR_LIBS) \ + $(GST_VIDEO_LIBS) \ + $(GST_LIBS) \ + $(NULL) + +libgstxcamfilter_la_LDFLAGS = \ + -module -avoid-version \ + $(XCORE_LA) $(OCL_LA) \ + $(NULL) + +libgstxcamfilter_la_LIBTOOLFLAGS = --tag=disable-static +endif + +# headers we need but don't want installed +noinst_HEADERS = \ + gst_xcam_utils.h \ + $(NULL) + +if ENABLE_IA_AIQ +noinst_HEADERS += \ + gstxcambufferpool.h \ + gstxcambuffermeta.h \ + main_dev_manager.h \ + gstxcamsrc.h \ + $(NULL) +endif + +if HAVE_LIBCL +noinst_HEADERS += \ + gstxcambuffermeta.h \ + main_pipe_manager.h \ + gstxcamfilter.h \ + $(NULL) +endif diff --git a/wrapper/gstreamer/gst_xcam_utils.h b/wrapper/gstreamer/gst_xcam_utils.h new file mode 100644 index 0000000..24f39c6 --- /dev/null +++ b/wrapper/gstreamer/gst_xcam_utils.h @@ -0,0 +1,48 @@ +/* + * gst_xcam_utils.h - gst xcam utilities + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#ifndef GST_XCAM_UTILS_H +#define GST_XCAM_UTILS_H + +#include "dma_video_buffer.h" + +class DmaGstBuffer + : public XCam::DmaVideoBuffer +{ +public: + DmaGstBuffer (const XCam::VideoBufferInfo &info, int dma_fd, GstBuffer *gst_buf) + : XCam::DmaVideoBuffer (info, dma_fd) + , _gst_buf (gst_buf) + { + gst_buffer_ref (_gst_buf); + } + + ~DmaGstBuffer () { + gst_buffer_unref (_gst_buf); + } + +private: + XCAM_DEAD_COPY (DmaGstBuffer); + +private: + GstBuffer *_gst_buf; +}; + +#endif // GST_XCAM_UTILS_H diff --git a/wrapper/gstreamer/gstxcambuffermeta.cpp b/wrapper/gstreamer/gstxcambuffermeta.cpp new file mode 100644 index 0000000..a683925 --- /dev/null +++ b/wrapper/gstreamer/gstxcambuffermeta.cpp @@ -0,0 +1,97 @@ +/* + * gstxcambuffermeta.cpp - gst xcam buffer meta data + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "gstxcambuffermeta.h" + +using namespace XCam; + +GType +gst_xcam_buffer_meta_api_get_type (void) +{ + static GType xcam_buf_type = 0; + static const gchar *xcam_buf_tags [] = + { GST_XCAM_META_TAG_XCAM, GST_XCAM_META_TAG_BUF, NULL }; + + if (g_once_init_enter (&xcam_buf_type)) { + GType _type = gst_meta_api_type_register ("GstXCamBuffer", xcam_buf_tags); + g_once_init_leave (&xcam_buf_type, _type); + } + + return xcam_buf_type; +} + +static gboolean +gst_xcam_buffer_meta_init (GstMeta *base, gpointer params, GstBuffer *buffer) +{ + XCAM_UNUSED (params); + XCAM_UNUSED (buffer); + GstXCamBufferMeta *meta = (GstXCamBufferMeta *)base; + + XCAM_CONSTRUCTOR (meta->buffer, SmartPtr<VideoBuffer>); + return TRUE; +} + + +static void +gst_xcam_buffer_meta_free (GstMeta *base, GstBuffer *buffer) +{ + XCAM_UNUSED (buffer); + GstXCamBufferMeta *meta = (GstXCamBufferMeta *)base; + + meta->buffer->unmap (); + XCAM_DESTRUCTOR (meta->buffer, SmartPtr<VideoBuffer>); +} + +static const GstMetaInfo * +gst_xcam_buffer_meta_get_info (void) +{ + static const GstMetaInfo *meta_info = NULL; + + if (g_once_init_enter (&meta_info)) { + const GstMetaInfo *_meta = + gst_meta_register (GST_XCAM_BUFFER_META_API_TYPE, + "GstXCamBufferMeta", + sizeof (GstXCamBufferMeta), + gst_xcam_buffer_meta_init, + gst_xcam_buffer_meta_free, + NULL); + g_once_init_leave (&meta_info, _meta); + } + return meta_info; +} + +GstXCamBufferMeta * +gst_buffer_add_xcam_buffer_meta ( + GstBuffer *buffer, + const SmartPtr<VideoBuffer> &data) +{ + XCAM_ASSERT (data.ptr ()); + + GstXCamBufferMeta *meta = (GstXCamBufferMeta*) gst_buffer_add_meta ( + buffer, gst_xcam_buffer_meta_get_info(), NULL); + + g_return_val_if_fail (meta, NULL); + + meta->buffer = data; + + return meta; +} + + diff --git a/wrapper/gstreamer/gstxcambuffermeta.h b/wrapper/gstreamer/gstxcambuffermeta.h new file mode 100644 index 0000000..698a55d --- /dev/null +++ b/wrapper/gstreamer/gstxcambuffermeta.h @@ -0,0 +1,55 @@ +/* + * gstxcambuffermeta.h - gst xcam buffer meta data + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef GST_XCAM_BUFFER_META_H +#define GST_XCAM_BUFFER_META_H + +#include <gst/gst.h> +#include <gst/gstmeta.h> + +#include <video_buffer.h> + +XCAM_BEGIN_DECLARE + +#define GST_XCAM_META_TAG_XCAM "xcam" +#define GST_XCAM_META_TAG_BUF "buf" + +#define GST_XCAM_BUFFER_META_API_TYPE \ + (gst_xcam_buffer_meta_api_get_type ()) + +#define gst_buffer_get_xcam_buffer_meta(b) \ + ((GstXCamBufferMeta*)gst_buffer_get_meta ((b), GST_XCAM_BUFFER_META_API_TYPE)) + +typedef struct _GstXCamBufferMeta { + GstMeta meta_base; + XCam::SmartPtr<XCam::VideoBuffer> buffer; +} GstXCamBufferMeta; + +GType +gst_xcam_buffer_meta_api_get_type (void); + +GstXCamBufferMeta * +gst_buffer_add_xcam_buffer_meta ( + GstBuffer *buffer, + const XCam::SmartPtr<XCam::VideoBuffer> &data); + +XCAM_END_DECLARE + +#endif //GST_XCAM_BUFFER_META_H diff --git a/wrapper/gstreamer/gstxcambufferpool.cpp b/wrapper/gstreamer/gstxcambufferpool.cpp new file mode 100644 index 0000000..31b7ee1 --- /dev/null +++ b/wrapper/gstreamer/gstxcambufferpool.cpp @@ -0,0 +1,256 @@ +/* + * gstxcambufferpool.cpp - bufferpool + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: John Ye <john.ye@intel.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +/** + * SECTION:element-xcambufferpool + * + * FIXME:Describe xcambufferpool here. + * + * <refsect2> + * <title>Example launch line</title> + * |[ + * gst-launch -v -m fakesrc ! xcambufferpool ! fakesink silent=TRUE + * ]| + * </refsect2> + */ + +#include "gstxcambufferpool.h" +#include "gstxcambuffermeta.h" + +#include <gst/video/gstvideopool.h> +#include <gst/allocators/gstdmabuf.h> +#include <gst/gstmeta.h> + +using namespace XCam; +using namespace GstXCam; + +XCAM_BEGIN_DECLARE + +GST_DEBUG_CATEGORY_EXTERN (gst_xcam_src_debug); +#define GST_CAT_DEFAULT gst_xcam_src_debug + +G_DEFINE_TYPE (GstXCamBufferPool, gst_xcam_buffer_pool, GST_TYPE_BUFFER_POOL); +#define parent_class gst_xcam_buffer_pool_parent_class + +static void +gst_xcam_buffer_pool_finalize (GObject * object); + +static gboolean +gst_xcam_buffer_pool_start (GstBufferPool *pool); + +static gboolean +gst_xcam_buffer_pool_stop (GstBufferPool *pool); + +static gboolean +gst_xcam_buffer_pool_set_config (GstBufferPool *pool, GstStructure *config); + +static GstFlowReturn +gst_xcam_buffer_pool_acquire_buffer ( + GstBufferPool *bpool, + GstBuffer **buffer, + GstBufferPoolAcquireParams *params); + +static void +gst_xcam_buffer_pool_release_buffer (GstBufferPool *bpool, GstBuffer *buffer); + + +XCAM_END_DECLARE + +static void +gst_xcam_buffer_pool_class_init (GstXCamBufferPoolClass * class_self) +{ + GObjectClass *object_class; + GstBufferPoolClass *bufferpool_class; + + object_class = G_OBJECT_CLASS (class_self); + bufferpool_class = GST_BUFFER_POOL_CLASS (class_self); + + object_class->finalize = gst_xcam_buffer_pool_finalize; + + bufferpool_class->start = gst_xcam_buffer_pool_start; + bufferpool_class->stop = gst_xcam_buffer_pool_stop; + bufferpool_class->set_config = gst_xcam_buffer_pool_set_config; + bufferpool_class->acquire_buffer = gst_xcam_buffer_pool_acquire_buffer; + bufferpool_class->release_buffer = gst_xcam_buffer_pool_release_buffer; + +} + +static void +gst_xcam_buffer_pool_init (GstXCamBufferPool *pool) +{ + pool->need_video_meta = FALSE; + XCAM_CONSTRUCTOR (pool->device_manager, SmartPtr<MainDeviceManager>); +} + +static void +gst_xcam_buffer_pool_finalize (GObject * object) +{ + GstXCamBufferPool *pool = GST_XCAM_BUFFER_POOL (object); + XCAM_ASSERT (pool); + + if (pool->src) + gst_object_unref (pool->src); + if (pool->allocator) + gst_object_unref (pool->allocator); + XCAM_DESTRUCTOR (pool->device_manager, SmartPtr<MainDeviceManager>); +} + +static gboolean +gst_xcam_buffer_pool_start (GstBufferPool *base_pool) +{ + GstXCamBufferPool *pool = GST_XCAM_BUFFER_POOL (base_pool); + XCAM_ASSERT (pool); + SmartPtr<MainDeviceManager> device_manager = pool->device_manager; + XCAM_ASSERT (device_manager.ptr ()); + device_manager->resume_dequeue (); + return TRUE; +} + +static gboolean +gst_xcam_buffer_pool_stop (GstBufferPool *base_pool) +{ + GstXCamBufferPool *pool = GST_XCAM_BUFFER_POOL (base_pool); + XCAM_ASSERT (pool); + SmartPtr<MainDeviceManager> device_manager = pool->device_manager; + XCAM_ASSERT (device_manager.ptr ()); + + device_manager->pause_dequeue (); + return TRUE; +} + +gboolean +gst_xcam_buffer_pool_set_config (GstBufferPool *base_pool, GstStructure *config) +{ + GstXCamBufferPool *pool = GST_XCAM_BUFFER_POOL (base_pool); + + XCAM_ASSERT (pool); + pool->need_video_meta = gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); + + pool->allocator = gst_dmabuf_allocator_new (); + if (pool->allocator == NULL) { + GST_WARNING ("xcam buffer pool get allocator failed"); + return FALSE; + } + + return TRUE; +} + +static GstFlowReturn +gst_xcam_buffer_pool_acquire_buffer ( + GstBufferPool *base_pool, + GstBuffer **buffer, + GstBufferPoolAcquireParams *params) +{ + GstXCamBufferPool *pool = GST_XCAM_BUFFER_POOL (base_pool); + XCAM_ASSERT (pool); + GstBuffer *out_buf = NULL; + GstMemory *mem = NULL; + GstXCamBufferMeta *meta = NULL; + SmartPtr<MainDeviceManager> device_manager = pool->device_manager; + SmartPtr<VideoBuffer> video_buf = device_manager->dequeue_buffer (); + VideoBufferInfo video_info; + gsize offsets[XCAM_VIDEO_MAX_COMPONENTS]; + + XCAM_UNUSED (params); + + if (!video_buf.ptr ()) + return GST_FLOW_ERROR; + + video_info = video_buf->get_video_info (); + for (int i = 0; i < XCAM_VIDEO_MAX_COMPONENTS; i++) { + offsets[i] = video_info.offsets[i]; + } + + out_buf = gst_buffer_new (); + meta = gst_buffer_add_xcam_buffer_meta (out_buf, video_buf); + XCAM_ASSERT (meta); + ((GstMeta *)(meta))->flags = (GstMetaFlags)(GST_META_FLAG_POOLED | GST_META_FLAG_LOCKED | GST_META_FLAG_READONLY); + //GST_META_FLAG_SET (meta, (GST_META_FLAG_POOLED | GST_META_FLAG_LOCKED | GST_META_FLAG_READONLY)); + + if (GST_XCAM_SRC_MEM_MODE (pool->src) == V4L2_MEMORY_DMABUF) { + mem = gst_dmabuf_allocator_alloc ( + pool->allocator, dup (video_buf->get_fd ()), video_buf->get_size ()); + } else if (GST_XCAM_SRC_MEM_MODE (pool->src) == V4L2_MEMORY_MMAP) { + mem = gst_memory_new_wrapped ( + (GstMemoryFlags)(GST_MEMORY_FLAG_READONLY | GST_MEMORY_FLAG_NO_SHARE), + video_buf->map (), video_buf->get_size (), + video_info.offsets[0], video_info.size, + NULL, NULL); + } else { + GST_WARNING ("xcam buffer pool acquire buffer failed since mem_type not supported"); + return GST_FLOW_ERROR; + } + + XCAM_ASSERT (mem); + gst_buffer_append_memory (out_buf, mem); + if (pool->need_video_meta) { + GstVideoMeta *video_meta = + gst_buffer_add_video_meta_full ( + out_buf, GST_VIDEO_FRAME_FLAG_NONE, + GST_VIDEO_INFO_FORMAT (GST_XCAM_SRC_OUT_VIDEO_INFO (pool->src)), + video_info.width, + video_info.height, + video_info.components, + offsets, + (gint*)(video_info.strides)); + XCAM_ASSERT (video_meta); + // TODO, consider map and unmap later + video_meta->map = NULL; + video_meta->unmap = NULL; + } + + GST_BUFFER_TIMESTAMP (out_buf) = video_buf->get_timestamp () * 1000; //us to ns + + *buffer = out_buf; + return GST_FLOW_OK; +} + +static void +gst_xcam_buffer_pool_release_buffer (GstBufferPool *base_pool, GstBuffer *buffer) +{ + XCAM_UNUSED (base_pool); + gst_buffer_unref (buffer); +} + +GstBufferPool * +gst_xcam_buffer_pool_new (GstXCamSrc *src, GstCaps *caps, SmartPtr<MainDeviceManager> &device_manager) +{ + GstXCamBufferPool *pool; + GstStructure *structure; + + pool = (GstXCamBufferPool *)g_object_new (GST_TYPE_XCAM_BUFFER_POOL, NULL); + XCAM_ASSERT (pool); + + structure = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); + XCAM_ASSERT (structure); + gst_buffer_pool_config_set_params ( + structure, caps, + GST_VIDEO_INFO_SIZE (GST_XCAM_SRC_OUT_VIDEO_INFO (src)), + GST_XCAM_SRC_BUF_COUNT (src), + GST_XCAM_SRC_BUF_COUNT (src)); + gst_buffer_pool_config_add_option (structure, GST_BUFFER_POOL_OPTION_VIDEO_META); + gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), structure); + + pool->src = src; + gst_object_ref (src); + pool->device_manager = device_manager; + return GST_BUFFER_POOL (pool); +} diff --git a/wrapper/gstreamer/gstxcambufferpool.h b/wrapper/gstreamer/gstxcambufferpool.h new file mode 100644 index 0000000..75bd58d --- /dev/null +++ b/wrapper/gstreamer/gstxcambufferpool.h @@ -0,0 +1,60 @@ +/* + * gstxcambufferpool.h - buffer pool + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: John Ye <john.ye@intel.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef GST_XCAM_BUFFER_POOL_H +#define GST_XCAM_BUFFER_POOL_H + +#include <gst/gst.h> +#include "main_dev_manager.h" +#include "gstxcamsrc.h" + +G_BEGIN_DECLS + +#define GST_TYPE_XCAM_BUFFER_POOL \ + (gst_xcam_buffer_pool_get_type()) +#define GST_XCAM_BUFFER_POOL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XCAM_BUFFER_POOL,GstXCamBufferPool)) + +typedef struct _GstXCamBufferPool GstXCamBufferPool; +typedef struct _GstXCamBufferPoolClass GstXCamBufferPoolClass; + +struct _GstXCamBufferPool +{ + GstBufferPool parent; + GstAllocator *allocator; + GstXCamSrc *src; + gboolean need_video_meta; + XCam::SmartPtr<GstXCam::MainDeviceManager> device_manager; +}; + +struct _GstXCamBufferPoolClass +{ + GstBufferPoolClass parent_class; +}; + +GType gst_xcam_buffer_pool_get_type (void); + +GstBufferPool * +gst_xcam_buffer_pool_new (GstXCamSrc *xcamsrc, GstCaps *caps, XCam::SmartPtr<GstXCam::MainDeviceManager> &device_manager); + +G_END_DECLS + +#endif // GST_XCAM_BUFFER_POOL_H diff --git a/wrapper/gstreamer/gstxcamfilter.cpp b/wrapper/gstreamer/gstxcamfilter.cpp new file mode 100644 index 0000000..21b38d8 --- /dev/null +++ b/wrapper/gstreamer/gstxcamfilter.cpp @@ -0,0 +1,1005 @@ +/* + * gstxcamfilter.cpp -gst xcamfilter plugin + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include "gstxcamfilter.h" +#include "gstxcambuffermeta.h" + +#include <gst/gstmeta.h> +#include <gst/allocators/gstdmabuf.h> + +using namespace XCam; +using namespace GstXCam; + +#define DEFAULT_SMART_ANALYSIS_LIB_DIR "/usr/lib/xcam/plugins/smart" +#define DEFAULT_DELAY_BUFFER_NUM 2 + +#define DEFAULT_PROP_BUFFERCOUNT 8 +#define DEFAULT_PROP_COPY_MODE COPY_MODE_CPU +#define DEFAULT_PROP_DEFOG_MODE DEFOG_NONE +#define DEFAULT_PROP_WAVELET_MODE NONE_WAVELET +#define DEFAULT_PROP_3D_DENOISE_MODE DENOISE_3D_NONE +#define DEFAULT_PROP_ENABLE_WIREFRAME FALSE +#define DEFAULT_PROP_ENABLE_IMAGE_WARP FALSE +#define DEFAULT_PROP_ENABLE_IMAGE_STITCH FALSE +#define DEFAULT_PROP_STITCH_ENABLE_SEAM FALSE +#define DEFAULT_PROP_STITCH_SCALE_MODE CLBlenderScaleLocal +#define DEFAULT_PROP_STITCH_FISHEYE_MAP FALSE +#define DEFAULT_PROP_STITCH_LSC FALSE +#define DEFAULT_PROP_STITCH_FM_OCL FALSE +#define DEFAULT_PROP_STITCH_RES_MODE StitchRes1080P + +XCAM_BEGIN_DECLARE + +enum { + PROP_0, + PROP_BUFFERCOUNT, + PROP_COPY_MODE, + PROP_DEFOG_MODE, + PROP_WAVELET_MODE, + PROP_DENOISE_3D_MODE, + PROP_ENABLE_WIREFRAME, + PROP_ENABLE_IMAGE_WARP, + PROP_ENABLE_IMAGE_STITCH, + PROP_STITCH_ENABLE_SEAM, + PROP_STITCH_SCALE_MODE, + PROP_STITCH_FISHEYE_MAP, + PROP_STITCH_LSC, + PROP_STITCH_FM_OCL, + PROP_STITCH_RES_MODE +}; + +#define GST_TYPE_XCAM_FILTER_COPY_MODE (gst_xcam_filter_copy_mode_get_type ()) +static GType +gst_xcam_filter_copy_mode_get_type (void) +{ + static GType g_type = 0; + static const GEnumValue copy_mode_types[] = { + {COPY_MODE_CPU, "Copy buffer with CPU", "cpu"}, + {COPY_MODE_DMA, "Copy buffer with DMA", "dma"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstXCamFilterCopyModeType", copy_mode_types); + g_once_init_leave (&g_type, type); + } + + return g_type; +} + +#define GST_TYPE_XCAM_FILTER_DEFOG_MODE (gst_xcam_filter_defog_mode_get_type ()) +static GType +gst_xcam_filter_defog_mode_get_type (void) +{ + static GType g_type = 0; + static const GEnumValue defog_mode_types [] = { + {DEFOG_NONE, "Defog disabled", "none"}, + {DEFOG_RETINEX, "Defog retinex", "retinex"}, + {DEFOG_DCP, "Defog dark channel prior", "dcp"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstXCamFilterDefogModeType", defog_mode_types); + g_once_init_leave (&g_type, type); + } + + return g_type; +} + +#define GST_TYPE_XCAM_FILTER_WAVELET_MODE (gst_xcam_filter_wavelet_mode_get_type ()) +static GType +gst_xcam_filter_wavelet_mode_get_type (void) +{ + static GType g_type = 0; + static const GEnumValue wavelet_mode_types[] = { + {NONE_WAVELET, "Wavelet disabled", "none"}, + {HAT_WAVELET_Y, "Hat wavelet Y", "hat Y"}, + {HAT_WAVELET_UV, "Hat wavelet UV", "hat UV"}, + {HARR_WAVELET_Y, "Haar wavelet Y", "haar Y"}, + {HARR_WAVELET_UV, "Haar wavelet UV", "haar UV"}, + {HARR_WAVELET_YUV, "Haar wavelet YUV", "haar YUV"}, + {HARR_WAVELET_BAYES, "Haar wavelet bayes shrink", "haar Bayes"}, + {0, NULL, NULL}, + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstXCamFilterWaveletModeType", wavelet_mode_types); + g_once_init_leave (&g_type, type); + } + + return g_type; +} + +#define GST_TYPE_XCAM_FILTER_3D_DENOISE_MODE (gst_xcam_filter_3d_denoise_mode_get_type ()) +static GType +gst_xcam_filter_3d_denoise_mode_get_type (void) +{ + static GType g_type = 0; + static const GEnumValue denoise_3d_mode_types [] = { + {DENOISE_3D_NONE, "3D Denoise disabled", "none"}, + {DENOISE_3D_YUV, "3D Denoise yuv", "yuv"}, + {DENOISE_3D_UV, "3D Denoise uv", "uv"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstXCamFilter3DDenoiseModeType", denoise_3d_mode_types); + g_once_init_leave (&g_type, type); + } + + return g_type; +} + +#define GST_TYPE_XCAM_FILTER_STITCH_SCALE_MODE (gst_xcam_filter_stitch_scale_mode_get_type ()) +static GType +gst_xcam_filter_stitch_scale_mode_get_type (void) +{ + static GType g_type = 0; + static const GEnumValue stitch_scale_mode_types [] = { + {CLBlenderScaleLocal, "Image stitch local scale", "local"}, + {CLBlenderScaleGlobal, "Image stitch glocal scale", "global"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstXCamFilterStitchScaleModeType", stitch_scale_mode_types); + g_once_init_leave (&g_type, type); + } + + return g_type; +} + +#define GST_TYPE_XCAM_FILTER_STITCH_RES_MODE (gst_xcam_filter_stitch_res_mode_get_type ()) +static GType +gst_xcam_filter_stitch_res_mode_get_type (void) +{ + static GType g_type = 0; + static const GEnumValue stitch_res_mode_types [] = { + {StitchRes1080P, "Image stitch 1080P mode", "1080p"}, + {StitchRes4K, "Image stitch 4K mode", "4k"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstXCamFilterStitchResModeType", stitch_res_mode_types); + g_once_init_leave (&g_type, type); + } + + return g_type; +} + +static GstStaticPadTemplate gst_xcam_sink_factory = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ NV12 }"))); + +static GstStaticPadTemplate gst_xcam_src_factory = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ NV12 }"))); + +GST_DEBUG_CATEGORY (gst_xcam_filter_debug); +#define GST_CAT_DEFAULT gst_xcam_filter_debug + +#define gst_xcam_filter_parent_class parent_class +G_DEFINE_TYPE (GstXCamFilter, gst_xcam_filter, GST_TYPE_BASE_TRANSFORM); + +static void gst_xcam_filter_finalize (GObject * object); +static void gst_xcam_filter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_xcam_filter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); +static gboolean gst_xcam_filter_start (GstBaseTransform *trans); +static GstCaps *gst_xcam_filter_transform_caps ( + GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, GstCaps *filter); +static gboolean gst_xcam_filter_set_caps (GstBaseTransform *trans, GstCaps *incaps, GstCaps *outcaps); +static gboolean gst_xcam_filter_stop (GstBaseTransform *trans); +static void gst_xcam_filter_before_transform (GstBaseTransform *trans, GstBuffer *buffer); +static GstFlowReturn gst_xcam_filter_prepare_output_buffer (GstBaseTransform * trans, GstBuffer *input, GstBuffer **outbuf); +static GstFlowReturn gst_xcam_filter_transform (GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf); + +XCAM_END_DECLARE + +static void +gst_xcam_filter_class_init (GstXCamFilterClass *class_self) +{ + GObjectClass *gobject_class; + GstElementClass *element_class; + GstBaseTransformClass *basetrans_class; + + gobject_class = (GObjectClass *) class_self; + element_class = (GstElementClass *) class_self; + basetrans_class = (GstBaseTransformClass *) class_self; + + GST_DEBUG_CATEGORY_INIT (gst_xcam_filter_debug, "xcamfilter", 0, "LibXCam filter plugin"); + + gobject_class->finalize = gst_xcam_filter_finalize; + gobject_class->set_property = gst_xcam_filter_set_property; + gobject_class->get_property = gst_xcam_filter_get_property; + + g_object_class_install_property ( + gobject_class, PROP_BUFFERCOUNT, + g_param_spec_int ("buffercount", "buffer count", "Buffer count", + 0, G_MAXINT, DEFAULT_PROP_BUFFERCOUNT, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_COPY_MODE, + g_param_spec_enum ("copy-mode", "copy mode", "Copy Mode", + GST_TYPE_XCAM_FILTER_COPY_MODE, DEFAULT_PROP_COPY_MODE, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_DEFOG_MODE, + g_param_spec_enum ("defog-mode", "defog mode", "Defog mode", + GST_TYPE_XCAM_FILTER_DEFOG_MODE, DEFAULT_PROP_DEFOG_MODE, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_WAVELET_MODE, + g_param_spec_enum ("wavelet-mode", "wavelet mode", "Wavelet Mode", + GST_TYPE_XCAM_FILTER_WAVELET_MODE, DEFAULT_PROP_WAVELET_MODE, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_DENOISE_3D_MODE, + g_param_spec_enum ("denoise-3d", "3D Denoise mode", "3D Denoise mode", + GST_TYPE_XCAM_FILTER_3D_DENOISE_MODE, DEFAULT_PROP_3D_DENOISE_MODE, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_ENABLE_WIREFRAME, + g_param_spec_boolean ("enable-wireframe", "enable wire frame", "Enable wire frame", + DEFAULT_PROP_ENABLE_WIREFRAME, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_ENABLE_IMAGE_WARP, + g_param_spec_boolean ("enable-warp", "enable image warp", "Enable Image Warp", + DEFAULT_PROP_ENABLE_IMAGE_WARP, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_ENABLE_IMAGE_STITCH, + g_param_spec_boolean ("enable-stitch", "enable image stitch", "Enable Image Stitch", + DEFAULT_PROP_ENABLE_IMAGE_STITCH, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_STITCH_ENABLE_SEAM, + g_param_spec_boolean ("stitch-seam", "enable seam just for stitch", "Enable Seam Just For Stitch", + DEFAULT_PROP_STITCH_ENABLE_SEAM, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_STITCH_SCALE_MODE, + g_param_spec_enum ("stitch-scale", "stitch scale mode", "Stitch Scale Mode", + GST_TYPE_XCAM_FILTER_STITCH_SCALE_MODE, DEFAULT_PROP_STITCH_SCALE_MODE, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_STITCH_FISHEYE_MAP, + g_param_spec_boolean ("stitch-fisheye-map", "stitch fisheye map", "Enable fisheye map for stitch", + DEFAULT_PROP_STITCH_FISHEYE_MAP, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_STITCH_LSC, + g_param_spec_boolean ("stitch-lsc", "stitch enable lens shading correction", "Enable Lens Shading Correction", + DEFAULT_PROP_STITCH_LSC, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + +#if HAVE_OPENCV + g_object_class_install_property ( + gobject_class, PROP_STITCH_FM_OCL, + g_param_spec_boolean ("stitch-fm-ocl", "stitch enable ocl for feature match", "Enable ocl for feature match", + DEFAULT_PROP_STITCH_FM_OCL, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); +#endif + + g_object_class_install_property ( + gobject_class, PROP_STITCH_RES_MODE, + g_param_spec_enum ("stitch-res-mode", "stitch resolution mode", "Stitch Resolution Mode", + GST_TYPE_XCAM_FILTER_STITCH_RES_MODE, DEFAULT_PROP_STITCH_RES_MODE, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + gst_element_class_set_details_simple (element_class, + "Libxcam Filter", + "Filter/Effect/Video", + "Process NV12 stream using xcam library", + "Wind Yuan <feng.yuan@intel.com> & Yinhang Liu <yinhangx.liu@intel.com>"); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_xcam_src_factory)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_xcam_sink_factory)); + + basetrans_class->start = GST_DEBUG_FUNCPTR (gst_xcam_filter_start); + basetrans_class->stop = GST_DEBUG_FUNCPTR (gst_xcam_filter_stop); + basetrans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_xcam_filter_transform_caps); + basetrans_class->set_caps = GST_DEBUG_FUNCPTR (gst_xcam_filter_set_caps); + basetrans_class->before_transform = GST_DEBUG_FUNCPTR (gst_xcam_filter_before_transform); + basetrans_class->prepare_output_buffer = GST_DEBUG_FUNCPTR (gst_xcam_filter_prepare_output_buffer); + basetrans_class->transform = GST_DEBUG_FUNCPTR (gst_xcam_filter_transform); +} + +static void +gst_xcam_filter_init (GstXCamFilter *xcamfilter) +{ + xcamfilter->buf_count = DEFAULT_PROP_BUFFERCOUNT; + xcamfilter->copy_mode = DEFAULT_PROP_COPY_MODE; + xcamfilter->defog_mode = DEFAULT_PROP_DEFOG_MODE; + xcamfilter->wavelet_mode = DEFAULT_PROP_WAVELET_MODE; + xcamfilter->denoise_3d_mode = DEFAULT_PROP_3D_DENOISE_MODE; + xcamfilter->denoise_3d_ref_count = 2; + xcamfilter->enable_wireframe = DEFAULT_PROP_ENABLE_WIREFRAME; + xcamfilter->enable_image_warp = DEFAULT_PROP_ENABLE_IMAGE_WARP; + xcamfilter->enable_stitch = DEFAULT_PROP_ENABLE_IMAGE_STITCH; + xcamfilter->stitch_enable_seam = DEFAULT_PROP_STITCH_ENABLE_SEAM; + xcamfilter->stitch_fisheye_map = DEFAULT_PROP_STITCH_FISHEYE_MAP; + xcamfilter->stitch_lsc = DEFAULT_PROP_STITCH_LSC; + xcamfilter->stitch_fm_ocl = DEFAULT_PROP_STITCH_FM_OCL; + xcamfilter->stitch_scale_mode = DEFAULT_PROP_STITCH_SCALE_MODE; + xcamfilter->stitch_res_mode = DEFAULT_PROP_STITCH_RES_MODE; + + xcamfilter->delay_buf_num = DEFAULT_DELAY_BUFFER_NUM; + xcamfilter->cached_buf_num = 0; + + XCAM_CONSTRUCTOR (xcamfilter->pipe_manager, SmartPtr<MainPipeManager>); + xcamfilter->pipe_manager = new MainPipeManager; + XCAM_ASSERT (xcamfilter->pipe_manager.ptr ()); +} + +static void +gst_xcam_filter_finalize (GObject *object) +{ + GstXCamFilter *xcamfilter = GST_XCAM_FILTER (object); + + if (xcamfilter->allocator) + gst_object_unref (xcamfilter->allocator); + + xcamfilter->pipe_manager.release (); + XCAM_DESTRUCTOR (xcamfilter->pipe_manager, SmartPtr<MainPipeManager>); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_xcam_filter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstXCamFilter *xcamfilter = GST_XCAM_FILTER (object); + + switch (prop_id) { + case PROP_BUFFERCOUNT: + xcamfilter->buf_count = g_value_get_int (value); + break; + case PROP_COPY_MODE: + xcamfilter->copy_mode = (CopyMode) g_value_get_enum (value); + break; + case PROP_DEFOG_MODE: + xcamfilter->defog_mode = (DefogModeType) g_value_get_enum (value); + break; + case PROP_WAVELET_MODE: + xcamfilter->wavelet_mode = (WaveletModeType) g_value_get_enum (value); + break; + case PROP_DENOISE_3D_MODE: + xcamfilter->denoise_3d_mode = (Denoise3DModeType) g_value_get_enum (value); + break; + case PROP_ENABLE_WIREFRAME: + xcamfilter->enable_wireframe = g_value_get_boolean (value); + break; + case PROP_ENABLE_IMAGE_WARP: + xcamfilter->enable_image_warp = g_value_get_boolean (value); + break; + case PROP_ENABLE_IMAGE_STITCH: + xcamfilter->enable_stitch = g_value_get_boolean (value); + break; + case PROP_STITCH_ENABLE_SEAM: + xcamfilter->stitch_enable_seam = g_value_get_boolean (value); + break; + case PROP_STITCH_SCALE_MODE: + xcamfilter->stitch_scale_mode = (CLBlenderScaleMode) g_value_get_enum (value); + break; + case PROP_STITCH_FISHEYE_MAP: + xcamfilter->stitch_fisheye_map = g_value_get_boolean (value); + break; + case PROP_STITCH_LSC: + xcamfilter->stitch_lsc = g_value_get_boolean (value); + break; +#if HAVE_OPENCV + case PROP_STITCH_FM_OCL: + xcamfilter->stitch_fm_ocl = g_value_get_boolean (value); + break; +#endif + case PROP_STITCH_RES_MODE: + xcamfilter->stitch_res_mode = (StitchResMode) g_value_get_enum (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_xcam_filter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstXCamFilter *xcamfilter = GST_XCAM_FILTER (object); + + switch (prop_id) { + case PROP_BUFFERCOUNT: + g_value_set_int (value, xcamfilter->buf_count); + break; + case PROP_COPY_MODE: + g_value_set_enum (value, xcamfilter->copy_mode); + break; + case PROP_DEFOG_MODE: + g_value_set_enum (value, xcamfilter->defog_mode); + break; + case PROP_WAVELET_MODE: + g_value_set_enum (value, xcamfilter->wavelet_mode); + break; + case PROP_DENOISE_3D_MODE: + g_value_set_enum (value, xcamfilter->denoise_3d_mode); + break; + case PROP_ENABLE_WIREFRAME: + g_value_set_boolean (value, xcamfilter->enable_wireframe); + break; + case PROP_ENABLE_IMAGE_WARP: + g_value_set_boolean (value, xcamfilter->enable_image_warp); + break; + case PROP_ENABLE_IMAGE_STITCH: + g_value_set_boolean (value, xcamfilter->enable_stitch); + break; + case PROP_STITCH_ENABLE_SEAM: + g_value_set_boolean (value, xcamfilter->stitch_enable_seam); + break; + case PROP_STITCH_SCALE_MODE: + g_value_set_enum (value, xcamfilter->stitch_scale_mode); + break; + case PROP_STITCH_FISHEYE_MAP: + g_value_set_boolean (value, xcamfilter->stitch_fisheye_map); + break; + case PROP_STITCH_LSC: + g_value_set_boolean (value, xcamfilter->stitch_lsc); + break; +#if HAVE_OPENCV + case PROP_STITCH_FM_OCL: + g_value_set_boolean (value, xcamfilter->stitch_fm_ocl); + break; +#endif + case PROP_STITCH_RES_MODE: + g_value_set_enum (value, xcamfilter->stitch_res_mode); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_xcam_filter_start (GstBaseTransform *trans) +{ + GstXCamFilter *xcamfilter = GST_XCAM_FILTER (trans); + + if (xcamfilter->buf_count <= xcamfilter->delay_buf_num) { + XCAM_LOG_ERROR ( + "buffer count (%d) should be greater than delayed buffer number (%d)", + xcamfilter->buf_count, + xcamfilter->delay_buf_num); + return false; + } + + SmartPtr<MainPipeManager> pipe_manager = xcamfilter->pipe_manager; + SmartPtr<SmartAnalyzer> smart_analyzer; + SmartPtr<CLPostImageProcessor> image_processor; + + SmartHandlerList smart_handlers = SmartAnalyzerLoader::load_smart_handlers (DEFAULT_SMART_ANALYSIS_LIB_DIR); + if (!smart_handlers.empty ()) { + smart_analyzer = new SmartAnalyzer (); + if (smart_analyzer.ptr ()) { + SmartHandlerList::iterator i_handler = smart_handlers.begin (); + for (; i_handler != smart_handlers.end (); ++i_handler) + { + XCAM_ASSERT ((*i_handler).ptr ()); + smart_analyzer->add_handler (*i_handler); + } + if (smart_analyzer->prepare_handlers () != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("analyzer(%s) prepare handlers failed", smart_analyzer->get_name ()); + return false; + } + pipe_manager->set_smart_analyzer (smart_analyzer); + } else { + XCAM_LOG_WARNING ("load smart analyzer(%s) failed, please check.", DEFAULT_SMART_ANALYSIS_LIB_DIR); + } + } + + image_processor = new CLPostImageProcessor (); + XCAM_ASSERT (image_processor.ptr ()); + image_processor->set_stats_callback (pipe_manager); + image_processor->set_defog_mode ((CLPostImageProcessor::CLDefogMode) xcamfilter->defog_mode); + + if (NONE_WAVELET != xcamfilter->wavelet_mode) { + if (HAT_WAVELET_Y == xcamfilter->wavelet_mode) { + image_processor->set_wavelet (CL_WAVELET_HAT, CL_IMAGE_CHANNEL_Y, false); + } else if (HAT_WAVELET_UV == xcamfilter->wavelet_mode) { + image_processor->set_wavelet (CL_WAVELET_HAT, CL_IMAGE_CHANNEL_UV, false); + } else if (HARR_WAVELET_Y == xcamfilter->wavelet_mode) { + image_processor->set_wavelet (CL_WAVELET_HAAR, CL_IMAGE_CHANNEL_Y, false); + } else if (HARR_WAVELET_UV == xcamfilter->wavelet_mode) { + image_processor->set_wavelet (CL_WAVELET_HAAR, CL_IMAGE_CHANNEL_UV, false); + } else if (HARR_WAVELET_YUV == xcamfilter->wavelet_mode) { + image_processor->set_wavelet (CL_WAVELET_HAAR, CL_IMAGE_CHANNEL_UV | CL_IMAGE_CHANNEL_Y, false); + } else if (HARR_WAVELET_BAYES == xcamfilter->wavelet_mode) { + image_processor->set_wavelet (CL_WAVELET_HAAR, CL_IMAGE_CHANNEL_UV | CL_IMAGE_CHANNEL_Y, true); + } else { + image_processor->set_wavelet (CL_WAVELET_DISABLED, CL_IMAGE_CHANNEL_UV, false); + } + } + + image_processor->set_3ddenoise_mode ( + (CLPostImageProcessor::CL3DDenoiseMode) xcamfilter->denoise_3d_mode, xcamfilter->denoise_3d_ref_count); + + image_processor->set_wireframe (xcamfilter->enable_wireframe); + image_processor->set_image_warp (xcamfilter->enable_image_warp); + if (smart_analyzer.ptr ()) { + if (xcamfilter->enable_wireframe) + image_processor->set_scaler (true); + + if (xcamfilter->enable_image_warp) { + image_processor->set_scaler (true); + xcamfilter->delay_buf_num = DEFAULT_DELAY_BUFFER_NUM + 16; + } + } + + pipe_manager->add_image_processor (image_processor); + pipe_manager->set_image_processor (image_processor); + + xcamfilter->buf_pool = new CLVideoBufferPool (); + XCAM_ASSERT (xcamfilter->buf_pool.ptr ()); + if (xcamfilter->copy_mode == COPY_MODE_DMA) { + XCAM_LOG_WARNING ("CLVideoBuffer doesn't support DMA copy mode, switch to CPU copy mode"); + xcamfilter->copy_mode = COPY_MODE_CPU; + } + + if (xcamfilter->copy_mode == COPY_MODE_DMA) { + xcamfilter->allocator = gst_dmabuf_allocator_new (); + if (!xcamfilter->allocator) { + GST_WARNING ("xcamfilter get allocator failed"); + return false; + } + } + + return true; +} + +static gboolean +gst_xcam_filter_stop (GstBaseTransform *trans) +{ + GstXCamFilter *xcamfilter = GST_XCAM_FILTER (trans); + + SmartPtr<BufferPool> buf_pool = xcamfilter->buf_pool; + if (buf_pool.ptr ()) + buf_pool->stop (); + + SmartPtr<MainPipeManager> pipe_manager = xcamfilter->pipe_manager; + if (pipe_manager.ptr ()) + pipe_manager->stop (); + + return true; +} + +static GstCaps * +gst_xcam_filter_transform_caps ( + GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, GstCaps *filter) +{ + GstXCamFilter *xcamfilter = GST_XCAM_FILTER (trans); + + GstCaps *src_caps, *peer_caps, *intersect_caps; + GstStructure *sink_struct, *src_struct; + GstPad *peer_pad; + gint sink_width, sink_height, src_width, src_height; + + gboolean is_sink_width = false; + gboolean is_sink_height = false; + + src_caps = gst_pad_get_pad_template_caps (trans->srcpad); + + if (direction == GST_PAD_SRC || !gst_caps_is_fixed (caps)) + goto filtering; + + sink_struct = gst_caps_get_structure (caps, 0); + if (!gst_structure_get_int (sink_struct, "width", &sink_width) || + !gst_structure_get_int (sink_struct, "height", &sink_height)) + goto filtering; + + peer_pad = gst_pad_get_peer (trans->srcpad); + peer_caps = gst_pad_query_caps (peer_pad, src_caps); + if (!peer_pad || gst_caps_is_empty (peer_caps)) { + if (xcamfilter->enable_stitch) { + src_height = XCAM_ALIGN_UP (sink_width / 2, 16); + if (src_height * 2 != sink_width) { + gst_caps_unref (src_caps); + gst_caps_unref (peer_caps); + XCAM_LOG_ERROR ("xcamfilter stitch incorrect size, sink-width(%d) / 2 should be aligned with 16", + sink_width); + return NULL; + } + src_width = sink_width; + + gst_caps_unref (src_caps); + src_caps = gst_caps_copy (caps); + src_struct = gst_caps_get_structure (src_caps, 0); + + gst_structure_set (src_struct, "width", G_TYPE_INT, src_width, + "height", G_TYPE_INT, src_height, NULL); + } + + gst_caps_unref (peer_caps); + goto filtering; + } + + intersect_caps = gst_caps_intersect_full (peer_caps, src_caps, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (src_caps); + src_caps = intersect_caps; + + src_struct = gst_caps_get_structure (src_caps, 0); + if (!gst_structure_get_int (src_struct, "width", &src_width)) { + is_sink_width = true; + src_width = sink_width; + } + if (!gst_structure_get_int (src_struct, "height", &src_height)) { + is_sink_height = true; + src_height = sink_height; + } + + if (xcamfilter->enable_stitch) { + if (is_sink_width && is_sink_height) + src_height = XCAM_ALIGN_UP (src_width / 2, 16); + + if (src_width != src_height * 2) { + XCAM_LOG_ERROR ("xcamfilter incorrect stitch size width:%d height:%d", src_width, src_height); + gst_caps_unref (src_caps); + return NULL; + } + } + + gint fps_n, fps_d; + if (!gst_structure_get_fraction (src_struct, "framerate", &fps_n, &fps_d) && + !gst_structure_get_fraction (sink_struct, "framerate", &fps_n, &fps_d)) { + fps_n = 25; + fps_d = 1; + } + + gst_structure_set (src_struct, "width", G_TYPE_INT, src_width, + "height", G_TYPE_INT, src_height, + "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL); + +filtering: + if (filter) { + intersect_caps = gst_caps_intersect_full (filter, src_caps, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (src_caps); + src_caps = intersect_caps; + } + + return src_caps; +} + +static gboolean +gst_xcam_filter_set_caps (GstBaseTransform *trans, GstCaps *incaps, GstCaps *outcaps) +{ + GstXCamFilter *xcamfilter = GST_XCAM_FILTER (trans); + GstVideoInfo in_info, out_info; + + if (!gst_video_info_from_caps (&in_info, incaps) || + !gst_video_info_from_caps (&out_info, outcaps)) { + XCAM_LOG_WARNING ("fail to parse incaps or outcaps"); + return false; + } + + XCAM_FAIL_RETURN ( + ERROR, + GST_VIDEO_INFO_FORMAT (&in_info) == GST_VIDEO_FORMAT_NV12 || + GST_VIDEO_INFO_FORMAT (&out_info) == GST_VIDEO_FORMAT_NV12, + false, + "xcamfilter only support NV12 stream"); + xcamfilter->gst_sink_video_info = in_info; + xcamfilter->gst_src_video_info = out_info; + + SmartPtr<MainPipeManager> pipe_manager = xcamfilter->pipe_manager; + SmartPtr<CLPostImageProcessor> processor = pipe_manager->get_image_processor(); + XCAM_ASSERT (pipe_manager.ptr () && processor.ptr ()); + if (!processor->set_output_format (V4L2_PIX_FMT_NV12)) + return false; + + if (processor->is_scaled ()) + processor->set_scaler_factor (640.0 / GST_VIDEO_INFO_WIDTH (&in_info)); + //processor->set_scaler_factor (0.5f); + + if (xcamfilter->enable_stitch) { + processor->set_image_stitch ( + xcamfilter->enable_stitch, xcamfilter->stitch_enable_seam, xcamfilter->stitch_scale_mode, + xcamfilter->stitch_fisheye_map, xcamfilter->stitch_lsc, xcamfilter->stitch_fm_ocl, + GST_VIDEO_INFO_WIDTH (&out_info), GST_VIDEO_INFO_HEIGHT (&out_info), (uint32_t) xcamfilter->stitch_res_mode); + XCAM_LOG_INFO ("xcamfilter stitch output size width:%d height:%d", + GST_VIDEO_INFO_WIDTH (&out_info), GST_VIDEO_INFO_HEIGHT (&out_info)); + } + + if (pipe_manager->start () != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("pipe manager start failed"); + return false; + } + + VideoBufferInfo buf_info; + buf_info.init ( + V4L2_PIX_FMT_NV12, + GST_VIDEO_INFO_WIDTH (&in_info), + GST_VIDEO_INFO_HEIGHT (&in_info), + XCAM_ALIGN_UP (GST_VIDEO_INFO_WIDTH (&in_info), 16), + XCAM_ALIGN_UP (GST_VIDEO_INFO_HEIGHT (&in_info), 16)); + + SmartPtr<BufferPool> buf_pool = xcamfilter->buf_pool; + XCAM_ASSERT (buf_pool.ptr ()); + if (!buf_pool->set_video_info (buf_info) || + !buf_pool->reserve (xcamfilter->buf_count)) { + XCAM_LOG_ERROR ("init buffer pool failed"); + return false; + } + + return true; +} + +static GstFlowReturn +copy_gstbuf_to_xcambuf (GstVideoInfo gstinfo, GstBuffer *gstbuf, SmartPtr<VideoBuffer> xcambuf) +{ + GstMapInfo mapinfo; + VideoBufferPlanarInfo planar; + const VideoBufferInfo xcaminfo = xcambuf->get_video_info (); + + uint8_t *memory = xcambuf->map (); + gboolean ret = gst_buffer_map (gstbuf, &mapinfo, GST_MAP_READ); + if (!memory || !ret) { + XCAM_LOG_WARNING ("xcamfilter map buffer failed"); + return GST_FLOW_ERROR; + } + + uint8_t *src = NULL; + uint8_t *dest = NULL; + for (uint32_t index = 0; index < xcaminfo.components; index++) { + xcaminfo.get_planar_info (planar, index); + + src = mapinfo.data + GST_VIDEO_INFO_PLANE_OFFSET (&gstinfo, index); + dest = memory + xcaminfo.offsets [index]; + for (uint32_t i = 0; i < planar.height; i++) { + memcpy (dest, src, GST_VIDEO_INFO_WIDTH (&gstinfo)); + src += GST_VIDEO_INFO_PLANE_STRIDE (&gstinfo, index); + dest += xcaminfo.strides [index]; + } + } + + gst_buffer_unmap (gstbuf, &mapinfo); + xcambuf->unmap (); + + return GST_FLOW_OK; +} + +static GstFlowReturn +copy_xcambuf_to_gstbuf (GstVideoInfo gstinfo, SmartPtr<VideoBuffer> xcambuf, GstBuffer **gstbuf) +{ + GstMapInfo mapinfo; + VideoBufferPlanarInfo planar; + const VideoBufferInfo xcaminfo = xcambuf->get_video_info (); + + GstBuffer *tmpbuf = gst_buffer_new_allocate (NULL, GST_VIDEO_INFO_SIZE (&gstinfo), NULL); + if (!tmpbuf) { + XCAM_LOG_ERROR ("xcamfilter allocate buffer failed"); + return GST_FLOW_ERROR; + } + + uint8_t *memory = xcambuf->map (); + gboolean ret = gst_buffer_map (tmpbuf, &mapinfo, GST_MAP_WRITE); + if (!memory || !ret) { + XCAM_LOG_WARNING ("xcamfilter map buffer failed"); + return GST_FLOW_ERROR; + } + + uint8_t *src = NULL; + uint8_t *dest = NULL; + for (uint32_t index = 0; index < GST_VIDEO_INFO_N_PLANES (&gstinfo); index++) { + xcaminfo.get_planar_info (planar, index); + + src = memory + xcaminfo.offsets [index]; + dest = mapinfo.data + GST_VIDEO_INFO_PLANE_OFFSET (&gstinfo, index); + for (uint32_t i = 0; i < planar.height; i++) { + memcpy (dest, src, planar.width); + src += xcaminfo.strides [index]; + dest += GST_VIDEO_INFO_PLANE_STRIDE (&gstinfo, index); + } + } + + gst_buffer_unmap (tmpbuf, &mapinfo); + xcambuf->unmap (); + + *gstbuf = tmpbuf; + + return GST_FLOW_OK; +} + +static GstFlowReturn +append_xcambuf_to_gstbuf (GstAllocator *allocator, SmartPtr<VideoBuffer> xcambuf, GstBuffer **gstbuf) +{ + gsize offsets [XCAM_VIDEO_MAX_COMPONENTS]; + + VideoBufferInfo xcaminfo = xcambuf->get_video_info (); + for (int i = 0; i < XCAM_VIDEO_MAX_COMPONENTS; i++) { + offsets [i] = xcaminfo.offsets [i]; + } + + GstBuffer *tmpbuf = gst_buffer_new (); + GstMemory *mem = gst_dmabuf_allocator_alloc (allocator, dup (xcambuf->get_fd ()), xcambuf->get_size ()); + XCAM_ASSERT (mem); + + gst_buffer_append_memory (tmpbuf, mem); + + gst_buffer_add_video_meta_full ( + tmpbuf, + GST_VIDEO_FRAME_FLAG_NONE, + GST_VIDEO_FORMAT_NV12, + xcaminfo.width, + xcaminfo.height, + xcaminfo.components, + offsets, + (gint *) (xcaminfo.strides)); + + *gstbuf = tmpbuf; + + return GST_FLOW_OK; +} + +static gint +get_dmabuf_fd (GstBuffer *buffer) +{ + GstMemory *mem = gst_buffer_peek_memory (buffer, 0); + if (!gst_is_dmabuf_memory (mem)) { + return -1; + } + + return gst_dmabuf_memory_get_fd (mem); +} + +static void +gst_xcam_filter_before_transform (GstBaseTransform *trans, GstBuffer *buffer) +{ + GstXCamFilter *xcamfilter = GST_XCAM_FILTER (trans); + + SmartPtr<BufferPool> buf_pool = xcamfilter->buf_pool; + SmartPtr<MainPipeManager> pipe_manager = xcamfilter->pipe_manager; + XCAM_ASSERT (buf_pool.ptr () && pipe_manager.ptr ()); + + if (xcamfilter->cached_buf_num > xcamfilter->delay_buf_num) + return; + + SmartPtr<VideoBuffer> video_buf; + gint dma_fd = get_dmabuf_fd (buffer); + if (dma_fd >= 0) { +#if HAVE_LIBDRM + SmartPtr<DrmBoBufferPool> bo_buf_pool = buf_pool.dynamic_cast_ptr<DrmBoBufferPool> (); + SmartPtr<DrmDisplay> display = bo_buf_pool->get_drm_display (); + VideoBufferInfo info = bo_buf_pool->get_video_info (); + + SmartPtr<VideoBuffer> dma_buf = new DmaGstBuffer (info, dma_fd, buffer); + video_buf = display->convert_to_drm_bo_buf (display, dma_buf); +#endif + if (!video_buf.ptr ()) { + XCAM_LOG_ERROR ("xcamfilter convert to drm bo buffer failed"); + return; + } + } else { + video_buf = buf_pool->get_buffer (buf_pool); + if (!buf_pool.ptr ()) { + XCAM_LOG_ERROR ("xcamfilter sink-pad get buffer failed"); + return; + } + + copy_gstbuf_to_xcambuf (xcamfilter->gst_sink_video_info, buffer, video_buf); + } + + if (pipe_manager->push_buffer (video_buf) != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("xcamfilter push buffer failed"); + return; + } + + xcamfilter->cached_buf_num++; +} + +static GstFlowReturn +gst_xcam_filter_prepare_output_buffer (GstBaseTransform *trans, GstBuffer *input, GstBuffer **outbuf) +{ + GstXCamFilter *xcamfilter = GST_XCAM_FILTER (trans); + GstFlowReturn ret = GST_FLOW_OK; + + SmartPtr<MainPipeManager> pipe_manager = xcamfilter->pipe_manager; + SmartPtr<VideoBuffer> video_buf; + + if (xcamfilter->cached_buf_num > xcamfilter->buf_count) + return GST_FLOW_ERROR; + + int32_t timeout = -1; + if (xcamfilter->cached_buf_num <= xcamfilter->delay_buf_num) + timeout = 0; + + video_buf = pipe_manager->dequeue_buffer (timeout); + if (!video_buf.ptr ()) { + XCAM_LOG_WARNING ("xcamfilter dequeue buffer failed"); + *outbuf = NULL; + return GST_FLOW_OK; + } + + if (xcamfilter->copy_mode == COPY_MODE_CPU) { + ret = copy_xcambuf_to_gstbuf (xcamfilter->gst_src_video_info, video_buf, outbuf); + } else if (xcamfilter->copy_mode == COPY_MODE_DMA) { + GstAllocator *allocator = xcamfilter->allocator; + ret = append_xcambuf_to_gstbuf (allocator, video_buf, outbuf); + } + + if (ret == GST_FLOW_OK) { + xcamfilter->cached_buf_num--; + GST_BUFFER_TIMESTAMP (*outbuf) = GST_BUFFER_TIMESTAMP (input); + } + + return ret; +} + +static GstFlowReturn +gst_xcam_filter_transform (GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf) +{ + XCAM_UNUSED (trans); + XCAM_UNUSED (inbuf); + + if (!outbuf) { + XCAM_LOG_ERROR ("transform failed with null outbufer"); + return GST_FLOW_ERROR; + } + + XCAM_STATIC_FPS_CALCULATION (gstxcamfilter, XCAM_OBJ_DUR_FRAME_NUM); + return GST_FLOW_OK; +} + +static gboolean +gst_xcam_filter_plugin_init (GstPlugin *xcamfilter) +{ + return gst_element_register (xcamfilter, "xcamfilter", GST_RANK_NONE, + GST_TYPE_XCAM_FILTER); +} + +#ifndef PACKAGE +#define PACKAGE "libxam" +#endif + +GST_PLUGIN_DEFINE ( + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + xcamfilter, + "Libxcam filter plugin", + gst_xcam_filter_plugin_init, + VERSION, + GST_LICENSE_UNKNOWN, + "libxcamfilter", + "https://github.com/01org/libxcam" +) diff --git a/wrapper/gstreamer/gstxcamfilter.h b/wrapper/gstreamer/gstxcamfilter.h new file mode 100644 index 0000000..fddfed2 --- /dev/null +++ b/wrapper/gstreamer/gstxcamfilter.h @@ -0,0 +1,110 @@ +/* + * gstxcamfilter.h -gst xcamfilter plugin + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#ifndef GST_XCAM_FILTER_H +#define GST_XCAM_FILTER_H + +#include <gst/gst.h> +#include <gst/video/video.h> + +#include "main_pipe_manager.h" +#include "gst_xcam_utils.h" + +XCAM_BEGIN_DECLARE + +#define GST_TYPE_XCAM_FILTER (gst_xcam_filter_get_type()) +#define GST_XCAM_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XCAM_FILTER,GstXCamFilter)) +#define GST_XCAM_FILTER_CAST(obj) ((GstXCamFilter *) obj) + + +typedef enum { + COPY_MODE_CPU = 0, + COPY_MODE_DMA +} CopyMode; + +typedef enum { + DEFOG_NONE = 0, + DEFOG_RETINEX, + DEFOG_DCP +} DefogModeType; + +typedef enum { + NONE_WAVELET = 0, + HAT_WAVELET_Y, + HAT_WAVELET_UV, + HARR_WAVELET_Y, + HARR_WAVELET_UV, + HARR_WAVELET_YUV, + HARR_WAVELET_BAYES +} WaveletModeType; + +typedef enum { + DENOISE_3D_NONE = 0, + DENOISE_3D_YUV, + DENOISE_3D_UV +} Denoise3DModeType; + +enum StitchResMode { + StitchRes1080P = 0, + StitchRes4K = 2 +}; + +typedef struct _GstXCamFilter GstXCamFilter; +typedef struct _GstXCamFilterClass GstXCamFilterClass; + +struct _GstXCamFilter +{ + GstBaseTransform transform; + + uint32_t buf_count; + CopyMode copy_mode; + DefogModeType defog_mode; + WaveletModeType wavelet_mode; + Denoise3DModeType denoise_3d_mode; + uint8_t denoise_3d_ref_count; + gboolean enable_wireframe; + gboolean enable_image_warp; + gboolean enable_stitch; + gboolean stitch_enable_seam; + gboolean stitch_fisheye_map; + gboolean stitch_fm_ocl; + gboolean stitch_lsc; + XCam::CLBlenderScaleMode stitch_scale_mode; + StitchResMode stitch_res_mode; + + uint32_t delay_buf_num; + uint32_t cached_buf_num; + GstAllocator *allocator; + GstVideoInfo gst_sink_video_info; + GstVideoInfo gst_src_video_info; + XCam::SmartPtr<XCam::BufferPool> buf_pool; + XCam::SmartPtr<GstXCam::MainPipeManager> pipe_manager; +}; + +struct _GstXCamFilterClass +{ + GstBaseTransformClass parent_class; +}; + +GType gst_xcam_filter_get_type (void); + +XCAM_END_DECLARE + +#endif // GST_XCAM_FILTER_H diff --git a/wrapper/gstreamer/gstxcamsrc.cpp b/wrapper/gstreamer/gstxcamsrc.cpp new file mode 100644 index 0000000..cb3a6f4 --- /dev/null +++ b/wrapper/gstreamer/gstxcamsrc.cpp @@ -0,0 +1,1737 @@ +/* + * gstxcamsrc.cpp - gst xcamsrc plugin + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: John Ye <john.ye@intel.com> + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Jia Meng <jia.meng@intel.com> + */ + +/** + * SECTION:element-xcamsrc + * + * FIXME:Describe xcamsrc here. + * + * <refsect2> + * <title>Example launch line</title> + * |[ + * gst-launch-1.0 xcamsrc io-mode=4 sensor-id=0 imageprocessor=0 analyzer=1 \ + * ! video/x-raw, format=NV12, width=1920, height=1080, framerate=25/1 \ + * ! vaapiencode_h264 ! fakesink + * ]| + * </refsect2> + */ + +#include "gstxcamsrc.h" +#include "gstxcambufferpool.h" +#if HAVE_IA_AIQ +#include "gstxcaminterface.h" +#include "dynamic_analyzer_loader.h" +#include "isp/hybrid_analyzer_loader.h" +#include "x3a_analyze_tuner.h" +#include "isp/isp_poll_thread.h" +#endif +#if HAVE_LIBCL +#include "smart_analyzer_loader.h" +#include "smart_analysis_handler.h" +#endif +#include "fake_poll_thread.h" +#include "fake_v4l2_device.h" + +#include <signal.h> +#include <uvc_device.h> + +using namespace XCam; +using namespace GstXCam; + +#define CAPTURE_DEVICE_STILL "/dev/video0" +#define CAPTURE_DEVICE_VIDEO "/dev/video3" +#define DEFAULT_EVENT_DEVICE "/dev/v4l-subdev6" +#if HAVE_IA_AIQ +#define DEFAULT_CPF_FILE_NAME "/etc/atomisp/imx185.cpf" +#define DEFAULT_DYNAMIC_3A_LIB "/usr/lib/xcam/plugins/3a/libxcam_3a_aiq.so" +#endif + +#define V4L2_CAPTURE_MODE_STILL 0x2000 +#define V4L2_CAPTURE_MODE_VIDEO 0x4000 +#define V4L2_CAPTURE_MODE_PREVIEW 0x8000 + +#define DEFAULT_PROP_SENSOR 0 +#define DEFAULT_PROP_MEM_MODE V4L2_MEMORY_DMABUF +#if HAVE_IA_AIQ +#define DEFAULT_PROP_ENABLE_3A TRUE +#endif +#define DEFAULT_PROP_ENABLE_USB FALSE +#define DEFAULT_PROP_BUFFERCOUNT 8 +#define DEFAULT_PROP_PIXELFORMAT V4L2_PIX_FMT_NV12 //420 instead of 0 +#define DEFAULT_PROP_FIELD V4L2_FIELD_NONE // 0 +#define DEFAULT_PROP_ANALYZER SIMPLE_ANALYZER +#if HAVE_IA_AIQ +#define DEFAULT_PROP_IMAGE_PROCESSOR ISP_IMAGE_PROCESSOR +#elif HAVE_LIBCL +#define DEFAULT_PROP_IMAGE_PROCESSOR CL_IMAGE_PROCESSOR +#endif +#if HAVE_LIBCL +#define DEFAULT_PROP_WDR_MODE NONE_WDR +#define DEFAULT_PROP_DEFOG_MODE DEFOG_NONE +#define DEFAULT_PROP_3D_DENOISE_MODE DENOISE_3D_NONE +#define DEFAULT_PROP_WAVELET_MODE CL_WAVELET_DISABLED +#define DEFAULT_PROP_ENABLE_WIREFRAME FALSE +#define DEFAULT_PROP_ENABLE_IMAGE_WARP FALSE +#define DEFAULT_PROP_CL_PIPE_PROFILE 0 +#define DEFAULT_SMART_ANALYSIS_LIB_DIR "/usr/lib/xcam/plugins/smart" +#endif + +#define DEFAULT_VIDEO_WIDTH 1920 +#define DEFAULT_VIDEO_HEIGHT 1080 + +#define GST_XCAM_INTERFACE_HEADER(from, src, device_manager, analyzer) \ + GstXCamSrc *src = GST_XCAM_SRC (from); \ + XCAM_ASSERT (src); \ + SmartPtr<MainDeviceManager> device_manager = src->device_manager; \ + XCAM_ASSERT (src->device_manager.ptr ()); \ + SmartPtr<X3aAnalyzer> analyzer = device_manager->get_analyzer (); \ + XCAM_ASSERT (analyzer.ptr ()) + + +XCAM_BEGIN_DECLARE + +static GstStaticPadTemplate gst_xcam_src_factory = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL))); + + +GST_DEBUG_CATEGORY (gst_xcam_src_debug); +#define GST_CAT_DEFAULT gst_xcam_src_debug + +#define GST_TYPE_XCAM_SRC_MEM_MODE (gst_xcam_src_mem_mode_get_type ()) +static GType +gst_xcam_src_mem_mode_get_type (void) +{ + static GType g_type = 0; + + if (!g_type) { + static const GEnumValue mem_types [] = { + {V4L2_MEMORY_MMAP, "memory map mode", "mmap"}, + {V4L2_MEMORY_USERPTR, "user pointer mode", "userptr"}, + {V4L2_MEMORY_OVERLAY, "overlay mode", "overlay"}, + {V4L2_MEMORY_DMABUF, "dmabuf mode", "dmabuf"}, + {0, NULL, NULL} + }; + g_type = g_enum_register_static ("GstXCamMemoryModeType", mem_types); + } + return g_type; +} + +#define GST_TYPE_XCAM_SRC_FIELD (gst_xcam_src_field_get_type ()) +static GType +gst_xcam_src_field_get_type (void) +{ + static GType g_type = 0; + + if (!g_type) { + static const GEnumValue field_types [] = { + {V4L2_FIELD_NONE, "no field", "none"}, + {V4L2_FIELD_TOP, "top field", "top"}, + {V4L2_FIELD_BOTTOM, "bottom field", "bottom"}, + {V4L2_FIELD_INTERLACED, "interlaced fields", "interlaced"}, + {V4L2_FIELD_SEQ_TB, "both fields sequential, top first", "seq-tb"}, + {V4L2_FIELD_SEQ_BT, "both fields sequential, bottom first", "seq-bt"}, + {V4L2_FIELD_ALTERNATE, "both fields alternating", "alternate"}, + {V4L2_FIELD_INTERLACED_TB, "interlaced fields, top first", "interlaced-tb"}, + {V4L2_FIELD_INTERLACED_BT, "interlaced fields, bottom first", "interlaced-bt"}, + {0, NULL, NULL} + }; + g_type = g_enum_register_static ("GstXCamSrcFieldType", field_types); + } + return g_type; +} + + +#define GST_TYPE_XCAM_SRC_IMAGE_PROCESSOR (gst_xcam_src_image_processor_get_type ()) +static GType +gst_xcam_src_image_processor_get_type (void) +{ + static GType g_type = 0; + static const GEnumValue image_processor_types[] = { +#if HAVE_IA_AIQ + {ISP_IMAGE_PROCESSOR, "ISP image processor", "isp"}, +#endif +#if HAVE_LIBCL + {CL_IMAGE_PROCESSOR, "CL image processor", "cl"}, +#endif + {0, NULL, NULL}, + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstXCamSrcImageProcessorType", image_processor_types); + g_once_init_leave (&g_type, type); + } + + return g_type; +} + +#define GST_TYPE_XCAM_SRC_ANALYZER (gst_xcam_src_analyzer_get_type ()) +static GType +gst_xcam_src_analyzer_get_type (void) +{ + static GType g_type = 0; + static const GEnumValue analyzer_types[] = { + {SIMPLE_ANALYZER, "simple 3A analyzer", "simple"}, +#if HAVE_IA_AIQ + {AIQ_TUNER_ANALYZER, "aiq 3A analyzer", "aiq"}, +#if HAVE_LIBCL + {DYNAMIC_ANALYZER, "dynamic load 3A analyzer", "dynamic"}, + {HYBRID_ANALYZER, "hybrid 3A analyzer", "hybrid"}, +#endif +#endif + {0, NULL, NULL}, + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstXCamSrcAnalyzerType", analyzer_types); + g_once_init_leave (&g_type, type); + } + + return g_type; +} + +#if HAVE_LIBCL +#define GST_TYPE_XCAM_SRC_WDR_MODE (gst_xcam_src_wdr_mode_get_type ()) +static GType +gst_xcam_src_wdr_mode_get_type (void) +{ + static GType g_type = 0; + static const GEnumValue wdr_mode_types[] = { + {NONE_WDR, "WDR disabled", "none"}, + {GAUSSIAN_WDR, "Gaussian WDR mode", "gaussian"}, + {HALEQ_WDR, "Haleq WDR mode", "haleq"}, + {0, NULL, NULL}, + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstXCamSrcWDRModeType", wdr_mode_types); + g_once_init_leave (&g_type, type); + } + + return g_type; +} + +#define GST_TYPE_XCAM_SRC_DEFOG_MODE (gst_xcam_src_defog_mode_get_type ()) +static GType +gst_xcam_src_defog_mode_get_type (void) +{ + static GType g_type = 0; + static const GEnumValue defog_mode_types [] = { + {DEFOG_NONE, "Defog disabled", "none"}, + {DEFOG_RETINEX, "Defog retinex", "retinex"}, + {DEFOG_DCP, "Defog dark channel prior", "dcp"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstXCamSrcDefogModeType", defog_mode_types); + g_once_init_leave (&g_type, type); + } + + return g_type; +} + +#define GST_TYPE_XCAM_SRC_3D_DENOISE_MODE (gst_xcam_src_3d_denoise_mode_get_type ()) +static GType +gst_xcam_src_3d_denoise_mode_get_type (void) +{ + static GType g_type = 0; + static const GEnumValue denoise_3d_mode_types [] = { + {DENOISE_3D_NONE, "3D Denoise disabled", "none"}, + {DENOISE_3D_YUV, "3D Denoise yuv", "yuv"}, + {DENOISE_3D_UV, "3D Denoise uv", "uv"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstXCamSrc3DDenoiseModeType", denoise_3d_mode_types); + g_once_init_leave (&g_type, type); + } + + return g_type; +} + +#define GST_TYPE_XCAM_SRC_WAVELET_MODE (gst_xcam_src_wavelet_mode_get_type ()) +static GType +gst_xcam_src_wavelet_mode_get_type (void) +{ + static GType g_type = 0; + static const GEnumValue wavelet_mode_types[] = { + {NONE_WAVELET, "Wavelet disabled", "none"}, + {HAT_WAVELET_Y, "Hat wavelet Y", "hat Y"}, + {HAT_WAVELET_UV, "Hat wavelet UV", "hat UV"}, + {HARR_WAVELET_Y, "Haar wavelet Y", "haar Y"}, + {HARR_WAVELET_UV, "Haar wavelet UV", "haar UV"}, + {HARR_WAVELET_YUV, "Haar wavelet YUV", "haar YUV"}, + {HARR_WAVELET_BAYES, "Haar wavelet bayes shrink", "haar Bayes"}, + {0, NULL, NULL}, + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstXCamSrcWaveletModeType", wavelet_mode_types); + g_once_init_leave (&g_type, type); + } + + return g_type; +} + + +#define GST_TYPE_XCAM_SRC_CL_PIPE_PROFILE (gst_xcam_src_cl_pipe_profile_get_type ()) +static GType +gst_xcam_src_cl_pipe_profile_get_type (void) +{ + static GType g_type = 0; + static const GEnumValue profile_types[] = { + {CL3aImageProcessor::BasicPipelineProfile, "cl basic pipe profile", "basic"}, + {CL3aImageProcessor::AdvancedPipelineProfile, "cl advanced pipe profile", "advanced"}, + {CL3aImageProcessor::ExtremePipelineProfile, "cl extreme pipe profile", "extreme"}, + {0, NULL, NULL}, + }; + + if (g_once_init_enter (&g_type)) { + const GType type = + g_enum_register_static ("GstXCamSrcCLPipeProfile", profile_types); + g_once_init_leave (&g_type, type); + } + + return g_type; +} +#endif + +enum { + PROP_0, + PROP_DEVICE, + PROP_SENSOR, + PROP_MEM_MODE, + PROP_BUFFERCOUNT, + PROP_FIELD, + PROP_IMAGE_PROCESSOR, + PROP_WDR_MODE, + PROP_3A_ANALYZER, + PROP_PIPE_PROFLE, + PROP_CPF, +#if HAVE_IA_AIQ + PROP_ENABLE_3A, + PROP_3A_LIB, +#endif + PROP_INPUT_FMT, + PROP_ENABLE_USB, + PROP_WAVELET_MODE, + PROP_DEFOG_MODE, + PROP_DENOISE_3D_MODE, + PROP_ENABLE_WIREFRAME, + PROP_ENABLE_IMAGE_WARP, + PROP_FAKE_INPUT +}; + +#if HAVE_IA_AIQ +static void gst_xcam_src_xcam_3a_interface_init (GstXCam3AInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (GstXCamSrc, gst_xcam_src, GST_TYPE_PUSH_SRC, + G_IMPLEMENT_INTERFACE (GST_TYPE_XCAM_3A_IF, + gst_xcam_src_xcam_3a_interface_init)); +#else +G_DEFINE_TYPE (GstXCamSrc, gst_xcam_src, GST_TYPE_PUSH_SRC); +#endif + +#define parent_class gst_xcam_src_parent_class + +static void gst_xcam_src_finalize (GObject * object); +static void gst_xcam_src_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_xcam_src_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); +static GstCaps* gst_xcam_src_get_caps (GstBaseSrc *src, GstCaps *filter); +static gboolean gst_xcam_src_set_caps (GstBaseSrc *src, GstCaps *caps); +static gboolean gst_xcam_src_decide_allocation (GstBaseSrc *src, GstQuery *query); +static gboolean gst_xcam_src_start (GstBaseSrc *src); +static gboolean gst_xcam_src_stop (GstBaseSrc *src); +static gboolean gst_xcam_src_unlock (GstBaseSrc *src); +static gboolean gst_xcam_src_unlock_stop (GstBaseSrc *src); +static GstFlowReturn gst_xcam_src_alloc (GstBaseSrc *src, guint64 offset, guint size, GstBuffer **buffer); +static GstFlowReturn gst_xcam_src_fill (GstPushSrc *src, GstBuffer *out); + +#if HAVE_IA_AIQ +/* GstXCamInterface implementation */ +static gboolean gst_xcam_src_set_white_balance_mode (GstXCam3A *xcam3a, XCamAwbMode mode); +static gboolean gst_xcam_src_set_awb_speed (GstXCam3A *xcam3a, double speed); +static gboolean gst_xcam_src_set_wb_color_temperature_range (GstXCam3A *xcam3a, guint cct_min, guint cct_max); +static gboolean gst_xcam_src_set_manual_wb_gain (GstXCam3A *xcam3a, double gr, double r, double b, double gb); +static gboolean gst_xcam_src_set_exposure_mode (GstXCam3A *xcam3a, XCamAeMode mode); +static gboolean gst_xcam_src_set_ae_metering_mode (GstXCam3A *xcam3a, XCamAeMeteringMode mode); +static gboolean gst_xcam_src_set_exposure_window (GstXCam3A *xcam3a, XCam3AWindow *window, guint8 count = 1); +static gboolean gst_xcam_src_set_exposure_value_offset (GstXCam3A *xcam3a, double ev_offset); +static gboolean gst_xcam_src_set_ae_speed (GstXCam3A *xcam3a, double speed); +static gboolean gst_xcam_src_set_exposure_flicker_mode (GstXCam3A *xcam3a, XCamFlickerMode flicker); +static XCamFlickerMode gst_xcam_src_get_exposure_flicker_mode (GstXCam3A *xcam3a); +static gint64 gst_xcam_src_get_current_exposure_time (GstXCam3A *xcam3a); +static double gst_xcam_src_get_current_analog_gain (GstXCam3A *xcam3a); +static gboolean gst_xcam_src_set_manual_exposure_time (GstXCam3A *xcam3a, gint64 time_in_us); +static gboolean gst_xcam_src_set_manual_analog_gain (GstXCam3A *xcam3a, double gain); +static gboolean gst_xcam_src_set_aperture (GstXCam3A *xcam3a, double fn); +static gboolean gst_xcam_src_set_max_analog_gain (GstXCam3A *xcam3a, double max_gain); +static double gst_xcam_src_get_max_analog_gain (GstXCam3A *xcam3a); +static gboolean gst_xcam_src_set_exposure_time_range (GstXCam3A *xcam3a, gint64 min_time_in_us, gint64 max_time_in_us); +static gboolean gst_xcam_src_get_exposure_time_range (GstXCam3A *xcam3a, gint64 *min_time_in_us, gint64 *max_time_in_us); +static gboolean gst_xcam_src_set_noise_reduction_level (GstXCam3A *xcam3a, guint8 level); +static gboolean gst_xcam_src_set_temporal_noise_reduction_level (GstXCam3A *xcam3a, guint8 level, gint8 mode); +static gboolean gst_xcam_src_set_gamma_table (GstXCam3A *xcam3a, double *r_table, double *g_table, double *b_table); +static gboolean gst_xcam_src_set_gbce (GstXCam3A *xcam3a, gboolean enable); +static gboolean gst_xcam_src_set_manual_brightness (GstXCam3A *xcam3a, guint8 value); +static gboolean gst_xcam_src_set_manual_contrast (GstXCam3A *xcam3a, guint8 value); +static gboolean gst_xcam_src_set_manual_hue (GstXCam3A *xcam3a, guint8 value); +static gboolean gst_xcam_src_set_manual_saturation (GstXCam3A *xcam3a, guint8 value); +static gboolean gst_xcam_src_set_manual_sharpness (GstXCam3A *xcam3a, guint8 value); +static gboolean gst_xcam_src_set_dvs (GstXCam3A *xcam3a, gboolean enable); +static gboolean gst_xcam_src_set_night_mode (GstXCam3A *xcam3a, gboolean enable); +static gboolean gst_xcam_src_set_hdr_mode (GstXCam3A *xcam3a, guint8 mode); +static gboolean gst_xcam_src_set_denoise_mode (GstXCam3A *xcam3a, guint32 mode); +static gboolean gst_xcam_src_set_gamma_mode (GstXCam3A *xcam3a, gboolean enable); +static gboolean gst_xcam_src_set_dpc_mode(GstXCam3A * xcam3a, gboolean enable); +#endif + +static gboolean gst_xcam_src_plugin_init (GstPlugin * xcamsrc); + +XCAM_END_DECLARE + +static void +gst_xcam_src_class_init (GstXCamSrcClass * class_self) +{ + GObjectClass *gobject_class; + GstElementClass *element_class; + GstBaseSrcClass *basesrc_class; + GstPushSrcClass *pushsrc_class; + + gobject_class = (GObjectClass *) class_self; + element_class = (GstElementClass *) class_self; + basesrc_class = GST_BASE_SRC_CLASS (class_self); + pushsrc_class = GST_PUSH_SRC_CLASS (class_self); + + GST_DEBUG_CATEGORY_INIT (gst_xcam_src_debug, "xcamsrc", 0, "libXCam source plugin"); + + gobject_class->finalize = gst_xcam_src_finalize; + gobject_class->set_property = gst_xcam_src_set_property; + gobject_class->get_property = gst_xcam_src_get_property; + + g_object_class_install_property ( + gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "device", "Device location", + NULL, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_SENSOR, + g_param_spec_int ("sensor-id", "sensor id", "Sensor ID to select", + 0, G_MAXINT, DEFAULT_PROP_SENSOR, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) )); + + g_object_class_install_property ( + gobject_class, PROP_MEM_MODE, + g_param_spec_enum ("io-mode", "memory mode", "Memory mode", + GST_TYPE_XCAM_SRC_MEM_MODE, DEFAULT_PROP_MEM_MODE, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_FIELD, + g_param_spec_enum ("field", "field", "field", + GST_TYPE_XCAM_SRC_FIELD, DEFAULT_PROP_FIELD, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_ENABLE_USB, + g_param_spec_boolean ("enable-usb", "enable usbcam", "Enable USB camera", + DEFAULT_PROP_ENABLE_USB, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_BUFFERCOUNT, + g_param_spec_int ("buffercount", "buffer count", "buffer count", + 0, G_MAXINT, DEFAULT_PROP_BUFFERCOUNT, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) )); + + g_object_class_install_property ( + gobject_class, PROP_INPUT_FMT, + g_param_spec_string ("input-format", "input format", "Input pixel format", + NULL, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_FAKE_INPUT, + g_param_spec_string ("fake-input", "fake input", "Use the specified raw file as fake input instead of live camera", + NULL, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_IMAGE_PROCESSOR, + g_param_spec_enum ("imageprocessor", "image processor", "Image Processor", + GST_TYPE_XCAM_SRC_IMAGE_PROCESSOR, DEFAULT_PROP_IMAGE_PROCESSOR, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_3A_ANALYZER, + g_param_spec_enum ("analyzer", "3a analyzer", "3A Analyzer", + GST_TYPE_XCAM_SRC_ANALYZER, DEFAULT_PROP_ANALYZER, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + +#if HAVE_IA_AIQ + g_object_class_install_property ( + gobject_class, PROP_ENABLE_3A, + g_param_spec_boolean ("enable-3a", "enable 3a", "Enable 3A", + DEFAULT_PROP_ENABLE_3A, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_CPF, + g_param_spec_string ("path-cpf", "cpf", "Path to cpf", + NULL, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_3A_LIB, + g_param_spec_string ("path-3alib", "3a lib", "Path to dynamic 3A library", + NULL, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); +#endif + +#if HAVE_LIBCL + g_object_class_install_property ( + gobject_class, PROP_PIPE_PROFLE, + g_param_spec_enum ("pipe-profile", "cl pipe profile", "CL pipeline profile (only for cl imageprocessor)", + GST_TYPE_XCAM_SRC_CL_PIPE_PROFILE, DEFAULT_PROP_CL_PIPE_PROFILE, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_DENOISE_3D_MODE, + g_param_spec_enum ("denoise-3d", "3D Denoise mode", "3D Denoise mode", + GST_TYPE_XCAM_SRC_3D_DENOISE_MODE, DEFAULT_PROP_3D_DENOISE_MODE, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_WDR_MODE, + g_param_spec_enum ("wdr-mode", "wdr mode", "WDR Mode", + GST_TYPE_XCAM_SRC_WDR_MODE, DEFAULT_PROP_WDR_MODE, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_WAVELET_MODE, + g_param_spec_enum ("wavelet-mode", "wavelet mode", "WAVELET Mode", + GST_TYPE_XCAM_SRC_WAVELET_MODE, DEFAULT_PROP_WAVELET_MODE, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_DEFOG_MODE, + g_param_spec_enum ("defog-mode", "defog mode", "Defog mode", + GST_TYPE_XCAM_SRC_DEFOG_MODE, DEFAULT_PROP_DEFOG_MODE, + (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_ENABLE_WIREFRAME, + g_param_spec_boolean ("enable-wireframe", "enable wire frame", "Enable wire frame", + DEFAULT_PROP_ENABLE_WIREFRAME, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property ( + gobject_class, PROP_ENABLE_IMAGE_WARP, + g_param_spec_boolean ("enable-warp", "enable image warp", "Enable Image Warp", + DEFAULT_PROP_ENABLE_IMAGE_WARP, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); +#endif + + gst_element_class_set_details_simple (element_class, + "Libxcam Source", + "Source/Base", + "Capture camera video using xcam library", + "John Ye <john.ye@intel.com> & Wind Yuan <feng.yuan@intel.com>"); + + gst_element_class_add_pad_template ( + element_class, + gst_static_pad_template_get (&gst_xcam_src_factory)); + + basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_xcam_src_get_caps); + basesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_xcam_src_set_caps); + basesrc_class->decide_allocation = GST_DEBUG_FUNCPTR (gst_xcam_src_decide_allocation); + + basesrc_class->start = GST_DEBUG_FUNCPTR (gst_xcam_src_start); + basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_xcam_src_stop); + basesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_xcam_src_unlock); + basesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_xcam_src_unlock_stop); + basesrc_class->alloc = GST_DEBUG_FUNCPTR (gst_xcam_src_alloc); + pushsrc_class->fill = GST_DEBUG_FUNCPTR (gst_xcam_src_fill); +} + +// FIXME remove this function? +static void +gst_xcam_src_init (GstXCamSrc *xcamsrc) +{ + gst_base_src_set_format (GST_BASE_SRC (xcamsrc), GST_FORMAT_TIME); + gst_base_src_set_live (GST_BASE_SRC (xcamsrc), TRUE); + gst_base_src_set_do_timestamp (GST_BASE_SRC (xcamsrc), TRUE); + + xcamsrc->buf_count = DEFAULT_PROP_BUFFERCOUNT; + xcamsrc->sensor_id = 0; + xcamsrc->capture_mode = V4L2_CAPTURE_MODE_VIDEO; + xcamsrc->device = NULL; + xcamsrc->enable_usb = DEFAULT_PROP_ENABLE_USB; + +#if HAVE_IA_AIQ + xcamsrc->enable_3a = DEFAULT_PROP_ENABLE_3A; + xcamsrc->path_to_cpf = strndup(DEFAULT_CPF_FILE_NAME, XCAM_MAX_STR_SIZE); + xcamsrc->path_to_3alib = strndup(DEFAULT_DYNAMIC_3A_LIB, XCAM_MAX_STR_SIZE); +#endif + +#if HAVE_LIBCL + xcamsrc->cl_pipe_profile = DEFAULT_PROP_CL_PIPE_PROFILE; + xcamsrc->wdr_mode_type = DEFAULT_PROP_WDR_MODE; + xcamsrc->wavelet_mode = NONE_WAVELET; + xcamsrc->defog_mode = DEFAULT_PROP_DEFOG_MODE; + xcamsrc->denoise_3d_mode = DEFAULT_PROP_3D_DENOISE_MODE; + xcamsrc->denoise_3d_ref_count = 2; + xcamsrc->enable_wireframe = DEFAULT_PROP_ENABLE_WIREFRAME; +#endif + + xcamsrc->path_to_fake = NULL; + xcamsrc->time_offset_ready = FALSE; + xcamsrc->time_offset = -1; + xcamsrc->buf_mark = 0; + xcamsrc->duration = 0; + xcamsrc->mem_type = DEFAULT_PROP_MEM_MODE; + xcamsrc->field = DEFAULT_PROP_FIELD; + + xcamsrc->in_format = 0; + if (xcamsrc->enable_usb) { + xcamsrc->out_format = GST_VIDEO_FORMAT_YUY2; + } + else { + xcamsrc->out_format = DEFAULT_PROP_PIXELFORMAT; + } + + gst_video_info_init (&xcamsrc->gst_video_info); + if (xcamsrc->enable_usb) { + gst_video_info_set_format (&xcamsrc->gst_video_info, GST_VIDEO_FORMAT_YUY2, DEFAULT_VIDEO_WIDTH, DEFAULT_VIDEO_HEIGHT); + } + else { + gst_video_info_set_format (&xcamsrc->gst_video_info, GST_VIDEO_FORMAT_NV12, DEFAULT_VIDEO_WIDTH, DEFAULT_VIDEO_HEIGHT); + } + + XCAM_CONSTRUCTOR (xcamsrc->xcam_video_info, VideoBufferInfo); + xcamsrc->xcam_video_info.init (DEFAULT_PROP_PIXELFORMAT, DEFAULT_VIDEO_WIDTH, DEFAULT_VIDEO_HEIGHT); + xcamsrc->image_processor_type = DEFAULT_PROP_IMAGE_PROCESSOR; + xcamsrc->analyzer_type = DEFAULT_PROP_ANALYZER; + XCAM_CONSTRUCTOR (xcamsrc->device_manager, SmartPtr<MainDeviceManager>); + xcamsrc->device_manager = new MainDeviceManager; +} + +static void +gst_xcam_src_finalize (GObject * object) +{ + GstXCamSrc *xcamsrc = GST_XCAM_SRC (object); + + xcamsrc->device_manager.release (); + XCAM_DESTRUCTOR (xcamsrc->device_manager, SmartPtr<MainDeviceManager>); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_xcam_src_get_property ( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GstXCamSrc *src = GST_XCAM_SRC (object); + + switch (prop_id) { + case PROP_DEVICE: + g_value_set_string (value, src->device); + break; + case PROP_SENSOR: + g_value_set_int (value, src->sensor_id); + break; + case PROP_MEM_MODE: + g_value_set_enum (value, src->mem_type); + break; + case PROP_FIELD: + g_value_set_enum (value, src->field); + break; + case PROP_BUFFERCOUNT: + g_value_set_int (value, src->buf_count); + break; + case PROP_INPUT_FMT: + g_value_set_string (value, xcam_fourcc_to_string (src->in_format)); + break; + case PROP_ENABLE_USB: + g_value_set_boolean (value, src->enable_usb); + break; + case PROP_FAKE_INPUT: + g_value_set_string (value, src->path_to_fake); + break; + case PROP_IMAGE_PROCESSOR: + g_value_set_enum (value, src->image_processor_type); + break; + case PROP_3A_ANALYZER: + g_value_set_enum (value, src->analyzer_type); + break; + +#if HAVE_IA_AIQ + case PROP_ENABLE_3A: + g_value_set_boolean (value, src->enable_3a); + break; + case PROP_CPF: + g_value_set_string (value, src->path_to_cpf); + break; + case PROP_3A_LIB: + g_value_set_string (value, src->path_to_3alib); + break; +#endif + +#if HAVE_LIBCL + case PROP_PIPE_PROFLE: + g_value_set_enum (value, src->cl_pipe_profile); + break; + case PROP_DENOISE_3D_MODE: + g_value_set_enum (value, src->denoise_3d_mode); + break; + case PROP_WDR_MODE: + g_value_set_enum (value, src->wdr_mode_type); + break; + case PROP_WAVELET_MODE: + g_value_set_enum (value, src->wavelet_mode); + break; + case PROP_DEFOG_MODE: + g_value_set_enum (value, src->defog_mode); + break; + case PROP_ENABLE_WIREFRAME: + g_value_set_boolean (value, src->enable_wireframe); + break; + case PROP_ENABLE_IMAGE_WARP: + g_value_set_boolean (value, src->enable_image_warp); + break; +#endif + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_xcam_src_set_property ( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GstXCamSrc *src = GST_XCAM_SRC (object); + + switch (prop_id) { + case PROP_DEVICE: { + const char * device = g_value_get_string (value); + if (src->device) + xcam_free (src->device); + src->device = NULL; + if (device) + src->device = strndup (device, XCAM_MAX_STR_SIZE); + break; + } + case PROP_SENSOR: + src->sensor_id = g_value_get_int (value); + break; + case PROP_MEM_MODE: + src->mem_type = (enum v4l2_memory)g_value_get_enum (value); + break; + case PROP_BUFFERCOUNT: + src->buf_count = g_value_get_int (value); + break; + case PROP_FIELD: + src->field = (enum v4l2_field) g_value_get_enum (value); + break; + case PROP_INPUT_FMT: { + const char * fmt = g_value_get_string (value); + if (strlen (fmt) == 4) + src->in_format = v4l2_fourcc ((unsigned)fmt[0], + (unsigned)fmt[1], + (unsigned)fmt[2], + (unsigned)fmt[3]); + else + GST_ERROR_OBJECT (src, "Invalid input format: not fourcc"); + break; + } + case PROP_ENABLE_USB: + src->enable_usb = g_value_get_boolean (value); + break; + case PROP_FAKE_INPUT: { + const char * raw_path = g_value_get_string (value); + if (src->path_to_fake) + xcam_free (src->path_to_fake); + src->path_to_fake = NULL; + if (raw_path) + src->path_to_fake = strndup (raw_path, XCAM_MAX_STR_SIZE); + break; + } + case PROP_IMAGE_PROCESSOR: + src->image_processor_type = (ImageProcessorType)g_value_get_enum (value); + if (src->image_processor_type == ISP_IMAGE_PROCESSOR) { + src->capture_mode = V4L2_CAPTURE_MODE_VIDEO; + } +#if HAVE_LIBCL + else if (src->image_processor_type == CL_IMAGE_PROCESSOR) { + src->capture_mode = V4L2_CAPTURE_MODE_STILL; + } +#else + else { + XCAM_LOG_WARNING ("this release only supports ISP image processor"); + src->image_processor_type = ISP_IMAGE_PROCESSOR; + src->capture_mode = V4L2_CAPTURE_MODE_VIDEO; + } +#endif + break; + case PROP_3A_ANALYZER: + src->analyzer_type = (AnalyzerType)g_value_get_enum (value); + break; + +#if HAVE_IA_AIQ + case PROP_ENABLE_3A: + src->enable_3a = g_value_get_boolean (value); + break; + case PROP_CPF: { + const char * cpf = g_value_get_string (value); + if (src->path_to_cpf) + xcam_free (src->path_to_cpf); + src->path_to_cpf = NULL; + if (cpf) + src->path_to_cpf = strndup (cpf, XCAM_MAX_STR_SIZE); + break; + } + case PROP_3A_LIB: { + const char * path = g_value_get_string (value); + if (src->path_to_3alib) + xcam_free (src->path_to_3alib); + src->path_to_3alib = NULL; + if (path) + src->path_to_3alib = strndup (path, XCAM_MAX_STR_SIZE); + break; + } +#endif + +#if HAVE_LIBCL + case PROP_PIPE_PROFLE: + src->cl_pipe_profile = g_value_get_enum (value); + break; + case PROP_DENOISE_3D_MODE: + src->denoise_3d_mode = (Denoise3DModeType) g_value_get_enum (value); + break; + case PROP_WDR_MODE: + src->wdr_mode_type = (WDRModeType)g_value_get_enum (value); + break; + case PROP_WAVELET_MODE: + src->wavelet_mode = (WaveletModeType)g_value_get_enum (value); + break; + case PROP_DEFOG_MODE: + src->defog_mode = (DefogModeType) g_value_get_enum (value); + break; + case PROP_ENABLE_WIREFRAME: + src->enable_wireframe = g_value_get_boolean (value); + break; + case PROP_ENABLE_IMAGE_WARP: + src->enable_image_warp = g_value_get_boolean (value); + break; +#endif + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +#if HAVE_IA_AIQ +static void +gst_xcam_src_xcam_3a_interface_init (GstXCam3AInterface *iface) +{ + iface->set_white_balance_mode = gst_xcam_src_set_white_balance_mode; + iface->set_awb_speed = gst_xcam_src_set_awb_speed; + + iface->set_wb_color_temperature_range = gst_xcam_src_set_wb_color_temperature_range; + iface->set_manual_wb_gain = gst_xcam_src_set_manual_wb_gain; + + iface->set_exposure_mode = gst_xcam_src_set_exposure_mode; + iface->set_ae_metering_mode = gst_xcam_src_set_ae_metering_mode; + iface->set_exposure_window = gst_xcam_src_set_exposure_window; + iface->set_exposure_value_offset = gst_xcam_src_set_exposure_value_offset; + iface->set_ae_speed = gst_xcam_src_set_ae_speed; + + iface->set_exposure_flicker_mode = gst_xcam_src_set_exposure_flicker_mode; + iface->get_exposure_flicker_mode = gst_xcam_src_get_exposure_flicker_mode; + iface->get_current_exposure_time = gst_xcam_src_get_current_exposure_time; + iface->get_current_analog_gain = gst_xcam_src_get_current_analog_gain; + iface->set_manual_exposure_time = gst_xcam_src_set_manual_exposure_time; + iface->set_manual_analog_gain = gst_xcam_src_set_manual_analog_gain; + iface->set_aperture = gst_xcam_src_set_aperture; + iface->set_max_analog_gain = gst_xcam_src_set_max_analog_gain; + iface->get_max_analog_gain = gst_xcam_src_get_max_analog_gain; + iface->set_exposure_time_range = gst_xcam_src_set_exposure_time_range; + iface->get_exposure_time_range = gst_xcam_src_get_exposure_time_range; + iface->set_dvs = gst_xcam_src_set_dvs; + iface->set_noise_reduction_level = gst_xcam_src_set_noise_reduction_level; + iface->set_temporal_noise_reduction_level = gst_xcam_src_set_temporal_noise_reduction_level; + iface->set_gamma_table = gst_xcam_src_set_gamma_table; + iface->set_gbce = gst_xcam_src_set_gbce; + iface->set_manual_brightness = gst_xcam_src_set_manual_brightness; + iface->set_manual_contrast = gst_xcam_src_set_manual_contrast; + iface->set_manual_hue = gst_xcam_src_set_manual_hue; + iface->set_manual_saturation = gst_xcam_src_set_manual_saturation; + iface->set_manual_sharpness = gst_xcam_src_set_manual_sharpness; + iface->set_night_mode = gst_xcam_src_set_night_mode; + iface->set_hdr_mode = gst_xcam_src_set_hdr_mode; + iface->set_denoise_mode = gst_xcam_src_set_denoise_mode; + iface->set_gamma_mode = gst_xcam_src_set_gamma_mode; + iface->set_dpc_mode = gst_xcam_src_set_dpc_mode; +} +#endif + +static gboolean +gst_xcam_src_start (GstBaseSrc *src) +{ + GstXCamSrc *xcamsrc = GST_XCAM_SRC (src); + SmartPtr<MainDeviceManager> device_manager = xcamsrc->device_manager; + SmartPtr<X3aAnalyzer> analyzer; +#if HAVE_IA_AIQ + SmartPtr<ImageProcessor> isp_processor; + SmartPtr<IspController> isp_controller; +#endif +#if HAVE_LIBCL + SmartPtr<SmartAnalyzer> smart_analyzer; + SmartPtr<CL3aImageProcessor> cl_processor; + SmartPtr<CLPostImageProcessor> cl_post_processor; +#endif + SmartPtr<V4l2Device> capture_device; + SmartPtr<V4l2SubDevice> event_device; + SmartPtr<PollThread> poll_thread; + + // Check device + if (xcamsrc->device == NULL) { + if (xcamsrc->capture_mode == V4L2_CAPTURE_MODE_STILL) + xcamsrc->device = strndup (CAPTURE_DEVICE_STILL, XCAM_MAX_STR_SIZE); + else + xcamsrc->device = strndup (CAPTURE_DEVICE_VIDEO, XCAM_MAX_STR_SIZE); + } + XCAM_ASSERT (xcamsrc->device); + + // set default input format if set prop wasn't called + if (xcamsrc->in_format == 0) { + if (xcamsrc->image_processor_type == CL_IMAGE_PROCESSOR) + xcamsrc->in_format = V4L2_PIX_FMT_SGRBG10; + else if (xcamsrc->enable_usb) + xcamsrc->in_format = V4L2_PIX_FMT_YUYV; + else + xcamsrc->in_format = V4L2_PIX_FMT_NV12; + } + + if (xcamsrc->path_to_fake) { + capture_device = new FakeV4l2Device (); + } else if (xcamsrc->enable_usb) { + capture_device = new UVCDevice (xcamsrc->device); + } +#if HAVE_IA_AIQ + else { + capture_device = new AtomispDevice (xcamsrc->device); + } +#endif + + capture_device->set_sensor_id (xcamsrc->sensor_id); + capture_device->set_capture_mode (xcamsrc->capture_mode); + capture_device->set_mem_type (xcamsrc->mem_type); + capture_device->set_buffer_count (xcamsrc->buf_count); + capture_device->open (); + device_manager->set_capture_device (capture_device); + +#if HAVE_IA_AIQ + if (!xcamsrc->enable_usb && !xcamsrc->path_to_fake) { + event_device = new V4l2SubDevice (DEFAULT_EVENT_DEVICE); + XCamReturn ret = event_device->open (); + if (ret == XCAM_RETURN_NO_ERROR) { + event_device->subscribe_event (V4L2_EVENT_ATOMISP_3A_STATS_READY); + device_manager->set_event_device (event_device); + } + } + + isp_controller = new IspController (capture_device); +#endif + + switch (xcamsrc->image_processor_type) { +#if HAVE_LIBCL + case CL_IMAGE_PROCESSOR: { +#if HAVE_IA_AIQ + isp_processor = new IspExposureImageProcessor (isp_controller); + XCAM_ASSERT (isp_processor.ptr ()); + device_manager->add_image_processor (isp_processor); +#endif + cl_processor = new CL3aImageProcessor (); + cl_processor->set_stats_callback (device_manager); + if(xcamsrc->wdr_mode_type != NONE_WDR) + { + cl_processor->set_gamma (false); + xcamsrc->in_format = V4L2_PIX_FMT_SGRBG12; + cl_processor->set_3a_stats_bits(12); + setenv ("AIQ_CPF_PATH", "/etc/atomisp/imx185_wdr.cpf", 1); + + if(xcamsrc->wdr_mode_type == GAUSSIAN_WDR) + { + cl_processor->set_tonemapping(CL3aImageProcessor::CLTonemappingMode::Gaussian); + } + else if(xcamsrc->wdr_mode_type == HALEQ_WDR) + { + cl_processor->set_tonemapping(CL3aImageProcessor::CLTonemappingMode::Haleq); + } + } + + cl_processor->set_profile ((CL3aImageProcessor::PipelineProfile)xcamsrc->cl_pipe_profile); + device_manager->add_image_processor (cl_processor); + device_manager->set_cl_image_processor (cl_processor); + break; + } +#endif +#if HAVE_IA_AIQ + case ISP_IMAGE_PROCESSOR: { + isp_processor = new IspImageProcessor (isp_controller); + device_manager->add_image_processor (isp_processor); + break; + } +#endif + default: + XCAM_LOG_ERROR ("unknown image processor type"); + return false; + } + +#if HAVE_LIBCL + cl_post_processor = new CLPostImageProcessor (); + + cl_post_processor->set_stats_callback (device_manager); + cl_post_processor->set_defog_mode ((CLPostImageProcessor::CLDefogMode) xcamsrc->defog_mode); + cl_post_processor->set_3ddenoise_mode ( + (CLPostImageProcessor::CL3DDenoiseMode) xcamsrc->denoise_3d_mode, xcamsrc->denoise_3d_ref_count); + + if (NONE_WAVELET != xcamsrc->wavelet_mode) { + if (HAT_WAVELET_Y == xcamsrc->wavelet_mode) { + cl_post_processor->set_wavelet (CL_WAVELET_HAT, CL_IMAGE_CHANNEL_Y, false); + } else if (HAT_WAVELET_UV == xcamsrc->wavelet_mode) { + cl_post_processor->set_wavelet (CL_WAVELET_HAT, CL_IMAGE_CHANNEL_UV, false); + } else if (HARR_WAVELET_Y == xcamsrc->wavelet_mode) { + cl_post_processor->set_wavelet (CL_WAVELET_HAAR, CL_IMAGE_CHANNEL_Y, false); + } else if (HARR_WAVELET_UV == xcamsrc->wavelet_mode) { + cl_post_processor->set_wavelet (CL_WAVELET_HAAR, CL_IMAGE_CHANNEL_UV, false); + } else if (HARR_WAVELET_YUV == xcamsrc->wavelet_mode) { + cl_post_processor->set_wavelet (CL_WAVELET_HAAR, CL_IMAGE_CHANNEL_UV | CL_IMAGE_CHANNEL_Y, false); + } else if (HARR_WAVELET_BAYES == xcamsrc->wavelet_mode) { + cl_post_processor->set_wavelet (CL_WAVELET_HAAR, CL_IMAGE_CHANNEL_UV | CL_IMAGE_CHANNEL_Y, true); + } else { + cl_post_processor->set_wavelet (CL_WAVELET_DISABLED, CL_IMAGE_CHANNEL_UV, false); + } + } + + cl_post_processor->set_wireframe (xcamsrc->enable_wireframe); + + device_manager->add_image_processor (cl_post_processor); + device_manager->set_cl_post_image_processor (cl_post_processor); +#endif + + switch (xcamsrc->analyzer_type) { + case SIMPLE_ANALYZER: { + analyzer = new X3aAnalyzerSimple (); + break; + } +#if HAVE_IA_AIQ + case AIQ_TUNER_ANALYZER: { + XCAM_LOG_INFO ("cpf: %s", xcamsrc->path_to_cpf); + SmartPtr<X3aAnalyzer> aiq_analyzer = new X3aAnalyzerAiq (isp_controller, xcamsrc->path_to_cpf); + SmartPtr<X3aAnalyzeTuner> tuner_analyzer = new X3aAnalyzeTuner (); + XCAM_ASSERT (aiq_analyzer.ptr () && tuner_analyzer.ptr ()); + tuner_analyzer->set_analyzer (aiq_analyzer); + analyzer = tuner_analyzer; + break; + } +#if HAVE_LIBCL + case DYNAMIC_ANALYZER: { + XCAM_LOG_INFO ("dynamic 3a library: %s", xcamsrc->path_to_3alib); + SmartPtr<DynamicAnalyzerLoader> dynamic_loader = new DynamicAnalyzerLoader (xcamsrc->path_to_3alib); + SmartPtr<AnalyzerLoader> loader = dynamic_loader.dynamic_cast_ptr<AnalyzerLoader> (); + analyzer = dynamic_loader->load_analyzer (loader); + if (!analyzer.ptr ()) { + XCAM_LOG_ERROR ("load dynamic analyzer(%s) failed, please check.", xcamsrc->path_to_3alib); + return FALSE; + } + break; + } + case HYBRID_ANALYZER: { + XCAM_LOG_INFO ("hybrid 3a library: %s", xcamsrc->path_to_3alib); + SmartPtr<HybridAnalyzerLoader> hybrid_loader = new HybridAnalyzerLoader (xcamsrc->path_to_3alib); + hybrid_loader->set_cpf_path (DEFAULT_CPF_FILE_NAME); + hybrid_loader->set_isp_controller (isp_controller); + SmartPtr<AnalyzerLoader> loader = hybrid_loader.dynamic_cast_ptr<AnalyzerLoader> (); + analyzer = hybrid_loader->load_analyzer (loader); + if (!analyzer.ptr ()) { + XCAM_LOG_ERROR ("load hybrid analyzer(%s) failed, please check.", xcamsrc->path_to_3alib); + return FALSE; + } + break; + } +#endif +#endif + default: + XCAM_LOG_ERROR ("unknown analyzer type"); + return false; + } + + XCAM_ASSERT (analyzer.ptr ()); + if (analyzer->prepare_handlers () != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("analyzer(%s) prepare handlers failed", analyzer->get_name ()); + return FALSE; + } + + if(xcamsrc->wdr_mode_type != NONE_WDR) + { + analyzer->set_ae_exposure_time_range (80 * 1110 * 1000 / 37125, 1120 * 1110 * 1000 / 37125); + analyzer->set_ae_max_analog_gain (3.98); + } + device_manager->set_3a_analyzer (analyzer); + +#if HAVE_LIBCL + SmartHandlerList smart_handlers = SmartAnalyzerLoader::load_smart_handlers (DEFAULT_SMART_ANALYSIS_LIB_DIR); + if (!smart_handlers.empty ()) { + smart_analyzer = new SmartAnalyzer (); + if (smart_analyzer.ptr ()) { + SmartHandlerList::iterator i_handler = smart_handlers.begin (); + for (; i_handler != smart_handlers.end (); ++i_handler) + { + XCAM_ASSERT ((*i_handler).ptr ()); + smart_analyzer->add_handler (*i_handler); + } + } else { + XCAM_LOG_WARNING ("load smart analyzer(%s) failed, please check.", DEFAULT_SMART_ANALYSIS_LIB_DIR); + } + } + + if (smart_analyzer.ptr ()) { + if (cl_post_processor.ptr () && xcamsrc->enable_wireframe) { + cl_post_processor->set_scaler (true); + cl_post_processor->set_scaler_factor (640.0 / DEFAULT_VIDEO_WIDTH); + } + if (smart_analyzer->prepare_handlers () != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_INFO ("analyzer(%s) prepare handlers failed", smart_analyzer->get_name ()); + return TRUE; + } + device_manager->set_smart_analyzer (smart_analyzer); + } +#endif + + if (xcamsrc->enable_usb) { + poll_thread = new PollThread (); + } else if (xcamsrc->path_to_fake) { + poll_thread = new FakePollThread (xcamsrc->path_to_fake); + } +#if HAVE_IA_AIQ + else { + SmartPtr<IspPollThread> isp_poll_thread = new IspPollThread (); + isp_poll_thread->set_isp_controller (isp_controller); + poll_thread = isp_poll_thread; + } +#endif + device_manager->set_poll_thread (poll_thread); + + return TRUE; +} + +static gboolean +gst_xcam_src_stop (GstBaseSrc *src) +{ + SmartPtr<V4l2SubDevice> event_device; + GstXCamSrc *xcamsrc = GST_XCAM_SRC_CAST (src); + SmartPtr<MainDeviceManager> device_manager = xcamsrc->device_manager; + XCAM_ASSERT (device_manager.ptr ()); + + device_manager->stop(); + device_manager->get_capture_device()->close (); + + event_device = device_manager->get_event_device(); + // For USB camera case, the event_device ptr will be NULL + if (event_device.ptr()) + event_device->close (); + + device_manager->pause_dequeue (); + return TRUE; +} + +static gboolean +gst_xcam_src_unlock (GstBaseSrc *src) +{ + GstXCamSrc *xcamsrc = GST_XCAM_SRC_CAST (src); + SmartPtr<MainDeviceManager> device_manager = xcamsrc->device_manager; + XCAM_ASSERT (device_manager.ptr ()); + + device_manager->pause_dequeue (); + return TRUE; +} + +static gboolean +gst_xcam_src_unlock_stop (GstBaseSrc *src) +{ + GstXCamSrc *xcamsrc = GST_XCAM_SRC_CAST (src); + SmartPtr<MainDeviceManager> device_manager = xcamsrc->device_manager; + XCAM_ASSERT (device_manager.ptr ()); + + device_manager->resume_dequeue (); + return TRUE; +} + +static GstCaps* +gst_xcam_src_get_caps (GstBaseSrc *src, GstCaps *filter) +{ + GstXCamSrc *xcamsrc = GST_XCAM_SRC (src); + XCAM_UNUSED (filter); + + return gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (xcamsrc)); +} + +static uint32_t +translate_format_to_xcam (GstVideoFormat format) +{ + switch (format) { + case GST_VIDEO_FORMAT_NV12: + return V4L2_PIX_FMT_NV12; + case GST_VIDEO_FORMAT_I420: + return V4L2_PIX_FMT_YUV420; + case GST_VIDEO_FORMAT_YUY2: + return V4L2_PIX_FMT_YUYV; + case GST_VIDEO_FORMAT_Y42B: + return V4L2_PIX_FMT_YUV422P; + + //RGB + case GST_VIDEO_FORMAT_RGBx: + return V4L2_PIX_FMT_RGB32; + case GST_VIDEO_FORMAT_BGRx: + return V4L2_PIX_FMT_BGR32; + default: + break; + } + return 0; +} + +static gboolean +gst_xcam_src_set_caps (GstBaseSrc *src, GstCaps *caps) +{ + GstXCamSrc *xcamsrc = GST_XCAM_SRC (src); + struct v4l2_format format; + uint32_t out_format = 0; + GstVideoInfo info; + + gst_video_info_from_caps (&info, caps); + XCAM_ASSERT ((GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_NV12) || + (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_YUY2)); + + out_format = translate_format_to_xcam (GST_VIDEO_INFO_FORMAT (&info)); + if (!out_format) { + GST_WARNING ("format doesn't support:%s", GST_VIDEO_INFO_NAME (&info)); + return FALSE; + } +#if HAVE_LIBCL + SmartPtr<CLPostImageProcessor> processor = xcamsrc->device_manager->get_cl_post_image_processor (); + XCAM_ASSERT (processor.ptr ()); + if (!processor->set_output_format (out_format)) { + GST_ERROR ("pipeline doesn't support output format:%" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (out_format)); + return FALSE; + } +#endif + + xcamsrc->out_format = out_format; + + SmartPtr<MainDeviceManager> device_manager = xcamsrc->device_manager; + SmartPtr<V4l2Device> capture_device = device_manager->get_capture_device (); + capture_device->set_framerate (GST_VIDEO_INFO_FPS_N (&info), GST_VIDEO_INFO_FPS_D (&info)); + capture_device->set_format ( + GST_VIDEO_INFO_WIDTH (&info), + GST_VIDEO_INFO_HEIGHT(&info), + xcamsrc->in_format, + xcamsrc->field, + info.stride [0]); + + if (device_manager->start () != XCAM_RETURN_NO_ERROR) + return FALSE; + + capture_device->get_format (format); + xcamsrc->gst_video_info = info; + size_t offset = 0; + for (uint32_t n = 0; n < GST_VIDEO_INFO_N_PLANES (&xcamsrc->gst_video_info); n++) { + GST_VIDEO_INFO_PLANE_OFFSET (&xcamsrc->gst_video_info, n) = offset; + if (out_format == V4L2_PIX_FMT_NV12) { + GST_VIDEO_INFO_PLANE_STRIDE (&xcamsrc->gst_video_info, n) = format.fmt.pix.bytesperline * 2 / 3; + } + else if (format.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) { + // for 4:2:2 format, stride is widthx2 + GST_VIDEO_INFO_PLANE_STRIDE (&xcamsrc->gst_video_info, n) = format.fmt.pix.bytesperline; + } + else { + GST_VIDEO_INFO_PLANE_STRIDE (&xcamsrc->gst_video_info, n) = format.fmt.pix.bytesperline / 2; + } + offset += GST_VIDEO_INFO_PLANE_STRIDE (&xcamsrc->gst_video_info, n) * format.fmt.pix.height; + //TODO, need set offsets + } + + // TODO, need calculate aligned width/height + xcamsrc->xcam_video_info.init (out_format, GST_VIDEO_INFO_WIDTH (&info), GST_VIDEO_INFO_HEIGHT (&info)); + + xcamsrc->duration = gst_util_uint64_scale_int ( + GST_SECOND, + GST_VIDEO_INFO_FPS_D(&xcamsrc->gst_video_info), + GST_VIDEO_INFO_FPS_N(&xcamsrc->gst_video_info)); + xcamsrc->pool = gst_xcam_buffer_pool_new (xcamsrc, caps, xcamsrc->device_manager); + + return TRUE; +} + +static gboolean +gst_xcam_src_decide_allocation (GstBaseSrc *src, GstQuery *query) +{ + GstXCamSrc *xcamsrc = GST_XCAM_SRC (src); + GstBufferPool *pool = NULL; + uint32_t pool_num = 0; + + XCAM_ASSERT (xcamsrc); + XCAM_ASSERT (xcamsrc->pool); + + pool_num = gst_query_get_n_allocation_pools (query); + if (pool_num > 0) { + for (uint32_t i = pool_num - 1; i > 0; --i) { + gst_query_remove_nth_allocation_pool (query, i); + } + gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL); + if (pool == xcamsrc->pool) + return TRUE; + gst_object_unref (pool); + gst_query_remove_nth_allocation_pool (query, 0); + } + + gst_query_add_allocation_pool ( + query, xcamsrc->pool, + GST_VIDEO_INFO_WIDTH (&xcamsrc->gst_video_info), + GST_XCAM_SRC_BUF_COUNT (xcamsrc), + GST_XCAM_SRC_BUF_COUNT (xcamsrc)); + + return GST_BASE_SRC_CLASS (parent_class)->decide_allocation (src, query); +} + +static GstFlowReturn +gst_xcam_src_alloc (GstBaseSrc *src, guint64 offset, guint size, GstBuffer **buffer) +{ + GstFlowReturn ret; + GstXCamSrc *xcamsrc = GST_XCAM_SRC (src); + + XCAM_UNUSED (offset); + XCAM_UNUSED (size); + + ret = gst_buffer_pool_acquire_buffer (xcamsrc->pool, buffer, NULL); + XCAM_ASSERT (*buffer); + return ret; +} + +static GstFlowReturn +gst_xcam_src_fill (GstPushSrc *basesrc, GstBuffer *buf) +{ + GstXCamSrc *src = GST_XCAM_SRC_CAST (basesrc); + + GST_BUFFER_OFFSET (buf) = src->buf_mark; + GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET (buf) + 1; + ++src->buf_mark; + + if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf))) + return GST_FLOW_OK; + + if (!src->time_offset_ready) { + GstClock *clock = GST_ELEMENT_CLOCK (src); + GstClockTime actual_time = 0; + + if (!clock) + return GST_FLOW_OK; + + actual_time = gst_clock_get_time (clock) - GST_ELEMENT_CAST (src)->base_time; + src->time_offset = actual_time - GST_BUFFER_TIMESTAMP (buf); + src->time_offset_ready = TRUE; + gst_object_ref (clock); + } + + GST_BUFFER_TIMESTAMP (buf) += src->time_offset; + //GST_BUFFER_DURATION (buf) = src->duration; + + XCAM_STATIC_FPS_CALCULATION (gstxcamsrc, XCAM_OBJ_DUR_FRAME_NUM); + return GST_FLOW_OK; +} + +#if HAVE_IA_AIQ +static gboolean +gst_xcam_src_set_white_balance_mode (GstXCam3A *xcam3a, XCamAwbMode mode) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_awb_mode (mode); +} + +static gboolean +gst_xcam_src_set_awb_speed (GstXCam3A *xcam3a, double speed) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_awb_speed (speed); +} + +static gboolean +gst_xcam_src_set_wb_color_temperature_range (GstXCam3A *xcam3a, guint cct_min, guint cct_max) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_awb_color_temperature_range (cct_min, cct_max); +} + +static gboolean +gst_xcam_src_set_manual_wb_gain (GstXCam3A *xcam3a, double gr, double r, double b, double gb) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_awb_manual_gain (gr, r, b, gb); +} + + +static gboolean +gst_xcam_src_set_exposure_mode (GstXCam3A *xcam3a, XCamAeMode mode) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_ae_mode (mode); +} + +static gboolean +gst_xcam_src_set_ae_metering_mode (GstXCam3A *xcam3a, XCamAeMeteringMode mode) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_ae_metering_mode (mode); +} + +static gboolean +gst_xcam_src_set_exposure_window (GstXCam3A *xcam3a, XCam3AWindow *window, guint8 count) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_ae_window (window, count); +} + +static gboolean +gst_xcam_src_set_exposure_value_offset (GstXCam3A *xcam3a, double ev_offset) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_ae_ev_shift (ev_offset); +} + +static gboolean +gst_xcam_src_set_ae_speed (GstXCam3A *xcam3a, double speed) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_ae_speed (speed); +} + +static gboolean +gst_xcam_src_set_exposure_flicker_mode (GstXCam3A *xcam3a, XCamFlickerMode flicker) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_ae_flicker_mode (flicker); +} + +static XCamFlickerMode +gst_xcam_src_get_exposure_flicker_mode (GstXCam3A *xcam3a) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->get_ae_flicker_mode (); +} + +static gint64 +gst_xcam_src_get_current_exposure_time (GstXCam3A *xcam3a) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->get_ae_current_exposure_time (); +} + +static double +gst_xcam_src_get_current_analog_gain (GstXCam3A *xcam3a) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->get_ae_current_analog_gain (); +} + +static gboolean +gst_xcam_src_set_manual_exposure_time (GstXCam3A *xcam3a, gint64 time_in_us) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_ae_manual_exposure_time (time_in_us); +} + +static gboolean +gst_xcam_src_set_manual_analog_gain (GstXCam3A *xcam3a, double gain) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_ae_manual_analog_gain (gain); +} + +static gboolean +gst_xcam_src_set_aperture (GstXCam3A *xcam3a, double fn) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_ae_aperture (fn); +} + +static gboolean +gst_xcam_src_set_max_analog_gain (GstXCam3A *xcam3a, double max_gain) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_ae_max_analog_gain (max_gain); +} + +static double +gst_xcam_src_get_max_analog_gain (GstXCam3A *xcam3a) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->get_ae_max_analog_gain (); +} + +static gboolean +gst_xcam_src_set_exposure_time_range (GstXCam3A *xcam3a, gint64 min_time_in_us, gint64 max_time_in_us) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_ae_exposure_time_range (min_time_in_us, max_time_in_us); +} + +static gboolean +gst_xcam_src_get_exposure_time_range (GstXCam3A *xcam3a, gint64 *min_time_in_us, gint64 *max_time_in_us) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->get_ae_exposure_time_range (min_time_in_us, max_time_in_us); +} + +static gboolean +gst_xcam_src_set_noise_reduction_level (GstXCam3A *xcam3a, guint8 level) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_noise_reduction_level ((level - 128) / 128.0); +} + +static gboolean +gst_xcam_src_set_temporal_noise_reduction_level (GstXCam3A *xcam3a, guint8 level, gint8 mode) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + bool ret = analyzer->set_temporal_noise_reduction_level ((level - 128) / 128.0); +#if HAVE_LIBCL + SmartPtr<CL3aImageProcessor> cl_image_processor = device_manager->get_cl_image_processor (); + if (cl_image_processor.ptr ()) { + ret = cl_image_processor->set_tnr(mode, level); + } + else { + ret = false; + } +#else + XCAM_UNUSED (mode); +#endif + return (gboolean)ret; +} + +static gboolean +gst_xcam_src_set_gamma_table (GstXCam3A *xcam3a, double *r_table, double *g_table, double *b_table) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_gamma_table (r_table, g_table, b_table); +} + +static gboolean +gst_xcam_src_set_gbce (GstXCam3A *xcam3a, gboolean enable) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_gbce (enable); +} + +static gboolean +gst_xcam_src_set_manual_brightness (GstXCam3A *xcam3a, guint8 value) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_manual_brightness ((value - 128) / 128.0); +} + +static gboolean +gst_xcam_src_set_manual_contrast (GstXCam3A *xcam3a, guint8 value) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_manual_contrast ((value - 128) / 128.0); +} + +static gboolean +gst_xcam_src_set_manual_hue (GstXCam3A *xcam3a, guint8 value) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_manual_hue ((value - 128) / 128.0); +} + +static gboolean +gst_xcam_src_set_manual_saturation (GstXCam3A *xcam3a, guint8 value) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_manual_saturation ((value - 128) / 128.0); +} + +static gboolean +gst_xcam_src_set_manual_sharpness (GstXCam3A *xcam3a, guint8 value) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_manual_sharpness ((value - 128) / 128.0); +} + +static gboolean +gst_xcam_src_set_dvs (GstXCam3A *xcam3a, gboolean enable) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_dvs (enable); +} + +static gboolean +gst_xcam_src_set_night_mode (GstXCam3A *xcam3a, gboolean enable) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + + return analyzer->set_night_mode (enable); +} + +static gboolean +gst_xcam_src_set_hdr_mode (GstXCam3A *xcam3a, guint8 mode) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + XCAM_UNUSED (analyzer); + +#if HAVE_LIBCL + SmartPtr<CL3aImageProcessor> cl_image_processor = device_manager->get_cl_image_processor (); + CL3aImageProcessor::CLTonemappingMode tone_map_value = + (mode ? CL3aImageProcessor::Haleq : CL3aImageProcessor::WDRdisabled); + if (cl_image_processor.ptr ()) + return (gboolean) cl_image_processor->set_tonemapping(tone_map_value); + else + return false; +#else + XCAM_UNUSED (mode); + return true; +#endif +} + +static gboolean +gst_xcam_src_set_denoise_mode (GstXCam3A *xcam3a, guint32 mode) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + XCAM_UNUSED (analyzer); + +#if HAVE_LIBCL + gboolean ret; + SmartPtr<CL3aImageProcessor> cl_image_processor = device_manager->get_cl_image_processor (); + if (cl_image_processor.ptr ()) { + ret = cl_image_processor->set_denoise (mode); + return ret; + } + else + return false; +#else + XCAM_UNUSED (mode); + return true; +#endif +} + +static gboolean +gst_xcam_src_set_gamma_mode (GstXCam3A *xcam3a, gboolean enable) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + XCAM_UNUSED (analyzer); + +#if HAVE_LIBCL + SmartPtr<CL3aImageProcessor> cl_image_processor = device_manager->get_cl_image_processor (); + if (cl_image_processor.ptr ()) + return cl_image_processor->set_gamma (enable); + else + return false; +#else + XCAM_UNUSED (enable); + return true; +#endif +} + +static gboolean +gst_xcam_src_set_dpc_mode (GstXCam3A *xcam3a, gboolean enable) +{ + GST_XCAM_INTERFACE_HEADER (xcam3a, src, device_manager, analyzer); + XCAM_UNUSED (analyzer); + XCAM_UNUSED (enable); + + XCAM_LOG_WARNING ("xcamsrc: dpc is not supported"); + return true; +} +#endif + +static gboolean +gst_xcam_src_plugin_init (GstPlugin * xcamsrc) +{ + return gst_element_register (xcamsrc, "xcamsrc", GST_RANK_NONE, + GST_TYPE_XCAM_SRC); +} + +#ifndef PACKAGE +#define PACKAGE "libxam" +#endif + +GST_PLUGIN_DEFINE ( + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + xcamsrc, + "xcamsrc", + gst_xcam_src_plugin_init, + VERSION, + GST_LICENSE_UNKNOWN, + "libxcamsrc", + "https://github.com/01org/libxcam" +) diff --git a/wrapper/gstreamer/gstxcamsrc.h b/wrapper/gstreamer/gstxcamsrc.h new file mode 100644 index 0000000..8e87e88 --- /dev/null +++ b/wrapper/gstreamer/gstxcamsrc.h @@ -0,0 +1,133 @@ +/* + * gstxcamsrc.h - gst xcamsrc plugin + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: John Ye <john.ye@intel.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef GST_XCAM_SRC_H +#define GST_XCAM_SRC_H + +#include "main_dev_manager.h" +#include <gst/base/gstpushsrc.h> + +XCAM_BEGIN_DECLARE + +#define GST_TYPE_XCAM_SRC \ + (gst_xcam_src_get_type ()) +#define GST_XCAM_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XCAM_SRC,GstXCamSrc)) +#define GST_XCAM_SRC_CAST(obj) ((GstXCamSrc *) obj) + +#define GST_XCAM_SRC_MEM_MODE(src) ((GST_XCAM_SRC_CAST(src))->mem_type) +#define GST_XCAM_SRC_FRMAE_DURATION(src) ((GST_XCAM_SRC_CAST(src))->duration) +#define GST_XCAM_SRC_BUF_COUNT(src) ((GST_XCAM_SRC_CAST(src))->buf_count) +#define GST_XCAM_SRC_OUT_VIDEO_INFO(src) (&(GST_XCAM_SRC_CAST(src))->gst_video_info) + + +typedef enum { + ISP_IMAGE_PROCESSOR = 0, + CL_IMAGE_PROCESSOR, +} ImageProcessorType; + +typedef enum { + NONE_WDR = 0, + GAUSSIAN_WDR, + HALEQ_WDR, +} WDRModeType; + +typedef enum { + NONE_WAVELET = 0, + HAT_WAVELET_Y, + HAT_WAVELET_UV, + HARR_WAVELET_Y, + HARR_WAVELET_UV, + HARR_WAVELET_YUV, + HARR_WAVELET_BAYES, +} WaveletModeType; + +typedef enum { + DEFOG_NONE = 0, + DEFOG_RETINEX, + DEFOG_DCP +} DefogModeType; + +typedef enum { + DENOISE_3D_NONE = 0, + DENOISE_3D_YUV, + DENOISE_3D_UV +} Denoise3DModeType; + +typedef enum { + SIMPLE_ANALYZER = 0, + AIQ_TUNER_ANALYZER, + DYNAMIC_ANALYZER, + HYBRID_ANALYZER, +} AnalyzerType; + +typedef struct _GstXCamSrc GstXCamSrc; +typedef struct _GstXCamSrcClass GstXCamSrcClass; + +struct _GstXCamSrc +{ + GstPushSrc pushsrc; + GstBufferPool *pool; + + uint32_t buf_count; + uint32_t sensor_id; + uint32_t capture_mode; + char *device; + char *path_to_cpf; + char *path_to_3alib; + gboolean enable_3a; + gboolean enable_usb; + DefogModeType defog_mode; + Denoise3DModeType denoise_3d_mode; + uint8_t denoise_3d_ref_count; + gboolean enable_wireframe; + gboolean enable_image_warp; + char *path_to_fake; + + gboolean time_offset_ready; + int64_t time_offset; + int64_t buf_mark; + GstClockTime duration; + + enum v4l2_memory mem_type; + enum v4l2_field field; + uint32_t in_format; + uint32_t out_format; + GstVideoInfo gst_video_info; + XCam::VideoBufferInfo xcam_video_info; + ImageProcessorType image_processor_type; + WDRModeType wdr_mode_type; + AnalyzerType analyzer_type; + int32_t cl_pipe_profile; + WaveletModeType wavelet_mode; + XCam::SmartPtr<GstXCam::MainDeviceManager> device_manager; +}; + +struct _GstXCamSrcClass +{ + GstPushSrcClass parent_class; +}; + +GType gst_xcam_src_get_type (void); + +XCAM_END_DECLARE + +#endif // GST_XCAM_SRC_H diff --git a/wrapper/gstreamer/interface/Makefile.am b/wrapper/gstreamer/interface/Makefile.am new file mode 100644 index 0000000..5170426 --- /dev/null +++ b/wrapper/gstreamer/interface/Makefile.am @@ -0,0 +1,21 @@ +lib_LTLIBRARIES = libgstxcaminterface.la + +libgstxcaminterface_la_SOURCES = gstxcaminterface.c + +libgstxcaminterface_la_CFLAGS = \ + $(GST_CFLAGS) \ + -I$(top_srcdir)/xcore \ + -I$(top_srcdir)/xcore/base \ + $(XCAM_CFLAGS) \ + $(NULL) + +libgstxcaminterface_la_LIBADD = \ + $(GST_LIBS) \ + $(NULL) + +libgstxcaminterfaceincludedir = \ + $(includedir)/gstreamer-1.0/gst + +libgstxcaminterfaceinclude_HEADERS = \ + gstxcaminterface.h + diff --git a/wrapper/gstreamer/interface/gstxcaminterface.c b/wrapper/gstreamer/interface/gstxcaminterface.c new file mode 100644 index 0000000..7d49902 --- /dev/null +++ b/wrapper/gstreamer/interface/gstxcaminterface.c @@ -0,0 +1,94 @@ +/* + * gstxcaminterface.c - Gstreamer XCam 3A interface + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "gstxcaminterface.h" +#include <string.h> + +static void gst_xcam_3a_iface_init (GstXCam3AInterface *iface); + +GType +gst_xcam_3a_interface_get_type (void) +{ + static GType gst_xcam_3a_interface_type = 0; + + if (!gst_xcam_3a_interface_type) { + static const GTypeInfo gst_xcam_3a_interface_info = { + sizeof (GstXCam3AInterface), + (GBaseInitFunc) gst_xcam_3a_iface_init, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + NULL, + NULL + }; + + gst_xcam_3a_interface_type = g_type_register_static (G_TYPE_INTERFACE, + "GsXCam3AInterface", &gst_xcam_3a_interface_info, 0); + } + return gst_xcam_3a_interface_type; +} + +static void +gst_xcam_3a_iface_init (GstXCam3AInterface * iface) +{ + /* default virtual functions */ + iface->set_white_balance_mode = NULL; + iface->set_awb_speed = NULL; + iface->set_wb_color_temperature_range = NULL; + iface->set_manual_wb_gain = NULL; + iface->set_exposure_mode = NULL; + iface->set_ae_metering_mode = NULL; + iface->set_exposure_window = NULL; + iface->set_exposure_value_offset = NULL; + iface->set_ae_speed = NULL; + iface->set_exposure_flicker_mode = NULL; + iface->get_exposure_flicker_mode = NULL; + iface->get_current_exposure_time = NULL; + iface->get_current_analog_gain = NULL; + iface->set_manual_exposure_time = NULL; + iface->set_manual_analog_gain = NULL; + iface->set_aperture = NULL; + iface->set_max_analog_gain = NULL; + iface->get_max_analog_gain = NULL; + iface->set_exposure_time_range = NULL; + iface->get_exposure_time_range = NULL; + iface->set_dvs = NULL; + iface->set_noise_reduction_level = NULL; + iface->set_temporal_noise_reduction_level = NULL; + iface->set_gamma_table = NULL; + iface->set_gbce = NULL; + iface->set_manual_brightness = NULL; + iface->set_manual_contrast = NULL; + iface->set_manual_hue = NULL; + iface->set_manual_saturation = NULL; + iface->set_manual_sharpness = NULL; + iface->set_night_mode = NULL; + iface->set_hdr_mode = NULL; + iface->set_denoise_mode = NULL; + iface->set_gamma_mode = NULL; + iface->set_dpc_mode = NULL; + iface->set_tonemapping_mode = NULL; +} diff --git a/wrapper/gstreamer/interface/gstxcaminterface.h b/wrapper/gstreamer/interface/gstxcaminterface.h new file mode 100644 index 0000000..febdf04 --- /dev/null +++ b/wrapper/gstreamer/interface/gstxcaminterface.h @@ -0,0 +1,481 @@ +/* + * gstxcaminterface.h - gst xcam interface + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +/*! \file gstxcaminterface.h + * \brief Gstreamer XCam 3A interface + * + */ + +#ifndef GST_XCAM_INTERFACE_H +#define GST_XCAM_INTERFACE_H + +#include <gst/gst.h> +#include <linux/videodev2.h> +#include <base/xcam_3a_types.h> + + +G_BEGIN_DECLS + +/*! \brief Get GST interface type of XCam 3A interface + * + * \return GType returned by g_type_register_static() + */ +#define GST_TYPE_XCAM_3A_IF (gst_xcam_3a_interface_get_type ()) + +/*! \brief Get GST XCam 3A handle. + * See usage of struct _GstXCam3AInterface. + * + * \return XCam 3A handle of _GstXCam3A * type + */ +#define GST_XCAM_3A(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XCAM_3A_IF, GstXCam3A)) + +/*! \brief Get GST XCam 3A interface + * + * See usage of struct _GstXCam3AInterface. + * + * \param[in] Xcam 3A handle + * \return GstXCam3AInterface* + */ +#define GST_XCAM_3A_GET_INTERFACE(inst) \ + (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_XCAM_3A_IF, GstXCam3AInterface)) + +typedef struct _GstXCam3A GstXCam3A; +typedef struct _GstXCam3AInterface GstXCam3AInterface; + +/*! \brief XCam 3A Interface + * + * Usage: + * - GstXCam3A *xcam = GST_XCAM_3A (xcamsrc); + * - GstXCam3AInterface *xcam_interface = GST_XCAM_3A_GET_INTERFACE (xcam); + * - ret = xcam_interface->set_exposure_mode(xcam, XCAM_AE_MODE_AUTO); + */ +struct _GstXCam3AInterface { + GTypeInterface base; /*!< inherent from GTypeInterface */ + + /*! \brief Set white balance mode. + * See xcam_3a_set_whitebalance_mode(). + * + * \param[in,out] xcam XCam handle + * \param[in] mode white balance mode + * return 0 on success; -1 on error (parameter error) + */ + gboolean (* set_white_balance_mode) (GstXCam3A *xcam, XCamAwbMode mode); + + /*! \brief set AWB speed. + * see xcam_3a_set_awb_speed(). + * + * \param[in,out] xcam XCam handle + * \param[in,out] speed AWB speed; speed meaturement will consider later + * return 0 on success; -1 on error + */ + gboolean (* set_awb_speed) (GstXCam3A *xcam, double speed); + + /*! \brief Set white balance temperature range. + * see xcam_3a_set_awb_color_temperature_range(). + * + * \param[in] cct_min 0 < cct_min <= cct_max <= 10000; if 0, disable cct range + * \param[in] cct_max 0 < cct_min <= cct_max <= 10000; if 0, disable cct range + * \return 0 on success; -1 on error + * + * Usage: + * + * - Enable: + * 1. set_white_balance_mode(%XCAM_AWB_MODE_MANUAL) + * 2. set_wb_color_temperature_range + * - Disable: + * set_white_balance_mode(%XCAM_AWB_MODE_AUTO) + * + */ + gboolean (* set_wb_color_temperature_range) (GstXCam3A *xcam, guint cct_min, guint cct_max); + + /*! \brief Set manual white balance gain. + * see xcam_3a_set_wb_manual_gain(). + * + * \param[in,out] xcam XCam handle + * \param[in] gr GR channel + * \param[in] r R channel + * \param[in] b B channel + * \param[in] gb GB channel + * + * Usage: + * + * - Enable: + * 1. need gr, r, b, gb => gain value [0.1~4.0]; + * 2. set_white_balance_mode(xcam, XCAM_AWB_MODE_NOT_SET) + * - Disable: + * 1. need set gr=0, r=0, b=0, gb=0; + * 2. set_white_balance_mode(xcam, mode); mode != XCAM_AWB_MODE_NOT_SET + */ + gboolean (* set_manual_wb_gain) (GstXCam3A *xcam, double gr, double r, double b, double gb); + + + /*! \brief set exposure mode. + * see xcam_3a_set_exposure_mode(). + * + * \param[in,out] xcam XCam handle + * \param[in] mode choose from XCAM_AE_MODE_AUTO and XCAM_AE_MODE_MANUAL; others not supported + */ + gboolean (* set_exposure_mode) (GstXCam3A *xcam, XCamAeMode mode); + + /*! \brief set AE metering mode. + * see xcam_3a_set_ae_metering_mode(). + * + * \param[in,out] xcam XCam handle + * \param[in] mode XCAM_AE_METERING_MODE_AUTO, default + * XCAM_AE_METERING_MODE_SPOT, need set spot window by set_exposure_window + * XCAM_AE_METERING_MODE_CENTER, more weight in center + * XCAM_AE_METERING_MODE_WEIGHTED_WINDOW, weighted multi metering window + */ + gboolean (* set_ae_metering_mode) (GstXCam3A *xcam, XCamAeMeteringMode mode); + + /* \brief set exposure window. + * see xcam_3a_set_ae_window(). + * + * \param[in,out] xcam XCam handle + * \param[in] window the area to set exposure with. x_end > x_start AND y_end > y_start; only ONE window can be set + * \param[in] count the number of metering window + * + * Usage + * - Enable: + * set_ae_metering_mode(@xcam, %XCAM_AE_METERING_MODE_SPOT) + * - Disable: + * set_ae_metering_mode(@xcam, @mode); #mode != %XCAM_AE_METERING_MODE_SPOT + */ + gboolean (* set_exposure_window) (GstXCam3A *xcam, XCam3AWindow *window, guint8 count); + + /*! \brief set exposure value offset. + * see xcam_3a_set_ae_value_shift(). + * + * \param[in,out] xcam XCam handle + * \param[in] ev_offset -4.0 <= ev_offset <= 4.0; default 0.0 + */ + gboolean (* set_exposure_value_offset) (GstXCam3A *xcam, double ev_offset); + + /*! \brief set AE speed. + * see xcam_3a_set_ae_speed(). + * + * \param[in,out] xcam XCam handle + * \param[in] speed AE speed + */ + gboolean (* set_ae_speed) (GstXCam3A *xcam, double speed); + + /*! \brief set exposure flicker mode. + * see xcam_3a_set_ae_flicker_mode(). + * + * \param[in,out] xcam XCam handle + * \param[in] flicker XCAM_AE_FLICKER_MODE_AUTO, default + * XCAM_AE_FLICKER_MODE_50HZ + * XCAM_AE_FLICKER_MODE_60HZ + * XCAM_AE_FLICKER_MODE_OFF, outside + */ + gboolean (*set_exposure_flicker_mode) (GstXCam3A *xcam, XCamFlickerMode flicker); + + /*! \brief get exposure flicker mode. + * see xcam_3a_get_ae_flicker_mode(). + * + * \param[in,out] xcam XCam handle + * \return XCamFlickerMode XCAM_AE_FLICKER_MODE_AUTO, default + * XCAM_AE_FLICKER_MODE_50HZ + * XCAM_AE_FLICKER_MODE_60HZ + * XCAM_AE_FLICKER_MODE_OFF, outside + */ + XCamFlickerMode (*get_exposure_flicker_mode) (GstXCam3A *xcam); + + /*! \brief get current exposure time. + * see xcam_3a_get_current_exposure_time(). + * + * \param[in,out] xcam XCam handle + * \return current exposure time in microsecond, if return -1, means xcam is not started + */ + gint64 (* get_current_exposure_time) (GstXCam3A *xcam); + + /*! \brief get current analog gain. + * see xcam_3a_get_current_analog_gain(). + * + * \param[in,out] xcam XCam handle + * \return current analog gain as multiplier. If return < 0.0 OR return < 1.0, xcam is not started. + */ + double (* get_current_analog_gain) (GstXCam3A *xcam); + + /*! \brief set manual exposure time + * + * \param[in,out] xcam XCam handle + * \param[in] time_in_us exposure time + * + * Usage: + * - Enable: + * set time_in_us, 0 < time_in_us < 1/fps + * - Disable: + * time_in_us = 0 + */ + gboolean (* set_manual_exposure_time) (GstXCam3A *xcam, gint64 time_in_us); + + /*! \brief set manual analog gain. + * see xcam_3a_set_ae_manual_analog_gain(). + * + * \param[in,out] xcam XCam handle + * \param[in] gain analog gain + * + * Usage: + * - Enable: + * set @gain value, 1.0 < @gain + * - Disable: + * set @gain = 0.0 + */ + gboolean (* set_manual_analog_gain) (GstXCam3A *xcam, double gain); + + /*! \brief set aperture. + * see xcam_3a_set_ae_set_aperture(). + * + * \param[in,out] xcam XCam3A handle + * \param[in] fn AE aperture fn + * \return bool 0 on success + */ + gboolean (* set_aperture) (GstXCam3A *xcam, double fn); + + /*! \brief set max analog gain. + * see xcam_3a_set_ae_max_analog_gain(). + * + * \param[in,out] xcam XCam3A handle + * \param[in] max_gain max analog gain + * \return gboolen 0 on success + */ + gboolean (* set_max_analog_gain) (GstXCam3A *xcam, double max_gain); + + /*! \brief get max analog gain. + * see xcam_3a_get_ae_max_analog_gain(). + * + * \param[in,out] xcam XCam3A handle + * \return max_gain max analog gain + */ + double (* get_max_analog_gain) (GstXCam3A *xcam); + + /*! + * \brief set AE time range + * + * \param[in,out] xcam XCam3A handle + * \param[in] min_time_in_us min time + * \param[in] max_time_in_us max time + * \return XCam3AStatus 0 on success + */ + gboolean (* set_exposure_time_range) (GstXCam3A *xcam, gint64 min_time_in_us, gint64 max_time_in_us); + + /*! + * \brief XCam3A get AE time range. + * Range in [0 ~ 1000000/fps] micro-seconds. see xcam_3a_set_ae_time_range(). + * + * \param[in,out] xcam XCam3A handle + * \param[out] min_time_in_us min time + * \param[out] max_time_in_us max time + * \return bool 0 on success + */ + gboolean (* get_exposure_time_range) (GstXCam3A *xcam, gint64 *min_time_in_us, gint64 *max_time_in_us); + + /*! \brief set DVS. + * digital video stabilization. see xcam_3a_enable_dvs(). + * + * \param[in,out] xcam XCam3A handle + * \param[in] enable enable/disable + * \return bool 0 on success + */ + gboolean (* set_dvs) (GstXCam3A *xcam, gboolean enable); + + /*! \brief set noice reduction level to BNR and YNR. + * see xcam_3a_set_noise_reduction_level(). + * + * \param[in,out] xcam XCam3A handle + * \param[in] level control BNR/YNR gain. 0 <= level <= 255; default level: 128 + * \return bool 0 on success + */ + gboolean (*set_noise_reduction_level) (GstXCam3A *xcam, guint8 level); + + /*! \brief set temporal noice reduction level. + * see xcam_3a_set_temporal_noise_reduction_level(). + * + * \param[in,out] xcam XCam3A handle + * \param[in] level control TNR gain. 0 <= level <= 255; default level: 128 + * \param[in] mode TNR filter mode 0: disable, 1: YUV mode, 2: RGB mode + * \return bool 0 on success + */ + gboolean (*set_temporal_noise_reduction_level) (GstXCam3A *xcam, guint8 level, gint8 mode); + + /*! + * \brief set gamma table. + * see xcam_3a_set_set_gamma_table(). + * + * \param[in,out] xcam XCam3A handle + * \param[in] r_table red color gamma table + * \param[in] g_table green color gamma table + * \param[in] b_table blue color gamma table + * \return bool 0 on success + * + * Restriction: + * 1. can't co-work with manual brightness and contrast, + * 2. table size = 256, and values in [0.0~1.0], e.g 0.0, 1.0/256, 2.0/256 ... 255.0/256 + * + * Usage: + * - to Disable: + * r_table = NULL && g_table = NULL && b_table=NULL + */ + gboolean (* set_gamma_table) (GstXCam3A *xcam, double *r_table, double *g_table, double *b_table); + + /*! + * \brief enable/disable gbce. + * see xcam_3a_enable_gbce(). + * + * \param[in,out] xcam XCam3A handle + * \param[in] enable enable/disable, i.e. TRUE to enable GBCE and otherwise disable GBCE. + * \return bool 0 on success + */ + gboolean (* set_gbce) (GstXCam3A *xcam, gboolean enable); + + /*! + * \brief set manual brightness. + * see xcam_3a_set_manual_brightness(). + * + * \param[in,out] xcam XCam3A handle + * \param[in] value manual brightness, 0 <= value <= 255; default:128 + * \return bool 0 on success */ + gboolean (* set_manual_brightness) (GstXCam3A *xcam, guint8 value); + + /*! + * \brief set manual contrast. + * see xcam_3a_set_manual_contrast(). + * + * \param[in,out] xcam XCam3A handle + * \param[in] value manual contrast, 0 <= value <= 255; default:128 + * \return bool 0 on success */ + gboolean (* set_manual_contrast) (GstXCam3A *xcam, guint8 value); + + /*! + * \brief set manual hue. + * see xcam_3a_set_manual_hue(). + * + * \param[in,out] xcam XCam3A handle + * \param[in] value manual hue, 0 <= value <= 255; default:128 + * \return bool 0 on success */ + gboolean (* set_manual_hue) (GstXCam3A *xcam, guint8 value); + + /*! + * \brief set manual saturation. + * see xcam_3a_set_manual_saturation(). + * + * \param[in,out] xcam XCam3A handle + * \param[in] value manual saturation, 0 <= value <= 255; default:128 + * \return bool 0 on success */ + gboolean (* set_manual_saturation) (GstXCam3A *xcam, guint8 value); + + /*! + * \brief set manual sharpness. + * see xcam_3a_set_manual_sharpness(). + * + * \param[in,out] xcam XCam3A handle + * \param[in] value manual sharpness, 0 <= value <= 255; default:128 + * \return bool 0 on success */ + gboolean (* set_manual_sharpness) (GstXCam3A *xcam, guint8 value); + + /* IR-cut */ + /*! + * \brief enable/disable night mode. + * see xcam_3a_enable_night_mode(). + * + * \param[in,out] xcam XCam3A handle + * \param[in] enable enable/disable, i.e. TRUE to enable night mode and otherwise disable night mode. + * \return bool 0 on success + */ + gboolean (* set_night_mode) (GstXCam3A *xcam, gboolean enable); + + /*! + * \brief set HDR mode. + * + * \param[in,out] xcam XCam3A handle + * \param[in] mode 0: disable, 1: HDR in RGB color space, 2: HDR in LAB color space + * \return bool 0 on success + */ + gboolean (* set_hdr_mode) (GstXCam3A *xcam, guint8 mode); + + /*! + * \brief set denoise mode. + * + * \param[in,out] xcam XCam3A handle + * \param[in] mode bit mask to enable/disable denoise functions + * each bit controls a specific denoise function, 0: disable, 1: enable + * bit 0: simple noise reduction + * bit 1: bilateral noise reduction + * bit 2: luminance noise reduction and edge enhancement + * bit 3: bayer noise reduction + * bit 4: advanced bayer noise reduction + * \return bool 0 on success + */ + gboolean (* set_denoise_mode) (GstXCam3A *xcam, guint32 mode); + + /*! + * \brief set gamma mode. + * + * \param[in,out] xcam XCam3A handle + * \param[in] enable true: enable, false: disable + * \return bool 0 on success + */ + gboolean (* set_gamma_mode) (GstXCam3A *xcam, gboolean enable); + + /*! + * \brief set dpc mode. + * + * \param[in,out] xcam XCam3A handle + * \param[in] enable true: enable, false: disable + * \return bool 0 on success + */ + gboolean (* set_dpc_mode) (GstXCam3A *xcam, gboolean enable); + + /*! + * \brief set tone mapping mode. + * + * \param[in,out] xcam XCam3A handle + * \param[in] enable true: enable, false: disable + * \return bool 0 on success + */ + gboolean (* set_tonemapping_mode) (GstXCam3A *xcam, gboolean enable); + + /*! + * \brief set retinex mode. + * + * \param[in,out] xcam XCam3A handle + * \param[in] enable true: enable, false: disable + * \return bool 0 on success + */ + gboolean (* set_retinex_mode) (GstXCam3A *xcam, gboolean enable); + + +}; + +/*! \brief Get GST interface type of XCam 3A interface. + * will try to register GsXcam3AInterface with + * g_type_register_static() if not done so yet, and in turn return the + * interface type it returns. + * + * \return GType XCam 3A interface type returned by g_type_register_static() + */ +GType +gst_xcam_3a_interface_get_type (void); + +G_END_DECLS + +#endif /* GST_XCAM_INTERFACE_H */ diff --git a/wrapper/gstreamer/main_dev_manager.cpp b/wrapper/gstreamer/main_dev_manager.cpp new file mode 100644 index 0000000..bda0879 --- /dev/null +++ b/wrapper/gstreamer/main_dev_manager.cpp @@ -0,0 +1,69 @@ +/* + * main_dev_manager.cpp - main device manager + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: John Ye <john.ye@intel.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "main_dev_manager.h" + +using namespace XCam; + +namespace GstXCam { + +MainDeviceManager::MainDeviceManager() +{ +} + +MainDeviceManager::~MainDeviceManager() +{ +} + +void +MainDeviceManager::handle_message (const SmartPtr<XCamMessage> &msg) +{ + XCAM_UNUSED (msg); +} + +void +MainDeviceManager::handle_buffer (const SmartPtr<VideoBuffer> &buf) +{ + XCAM_ASSERT (buf.ptr ()); + _ready_buffers.push (buf); +} + +SmartPtr<VideoBuffer> +MainDeviceManager::dequeue_buffer () +{ + SmartPtr<VideoBuffer> ret; + ret = _ready_buffers.pop (-1); + return ret; +} + +void +MainDeviceManager::pause_dequeue () +{ + return _ready_buffers.pause_pop (); +} + +void +MainDeviceManager::resume_dequeue () +{ + return _ready_buffers.resume_pop (); +} + +}; diff --git a/wrapper/gstreamer/main_dev_manager.h b/wrapper/gstreamer/main_dev_manager.h new file mode 100644 index 0000000..764b6b4 --- /dev/null +++ b/wrapper/gstreamer/main_dev_manager.h @@ -0,0 +1,103 @@ +/* + * main_dev_manager.h - main device manager + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: John Ye <john.ye@intel.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAMSRC_MAIN_DEV_MANAGER_H +#define XCAMSRC_MAIN_DEV_MANAGER_H + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <base/xcam_common.h> +#include <linux/videodev2.h> +#include <stdint.h> +#include <unistd.h> + +#include <gst/video/video.h> +#include <gst/gst.h> + +#include <queue> + +#include <xcam_mutex.h> +#include <video_buffer.h> +#include <v4l2_buffer_proxy.h> +#include <v4l2_device.h> +#include <device_manager.h> +#if HAVE_IA_AIQ +#include <isp/atomisp_device.h> +#include <isp/isp_controller.h> +#include <isp/isp_image_processor.h> +#include <isp/x3a_analyzer_aiq.h> +#endif +#if HAVE_LIBCL +#include <ocl/cl_3a_image_processor.h> +#include <ocl/cl_post_image_processor.h> +#endif +#include <x3a_analyzer_simple.h> + +namespace GstXCam { + +class MainDeviceManager; + +class MainDeviceManager + : public XCam::DeviceManager +{ +public: + MainDeviceManager (); + ~MainDeviceManager (); + + XCam::SmartPtr<XCam::VideoBuffer> dequeue_buffer (); + void pause_dequeue (); + void resume_dequeue (); + +#if HAVE_LIBCL +public: + void set_cl_image_processor (XCam::SmartPtr<XCam::CL3aImageProcessor> &processor) { + _cl_image_processor = processor; + } + + XCam::SmartPtr<XCam::CL3aImageProcessor> &get_cl_image_processor () { + return _cl_image_processor; + } + + void set_cl_post_image_processor (XCam::SmartPtr<XCam::CLPostImageProcessor> &processor) { + _cl_post_image_processor = processor; + } + + XCam::SmartPtr<XCam::CLPostImageProcessor> &get_cl_post_image_processor () { + return _cl_post_image_processor; + } +#endif + +protected: + virtual void handle_message (const XCam::SmartPtr<XCam::XCamMessage> &msg); + virtual void handle_buffer (const XCam::SmartPtr<XCam::VideoBuffer> &buf); + +private: + XCam::SafeList<XCam::VideoBuffer> _ready_buffers; +#if HAVE_LIBCL + XCam::SmartPtr<XCam::CL3aImageProcessor> _cl_image_processor; + XCam::SmartPtr<XCam::CLPostImageProcessor> _cl_post_image_processor; +#endif +}; + +}; + +#endif //XCAMSRC_MAIN_DEV_MANAGER_H diff --git a/wrapper/gstreamer/main_pipe_manager.cpp b/wrapper/gstreamer/main_pipe_manager.cpp new file mode 100644 index 0000000..00f7dfd --- /dev/null +++ b/wrapper/gstreamer/main_pipe_manager.cpp @@ -0,0 +1,54 @@ +/* + * main_pipe_manager.cpp -main pipe manager + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include "main_pipe_manager.h" + +using namespace XCam; + +namespace GstXCam { + +void +MainPipeManager::post_buffer (const SmartPtr<VideoBuffer> &buf) +{ + XCAM_ASSERT (buf.ptr ()); + _ready_buffers.push (buf); +} + +SmartPtr<VideoBuffer> +MainPipeManager::dequeue_buffer (const int32_t timeout) +{ + SmartPtr<VideoBuffer> ret; + ret = _ready_buffers.pop (timeout); + return ret; +} + +void +MainPipeManager::pause_dequeue () +{ + return _ready_buffers.pause_pop (); +} + +void +MainPipeManager::resume_dequeue () +{ + return _ready_buffers.resume_pop (); +} + +}; diff --git a/wrapper/gstreamer/main_pipe_manager.h b/wrapper/gstreamer/main_pipe_manager.h new file mode 100644 index 0000000..dffa4e6 --- /dev/null +++ b/wrapper/gstreamer/main_pipe_manager.h @@ -0,0 +1,64 @@ +/* + * main_pipe_manager.h -main pipe manager + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#ifndef XCAMFILTER_MAIN_PIPE_MANAGER_H +#define XCAMFILTER_MAIN_PIPE_MANAGER_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <pipe_manager.h> +#include <video_buffer.h> +#include <smart_analyzer_loader.h> +#include <ocl/cl_post_image_processor.h> + +namespace GstXCam { + +class MainPipeManager + : public XCam::PipeManager +{ +public: + MainPipeManager () {}; + ~MainPipeManager () {}; + + XCam::SmartPtr<XCam::VideoBuffer> dequeue_buffer (const int32_t timeout); + void pause_dequeue (); + void resume_dequeue (); + + void set_image_processor (XCam::SmartPtr<XCam::CLPostImageProcessor> &processor) { + _image_processor = processor; + } + + XCam::SmartPtr<XCam::CLPostImageProcessor> &get_image_processor () { + return _image_processor; + } + +protected: + virtual void post_buffer (const XCam::SmartPtr<XCam::VideoBuffer> &buf); + +private: + XCam::SafeList<XCam::VideoBuffer> _ready_buffers; + XCam::SmartPtr<XCam::CLPostImageProcessor> _image_processor; +}; + +}; + +#endif // XCAMFILTER_MAIN_PIPE_MANAGER_H diff --git a/xcore/Makefile.am b/xcore/Makefile.am new file mode 100644 index 0000000..bcadd7c --- /dev/null +++ b/xcore/Makefile.am @@ -0,0 +1,146 @@ +lib_LTLIBRARIES = libxcam_core.la + +XCAM_CORE_CXXFLAGS = $(XCAM_CXXFLAGS) +XCAM_CORE_LIBS = \ + -ldl \ + -lpthread \ + $(NULL) + +xcam_sources = \ + analyzer_loader.cpp \ + smart_analyzer_loader.cpp \ + buffer_pool.cpp \ + calibration_parser.cpp \ + device_manager.cpp \ + pipe_manager.cpp \ + dma_video_buffer.cpp \ + dynamic_analyzer.cpp \ + dynamic_analyzer_loader.cpp \ + smart_analyzer.cpp \ + smart_analysis_handler.cpp \ + smart_buffer_priv.cpp \ + fake_poll_thread.cpp \ + file_handle.cpp \ + handler_interface.cpp \ + image_handler.cpp \ + image_processor.cpp \ + image_projector.cpp \ + image_file_handle.cpp \ + poll_thread.cpp \ + surview_fisheye_dewarp.cpp \ + swapped_buffer.cpp \ + thread_pool.cpp \ + uvc_device.cpp \ + v4l2_buffer_proxy.cpp \ + v4l2_device.cpp \ + video_buffer.cpp \ + worker.cpp \ + xcam_analyzer.cpp \ + x3a_analyzer.cpp \ + x3a_analyzer_manager.cpp \ + x3a_analyzer_simple.cpp \ + x3a_image_process_center.cpp \ + x3a_stats_pool.cpp \ + x3a_result.cpp \ + x3a_result_factory.cpp \ + xcam_common.cpp \ + xcam_buffer.cpp \ + xcam_thread.cpp \ + xcam_utils.cpp \ + interface/feature_match.cpp \ + interface/blender.cpp \ + interface/geo_mapper.cpp \ + interface/stitcher.cpp \ + $(NULL) + +if HAVE_LIBDRM +XCAM_CORE_CXXFLAGS += $(LIBDRM_CFLAGS) +XCAM_CORE_LIBS += \ + -ldrm_intel \ + $(LIBDRM_LIBS) \ + $(NULL) + +xcam_sources += \ + drm_bo_buffer.cpp \ + drm_display.cpp \ + drm_v4l2_buffer.cpp \ + $(NULL) +endif + +libxcam_core_la_CXXFLAGS = \ + $(XCAM_CORE_CXXFLAGS) \ + $(NULL) + +libxcam_core_la_SOURCES = \ + $(xcam_sources) \ + $(NULL) + +libxcam_core_la_LDFLAGS = \ + -no-undefined \ + $(XCAM_LT_LDFLAGS) \ + $(PTHREAD_LDFLAGS) \ + $(NULL) + +libxcam_core_la_LIBADD = \ + $(XCAM_CORE_LIBS) \ + $(NULL) + +libxcam_coreincludedir = $(includedir)/xcam + +nobase_libxcam_coreinclude_HEADERS = \ + base/xcam_3a_result.h \ + base/xcam_3a_types.h \ + base/xcam_3a_description.h \ + base/xcam_buffer.h \ + base/xcam_params.h \ + base/xcam_common.h \ + base/xcam_defs.h \ + base/xcam_smart_description.h \ + base/xcam_smart_result.h \ + calibration_parser.h \ + device_manager.h \ + dma_video_buffer.h \ + file_handle.h \ + pipe_manager.h \ + handler_interface.h \ + image_handler.h \ + image_processor.h \ + image_projector.h \ + image_file_handle.h \ + safe_list.h \ + smartptr.h \ + surview_fisheye_dewarp.h \ + swapped_buffer.h \ + thread_pool.h \ + v4l2_buffer_proxy.h \ + v4l2_device.h \ + video_buffer.h \ + worker.h \ + xcam_analyzer.h \ + x3a_analyzer.h \ + x3a_analyzer_manager.h \ + x3a_event.h \ + x3a_image_process_center.h \ + x3a_result.h \ + xcam_mutex.h \ + xcam_thread.h \ + xcam_std.h \ + xcam_utils.h \ + xcam_obj_debug.h \ + buffer_pool.h \ + meta_data.h \ + vec_mat.h \ + interface/data_types.h \ + interface/feature_match.h \ + interface/blender.h \ + interface/geo_mapper.h \ + interface/stitcher.h \ + $(NULL) + +if HAVE_LIBDRM +nobase_libxcam_coreinclude_HEADERS += \ + drm_bo_buffer.h \ + drm_display.h \ + drm_v4l2_buffer.h \ + $(NULL) +endif diff --git a/xcore/analyzer_loader.cpp b/xcore/analyzer_loader.cpp new file mode 100644 index 0000000..1629cac --- /dev/null +++ b/xcore/analyzer_loader.cpp @@ -0,0 +1,111 @@ +/* + * analyzer_loader.cpp - analyzer loader + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "analyzer_loader.h" +#include <dlfcn.h> + +namespace XCam { + +AnalyzerLoader::AnalyzerLoader (const char *lib_path, const char *symbol) + : _handle (NULL) +{ + XCAM_ASSERT (lib_path); + _path = strndup (lib_path, XCAM_MAX_STR_SIZE); + XCAM_ASSERT (symbol); + _symbol = strndup (symbol, XCAM_MAX_STR_SIZE); +} + +AnalyzerLoader::~AnalyzerLoader () +{ + close_handle (); + if (_path) + xcam_free (_path); + if (_symbol) + xcam_free (_symbol); +} + +void * +AnalyzerLoader::load_library (const char *lib_path) +{ + void *desc = NULL; + + void *handle = open_handle (lib_path); + //XCAM_ASSERT (handle); + if (!handle) { + XCAM_LOG_WARNING ("open dynamic lib:%s failed", XCAM_STR (lib_path)); + return NULL; + } + desc = load_symbol (handle); + if (!desc) { + XCAM_LOG_WARNING ("get symbol(%s) from lib:%s failed", _symbol, XCAM_STR (lib_path)); + close_handle (); + return NULL; + } + + XCAM_LOG_DEBUG ("got symbols(%s) from lib(%s)", _symbol, XCAM_STR (lib_path)); + return desc; +} + +void* +AnalyzerLoader::open_handle (const char *lib_path) +{ + void *handle = NULL; + + if (_handle != NULL) + return _handle; + + handle = dlopen (lib_path, RTLD_LAZY); + if (!handle) { + XCAM_LOG_DEBUG ( + "open user-defined lib(%s) failed, reason:%s", + XCAM_STR (lib_path), dlerror ()); + return NULL; + } + _handle = handle; + return handle; +} + +void * +AnalyzerLoader::get_symbol (void* handle) +{ + void *desc = NULL; + + XCAM_ASSERT (handle); + XCAM_ASSERT (_symbol); + desc = (void *)dlsym (handle, _symbol); + if (!desc) { + XCAM_LOG_DEBUG ("get symbol(%s) failed from lib(%s), reason:%s", _symbol, XCAM_STR (_path), dlerror ()); + return NULL; + } + + return desc; +} + +bool +AnalyzerLoader::close_handle () +{ + if (!_handle) + return true; + dlclose (_handle); + _handle = NULL; + return true; +} + +}; diff --git a/xcore/analyzer_loader.h b/xcore/analyzer_loader.h new file mode 100644 index 0000000..db5f98e --- /dev/null +++ b/xcore/analyzer_loader.h @@ -0,0 +1,56 @@ +/* + * analyzer_loader.h - analyzer loader + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_ANALYZER_LOADER_H +#define XCAM_ANALYZER_LOADER_H + +#include <base/xcam_common.h> + +namespace XCam { + +class AnalyzerLoader +{ +public: + AnalyzerLoader (const char *lib_path, const char *symbol); + virtual ~AnalyzerLoader (); + +protected: + void *load_library (const char *lib_path); + void *get_symbol (void* handle); + virtual void *load_symbol (void* handle) = 0; + bool close_handle (); + const char * get_lib_path () const { + return _path; + } + +private: + void *open_handle (const char *lib_path); + + XCAM_DEAD_COPY(AnalyzerLoader); + +private: + void *_handle; + char *_symbol; + char *_path; +}; + +}; + +#endif //XCAM_ANALYZER_LOADER_H diff --git a/xcore/base/xcam_3a_description.h b/xcore/base/xcam_3a_description.h new file mode 100644 index 0000000..21fe514 --- /dev/null +++ b/xcore/base/xcam_3a_description.h @@ -0,0 +1,60 @@ +/* + * xcam_3a_description.h - 3A description + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef C_XCAM_3A_DESCRIPTION_H +#define C_XCAM_3A_DESCRIPTION_H + +#include <string.h> +#include <stddef.h> +#include <stdio.h> +#include <stdint.h> +#include <base/xcam_defs.h> +#include <base/xcam_params.h> +#include <base/xcam_3a_result.h> +#include <base/xcam_3a_stats.h> + + +XCAM_BEGIN_DECLARE + +#define XCAM_3A_LIB_DESCRIPTION "xcam_3a_desciption" + +typedef struct _XCam3AContext XCam3AContext; + +/* C interface of 3A lib */ +typedef struct _XCam3ADescription { + uint32_t version; + uint32_t size; + XCamReturn (*create_context) (XCam3AContext **context); + XCamReturn (*destroy_context) (XCam3AContext *context); + XCamReturn (*configure_3a) (XCam3AContext *context, uint32_t width, uint32_t height, double framerate); + XCamReturn (*set_3a_stats) (XCam3AContext *context, XCam3AStats *stats, int64_t timestamp); + XCamReturn (*update_common_params) (XCam3AContext *context, XCamCommonParam *params); + XCamReturn (*analyze_awb) (XCam3AContext *context, XCamAwbParam *params); + XCamReturn (*analyze_ae) (XCam3AContext *context, XCamAeParam *params); + XCamReturn (*analyze_af) (XCam3AContext *context, XCamAfParam *params); + + /* res_count should equal to or less than XCAM_3A_MAX_RESULT_COUNT*/ + XCamReturn (*combine_analyze_results) (XCam3AContext *context, XCam3aResultHead *results[], uint32_t *res_count); + void (*free_results) (XCam3aResultHead *results[], uint32_t res_count); +} XCam3ADescription; + +XCAM_END_DECLARE + +#endif //C_XCAM_3A_DESCRIPTION_H diff --git a/xcore/base/xcam_3a_result.h b/xcore/base/xcam_3a_result.h new file mode 100644 index 0000000..e09273a --- /dev/null +++ b/xcore/base/xcam_3a_result.h @@ -0,0 +1,245 @@ +/* + * xcam_3a_result.h - 3A result interface + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Zong Wei <wei.zong@intel.com> + */ + +#ifndef C_XCAM_3A_RESULT_H +#define C_XCAM_3A_RESULT_H + +#include <stdlib.h> +#include <stdint.h> +#include <stddef.h> +#include <base/xcam_defs.h> + +XCAM_BEGIN_DECLARE + +#define XCAM_3A_MAX_RESULT_COUNT 256 +#define xcam_3a_result_type(result) (((XCam3aResultHead*)result)->type) + +typedef enum _ImageProcessType { + XCAM_IMAGE_PROCESS_ONCE, + XCAM_IMAGE_PROCESS_ALWAYS, + XCAM_IMAGE_PROCESS_POST, +} XCamImageProcessType; + +typedef enum _XCam3aResultType { + XCAM_3A_RESULT_NULL = 0, + /* White Balance */ + XCAM_3A_RESULT_WHITE_BALANCE, + XCAM_3A_RESULT_BLACK_LEVEL, + XCAM_3A_RESULT_YUV2RGB_MATRIX, + XCAM_3A_RESULT_RGB2YUV_MATRIX, + + /* Exposure */ + XCAM_3A_RESULT_EXPOSURE, + + /* Focus */ + XCAM_3A_RESULT_FOCUS, + + XCAM_3A_RESULT_DEMOSAIC, + //XCAM_3A_RESULT_EIGEN_COLOR_DEMOSAICING, + XCAM_3A_RESULT_DEFECT_PIXEL_CORRECTION, + + /* noise reduction */ + XCAM_3A_RESULT_NOISE_REDUCTION, + XCAM_3A_RESULT_3D_NOISE_REDUCTION, + XCAM_3A_RESULT_TEMPORAL_NOISE_REDUCTION_YUV, + XCAM_3A_RESULT_LUMA_NOISE_REDUCTION, + XCAM_3A_RESULT_ADVANCED_NOISE_REDUCTION, + XCAM_3A_RESULT_CHROMA_NOISER_EDUCTION, + XCAM_3A_RESULT_BAYER_NOISE_REDUCTION, + XCAM_3A_RESULT_WAVELET_NOISE_REDUCTION, + + XCAM_3A_RESULT_EDGE_ENHANCEMENT, + //XCAM_3A_RESULT_FRIGLE_CONTROL, + XCAM_3A_RESULT_MACC, + //XCAM_3A_RESULT_MACCTABLE, + XCAM_3A_RESULT_CHROMA_TONE_CONTROL, + //XCAM_3A_RESULT_CHROMATONECONTROLTABLE, + XCAM_3A_RESULT_CHROMA_ENHANCEMENT, + XCAM_3A_RESULT_Y_GAMMA, + XCAM_3A_RESULT_R_GAMMA, + XCAM_3A_RESULT_G_GAMMA, + XCAM_3A_RESULT_B_GAMMA, + XCAM_3A_RESULT_BRIGHTNESS, + //XCAM_3A_RESULT_SHADING_TABLE, + + //Smart Analysis Type + XCAM_3A_RESULT_FACE_DETECTION = 0x4000, + XCAM_3A_RESULT_DVS, + + XCAM_3A_RESULT_USER_DEFINED_TYPE = 0x8000, +} XCam3aResultType; + +/* matrix size 3x3 */ +#define XCAM_COLOR_MATRIX_SIZE 9 +#define XCAM_GAMMA_TABLE_SIZE 256 +#define XCAM_CHROMA_AXIS_SIZE 16 +#define XCAM_CHROMA_MATRIX_SIZE 4 +#define XCAM_BNR_TABLE_SIZE 64 + +typedef struct _XCam3aResultHead XCam3aResultHead; + +struct _XCam3aResultHead { + XCam3aResultType type; + XCamImageProcessType process_type; + uint32_t version; + void (*destroy) (XCam3aResultHead *); +}; + +typedef struct _XCam3aResultWhiteBalance { + XCam3aResultHead head; + + /* data */ + double r_gain; + double gr_gain; + double gb_gain; + double b_gain; +} XCam3aResultWhiteBalance; + +typedef struct _XCam3aResultBlackLevel { + XCam3aResultHead head; + + /* data */ + double r_level; + double gr_level; + double gb_level; + double b_level; +} XCam3aResultBlackLevel; + +typedef struct _XCam3aResultColorMatrix { + XCam3aResultHead head; + + /* data */ + double matrix [XCAM_COLOR_MATRIX_SIZE]; +} XCam3aResultColorMatrix; + +typedef struct _XCam3aResultExposure { + XCam3aResultHead head; + + /* data */ + int32_t exposure_time; //in micro seconds + double analog_gain; // multipler + double digital_gain; // multipler + double aperture; //fn +} XCam3aResultExposure; + +typedef struct _XCam3aResultFocus { + XCam3aResultHead head; + + /* data */ + int32_t position; +} XCam3aResultFocus; + +typedef struct _XCam3aResultDemosaic { + XCam3aResultHead head; + + /* data */ + double noise; + double threshold_cr; + double threshold_cb; +} XCam3aResultDemosaic; + + +/* DefectPixel Correction */ +typedef struct _XCam3aResultDefectPixel { + XCam3aResultHead head; + + /* data */ + double gain; + double gr_threshold; + double r_threshold; + double b_threshold; + double gb_threshold; +} XCam3aResultDefectPixel; + +typedef struct _XCam3aResultNoiseReduction { + XCam3aResultHead head; + + /* data */ + double gain; + double threshold1; + double threshold2; +} XCam3aResultNoiseReduction; + +typedef struct _XCam3aResultBayerNoiseReduction { + XCam3aResultHead head; + + /* data */ + double bnr_gain; + double direction; + double table[XCAM_BNR_TABLE_SIZE]; +} XCam3aResultBayerNoiseReduction; + +typedef struct _XCam3aResultEdgeEnhancement { + XCam3aResultHead head; + + /* data */ + double gain; + double threshold; +} XCam3aResultEdgeEnhancement; + +typedef struct _XCam3aResultGammaTable { + XCam3aResultHead head; + + /* data */ + double table[XCAM_GAMMA_TABLE_SIZE]; +} XCam3aResultGammaTable; + +typedef struct _XCam3aResultMaccMatrix { + XCam3aResultHead head; + + /* data */ + double table[XCAM_CHROMA_AXIS_SIZE * XCAM_CHROMA_MATRIX_SIZE]; +} XCam3aResultMaccMatrix; + +typedef struct _XCam3aResultChromaToneControl { + XCam3aResultHead head; + + /* data */ + double uv_gain [XCAM_GAMMA_TABLE_SIZE]; // according to Y +} XCam3aResultChromaToneControl; + +typedef struct _XCam3aResultBrightness { + XCam3aResultHead head; + + /* data */ + double brightness_level; // range [-1,1], -1 is full dark , 0 is normal val, 1 is full bright +} XCam3aResultBrightness; + +typedef struct _XCam3aResultTemporalNoiseReduction { + XCam3aResultHead head; + + /* data */ + double gain; + double threshold[3]; +} XCam3aResultTemporalNoiseReduction; + +typedef struct _XCam3aResultWaveletNoiseReduction { + XCam3aResultHead head; + + /* data */ + uint8_t decomposition_levels; + double threshold[2]; /* [0]:soft threshold / [1]:hard threshold */ + double analog_gain; +} XCam3aResultWaveletNoiseReduction; + +XCAM_END_DECLARE + +#endif diff --git a/xcore/base/xcam_3a_stats.h b/xcore/base/xcam_3a_stats.h new file mode 100644 index 0000000..f43bb14 --- /dev/null +++ b/xcore/base/xcam_3a_stats.h @@ -0,0 +1,72 @@ +/* + * xcam_3a_stats.h - 3a stats standard version + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef C_XCAM_3A_STATS_H +#define C_XCAM_3A_STATS_H + +#include <base/xcam_common.h> + +XCAM_BEGIN_DECLARE + +typedef struct _XCam3AStatsInfo { + uint32_t width; + uint32_t height; + uint32_t aligned_width; + uint32_t aligned_height; + uint32_t grid_pixel_size; // in pixel + uint32_t bit_depth; + uint32_t histogram_bins; + + uint32_t reserved[2]; +} XCam3AStatsInfo; + +typedef struct _XCamHistogram { + uint32_t r; + uint32_t gr; + uint32_t gb; + uint32_t b; +} XCamHistogram; + +typedef struct _XCamGridStat { + /* ae */ + uint32_t avg_y; + + /* awb */ + uint32_t avg_r; + uint32_t avg_gr; + uint32_t avg_gb; + uint32_t avg_b; + uint32_t valid_wb_count; + + /* af */ + uint32_t f_value1; + uint32_t f_value2; +} XCamGridStat; + +typedef struct _XCam3AStats { + XCam3AStatsInfo info; + XCamHistogram *hist_rgb; + uint32_t *hist_y; + XCamGridStat stats[0]; +} XCam3AStats; + +XCAM_END_DECLARE + +#endif //C_XCAM_3A_STATS_H diff --git a/xcore/base/xcam_3a_types.h b/xcore/base/xcam_3a_types.h new file mode 100644 index 0000000..c258c0e --- /dev/null +++ b/xcore/base/xcam_3a_types.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2014 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +/*! + * \file xcam_3a_types.h + * \brief 3A interface variable types + */ + +#ifndef __XCAM_3A_TYPES_H +#define __XCAM_3A_TYPES_H + +#include <string.h> +#include <stddef.h> +#include <stdio.h> +#include <stdint.h> +#include <base/xcam_defs.h> + +XCAM_BEGIN_DECLARE + +typedef enum { + XCAM_MODE_NONE = -1, + XCAM_MODE_PREVIEW = 0, + XCAM_MODE_CAPTURE = 1, + XCAM_MODE_VIDEO = 2, + XCAM_MODE_CONTINUOUS_CAPTURE = 3 +} XCamMode; + +typedef enum { + XCAM_AE_MODE_NOT_SET = -1, + XCAM_AE_MODE_AUTO, + XCAM_AE_MODE_MANUAL, + XCAM_AE_MODE_SHUTTER_PRIORITY, + XCAM_AE_MODE_APERTURE_PRIORITY +} XCamAeMode; + +#define XCAM_AE_MAX_METERING_WINDOW_COUNT 6 + +typedef enum { + XCAM_AE_METERING_MODE_AUTO, /*mode_evaluative*/ + XCAM_AE_METERING_MODE_SPOT, /*window*/ + XCAM_AE_METERING_MODE_CENTER, /*mode_center*/ + XCAM_AE_METERING_MODE_WEIGHTED_WINDOW, /* weighted_window */ +} XCamAeMeteringMode; + +typedef enum { + XCAM_SCENE_MODE_NOT_SET = -1, + XCAM_SCENE_MODE_AUTO, + XCAM_SCENE_MODE_PORTRAIT, + XCAM_SCENE_MODE_SPORTS, + XCAM_SCENE_MODE_LANDSCAPE, + XCAM_SCENE_MODE_NIGHT, + XCAM_SCENE_MODE_NIGHT_PORTRAIT, + XCAM_SCENE_MODE_FIREWORKS, + XCAM_SCENE_MODE_TEXT, + XCAM_SCENE_MODE_SUNSET, + XCAM_SCENE_MODE_PARTY, + XCAM_SCENE_MODE_CANDLELIGHT, + XCAM_SCENE_MODE_BEACH_SNOW, + XCAM_SCENE_MODE_DAWN_DUSK, + XCAM_SCENE_MODE_FALL_COLORS, + XCAM_SCENE_MODE_BACKLIGHT +} XCamSceneMode; + +typedef enum { + XCAM_AWB_MODE_NOT_SET = -1, + XCAM_AWB_MODE_AUTO = 0, + XCAM_AWB_MODE_MANUAL, + XCAM_AWB_MODE_DAYLIGHT, + XCAM_AWB_MODE_SUNSET, + XCAM_AWB_MODE_CLOUDY, + XCAM_AWB_MODE_TUNGSTEN, + XCAM_AWB_MODE_FLUORESCENT, + XCAM_AWB_MODE_WARM_FLUORESCENT, + XCAM_AWB_MODE_SHADOW, + XCAM_AWB_MODE_WARM_INCANDESCENT +} XCamAwbMode; + +typedef enum { + XCAM_AE_ISO_MODE_AUTO, /* Automatic */ + XCAM_AE_ISO_MODE_MANUAL /* Manual */ +} XCamIsoMode; + +typedef enum { + XCAM_AE_FLICKER_MODE_AUTO, + XCAM_AE_FLICKER_MODE_50HZ, + XCAM_AE_FLICKER_MODE_60HZ, + XCAM_AE_FLICKER_MODE_OFF +} XCamFlickerMode; + +#if 0 +typedef enum { + XCAM_AF_MODE_NOT_SET = -1, + XCAM_AF_MODE_AUTO, + XCAM_AF_MODE_MACRO, + XCAM_AF_MODE_INFINITY, + XCAM_AF_MODE_FIXED, + XCAM_AF_MODE_MANUAL, + XCAM_AF_MODE_CONTINUOUS +} XCamAfMode; +#endif + +/*! \brief XCam3AWindow. + * Represents a rectangle area. Could be converted to + * AIQ ia_rectangle, see convert_xcam_to_ia_window(). + */ +typedef struct _XCam3AWindow { + int32_t x_start; /*!< X of start point (left-upper corner) */ + int32_t y_start; /*!< Y of start point (left-upper corner) */ + int32_t x_end; /*!< X of end point (right-bottom corner) */ + int32_t y_end; /*!< Y of start point (left-upper corner) */ + int weight; +} XCam3AWindow; + +typedef struct _XCamExposureResult { + int64_t time_in_us; + double analog_gain; + double digital_gain; + double aperture_fn; + int32_t iso; +} XCamExposureResult; + +typedef enum { + XCAM_COLOR_EFFECT_NONE, + XCAM_COLOR_EFFECT_SKY_BLUE, + XCAM_COLOR_EFFECT_SKIN_WHITEN_LOW, + XCAM_COLOR_EFFECT_SKIN_WHITEN, + XCAM_COLOR_EFFECT_SKIN_WHITEN_HIGH, + XCAM_COLOR_EFFECT_SEPIA, + XCAM_COLOR_EFFECT_NEGATIVE, + XCAM_COLOR_EFFECT_GRAYSCALE, +} XCamColorEffect; + +typedef enum { + //XCAM_DENOISE_TYPE_SIMPLE = (1UL << 0), // simple noise reduction + XCAM_DENOISE_TYPE_BILATERAL = (1UL << 1), // bilateral noise reduction + //XCAM_DENOISE_TYPE_EE = (1UL << 2), // luminance noise reduction and edge enhancement + XCAM_DENOISE_TYPE_BNR = (1UL << 3), // bayer noise reduction + //XCAM_DENOISE_TYPE_ANR = (1UL << 4), // advanced bayer noise reduction + //XCAM_DENOISE_TYPE_BIYUV = (1UL << 5), // bilateral on yuv noise reduction + XCAM_DENOISE_TYPE_RETINEX = (1UL << 6), // retinex on yuv + XCAM_DENOISE_TYPE_WAVELET = (1UL << 7), // wavelet on yuv +} XCamDenoiseType; + +XCAM_END_DECLARE + +#endif //__XCAM_3A_TYPES_H + diff --git a/xcore/base/xcam_buffer.h b/xcore/base/xcam_buffer.h new file mode 100644 index 0000000..02e1afa --- /dev/null +++ b/xcore/base/xcam_buffer.h @@ -0,0 +1,139 @@ +/* + * xcam_buffer.h - video buffer standard version + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef C_XCAM_BUFFER_H +#define C_XCAM_BUFFER_H + +#include <base/xcam_common.h> + +XCAM_BEGIN_DECLARE +#include <linux/videodev2.h> + +#ifndef V4L2_PIX_FMT_XBGR32 +#define V4L2_PIX_FMT_XBGR32 v4l2_fourcc('X', 'R', '2', '4') +#endif + +#ifndef V4L2_PIX_FMT_ABGR32 +#define V4L2_PIX_FMT_ABGR32 v4l2_fourcc('A', 'R', '2', '4') +#endif + +#ifndef V4L2_PIX_FMT_XRGB32 +#define V4L2_PIX_FMT_XRGB32 v4l2_fourcc('B', 'X', '2', '4') +#endif + +#ifndef V4L2_PIX_FMT_ARGB32 +#define V4L2_PIX_FMT_ARGB32 v4l2_fourcc('B', 'A', '2', '4') +#endif + +#ifndef V4L2_PIX_FMT_RGBA32 +#define V4L2_PIX_FMT_RGBA32 v4l2_fourcc('A', 'B', '2', '4') +#endif + +/* + * Define special format for 16 bit color + * every format start with 'X' + * + * XCAM_PIX_FMT_RGB48: RGB with color-bits = 16 + * XCAM_PIX_FMT_RGBA64, RGBA with color-bits = 16 + * XCAM_PIX_FMT_SGRBG16, Bayer, with color-bits = 16 + */ + +#define XCAM_PIX_FMT_RGB48 v4l2_fourcc('w', 'R', 'G', 'B') +#define XCAM_PIX_FMT_RGBA64 v4l2_fourcc('w', 'R', 'G', 'a') +#define XCAM_PIX_FMT_SGRBG16 v4l2_fourcc('w', 'B', 'A', '0') +#define XCAM_PIX_FMT_LAB v4l2_fourcc('h', 'L', 'a', 'b') +#define XCAM_PIX_FMT_RGB48_planar v4l2_fourcc('n', 'R', 'G', 0x48) +#define XCAM_PIX_FMT_RGB24_planar v4l2_fourcc('n', 'R', 'G', 0x24) +#define XCAM_PIX_FMT_SGRBG16_planar v4l2_fourcc('n', 'B', 'A', '0') +#define XCAM_PIX_FMT_SGRBG8_planar v4l2_fourcc('n', 'B', 'A', '8') + +#define XCAM_VIDEO_MAX_COMPONENTS 4 + + +typedef struct _XCamVideoBufferPlanarInfo XCamVideoBufferPlanarInfo; +struct _XCamVideoBufferPlanarInfo { + uint32_t width; + uint32_t height; + uint32_t pixel_bytes; +}; + +typedef struct _XCamVideoBufferInfo XCamVideoBufferInfo; +struct _XCamVideoBufferInfo { + uint32_t format; // v4l2 fourcc + uint32_t color_bits; + uint32_t width; + uint32_t height; + uint32_t aligned_width; + uint32_t aligned_height; + uint32_t size; + uint32_t components; + uint32_t strides [XCAM_VIDEO_MAX_COMPONENTS]; + uint32_t offsets [XCAM_VIDEO_MAX_COMPONENTS]; +}; + +typedef enum { + XCAM_MEM_TYPE_CPU, + XCAM_MEM_TYPE_GPU, + XCAM_MEM_TYPE_PRIVATE = 0x8000, + XCAM_MEM_TYPE_PRIVATE_BO, +} XCamMemType; + +typedef struct _XCamVideoBuffer XCamVideoBuffer; + +struct _XCamVideoBuffer { + XCamVideoBufferInfo info; + uint32_t mem_type; + int64_t timestamp; + + void (*ref) (XCamVideoBuffer *); + void (*unref) (XCamVideoBuffer *); + uint8_t *(*map) (XCamVideoBuffer *); + void (*unmap) (XCamVideoBuffer *); + int (*get_fd) (XCamVideoBuffer *); +}; + +typedef struct _XCamVideoBufferIntel XCamVideoBufferIntel; +struct _XCamVideoBufferIntel { + XCamVideoBuffer base; + + void *(*get_bo) (XCamVideoBufferIntel *); +}; + +#define xcam_video_buffer_ref(buf) (buf)->ref(buf) +#define xcam_video_buffer_unref(buf) (buf)->unref(buf) +#define xcam_video_buffer_map(buf) (buf)->map(buf) +#define xcam_video_buffer_unmap(buf) (buf)->unmap(buf) +#define xcam_video_buffer_get_fd(buf) (buf)->get_fd(buf) +#define xcam_video_buffer_intel_get_bo(buf) (buf)->get_bo(buf) + +XCamReturn +xcam_video_buffer_info_reset ( + XCamVideoBufferInfo *info, + uint32_t format, uint32_t width, uint32_t height, + uint32_t aligned_width, uint32_t aligned_height, uint32_t size); + +XCamReturn +xcam_video_buffer_get_planar_info ( + const XCamVideoBufferInfo *buf_info, XCamVideoBufferPlanarInfo *planar_info, const uint32_t index); + + +XCAM_END_DECLARE + +#endif // C_XCAM_BUFFER_H diff --git a/xcore/base/xcam_common.h b/xcore/base/xcam_common.h new file mode 100644 index 0000000..46cc6fd --- /dev/null +++ b/xcore/base/xcam_common.h @@ -0,0 +1,119 @@ +/* + * xcam_common.h - xcam common and utilities + * + * Copyright (c) 2014 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_COMMON_H +#define XCAM_COMMON_H + +#include <string.h> +#include <stddef.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <errno.h> +#include <assert.h> +#include <pthread.h> +#include <math.h> +#include <base/xcam_defs.h> + +XCAM_BEGIN_DECLARE + +typedef enum { + XCAM_RETURN_NO_ERROR = 0, + XCAM_RETURN_BYPASS = 1, + + /* errors */ + XCAM_RETURN_ERROR_PARAM = -1, + XCAM_RETURN_ERROR_MEM = -2, + XCAM_RETURN_ERROR_FILE = -3, + XCAM_RETURN_ERROR_AIQ = -4, + XCAM_RETURN_ERROR_ISP = -5, + XCAM_RETURN_ERROR_SENSOR = -6, + XCAM_RETURN_ERROR_THREAD = -7, + XCAM_RETURN_ERROR_IOCTL = -8, + XCAM_RETURN_ERROR_CL = -9, + XCAM_RETURN_ERROR_ORDER = -10, + + XCAM_RETURN_ERROR_TIMEOUT = -20, + + XCAM_RETURN_ERROR_UNKNOWN = -255, +} XCamReturn; + +#define xcam_malloc_type(TYPE) (TYPE*)(xcam_malloc(sizeof(TYPE))) +#define xcam_malloc_type_array(TYPE, num) (TYPE*)(xcam_malloc(sizeof(TYPE) * (num))) + +#define xcam_malloc0_type(TYPE) (TYPE*)(xcam_malloc0(sizeof(TYPE))) +#define xcam_malloc0_type_array(TYPE, num) (TYPE*)(xcam_malloc0(sizeof(TYPE) * (num))) + +#define xcam_mem_clear(v_stack) memset(&(v_stack), 0, sizeof(v_stack)) + +uint32_t xcam_version (); +void * xcam_malloc (size_t size); +void * xcam_malloc0 (size_t size); + +void xcam_free (void *ptr); + +/* + * return, 0 successfully + * else, check errno + */ +int xcam_device_ioctl (int fd, int cmd, void *arg); +const char *xcam_fourcc_to_string (uint32_t fourcc); + +void xcam_set_log (const char* file_name); +void xcam_print_log (const char* format, ...); + +static inline uint32_t +xcam_ceil (uint32_t value, const uint32_t align) { + return (value + align - 1) / align * align; +} + +static inline uint32_t +xcam_around (uint32_t value, const uint32_t align) { + return (value + align / 2) / align * align; +} + +static inline uint32_t +xcam_floor (uint32_t value, const uint32_t align) { + return value / align * align; +} + +// return true or false +static inline int +xcam_ret_is_ok (XCamReturn err) { + return err >= XCAM_RETURN_NO_ERROR; +} + +//format to [0 ~ 360] +static inline float +format_angle (float angle) +{ + if (angle < 0.0f) + angle += 360.0f; + if (angle >= 360.0f) + angle -= 360.0f; + + XCAM_ASSERT (angle >= 0.0f && angle < 360.0f); + return angle; +} + +XCAM_END_DECLARE + +#endif //XCAM_COMMON_H + diff --git a/xcore/base/xcam_defs.h b/xcore/base/xcam_defs.h new file mode 100644 index 0000000..276644f --- /dev/null +++ b/xcore/base/xcam_defs.h @@ -0,0 +1,125 @@ +/* + * xcam_defs.h - macros defines + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_DEFS_H +#define XCAM_DEFS_H + +#ifndef XCAM_LOG_ERROR +#define XCAM_LOG_ERROR(format, ...) \ + xcam_print_log ("XCAM ERROR %s:%d: " format "\n", __FILE__, __LINE__, ## __VA_ARGS__) +#endif + +#ifndef XCAM_LOG_WARNING +#define XCAM_LOG_WARNING(format, ...) \ + xcam_print_log ("XCAM WARNING %s:%d: " format "\n", __FILE__, __LINE__, ## __VA_ARGS__) +#endif + +#ifndef XCAM_LOG_INFO +#define XCAM_LOG_INFO(format, ...) \ + xcam_print_log ("XCAM INFO %s:%d: " format "\n", __FILE__, __LINE__, ## __VA_ARGS__) +#endif + +#ifdef DEBUG +#ifndef XCAM_LOG_DEBUG +#define XCAM_LOG_DEBUG(format, ...) \ + xcam_print_log ("XCAM DEBUG %s:%d: " format "\n", __FILE__, __LINE__, ## __VA_ARGS__) +#endif +#else +#define XCAM_LOG_DEBUG(...) +#endif + +#define XCAM_ASSERT(exp) assert(exp) + +#ifdef __cplusplus +#define XCAM_BEGIN_DECLARE extern "C" { +#define XCAM_END_DECLARE } +#else +#define XCAM_BEGIN_DECLARE +#define XCAM_END_DECLARE +#endif + +#ifndef __user +#define __user +#endif + +#define XCAM_UNUSED(variable) (void)(variable) + +#define XCAM_CONSTRUCTOR(obj, TYPE, ...) new (&obj) TYPE(## __VA_ARGS__) +#define XCAM_DESTRUCTOR(obj, TYPE) (obj).~TYPE() + +#define XCAM_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define XCAM_MIN(a, b) ((a) < (b) ? (a) : (b)) +#define XCAM_CLAMP(v, min, max) \ + (((v) < (min)) ? (min) : (((v) > (max)) ? (max) : (v))) + +#define XCAM_FAIL_RETURN(LEVEL, exp, ret, msg, ...) \ + if (!(exp)) { \ + XCAM_LOG_##LEVEL (msg, ## __VA_ARGS__); \ + return (ret); \ + } + +#define XCAM_DEAD_COPY(ClassObj) \ + ClassObj (const ClassObj&); \ + ClassObj & operator= (const ClassObj&) \ + + +#define XCAM_STR(str) ((str) ? (str) : "null") +#define XCAM_BOOL2STR(value) ((value) ? "true" : "false") + +#define XCAM_DOUBLE_EQUAL(a, b, tolerance) \ + (((a) >= ((b) - (tolerance))) && ((a) <= ((b) + (tolerance)))) + +#define XCAM_DOUBLE_EQUAL_AROUND(a, b) \ + XCAM_DOUBLE_EQUAL((a), (b), 0.000001) + +#define XCAM_GAMMA_TABLE_SIZE 256 +#define XCAM_MAX_STR_SIZE 4096 +#undef XCAM_CL_MAX_STR_SIZE +#define XCAM_CL_MAX_STR_SIZE 1024 + +#define XCAM_TIMESPEC_2_USEC(timespec) ((timespec).tv_sec*1000000LL + (timespec).tv_nsec/1000) +#define XCAM_TIMEVAL_2_USEC(timeval) ((timeval).tv_sec*1000000LL + (timeval).tv_usec) + +#define XCAM_TIMESTAMP_2_SECONDS(t) ((t)/1000000) +#define XCAM_SECONDS_2_TIMESTAMP(t) ((t)*1000000) + +#define XCAM_TIMESTAMP_FORMAT "%02d:%02d:%02d.%03d" + +#define XCAM_TIMESTAMP_ARGS(t) \ + (int32_t)(XCAM_TIMESTAMP_2_SECONDS(t)/3600), \ + (int32_t)((XCAM_TIMESTAMP_2_SECONDS(t)%3600)/60), \ + (int32_t)(XCAM_TIMESTAMP_2_SECONDS(t)%60), \ + (int32_t)(((t)/1000)%1000) + +// align must be a interger of power 2 +#define XCAM_ALIGN_UP(value, align) (((value)+((align)-1))&(~((align)-1))) +#define XCAM_ALIGN_DOWN(value, align) ((value)&(~((align)-1))) +#define XCAM_ALIGN_AROUND(value, align) (((value)+(align)/2)/(align)*(align)) + +#ifdef _LP64 +#define PRIuS "zu" +#else +#define PRIuS "u" +#endif + +#define PI 3.1415926f +#define degree2radian(degree) ((degree) * PI / 180.0f) + +#endif //XCAM_DEFS_H diff --git a/xcore/base/xcam_params.h b/xcore/base/xcam_params.h new file mode 100644 index 0000000..8f15a56 --- /dev/null +++ b/xcore/base/xcam_params.h @@ -0,0 +1,107 @@ +/* + * xcam_params.h - 3A parameters + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef C_XCAM_PARAMS_H +#define C_XCAM_PARAMS_H + +#include <base/xcam_defs.h> +#include <base/xcam_common.h> +#include <base/xcam_3a_types.h> + +XCAM_BEGIN_DECLARE + +typedef struct _XCamAeParam { + XCamAeMode mode; + XCamAeMeteringMode metering_mode; + XCam3AWindow window; + XCam3AWindow window_list[XCAM_AE_MAX_METERING_WINDOW_COUNT]; + XCamFlickerMode flicker_mode; + /* speed, default 1.0 */ + double speed; + + /* exposure limitation */ + uint64_t exposure_time_min, exposure_time_max; + double max_analog_gain; + + /* exposure manual values */ + uint64_t manual_exposure_time; + double manual_analog_gain; + + double aperture_fn; + + /*ev*/ + double ev_shift; +} XCamAeParam; + +typedef struct _XCamAwbParam { + XCamAwbMode mode; + /* speed, default 1.0 */ + double speed; + uint32_t cct_min, cct_max; + XCam3AWindow window; + + /* manual gain, default 0.0 */ + double gr_gain; + double r_gain; + double b_gain; + double gb_gain; +} XCamAwbParam; + +typedef struct _XCamAfParam { + +} XCamAfParam; + +typedef struct _XCamCommonParam { + /* R, G, B gamma table, size = XCAM_GAMMA_TABLE_SIZE */ + bool is_manual_gamma; + double r_gamma [XCAM_GAMMA_TABLE_SIZE]; + double g_gamma [XCAM_GAMMA_TABLE_SIZE]; + double b_gamma [XCAM_GAMMA_TABLE_SIZE]; + + /* + * manual brightness, contrast, hue, saturation, sharpness + * -1.0 < value < 1.0 + */ + double nr_level; + double tnr_level; + + double brightness; + double contrast; + double hue; + double saturation; + double sharpness; + + /* others */ + bool enable_dvs; + bool enable_gbce; + bool enable_night_mode; + XCamColorEffect color_effect; +} XCamCommonParam; + +typedef struct _XCamSmartAnalysisParam { + uint32_t width; + uint32_t height; + double fps; + +} XCamSmartAnalysisParam; + +XCAM_END_DECLARE + +#endif //C_XCAM_PARAMS_H diff --git a/xcore/base/xcam_smart_description.h b/xcore/base/xcam_smart_description.h new file mode 100644 index 0000000..62ca991 --- /dev/null +++ b/xcore/base/xcam_smart_description.h @@ -0,0 +1,100 @@ +/* + * xcam_smart_description.h - libxcam smart analysis description + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + * Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef C_XCAM_SMART_ANALYSIS_DESCRIPTION_H +#define C_XCAM_SMART_ANALYSIS_DESCRIPTION_H + +#include <base/xcam_common.h> +#include <base/xcam_params.h> +#include <base/xcam_3a_result.h> +#include <base/xcam_buffer.h> + +XCAM_BEGIN_DECLARE + +#define XCAM_SMART_ANALYSIS_LIB_DESCRIPTION "xcam_smart_analysis_desciption" + +typedef struct _XCamSmartAnalysisContext XCamSmartAnalysisContext; + +typedef XCamReturn (*XcamPostResultsFunc) ( + XCamSmartAnalysisContext *context, + const XCamVideoBuffer *buffer, + XCam3aResultHead *results[], uint32_t res_count); + + +#define XCAM_SMART_PLUGIN_PRIORITY_HIGH 1 +#define XCAM_SMART_PLUGIN_PRIORITY_DEFAULT 10 +#define XCAM_SMART_PLUGIN_PRIORITY_LOW 100 + +/* \brief C interface of Smart Analysis Description + * <version> xcam version + * <size> description structure size, sizeof (XCamSmartAnalysisDescription) + * <priority> smart plugin priority; the less value the higher priority; 0, highest priority + * <name> smart pluign name, or use file name if NULL + */ +typedef struct _XCamSmartAnalysisDescription { + uint32_t version; + uint32_t size; + uint32_t priority; + const char *name; + + /*! \brief initialize smart analysis context. + * + * \param[out] context create context handle + * \param[out] async_mode 0, sync mode; 1, async mode + * \param[in] post_func plugin can use post_func to post results in async mode + */ + XCamReturn (*create_context) (XCamSmartAnalysisContext **context, + uint32_t *async_mode, XcamPostResultsFunc post_func); + /*! \brief destroy smart analysis context. + * + * \param[in] context create context handle + */ + XCamReturn (*destroy_context) (XCamSmartAnalysisContext *context); + + /*! \brief update smart analysis context parameters. + * + * \param[in] context context handle + * \param[in] params new parameters + */ + XCamReturn (*update_params) (XCamSmartAnalysisContext *context, const XCamSmartAnalysisParam *params); + + /*! \brief analyze data and get result,. + * + * \param[in] context context handle + * \param[in] buffer image buffer + * \param[out] results analysis results array, only for sync mode (<async_mode> = 0) + * \param[in/out] res_count in, max results array size; out, return results count. + */ + XCamReturn (*analyze) (XCamSmartAnalysisContext *context, XCamVideoBuffer *buffer, + XCam3aResultHead *results[], uint32_t *res_count); + + /*! \brief free smart results. + * + * \param[in] context context handle + * \param[in] results analysis results + * \param[in] res_count analysis results count + */ + void (*free_results) (XCamSmartAnalysisContext *context, XCam3aResultHead *results[], uint32_t res_count); +} XCamSmartAnalysisDescription; + +XCAM_END_DECLARE + +#endif //C_XCAM_SMART_ANALYSIS_DESCRIPTION_H diff --git a/xcore/base/xcam_smart_result.h b/xcore/base/xcam_smart_result.h new file mode 100644 index 0000000..ba3684c --- /dev/null +++ b/xcore/base/xcam_smart_result.h @@ -0,0 +1,72 @@ +/* + * xcam_smart_result.h - smart result(meta data) + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef C_XCAM_SMART_RESULT_H +#define C_XCAM_SMART_RESULT_H + +#include <stdlib.h> +#include <stdint.h> +#include <stddef.h> +#include <base/xcam_3a_result.h> + +XCAM_BEGIN_DECLARE + +typedef struct _XCamFaceInfo { + uint32_t id; + uint32_t pos_x; + uint32_t pos_y; + uint32_t width; + uint32_t height; + uint32_t factor; + uint32_t landmark[128]; +} XCamFaceInfo; + +/* + * Face detection result + * head.type = XCAM_3A_RESULT_FACE_DETECTION; + * head.process_type = XCAM_IMAGE_PROCESS_POST; + * head.destroy = free fd result. + */ + +typedef struct _XCamFDResult { + XCam3aResultHead head; + uint32_t face_num; + XCamFaceInfo faces[0]; +} XCamFDResult; + +/* + * Digital Video Stabilizer result + * head.type = XCAM_3A_RESULT_DVS; + * head.process_type = XCAM_IMAGE_PROCESS_POST; + * head.destroy = free dvs result. + */ + +typedef struct _XCamDVSResult { + XCam3aResultHead head; + int frame_id; + int frame_width; + int frame_height; + double proj_mat[9]; +} XCamDVSResult; + +XCAM_END_DECLARE + +#endif //C_XCAM_SMART_RESULT_H + diff --git a/xcore/buffer_pool.cpp b/xcore/buffer_pool.cpp new file mode 100644 index 0000000..ce57363 --- /dev/null +++ b/xcore/buffer_pool.cpp @@ -0,0 +1,217 @@ +/* + * buffer_pool.cpp - buffer pool + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "buffer_pool.h" + +namespace XCam { + +BufferProxy::BufferProxy (const VideoBufferInfo &info, const SmartPtr<BufferData> &data) + : VideoBuffer (info) + , _data (data) +{ + XCAM_ASSERT (data.ptr ()); +} + +BufferProxy::BufferProxy (const SmartPtr<BufferData> &data) + : _data (data) +{ + XCAM_ASSERT (data.ptr ()); +} + +BufferProxy::~BufferProxy () +{ + if (_pool.ptr ()) { + _pool->release (_data); + } + _data.release (); +} + +uint8_t * +BufferProxy::map () +{ + XCAM_ASSERT (_data.ptr ()); + return _data->map (); +} + +bool +BufferProxy::unmap () +{ + XCAM_ASSERT (_data.ptr ()); + return _data->unmap (); +} + +int +BufferProxy::get_fd () +{ + XCAM_ASSERT (_data.ptr ()); + return _data->get_fd (); +} + +BufferPool::BufferPool () + : _allocated_num (0) + , _max_count (0) + , _started (false) +{ +} + +BufferPool::~BufferPool () +{ +} + +bool +BufferPool::set_video_info (const VideoBufferInfo &info) +{ + VideoBufferInfo new_info = info; + SmartLock lock (_mutex); + + XCAM_FAIL_RETURN ( + ERROR, + fixate_video_info (new_info), + false, + "BufferPool fixate video info failed"); + update_video_info_unsafe (new_info); + return true; +} + +void +BufferPool::update_video_info_unsafe (const VideoBufferInfo &info) +{ + _buffer_info = info; +} + +bool +BufferPool::reserve (uint32_t max_count) +{ + uint32_t i = 0; + + XCAM_ASSERT (max_count); + + SmartLock lock (_mutex); + + for (i = _allocated_num; i < max_count; ++i) { + SmartPtr<BufferData> new_data = allocate_data (_buffer_info); + if (!new_data.ptr ()) + break; + _buf_list.push (new_data); + } + + XCAM_FAIL_RETURN ( + ERROR, + i > 0, + false, + "BufferPool reserve failed with none buffer data allocated"); + + if (i != max_count) { + XCAM_LOG_WARNING ("BufferPool expect to reserve %d data but only reserved %d", max_count, i); + } + _max_count = i; + _allocated_num = _max_count; + _started = true; + + return true; +} + +bool +BufferPool::add_data_unsafe (const SmartPtr<BufferData> &data) +{ + if (!data.ptr ()) + return false; + + _buf_list.push (data); + ++_allocated_num; + + XCAM_ASSERT (_allocated_num <= _max_count || !_max_count); + return true; +} + +SmartPtr<VideoBuffer> +BufferPool::get_buffer (const SmartPtr<BufferPool> &self) +{ + SmartPtr<BufferProxy> ret_buf; + SmartPtr<BufferData> data; + + { + SmartLock lock (_mutex); + if (!_started) + return NULL; + } + + XCAM_ASSERT (self.ptr () == this); + XCAM_FAIL_RETURN( + WARNING, + self.ptr () == this, + NULL, + "BufferPool get_buffer failed since parameter<self> not this"); + + data = _buf_list.pop (); + if (!data.ptr ()) { + XCAM_LOG_DEBUG ("BufferPool failed to get buffer"); + return NULL; + } + ret_buf = create_buffer_from_data (data); + ret_buf->set_buf_pool (self); + + return ret_buf; +} + +SmartPtr<VideoBuffer> +BufferPool::get_buffer () +{ + return get_buffer (SmartPtr<BufferPool>(this)); +} + +void +BufferPool::stop () +{ + { + SmartLock lock (_mutex); + _started = false; + } + _buf_list.pause_pop (); +} + +void +BufferPool::release (SmartPtr<BufferData> &data) +{ + { + SmartLock lock (_mutex); + if (!_started) + return; + } + _buf_list.push (data); +} + +bool +BufferPool::fixate_video_info (VideoBufferInfo &info) +{ + XCAM_UNUSED (info); + return true; +} + +SmartPtr<BufferProxy> +BufferPool::create_buffer_from_data (SmartPtr<BufferData> &data) +{ + const VideoBufferInfo &info = get_video_info (); + + XCAM_ASSERT (data.ptr ()); + return new BufferProxy (info, data); +} + +}; diff --git a/xcore/buffer_pool.h b/xcore/buffer_pool.h new file mode 100644 index 0000000..899cbf0 --- /dev/null +++ b/xcore/buffer_pool.h @@ -0,0 +1,132 @@ +/* + * buffer_pool.h - buffer pool + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_BUFFER_POOL_H +#define XCAM_BUFFER_POOL_H + +#include <xcam_std.h> +#include <safe_list.h> +#include <video_buffer.h> + +namespace XCam { + +class BufferPool; + +class BufferData { +protected: + explicit BufferData () {} + +public: + virtual ~BufferData () {} + + virtual uint8_t *map () = 0; + virtual bool unmap () = 0; + virtual int get_fd () { + return -1; + } + +private: + XCAM_DEAD_COPY (BufferData); +}; + +class BufferProxy + : public VideoBuffer +{ +public: + explicit BufferProxy (const VideoBufferInfo &info, const SmartPtr<BufferData> &data); + explicit BufferProxy (const SmartPtr<BufferData> &data); + virtual ~BufferProxy (); + + void set_buf_pool (const SmartPtr<BufferPool> &pool) { + _pool = pool; + } + + // derived from VideoBuffer + virtual uint8_t *map (); + virtual bool unmap (); + virtual int get_fd(); + +protected: + SmartPtr<BufferData> &get_buffer_data () { + return _data; + } + +private: + XCAM_DEAD_COPY (BufferProxy); + +private: + SmartPtr<BufferData> _data; + SmartPtr<BufferPool> _pool; +}; + +class BufferPool + : public RefObj +{ + friend class BufferProxy; + +public: + explicit BufferPool (); + virtual ~BufferPool (); + + bool set_video_info (const VideoBufferInfo &info); + bool reserve (uint32_t max_count = 4); + SmartPtr<VideoBuffer> get_buffer (const SmartPtr<BufferPool> &self); + SmartPtr<VideoBuffer> get_buffer (); + + void stop (); + + const VideoBufferInfo & get_video_info () const { + return _buffer_info; + } + + bool has_free_buffers () { + return !_buf_list.is_empty (); + } + + uint32_t get_free_buffer_size () { + return _buf_list.size (); + } + +protected: + virtual bool fixate_video_info (VideoBufferInfo &info); + virtual SmartPtr<BufferData> allocate_data (const VideoBufferInfo &buffer_info) = 0; + virtual SmartPtr<BufferProxy> create_buffer_from_data (SmartPtr<BufferData> &data); + + bool add_data_unsafe (const SmartPtr<BufferData> &data); + + void update_video_info_unsafe (const VideoBufferInfo &info); + +private: + void release (SmartPtr<BufferData> &data); + XCAM_DEAD_COPY (BufferPool); + +private: + Mutex _mutex; + VideoBufferInfo _buffer_info; + SafeList<BufferData> _buf_list; + uint32_t _allocated_num; + uint32_t _max_count; + bool _started; +}; + +}; + +#endif //XCAM_BUFFER_POOL_H + diff --git a/xcore/calibration_parser.cpp b/xcore/calibration_parser.cpp new file mode 100644 index 0000000..5d6f4d5 --- /dev/null +++ b/xcore/calibration_parser.cpp @@ -0,0 +1,241 @@ +/* + * calibration_parser.cpp - parse fisheye calibration file + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Junkai Wu <junkai.wu@intel.com> + */ + +#include "calibration_parser.h" +#include "file_handle.h" + +namespace XCam { + +CalibrationParser::CalibrationParser() +{ +} + +#define CHECK_NULL(ptr) \ + if(ptr == NULL) { \ + XCAM_LOG_ERROR("Parse file failed"); \ + return XCAM_RETURN_ERROR_FILE; \ + } + +XCamReturn +CalibrationParser::parse_intrinsic_param(char *file_body, IntrinsicParameter &intrinsic_param) +{ + char *line_str = NULL; + char *line_endptr = NULL; + char *tok_str = NULL; + char *tok_endptr = NULL; + static const char *line_tokens = "\r\n"; + static const char *str_tokens = " \t"; + + do { + line_str = strtok_r(file_body, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + while(tok_str == NULL || tok_str[0] == '#') { + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + } + + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + while(tok_str == NULL || tok_str[0] == '#') { + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + } + intrinsic_param.poly_length = strtol(tok_str, NULL, 10); + + XCAM_FAIL_RETURN ( + ERROR, intrinsic_param.poly_length <= XCAM_INTRINSIC_MAX_POLY_SIZE, + XCAM_RETURN_ERROR_PARAM, + "intrinsic poly length:%d is larger than max_size:%d.", + intrinsic_param.poly_length, XCAM_INTRINSIC_MAX_POLY_SIZE); + + for(uint32_t i = 0; i < intrinsic_param.poly_length; i++) { + tok_str = strtok_r(NULL, str_tokens, &tok_endptr); + CHECK_NULL(tok_str); + intrinsic_param.poly_coeff[i] = (strtof(tok_str, NULL)); + } + + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + while(tok_str == NULL || tok_str[0] == '#') { + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + } + intrinsic_param.yc = strtof(tok_str, NULL); + + tok_str = strtok_r(NULL, str_tokens, &tok_endptr); + CHECK_NULL(tok_str); + intrinsic_param.xc = strtof(tok_str, NULL); + + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + while(tok_str == NULL || tok_str[0] == '#') { + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + } + intrinsic_param.c = strtof(tok_str, NULL); + + tok_str = strtok_r(NULL, str_tokens, &tok_endptr); + CHECK_NULL(tok_str); + intrinsic_param.d = strtof(tok_str, NULL); + + tok_str = strtok_r(NULL, str_tokens, &tok_endptr); + CHECK_NULL(tok_str); + intrinsic_param.e = strtof(tok_str, NULL); + } while(0); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CalibrationParser::parse_extrinsic_param(char *file_body, ExtrinsicParameter &extrinsic_param) +{ + char *line_str = NULL; + char *line_endptr = NULL; + char *tok_str = NULL; + char *tok_endptr = NULL; + static const char *line_tokens = "\r\n"; + static const char *str_tokens = " \t"; + + do { + line_str = strtok_r(file_body, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + while(tok_str == NULL || tok_str[0] == '#') { + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + } + extrinsic_param.trans_x = strtof(tok_str, NULL); + + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + while(tok_str == NULL || tok_str[0] == '#') { + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + } + extrinsic_param.trans_y = strtof(tok_str, NULL); + + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + while(tok_str == NULL || tok_str[0] == '#') { + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + } + extrinsic_param.trans_z = strtof(tok_str, NULL); + + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + while(tok_str == NULL || tok_str[0] == '#') { + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + } + extrinsic_param.roll = strtof(tok_str, NULL); + + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + while(tok_str == NULL || tok_str[0] == '#') { + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + } + extrinsic_param.pitch = strtof(tok_str, NULL); + + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + while(tok_str == NULL || tok_str[0] == '#') { + line_str = strtok_r(NULL, line_tokens, &line_endptr); + CHECK_NULL(line_str); + tok_str = strtok_r(line_str, str_tokens, &tok_endptr); + } + extrinsic_param.yaw = strtof(tok_str, NULL); + } while(0); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +CalibrationParser::parse_intrinsic_file(const char *file_path, IntrinsicParameter &intrinsic_param) +{ + XCAM_ASSERT (file_path); + + FileHandle file_reader; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + std::vector<char> context; + size_t file_size = 0; + + XCAM_FAIL_RETURN ( + WARNING, xcam_ret_is_ok (ret = file_reader.open (file_path, "r")), ret, + "open intrinsic file(%s) failed.", file_path); + XCAM_FAIL_RETURN ( + WARNING, xcam_ret_is_ok (ret = file_reader.get_file_size (file_size)), ret, + "read intrinsic file(%s) failed to get file size.", file_path); + context.resize (file_size + 1); + XCAM_FAIL_RETURN ( + WARNING, xcam_ret_is_ok (ret = file_reader.read_file (&context[0], file_size)), ret, + "read intrinsic file(%s) failed, file size:%d.", file_path, (int)file_size); + file_reader.close (); + context[file_size] = '\0'; + + return parse_intrinsic_param (&context[0], intrinsic_param); +} + +XCamReturn +CalibrationParser::parse_extrinsic_file(const char *file_path, ExtrinsicParameter &extrinsic_param) +{ + XCAM_ASSERT (file_path); + + FileHandle file_reader; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + std::vector<char> context; + size_t file_size = 0; + + XCAM_FAIL_RETURN ( + WARNING, xcam_ret_is_ok (ret = file_reader.open (file_path, "r")), ret, + "open extrinsic file(%s) failed.", file_path); + XCAM_FAIL_RETURN ( + WARNING, xcam_ret_is_ok (ret = file_reader.get_file_size (file_size)), ret, + "read extrinsic file(%s) failed to get file size.", file_path); + context.resize (file_size + 1); + XCAM_FAIL_RETURN ( + WARNING, xcam_ret_is_ok (ret = file_reader.read_file (&context[0], file_size)), ret, + "read extrinsic file(%s) failed, file size:%d.", file_path, (int)file_size); + file_reader.close (); + context[file_size] = '\0'; + + return parse_extrinsic_param (&context[0], extrinsic_param); +} + +} diff --git a/xcore/calibration_parser.h b/xcore/calibration_parser.h new file mode 100644 index 0000000..a07a3f4 --- /dev/null +++ b/xcore/calibration_parser.h @@ -0,0 +1,47 @@ +/* + * calibration_parser.h - parse fisheye calibration file + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Junkai Wu <junkai.wu@intel.com> + */ + +#ifndef XCAM_CALIBRATION_PARSER_H +#define XCAM_CALIBRATION_PARSER_H + +#include <xcam_utils.h> +#include <interface/data_types.h> + +namespace XCam { + +class CalibrationParser +{ +public: + explicit CalibrationParser (); + + XCamReturn parse_intrinsic_param(char *file_body, IntrinsicParameter &intrinsic_param); + XCamReturn parse_extrinsic_param(char *file_body, ExtrinsicParameter &extrinsic_param); + + //file generated by Scaramuzza's approach + XCamReturn parse_intrinsic_file(const char *file_path, IntrinsicParameter &intrinsic_param); + XCamReturn parse_extrinsic_file(const char *file_path, ExtrinsicParameter &extrinsic_param); + +private: + XCAM_DEAD_COPY (CalibrationParser); +}; + +} + +#endif // XCAM_CALIBRATION_PARSER_H diff --git a/xcore/device_manager.cpp b/xcore/device_manager.cpp new file mode 100644 index 0000000..6b92f5d --- /dev/null +++ b/xcore/device_manager.cpp @@ -0,0 +1,384 @@ +/* + * device_manager.h - device manager + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "device_manager.h" +#include "poll_thread.h" +#include "xcam_thread.h" +#include "x3a_image_process_center.h" +#include "x3a_analyzer_manager.h" + +#define XCAM_FAILED_STOP(exp, msg, ...) \ + if ((exp) != XCAM_RETURN_NO_ERROR) { \ + XCAM_LOG_ERROR (msg, ## __VA_ARGS__); \ + stop (); \ + return ret; \ + } + +namespace XCam { + +class MessageThread + : public Thread +{ +public: + explicit MessageThread (DeviceManager *dev_manager) + : Thread ("MessageThread") + , _manager (dev_manager) + {} + +protected: + virtual bool loop (); + + DeviceManager *_manager; +}; + +bool +MessageThread::loop() +{ + XCamReturn ret = _manager->message_loop(); + if (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_ERROR_TIMEOUT) + return true; + + return false; +} + +XCamMessage::XCamMessage (XCamMessageType type, int64_t timestamp, const char *message) + : timestamp (timestamp) + , msg_id (type) + , msg (NULL) +{ + if (message) + this->msg = strndup (message, XCAM_MAX_STR_SIZE); +} + +XCamMessage::~XCamMessage () +{ + if (msg) + xcam_free (msg); +} + +DeviceManager::DeviceManager() + : _has_3a (true) + , _is_running (false) +{ + _3a_process_center = new X3aImageProcessCenter; + XCAM_LOG_DEBUG ("~DeviceManager construction"); +} + +DeviceManager::~DeviceManager() +{ + XCAM_LOG_DEBUG ("~DeviceManager destruction"); +} + +bool +DeviceManager::set_capture_device (SmartPtr<V4l2Device> device) +{ + if (is_running()) + return false; + + XCAM_ASSERT (device.ptr () && !_device.ptr ()); + _device = device; + return true; +} + +bool +DeviceManager::set_event_device (SmartPtr<V4l2SubDevice> device) +{ + if (is_running()) + return false; + + XCAM_ASSERT (device.ptr () && !_subdevice.ptr ()); + _subdevice = device; + return true; +} + +bool +DeviceManager::set_3a_analyzer (SmartPtr<X3aAnalyzer> analyzer) +{ + if (is_running()) + return false; + + XCAM_ASSERT (analyzer.ptr () && !_3a_analyzer.ptr ()); + _3a_analyzer = analyzer; + + return true; +} + +bool +DeviceManager::set_smart_analyzer (SmartPtr<SmartAnalyzer> analyzer) +{ + if (is_running()) + return false; + + XCAM_ASSERT (analyzer.ptr () && !_smart_analyzer.ptr ()); + _smart_analyzer = analyzer; + + return true; +} + +bool +DeviceManager::add_image_processor (SmartPtr<ImageProcessor> processor) +{ + if (is_running()) + return false; + + XCAM_ASSERT (processor.ptr ()); + return _3a_process_center->insert_processor (processor); +} + +bool +DeviceManager::set_poll_thread (SmartPtr<PollThread> thread) +{ + if (is_running ()) + return false; + + XCAM_ASSERT (thread.ptr () && !_poll_thread.ptr ()); + _poll_thread = thread; + return true; +} + +XCamReturn +DeviceManager::start () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + // start device + XCAM_ASSERT (_device->is_opened()); + if (!_device.ptr() || !_device->is_opened()) { + XCAM_FAILED_STOP (ret = XCAM_RETURN_ERROR_FILE, "capture device not ready"); + } + XCAM_FAILED_STOP (ret = _device->start(), "capture device start failed"); + + //start subdevice + //XCAM_ASSERT (_subdevice->is_opened()); + if (_subdevice.ptr()) { + if (!_subdevice->is_opened()) + XCAM_FAILED_STOP (ret = XCAM_RETURN_ERROR_FILE, "event device not ready"); + XCAM_FAILED_STOP (ret = _subdevice->start(), "start event device failed"); + } + + if (_has_3a) { + // Initialize and start analyzer + uint32_t width = 0, height = 0; + uint32_t fps_n = 0, fps_d = 0; + double framerate = 30.0; + + if (!_3a_analyzer.ptr()) { + _3a_analyzer = X3aAnalyzerManager::instance()->create_analyzer(); + if (!_3a_analyzer.ptr()) { + XCAM_FAILED_STOP (ret = XCAM_RETURN_ERROR_PARAM, "create analyzer failed"); + } + } + if (_3a_analyzer->prepare_handlers () != XCAM_RETURN_NO_ERROR) { + XCAM_FAILED_STOP (ret = XCAM_RETURN_ERROR_PARAM, "prepare analyzer handler failed"); + } + _3a_analyzer->set_results_callback (this); + + _device->get_size (width, height); + _device->get_framerate (fps_n, fps_d); + if (fps_d) + framerate = (double)fps_n / (double)fps_d; + XCAM_FAILED_STOP ( + ret = _3a_analyzer->init (width, height, framerate), + "initialize analyzer failed"); + + XCAM_FAILED_STOP (ret = _3a_analyzer->start (), "start analyzer failed"); + + if (_smart_analyzer.ptr()) { + if (_smart_analyzer->prepare_handlers () != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_INFO ("prepare smart analyzer handler failed"); + } + _smart_analyzer->set_results_callback (this); + if (_smart_analyzer->init (width, height, framerate) != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_INFO ("initialize smart analyzer failed"); + } + if (_smart_analyzer->start () != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_INFO ("start smart analyzer failed"); + } + } + + if (!_3a_process_center->has_processors ()) { + XCAM_LOG_ERROR ("image processors empty"); + } + + _3a_process_center->set_image_callback(this); + XCAM_FAILED_STOP (ret = _3a_process_center->start (), "3A process center start failed"); + + } + + //Initialize and start poll thread + XCAM_ASSERT (_poll_thread.ptr ()); + _poll_thread->set_capture_device (_device); + if (_subdevice.ptr ()) + _poll_thread->set_event_device (_subdevice); + _poll_thread->set_poll_callback (this); + _poll_thread->set_stats_callback (this); + + XCAM_FAILED_STOP (ret = _poll_thread->start(), "start poll failed"); + + _is_running = true; + + XCAM_LOG_DEBUG ("Device manager started"); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +DeviceManager::stop () +{ + _is_running = false; + + if (_poll_thread.ptr()) + _poll_thread->stop (); + + if (_3a_analyzer.ptr()) { + _3a_analyzer->stop (); + _3a_analyzer->deinit (); + } + if (_smart_analyzer.ptr()) { + _smart_analyzer->stop (); + _smart_analyzer->deinit (); + } + + if (_3a_process_center.ptr()) + _3a_process_center->stop (); + + if (_subdevice.ptr ()) + _subdevice->stop (); + + _device->stop (); + + _poll_thread.release (); + + XCAM_LOG_DEBUG ("Device manager stopped"); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +DeviceManager::x3a_stats_ready (const SmartPtr<X3aStats> &stats) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + X3aResultList results; + XCAM_ASSERT (_3a_analyzer.ptr()); + + ret = _3a_analyzer->push_3a_stats (stats); + XCAM_FAIL_RETURN (ERROR, + ret == XCAM_RETURN_NO_ERROR, + ret, + "analyze 3a statistics failed"); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +DeviceManager::dvs_stats_ready () +{ + XCAM_ASSERT (false); + // TODO + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +DeviceManager::scaled_image_ready (const SmartPtr<VideoBuffer> &buffer) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + if (!_smart_analyzer.ptr()) { + return XCAM_RETURN_NO_ERROR; + } + + ret = _smart_analyzer->push_buffer (buffer); + XCAM_FAIL_RETURN ( + ERROR, ret == XCAM_RETURN_NO_ERROR, ret, + "push frame buffer failed"); + + return XCAM_RETURN_NO_ERROR; +} + + +XCamReturn +DeviceManager::poll_buffer_ready (SmartPtr<VideoBuffer> &buf) +{ + if (_has_3a) { + if (_3a_process_center->put_buffer (buf) == false) + return XCAM_RETURN_ERROR_UNKNOWN; + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +DeviceManager::poll_buffer_failed (int64_t timestamp, const char *msg) +{ + post_message (XCAM_MESSAGE_BUF_ERROR, timestamp, msg); + return XCAM_RETURN_NO_ERROR; +} + +void +DeviceManager::x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results) +{ + XCamReturn ret = _3a_process_center->put_3a_results (results); + if (ret != XCAM_RETURN_NO_ERROR && ret != XCAM_RETURN_BYPASS) { + XCAM_LOG_WARNING ("apply 3a results failed"); + return; + } + AnalyzerCallback::x3a_calculation_done (analyzer, results); +} + +void +DeviceManager::x3a_calculation_failed (XAnalyzer *analyzer, int64_t timestamp, const char *msg) +{ + AnalyzerCallback::x3a_calculation_failed (analyzer, timestamp, msg); +} + +void +DeviceManager::process_buffer_done (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf) +{ + ImageProcessCallback::process_buffer_done (processor, buf); + handle_buffer (buf); +} + +void +DeviceManager::process_buffer_failed (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf) +{ + ImageProcessCallback::process_buffer_failed (processor, buf); +} + +void +DeviceManager::process_image_result_done (ImageProcessor *processor, const SmartPtr<X3aResult> &result) +{ + ImageProcessCallback::process_image_result_done (processor, result); +} + +void +DeviceManager::post_message (XCamMessageType type, int64_t timestamp, const char *msg) +{ + SmartPtr<XCamMessage> new_msg = new XCamMessage (type, timestamp, msg); + _msg_queue.push (new_msg); +} + +XCamReturn +DeviceManager::message_loop () +{ + const static int32_t msg_time_out = -1; //wait until wakeup + SmartPtr<XCamMessage> msg = _msg_queue.pop (msg_time_out); + if (!msg.ptr ()) + return XCAM_RETURN_ERROR_THREAD; + handle_message (msg); + return XCAM_RETURN_NO_ERROR; +} + +}; diff --git a/xcore/device_manager.h b/xcore/device_manager.h new file mode 100644 index 0000000..6835873 --- /dev/null +++ b/xcore/device_manager.h @@ -0,0 +1,149 @@ +/* + * device_manager.h - device manager + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_DEVICE_MANAGER_H +#define XCAM_DEVICE_MANAGER_H + +#include <xcam_std.h> +#include <v4l2_device.h> +#include <v4l2_buffer_proxy.h> +#include <x3a_analyzer.h> +#include <smart_analyzer.h> +#include <x3a_image_process_center.h> +#include <image_processor.h> +#include <poll_thread.h> +#include <stats_callback_interface.h> + +namespace XCam { + +enum XCamMessageType { + XCAM_MESSAGE_BUF_OK = 0, + XCAM_MESSAGE_BUF_ERROR, + XCAM_MESSAGE_STATS_OK, + XCAM_MESSAGE_STATS_ERROR, + XCAM_MESSAGE_3A_RESULTS_OK, + XCAM_MESSAGE_3A_RESULTS_ERROR, +}; + +struct XCamMessage { + int64_t timestamp; + XCamMessageType msg_id; + char *msg; + + XCamMessage ( + XCamMessageType type, + int64_t timestamp = InvalidTimestamp, + const char *message = NULL); + ~XCamMessage (); + + XCAM_DEAD_COPY (XCamMessage); +}; + +class MessageThread; + +class DeviceManager + : public PollCallback + , public StatsCallback + , public AnalyzerCallback + , public ImageProcessCallback +{ + friend class MessageThread; + +public: + DeviceManager(); + virtual ~DeviceManager(); + + bool set_capture_device (SmartPtr<V4l2Device> device); + bool set_event_device (SmartPtr<V4l2SubDevice> device); + bool set_3a_analyzer (SmartPtr<X3aAnalyzer> analyzer); + bool set_smart_analyzer (SmartPtr<SmartAnalyzer> analyzer); + bool add_image_processor (SmartPtr<ImageProcessor> processor); + bool set_poll_thread (SmartPtr<PollThread> thread); + + SmartPtr<V4l2Device>& get_capture_device () { + return _device; + } + SmartPtr<V4l2SubDevice>& get_event_device () { + return _subdevice; + } + SmartPtr<X3aAnalyzer>& get_analyzer () { + return _3a_analyzer; + } + + bool is_running () const { + return _is_running; + } + bool has_3a () const { + return _has_3a; + } + + XCamReturn start (); + XCamReturn stop (); + +protected: + virtual void handle_message (const SmartPtr<XCamMessage> &msg) = 0; + virtual void handle_buffer (const SmartPtr<VideoBuffer> &buf) = 0; + +protected: + //virtual functions derived from PollCallback + virtual XCamReturn poll_buffer_ready (SmartPtr<VideoBuffer> &buf); + virtual XCamReturn poll_buffer_failed (int64_t timestamp, const char *msg); + virtual XCamReturn x3a_stats_ready (const SmartPtr<X3aStats> &stats); + virtual XCamReturn dvs_stats_ready (); + virtual XCamReturn scaled_image_ready (const SmartPtr<VideoBuffer> &buffer); + + //virtual functions derived from AnalyzerCallback + virtual void x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results); + virtual void x3a_calculation_failed (XAnalyzer *analyzer, int64_t timestamp, const char *msg); + + //virtual functions derived from ImageProcessCallback + virtual void process_buffer_done (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf); + virtual void process_buffer_failed (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf); + virtual void process_image_result_done (ImageProcessor *processor, const SmartPtr<X3aResult> &result); + +private: + void post_message (XCamMessageType type, int64_t timestamp, const char *msg); + XCamReturn message_loop (); + + XCAM_DEAD_COPY (DeviceManager); + +protected: + SmartPtr<V4l2Device> _device; + SmartPtr<V4l2SubDevice> _subdevice; + SmartPtr<PollThread> _poll_thread; + + /* 3A calculation and image processing*/ + bool _has_3a; + SmartPtr<X3aAnalyzer> _3a_analyzer; + SmartPtr<X3aImageProcessCenter> _3a_process_center; + + /* msg queue */ + SafeList<XCamMessage> _msg_queue; + SmartPtr<MessageThread> _msg_thread; + + bool _is_running; + + /* smart analysis */ + SmartPtr<SmartAnalyzer> _smart_analyzer; +}; + +}; + +#endif //XCAM_DEVICE_MANAGER_H diff --git a/xcore/dma_video_buffer.cpp b/xcore/dma_video_buffer.cpp new file mode 100644 index 0000000..73abe73 --- /dev/null +++ b/xcore/dma_video_buffer.cpp @@ -0,0 +1,109 @@ +/* + * dma_video_buffer.cpp - dma buffer + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "dma_video_buffer.h" + +namespace XCam { + +class DmaVideoBufferPriv + : public DmaVideoBuffer +{ + friend SmartPtr<DmaVideoBuffer> external_buf_to_dma_buf (XCamVideoBuffer *buf); +protected: + DmaVideoBufferPriv (const VideoBufferInfo &info, XCamVideoBuffer *buf); + ~DmaVideoBufferPriv (); + +private: + XCamVideoBuffer *_external_buf; +}; + +DmaVideoBuffer::DmaVideoBuffer (const VideoBufferInfo &info, int dma_fd, bool need_close_fd) + : VideoBuffer (info) + , _dma_fd (dma_fd) + , _need_close_fd (need_close_fd) +{ + XCAM_ASSERT (dma_fd >= 0); +} + +DmaVideoBuffer::~DmaVideoBuffer () +{ + if (_need_close_fd && _dma_fd > 0) + close (_dma_fd); +} + +uint8_t * +DmaVideoBuffer::map () +{ + XCAM_ASSERT (false && "DmaVideoBuffer::map not supported"); + return NULL; +} +bool +DmaVideoBuffer::unmap () +{ + XCAM_ASSERT (false && "DmaVideoBuffer::map not supported"); + return false; +} + +int +DmaVideoBuffer::get_fd () +{ + return _dma_fd; +} + +DmaVideoBufferPriv::DmaVideoBufferPriv (const VideoBufferInfo &info, XCamVideoBuffer *buf) + : DmaVideoBuffer (info, xcam_video_buffer_get_fd (buf), false) + , _external_buf (buf) +{ + if (buf->ref) + xcam_video_buffer_ref (buf); +} + +DmaVideoBufferPriv::~DmaVideoBufferPriv () +{ + if (_external_buf && _external_buf->unref && _external_buf->ref) + xcam_video_buffer_unref (_external_buf); +} + +SmartPtr<DmaVideoBuffer> +external_buf_to_dma_buf (XCamVideoBuffer *buf) +{ + VideoBufferInfo buf_info; + SmartPtr<DmaVideoBuffer> video_buffer; + + XCAM_FAIL_RETURN ( + ERROR, buf, NULL, + "external_buf_to_dma_buf failed since buf is NULL"); + + int buffer_fd = 0; + if (buf->get_fd) + buffer_fd = xcam_video_buffer_get_fd(buf); + + XCAM_FAIL_RETURN ( + ERROR, buffer_fd > 0, NULL, + "external_buf_to_dma_buf failed, can't get buf file-handle"); + + buf_info.init (buf->info.format, buf->info.width, buf->info.height, + buf->info.aligned_width, buf->info.aligned_height, buf->info.size); + video_buffer = new DmaVideoBufferPriv (buf_info, buf); + XCAM_ASSERT (video_buffer.ptr ()); + return video_buffer; +} + +} diff --git a/xcore/dma_video_buffer.h b/xcore/dma_video_buffer.h new file mode 100644 index 0000000..a0d9f96 --- /dev/null +++ b/xcore/dma_video_buffer.h @@ -0,0 +1,54 @@ +/* + * dma_video_buffer.h - dma video buffer + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ +#ifndef XCAM_DMA_VIDEO_BUFFER_H +#define XCAM_DMA_VIDEO_BUFFER_H + +#include <xcam_std.h> +#include <video_buffer.h> +#include <unistd.h> + +namespace XCam { + +class DmaVideoBuffer + : public VideoBuffer +{ +public: + DmaVideoBuffer (const VideoBufferInfo &info, int dma_fd, bool need_close_fd = false); + + virtual ~DmaVideoBuffer (); + + virtual uint8_t *map (); + virtual bool unmap (); + virtual int get_fd (); + +private: + + XCAM_DEAD_COPY (DmaVideoBuffer); + +private: + int _dma_fd; + bool _need_close_fd; +}; + +SmartPtr<DmaVideoBuffer> external_buf_to_dma_buf (XCamVideoBuffer *buf); + +} + +#endif //XCAM_DMA_VIDEO_BUFFER_H diff --git a/xcore/drm_bo_buffer.cpp b/xcore/drm_bo_buffer.cpp new file mode 100644 index 0000000..18cc0bc --- /dev/null +++ b/xcore/drm_bo_buffer.cpp @@ -0,0 +1,289 @@ +/* + * drm_bo_buffer.cpp - drm bo buffer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "drm_bo_buffer.h" +#include "x3a_stats_pool.h" + +#define OCL_TILING_NONE 0 + +namespace XCam { + +DrmBoData::DrmBoData (SmartPtr<DrmDisplay> &display, drm_intel_bo *bo) + : _display (display) + , _bo (bo) + , _buf (NULL) + , _prime_fd (-1) + , _need_close_fd (true) +{ + XCAM_ASSERT (display.ptr ()); + XCAM_ASSERT (bo); +} + +DrmBoData::~DrmBoData () +{ + unmap (); + if (_bo) + drm_intel_bo_unreference (_bo); + if (_prime_fd != -1 && _need_close_fd) + close (_prime_fd); +} + +uint8_t * +DrmBoData::map () +{ + if (_buf) { + return _buf; + } + + uint32_t tiling_mode, swizzle_mode; + + drm_intel_bo_get_tiling (_bo, &tiling_mode, &swizzle_mode); + + if (tiling_mode != OCL_TILING_NONE) { + if (drm_intel_gem_bo_map_gtt (_bo) != 0) + return NULL; + } + else { + if (drm_intel_bo_map (_bo, 1) != 0) + return NULL; + } + + _buf = (uint8_t *)_bo->virt; + return _buf; +} + +bool +DrmBoData::unmap () +{ + if (!_buf || !_bo) + return true; + + uint32_t tiling_mode, swizzle_mode; + + drm_intel_bo_get_tiling (_bo, &tiling_mode, &swizzle_mode); + + if (tiling_mode != OCL_TILING_NONE) { + if (drm_intel_gem_bo_unmap_gtt (_bo) != 0) + return false; + } + else { + if (drm_intel_bo_unmap (_bo) != 0) + return false; + } + + _buf = NULL; + return true; +} + +int +DrmBoData::get_fd () +{ + if (_prime_fd == -1) { + if (drm_intel_bo_gem_export_to_prime (_bo, &_prime_fd) < 0) { + _prime_fd = -1; + XCAM_LOG_ERROR ("DrmBoData: failed to obtain prime fd: %s", strerror(errno)); + } + _need_close_fd = true; + } + + return _prime_fd; +} + +bool +DrmBoData::set_prime_fd (int fd, bool need_close) +{ + if (_prime_fd != -1) { + XCAM_LOG_ERROR ("DrmBoData: set_dma_fd failed, the current prime fd was already set"); + return false; + } + _prime_fd = fd; + _need_close_fd = need_close; + return true; +} + +DrmBoBuffer::DrmBoBuffer (const VideoBufferInfo &info, const SmartPtr<DrmBoData> &data) + : BufferProxy (info, data) + , SwappedBuffer (info, data) +{ + XCAM_ASSERT (data.ptr ()); +} + +drm_intel_bo * +DrmBoBuffer::get_bo () +{ + SmartPtr<BufferData> data = get_buffer_data (); + SmartPtr<DrmBoData> bo = data.dynamic_cast_ptr<DrmBoData> (); + + XCAM_FAIL_RETURN( + WARNING, + bo.ptr(), + NULL, + "DrmBoBuffer get_buffer_data failed with NULL"); + return bo->get_bo (); +} + +SmartPtr<X3aStats> +DrmBoBuffer::find_3a_stats () +{ + return find_typed_attach<X3aStats> (); +} + +SmartPtr<SwappedBuffer> +DrmBoBuffer::create_new_swap_buffer ( + const VideoBufferInfo &info, SmartPtr<BufferData> &data) +{ + XCAM_ASSERT (get_buffer_data ().ptr () == data.ptr ()); + + SmartPtr<DrmBoData> bo = data.dynamic_cast_ptr<DrmBoData> (); + + XCAM_FAIL_RETURN( + WARNING, + bo.ptr(), + NULL, + "DrmBoBuffer create_new_swap_buffer failed with NULL buffer data"); + + return new DrmBoBuffer (info, bo); +} + +DrmBoBufferPool::DrmBoBufferPool (SmartPtr<DrmDisplay> &display) + : _swap_flags (SwappedBuffer::SwapNone) + , _swap_init_order ((uint32_t)(SwappedBuffer::OrderY0Y1) | (uint32_t)(SwappedBuffer::OrderUV0UV1)) + , _display (display) +{ + xcam_mem_clear (_swap_offsets); + XCAM_ASSERT (display.ptr ()); + XCAM_LOG_DEBUG ("DrmBoBufferPool constructed"); +} + +DrmBoBufferPool::~DrmBoBufferPool () +{ + _display.release (); + XCAM_LOG_DEBUG ("DrmBoBufferPool destructed"); +} + +bool +DrmBoBufferPool::update_swap_init_order (uint32_t init_order) +{ + VideoBufferInfo info = get_video_info (); + XCAM_ASSERT (info.format); + + if ((_swap_flags & (uint32_t)(SwappedBuffer::SwapY)) && !(init_order & (uint32_t)(SwappedBuffer::OrderYMask))) { + XCAM_LOG_WARNING ("update swap init order failed, need init Y order, error order:0x%04x", init_order); + return false; + } + + if ((_swap_flags & (uint32_t)(SwappedBuffer::SwapUV)) && !(init_order & (uint32_t)(SwappedBuffer::OrderUVMask))) { + XCAM_LOG_WARNING ("update swap init order failed, need init UV order, error order:0x%04x", init_order); + return false; + } + _swap_init_order = init_order; + + XCAM_FAIL_RETURN ( + WARNING, + init_swap_order (info), + false, + "CL3aImageProcessor post_config failed"); + + update_video_info_unsafe (info); + + return true; +} + +bool +DrmBoBufferPool::fixate_video_info (VideoBufferInfo &info) +{ + if (info.format != V4L2_PIX_FMT_NV12) + return true; + + VideoBufferInfo out_info; + out_info.init (info.format, info.width, info.height, info.aligned_width, info.aligned_height); + + if (_swap_flags & (uint32_t)(SwappedBuffer::SwapY)) { + _swap_offsets[SwappedBuffer::SwapYOffset0] = out_info.offsets[0]; + _swap_offsets[SwappedBuffer::SwapYOffset1] = out_info.size; + out_info.size += out_info.strides[0] * out_info.aligned_height; + } + + if (_swap_flags & (uint32_t)(SwappedBuffer::SwapUV)) { + _swap_offsets[SwappedBuffer::SwapUVOffset0] = out_info.offsets[1]; + _swap_offsets[SwappedBuffer::SwapUVOffset1] = out_info.size; + out_info.size += out_info.strides[1] * (out_info.aligned_height + 1) / 2; + } + + if(!init_swap_order (out_info)) { + XCAM_LOG_ERROR ("DrmBoBufferPool: fix video info faield to init swap order"); + return false; + } + + info = out_info; + return true; +} + +bool +DrmBoBufferPool::init_swap_order (VideoBufferInfo &info) +{ + if (_swap_flags & (uint32_t)(SwappedBuffer::SwapY)) { + if ((_swap_init_order & (uint32_t)(SwappedBuffer::OrderYMask)) == (uint32_t)(SwappedBuffer::OrderY0Y1)) { + info.offsets[0] = _swap_offsets[SwappedBuffer::SwapYOffset0]; + } else if ((_swap_init_order & (uint32_t)(SwappedBuffer::OrderYMask)) == + (uint32_t)(SwappedBuffer::OrderY1Y0)) { + info.offsets[0] = _swap_offsets[SwappedBuffer::SwapYOffset1]; + } else { + XCAM_LOG_WARNING ("BufferPool: There's unknown init_swap_order(Y):0x%04x", _swap_init_order); + return false; + } + } + + if (_swap_flags & (uint32_t)(SwappedBuffer::SwapUV)) { + if ((_swap_init_order & (uint32_t)(SwappedBuffer::OrderUVMask)) == (uint32_t)(SwappedBuffer::OrderUV0UV1)) { + info.offsets[1] = _swap_offsets[SwappedBuffer::SwapUVOffset0]; + } else if ((_swap_init_order & (uint32_t)(SwappedBuffer::OrderUVMask)) == + (uint32_t)(SwappedBuffer::OrderUV1UV0)) { + info.offsets[1] = _swap_offsets[SwappedBuffer::SwapUVOffset1]; + } else { + XCAM_LOG_WARNING ("BufferPool: There's unknown init_swap_order(UV):0x%04x", _swap_init_order); + return false; + } + } + + return true; +} + +SmartPtr<BufferData> +DrmBoBufferPool::allocate_data (const VideoBufferInfo &buffer_info) +{ + SmartPtr<DrmBoData> bo = _display->create_drm_bo (_display, buffer_info); + return bo; +} + +SmartPtr<BufferProxy> +DrmBoBufferPool::create_buffer_from_data (SmartPtr<BufferData> &data) +{ + const VideoBufferInfo & info = get_video_info (); + SmartPtr<DrmBoData> bo_data = data.dynamic_cast_ptr<DrmBoData> (); + XCAM_ASSERT (bo_data.ptr ()); + + SmartPtr<DrmBoBuffer> out_buf = new DrmBoBuffer (info, bo_data); + XCAM_ASSERT (out_buf.ptr ()); + out_buf->set_swap_info (_swap_flags, _swap_offsets); + return out_buf; +} + +}; diff --git a/xcore/drm_bo_buffer.h b/xcore/drm_bo_buffer.h new file mode 100644 index 0000000..fa661d3 --- /dev/null +++ b/xcore/drm_bo_buffer.h @@ -0,0 +1,137 @@ +/* + * drm_bo_buffer.h - drm bo buffer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ +#ifndef XCAM_DRM_BO_BUFFER_H +#define XCAM_DRM_BO_BUFFER_H + +#include <xcam_std.h> +#include <safe_list.h> +#include <xcam_mutex.h> +#include <buffer_pool.h> +#include <drm_display.h> +#include <swapped_buffer.h> + +namespace XCam { + +class DrmBoBufferPool; +class X3aStats; + +class DrmBoData + : public BufferData +{ + friend class DrmDisplay; + +public: + ~DrmBoData (); + drm_intel_bo *get_bo () { + return _bo; + } + + //derived from BufferData + virtual uint8_t *map (); + virtual bool unmap (); + virtual int get_fd (); + +protected: + explicit DrmBoData (SmartPtr<DrmDisplay> &display, drm_intel_bo *bo); + + bool set_prime_fd (int fd, bool need_close); + +private: + XCAM_DEAD_COPY (DrmBoData); + +private: + SmartPtr<DrmDisplay> _display; + drm_intel_bo *_bo; + uint8_t *_buf; + int _prime_fd; + bool _need_close_fd; +}; + +class DrmBoBuffer + : public virtual BufferProxy + , public SwappedBuffer +{ + friend class DrmBoBufferPool; + friend class DrmDisplay; + +public: + virtual ~DrmBoBuffer () {} + drm_intel_bo *get_bo (); + + SmartPtr<X3aStats> find_3a_stats (); + +protected: + DrmBoBuffer (const VideoBufferInfo &info, const SmartPtr<DrmBoData> &data); + + //derived from SwappedBuffer + virtual SmartPtr<SwappedBuffer> create_new_swap_buffer ( + const VideoBufferInfo &info, SmartPtr<BufferData> &data); + + XCAM_DEAD_COPY (DrmBoBuffer); +}; + +class DrmBoBufferPool + : public BufferPool +{ + friend class DrmBoBuffer; + +public: + explicit DrmBoBufferPool (SmartPtr<DrmDisplay> &display); + ~DrmBoBufferPool (); + + // **** MUST be set before set_video_info **** + void set_swap_flags (uint32_t flags, uint32_t init_order) { + _swap_flags = flags; + _swap_init_order = init_order; + } + uint32_t get_swap_flags () const { + return _swap_flags; + } + + bool update_swap_init_order (uint32_t init_order); + + SmartPtr<DrmDisplay> &get_drm_display () { + return _display; + } + +protected: + // derived from BufferPool + virtual bool fixate_video_info (VideoBufferInfo &info); + virtual SmartPtr<BufferData> allocate_data (const VideoBufferInfo &buffer_info); + virtual SmartPtr<BufferProxy> create_buffer_from_data (SmartPtr<BufferData> &data); + + bool init_swap_order (VideoBufferInfo &info); + +private: + XCAM_DEAD_COPY (DrmBoBufferPool); + +protected: + uint32_t _swap_flags; + uint32_t _swap_init_order; + uint32_t _swap_offsets[XCAM_VIDEO_MAX_COMPONENTS * 2]; + +private: + SmartPtr<DrmDisplay> _display; +}; + +}; + +#endif //XCAM_DRM_BO_BUFFER_H + diff --git a/xcore/drm_display.cpp b/xcore/drm_display.cpp new file mode 100644 index 0000000..a5c89db --- /dev/null +++ b/xcore/drm_display.cpp @@ -0,0 +1,569 @@ +/* + * drm_display.cpp - drm display + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: John Ye <john.ye@intel.com> + */ + + +#include "drm_display.h" +#include "drm_v4l2_buffer.h" +#include "drm_bo_buffer.h" +#include <drm_fourcc.h> +#include <sys/ioctl.h> +#include <fcntl.h> + + +#define DEFAULT_DRM_DEVICE "i915" +#define DEFAULT_DRM_BUSID "PCI:00:02:00" +#define DEFAULT_DRM_BATCH_SIZE 0x80000 + +namespace XCam { + +SmartPtr<DrmDisplay> DrmDisplay::_instance(NULL); +Mutex DrmDisplay::_mutex; + +static std::atomic<uint32_t> global_signal_index(0); + +bool DrmDisplay::_preview_flag = false; + +bool +DrmDisplay::set_preview (bool flag) { + if (_instance.ptr () && flag != _preview_flag) + return false; + _preview_flag = flag; + return true; +}; + +SmartPtr<DrmDisplay> +DrmDisplay::instance () +{ + SmartLock lock(_mutex); + if (_instance.ptr()) + return _instance; + _instance = new DrmDisplay (); + return _instance; +} + +DrmDisplay::DrmDisplay (const char *module) + : _module(NULL) + , _fd (-1) + , _buf_manager (NULL) + , _display_mode (DRM_DISPLAY_MODE_NONE) + , _crtc_index (-1) + , _crtc_id (0) + , _con_id (0) + , _encoder_id (0) + , _plane_id (0) + , _connector (NULL) + , _is_render_inited (false) + , _format (0) + , _width (0) + , _height (0) +{ + xcam_mem_clear(_compose); + + if (module) + _module = strndup (module, XCAM_MAX_STR_SIZE); + else + _module = strndup (DEFAULT_DRM_DEVICE, XCAM_MAX_STR_SIZE); + + if (!_preview_flag) { + _fd = open_drivers ("/dev/dri/renderD", 128); + } + + if (_fd < 0) + _fd = open_drivers ("/dev/dri/card", 0); + + if (_fd < 0) { + _fd = drmOpen (_module, DEFAULT_DRM_BUSID); + if (_fd >= 0 && !is_authenticated (_fd, DEFAULT_DRM_BUSID)) { + drmClose (_fd); + _fd = -1; + } + } + + if (_fd < 0) { + XCAM_LOG_WARNING ("please try root privilege if without X server"); + XCAM_LOG_ERROR ("failed to open drm device %s", XCAM_STR (_module)); + } + + _buf_manager = drm_intel_bufmgr_gem_init (_fd, DEFAULT_DRM_BATCH_SIZE); + drm_intel_bufmgr_gem_enable_reuse (_buf_manager); +} + +DrmDisplay::~DrmDisplay() +{ + _display_buf.release (); + + if (_buf_manager) + drm_intel_bufmgr_destroy (_buf_manager); + if (_fd >= 0) + drmClose (_fd); + if (_module) + xcam_free (_module); +}; + +int +DrmDisplay::open_drivers (const char *base_path, int base_id) +{ + int fd = -1; + char dev_path [32]; + XCAM_ASSERT (base_path); + + for (int i = 0; i < 16; i++) { + sprintf (dev_path, "%s%d", base_path, base_id + i); + if (access (dev_path, F_OK) != 0) + continue; + + fd = open_driver (dev_path); + if (fd >= 0) + break; + } + + return fd; +} + +int +DrmDisplay::open_driver (const char *dev_path) +{ + XCAM_ASSERT (dev_path); + + int fd = open (dev_path, O_RDWR); + if (fd < 0) { + XCAM_LOG_ERROR ("failed to open %s", dev_path); + return -1; + } + + if (!strncmp (dev_path, "/dev/dri/card", 13)) { + if (!is_authenticated (fd, dev_path)) { + close (fd); + return -1; + } + } + + return fd; +} + +bool +DrmDisplay::is_authenticated (int fd, const char *msg) +{ + drm_client_t client; + memset (&client, 0, sizeof (drm_client_t)); + if (ioctl (fd, DRM_IOCTL_GET_CLIENT, &client) == -1) { + XCAM_LOG_ERROR ("failed to get drm client"); + return false; + } + + if (!client.auth) { + XCAM_LOG_ERROR ("%s is not authenticated", msg); + return false; + } + + return true; +} + +uint32_t +DrmDisplay::to_drm_fourcc (uint32_t fourcc_of_v4l2) +{ + switch (fourcc_of_v4l2) { + case V4L2_PIX_FMT_RGB565: + return DRM_FORMAT_RGB565; + default: + break; + } + return fourcc_of_v4l2; +} + +XCamReturn +DrmDisplay::get_crtc(drmModeRes *res) +{ + _crtc_index = -1; + + drmModeEncoderPtr encoder = drmModeGetEncoder(_fd, _encoder_id); + XCAM_FAIL_RETURN(ERROR, encoder, XCAM_RETURN_ERROR_PARAM, + "drmModeGetEncoder failed: %s", strerror(errno)); + + _crtc_id = encoder->crtc_id; + drmModeFreeEncoder(encoder); + + for (int i = 0; i < res->count_crtcs; i++) { + if (_crtc_id == res->crtcs[i]) { + _crtc_index = i; + break; + } + } + XCAM_FAIL_RETURN(ERROR, _crtc_index != -1, XCAM_RETURN_ERROR_PARAM, + "CRTC %d not found", _crtc_id); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +DrmDisplay::get_connector(drmModeRes *res) +{ + XCAM_FAIL_RETURN(ERROR, res->count_connectors > 0, XCAM_RETURN_ERROR_PARAM, + "No connector found"); + for(int i = 0; i < res->count_connectors; ++i) { + _connector = drmModeGetConnector(_fd, res->connectors[i]); + if(_connector && _connector->connection == DRM_MODE_CONNECTED) { + _con_id = res->connectors[i]; + _encoder_id = res->encoders[i]; + _mode = *_connector->modes; + } + drmModeFreeConnector(_connector); + } + XCAM_FAIL_RETURN(ERROR, _connector, XCAM_RETURN_ERROR_PARAM, + "drmModeGetConnector failed: %s", strerror(errno)); + + return XCAM_RETURN_NO_ERROR; +} + + +XCamReturn +DrmDisplay::get_plane() +{ + drmModePlaneResPtr planes = drmModeGetPlaneResources(_fd); + XCAM_FAIL_RETURN(ERROR, planes, XCAM_RETURN_ERROR_PARAM, + "failed to query planes: %s", strerror(errno)); + + drmModePlanePtr plane = NULL; + for (uint32_t i = 0; i < planes->count_planes; i++) { + if (plane) { + drmModeFreePlane(plane); + plane = NULL; + } + plane = drmModeGetPlane(_fd, planes->planes[i]); + XCAM_FAIL_RETURN(ERROR, plane, XCAM_RETURN_ERROR_PARAM, + "failed to query plane %d: %s", i, strerror(errno)); + + if (plane->crtc_id || !(plane->possible_crtcs & (1 << _crtc_index))) { + continue; + } + + for (uint32_t j = 0; j < plane->count_formats; j++) { + // found a plane matching the requested format + if (plane->formats[j] == _format) { + _plane_id = plane->plane_id; + drmModeFreePlane(plane); + drmModeFreePlaneResources(planes); + return XCAM_RETURN_NO_ERROR; + } + } + } + + if (plane) + drmModeFreePlane(plane); + + drmModeFreePlaneResources(planes); + + return XCAM_RETURN_ERROR_PARAM; +} + +XCamReturn +DrmDisplay::render_init ( + uint32_t con_id, + uint32_t crtc_id, + uint32_t width, + uint32_t height, + uint32_t format, + const struct v4l2_rect* compose) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + if (is_render_inited ()) + return ret; + + _con_id = con_id; + _crtc_id = crtc_id; + _width = width; + _height = height; + _format = to_drm_fourcc (format); + _compose = *compose; + _crtc_index = -1; + _plane_id = 0; + _connector = NULL; + + drmModeRes *resource = drmModeGetResources(_fd); + XCAM_FAIL_RETURN(ERROR, resource, XCAM_RETURN_ERROR_PARAM, + "failed to query Drm Mode resources: %s", strerror(errno)); + + ret = get_connector(resource); + XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, + XCAM_RETURN_ERROR_PARAM, + "failed to get connector %s", strerror(errno)); + + ret = get_crtc(resource); + XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, + XCAM_RETURN_ERROR_PARAM, + "failed to get CRTC %s", strerror(errno)); + + ret = get_plane(); + XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, + XCAM_RETURN_ERROR_PARAM, + "failed to get plane with required format %s", strerror(errno)); + + drmModeFreeResources(resource); + if (_display_mode == DRM_DISPLAY_MODE_OVERLAY) + _is_render_inited = true; + return XCAM_RETURN_NO_ERROR; +} + + +SmartPtr<V4l2Buffer> +DrmDisplay::create_drm_buf ( + const struct v4l2_format &format, + const uint32_t index, + const enum v4l2_buf_type buf_type) +{ + struct drm_mode_create_dumb gem; + struct drm_prime_handle prime; + struct v4l2_buffer v4l2_buf; + int ret = 0; + + xcam_mem_clear (gem); + xcam_mem_clear (prime); + xcam_mem_clear (v4l2_buf); + + gem.width = format.fmt.pix.bytesperline; + gem.height = format.fmt.pix.height; + gem.bpp = 8; + ret = xcam_device_ioctl (_fd, DRM_IOCTL_MODE_CREATE_DUMB, &gem); + XCAM_ASSERT (ret >= 0); + + prime.handle = gem.handle; + ret = xcam_device_ioctl (_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime); + if (ret < 0) { + XCAM_LOG_WARNING ("create drm failed on DRM_IOCTL_PRIME_HANDLE_TO_FD"); + return NULL; + } + + v4l2_buf.index = index; + v4l2_buf.type = buf_type; + v4l2_buf.memory = V4L2_MEMORY_DMABUF; + v4l2_buf.m.fd = prime.fd; + v4l2_buf.length = XCAM_MAX (format.fmt.pix.sizeimage, gem.size); // todo check gem.size and format.fmt.pix.length + XCAM_LOG_DEBUG ("create drm buffer size:%lld", gem.size); + return new DrmV4l2Buffer (gem.handle, v4l2_buf, format, _instance); +} + +XCamReturn +DrmDisplay::render_setup_frame_buffer (SmartPtr<VideoBuffer> &buf) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + VideoBufferInfo video_info = buf->get_video_info (); + uint32_t fourcc = video_info.format; + uint32_t fb_handle = 0; + uint32_t bo_handle = 0; + uint32_t bo_handles[4] = { 0 }; + FB fb; + SmartPtr<V4l2BufferProxy> v4l2_proxy; + SmartPtr<DrmBoBuffer> bo_buf; + + v4l2_proxy = buf.dynamic_cast_ptr<V4l2BufferProxy> (); + bo_buf = buf.dynamic_cast_ptr<DrmBoBuffer> (); + if (v4l2_proxy.ptr ()) { + struct drm_prime_handle prime; + memset(&prime, 0, sizeof (prime)); + prime.fd = v4l2_proxy->get_v4l2_dma_fd(); + + ret = (XCamReturn) xcam_device_ioctl(_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime); + if (ret) { + XCAM_LOG_WARNING("FD_TO_PRIME_HANDLE failed: %s", strerror(errno)); + return XCAM_RETURN_ERROR_IOCTL; + } + bo_handle = prime.handle; + } else if (bo_buf.ptr ()) { + const drm_intel_bo* bo = bo_buf->get_bo (); + XCAM_ASSERT (bo); + bo_handle = bo->handle; + } else { + XCAM_ASSERT (false); + XCAM_LOG_WARNING("drm setup framebuffer doesn't support this buffer"); + return XCAM_RETURN_ERROR_PARAM; + } + + for (uint32_t i = 0; i < 4; ++i) { + bo_handles [i] = bo_handle; + } + + ret = (XCamReturn) drmModeAddFB2(_fd, video_info.width, video_info.height, fourcc, bo_handles, + video_info.strides, video_info.offsets, &fb_handle, 0); + + fb.fb_handle = fb_handle; + fb.index = global_signal_index++; + _buf_fb_handles[buf.ptr ()] = fb; + + XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, XCAM_RETURN_ERROR_PARAM, + "drmModeAddFB2 failed: %s", strerror(errno)); + + return ret; +} + +XCamReturn +DrmDisplay::set_crtc (const FB &fb) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + uint32_t fb_handle = fb.fb_handle; + //uint32_t index = fb.index; + + if( !_is_render_inited) { + ret = (XCamReturn) drmModeSetCrtc(_fd, _crtc_id, fb_handle, 0, + 0, &_con_id, 1, &_mode); + XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, XCAM_RETURN_ERROR_IOCTL, + "failed to set crct via drm: %s", strerror(errno)); + _is_render_inited = true; + } + return ret; +} + +XCamReturn +DrmDisplay::set_plane (const FB &fb) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + uint32_t fb_handle = fb.fb_handle; + //uint32_t index = fb.index; + + ret = (XCamReturn) drmModeSetPlane(_fd, _plane_id, _crtc_id, + fb_handle, 0, + _compose.left, _compose.top, + _compose.width, _compose.height, + 0, 0, _width << 16, _height << 16); + XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, XCAM_RETURN_ERROR_IOCTL, + "failed to set plane via drm: %s", strerror(errno)); +#if 0 + drmVBlank vblank; + vblank.request.type = (drmVBlankSeqType) (DRM_VBLANK_EVENT | DRM_VBLANK_RELATIVE); + vblank.request.sequence = 1; + vblank.request.signal = (unsigned long) index; + ret = (XCamReturn) drmWaitVBlank(_fd, &vblank); + XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, XCAM_RETURN_ERROR_IOCTL, + "failed to wait vblank: %s", strerror(errno)); +#endif + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +DrmDisplay::page_flip (const FB &fb) +{ + XCamReturn ret; + uint32_t fb_handle = fb.fb_handle; + uint32_t index = fb.index; + + ret = (XCamReturn) drmModePageFlip(_fd, _crtc_id, fb_handle, + DRM_MODE_PAGE_FLIP_EVENT, + (void*)(unsigned long) index); + XCAM_FAIL_RETURN(ERROR, ret == XCAM_RETURN_NO_ERROR, XCAM_RETURN_ERROR_IOCTL, + "failed on page flip: %s", strerror(errno)); + + drmEventContext evctx; + struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; + fd_set fds; + memset(&evctx, 0, sizeof evctx); + evctx.version = DRM_EVENT_CONTEXT_VERSION; + evctx.vblank_handler = NULL; + //evctx.page_flip_handler = page_flip_handler; + FD_ZERO(&fds); + FD_SET(_fd, &fds); + select(_fd + 1, &fds, NULL, NULL, &timeout); + drmHandleEvent(_fd, &evctx); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +DrmDisplay::render_buffer(SmartPtr<VideoBuffer> &buf) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + FBMap::iterator iter = _buf_fb_handles.find (buf.ptr ()); + XCAM_FAIL_RETURN( + ERROR, + iter != _buf_fb_handles.end (), + XCAM_RETURN_ERROR_PARAM, + "buffer not register on framebuf"); + if(_display_mode == DRM_DISPLAY_MODE_OVERLAY) + ret = _plane_id ? set_plane(iter->second) : page_flip(iter->second); + else if(_display_mode == DRM_DISPLAY_MODE_PRIMARY) { + ret = set_crtc (iter->second); + ret = page_flip (iter->second); + } + _display_buf = buf; + + return ret; +} + +SmartPtr<DrmBoBuffer> +DrmDisplay::convert_to_drm_bo_buf (SmartPtr<DrmDisplay> &self, SmartPtr<VideoBuffer> &buf_in) +{ + drm_intel_bo *bo = NULL; + int dma_fd = 0; + SmartPtr<DrmBoBuffer> new_bo_buf; + SmartPtr<DrmBoData> bo_data; + + XCAM_ASSERT (self.ptr () == this); + XCAM_ASSERT (buf_in.ptr ()); + + new_bo_buf = buf_in.dynamic_cast_ptr<DrmBoBuffer> (); + if (new_bo_buf.ptr ()) + return new_bo_buf; + + const VideoBufferInfo video_info = buf_in->get_video_info (); + dma_fd = buf_in->get_fd (); + if (dma_fd < 0) { + XCAM_LOG_DEBUG ("DrmDisplay only support dma buffer conversion to drm bo by now"); + return NULL; + } + + bo = drm_intel_bo_gem_create_from_prime (_buf_manager, dma_fd, video_info.size); + if (bo == NULL) { + XCAM_LOG_WARNING ("convert dma fd to drm bo failed"); + return NULL; + } + bo_data = new DrmBoData (self, bo); + bo_data->set_prime_fd (dma_fd, false); + new_bo_buf = new DrmBoBuffer (video_info, bo_data); + new_bo_buf->set_parent (buf_in); + new_bo_buf->set_timestamp (buf_in->get_timestamp ()); + return new_bo_buf; +} + +SmartPtr<DrmBoData> +DrmDisplay::create_drm_bo (SmartPtr<DrmDisplay> &self, const VideoBufferInfo &info) +{ + SmartPtr<DrmBoData> new_bo; + + XCAM_ASSERT (_buf_manager); + XCAM_ASSERT (self.ptr() == this); + drm_intel_bo *bo = drm_intel_bo_alloc ( + _buf_manager, "xcam drm bo buf", info.size, 0x1000); + + new_bo = new DrmBoData (self, bo); + return new_bo; +} + +drm_intel_bo * +DrmDisplay::create_drm_bo_from_fd (int32_t fd, uint32_t size) +{ + drm_intel_bo *bo = NULL; + XCAM_ASSERT (_buf_manager); + bo = drm_intel_bo_gem_create_from_prime (_buf_manager, fd, size); + + XCAM_ASSERT (bo); + return bo; +} + + +}; diff --git a/xcore/drm_display.h b/xcore/drm_display.h new file mode 100644 index 0000000..17705b7 --- /dev/null +++ b/xcore/drm_display.h @@ -0,0 +1,167 @@ +/* + * drm_display.h - drm display + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: John Ye <john.ye@intel.com> + */ + +#ifndef XCAM_DRM_DISPLAY_H +#define XCAM_DRM_DISPLAY_H + +#include <xcam_std.h> +#include <xcam_mutex.h> +#include <v4l2_buffer_proxy.h> + +extern "C" { +#include <drm.h> +#include <drm_mode.h> +#include <intel_bufmgr.h> +#include <linux/videodev2.h> +} + +#include <errno.h> +#include <unistd.h> +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include <list> +#include <vector> +#include <map> + +namespace XCam { + +class DrmBoData; +class DrmBoBufferPool; +class DrmBoBuffer; + +enum DrmDisplayMode { + DRM_DISPLAY_MODE_NONE = 0, + DRM_DISPLAY_MODE_PRIMARY, + DRM_DISPLAY_MODE_OVERLAY, +}; + +class DrmDisplay { + friend class DrmBoBufferPool; + friend class CLBoBufferPool; + + struct FB { + uint32_t fb_handle; + uint32_t index; + + FB () : fb_handle (0), index (0) {} + }; + +public: + // if need local preview, please call set_preview() before instance() + static SmartPtr<DrmDisplay> instance (); + static uint32_t to_drm_fourcc (uint32_t fourcc_of_v4l2); + + virtual ~DrmDisplay(); + const char *get_module_name () const { + return _module; + } + + bool is_render_inited () const { + return _is_render_inited; + } + XCamReturn render_init ( + uint32_t con_id, + uint32_t crtc_id, + uint32_t width, + uint32_t height, + uint32_t format, + const struct v4l2_rect* compose); + + bool has_frame_buffer (SmartPtr<VideoBuffer> &buf) { + return _buf_fb_handles.find (buf.ptr ()) != _buf_fb_handles.end (); + }; + XCamReturn render_setup_frame_buffer (SmartPtr<VideoBuffer> &buf); + XCamReturn render_buffer (SmartPtr<VideoBuffer> &buf); + + int get_drm_handle() const { + return _fd; + }; + + SmartPtr<V4l2Buffer> create_drm_buf ( + const struct v4l2_format &format, + const uint32_t index, + const enum v4l2_buf_type buf_type); + SmartPtr<DrmBoBuffer> convert_to_drm_bo_buf (SmartPtr<DrmDisplay> &self, SmartPtr<VideoBuffer> &buf_in); + + static bool set_preview (bool flag); + bool can_preview () { + return _preview_flag; + } + bool set_display_mode (DrmDisplayMode mode) { + _display_mode = mode; + return true; + }; + +private: + DrmDisplay (const char *module = NULL); + + SmartPtr<DrmBoData> create_drm_bo (SmartPtr<DrmDisplay> &self, const VideoBufferInfo& info); + drm_intel_bo *create_drm_bo_from_fd (int32_t fd, uint32_t size); + + bool is_authenticated (int fd, const char *msg); + int open_driver (const char *dev_path); + int open_drivers (const char *base_path, int base_id); + + XCamReturn get_crtc(drmModeRes *res); + XCamReturn get_connector(drmModeRes *res); + XCamReturn get_plane(); + XCamReturn set_plane(const FB &fb); + XCamReturn set_crtc(const FB &fb); + XCamReturn page_flip(const FB &fb); + +private: + typedef std::map<const VideoBuffer *, FB> FBMap; + + static bool _preview_flag; + + char *_module; + int _fd; + drm_intel_bufmgr *_buf_manager; + DrmDisplayMode _display_mode; + int _crtc_index; + unsigned int _crtc_id; + unsigned int _con_id; + unsigned int _encoder_id; + unsigned int _plane_id; + drmModeModeInfo _mode; + drmModeConnector *_connector; + bool _is_render_inited; + + unsigned int _format; + unsigned int _width; + unsigned int _height; + + struct v4l2_rect _compose; + + FBMap _buf_fb_handles; + SmartPtr<VideoBuffer> _display_buf; + +private: + XCAM_DEAD_COPY (DrmDisplay); + +private: + static SmartPtr<DrmDisplay> _instance; + static Mutex _mutex; +}; + +}; +#endif // XCAM_DRM_DISPLAY_H + diff --git a/xcore/drm_v4l2_buffer.cpp b/xcore/drm_v4l2_buffer.cpp new file mode 100644 index 0000000..822e286 --- /dev/null +++ b/xcore/drm_v4l2_buffer.cpp @@ -0,0 +1,38 @@ +/* + * drm_v4l2_buffer.cpp - drm buffer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: John Ye <john.ye@intel.com> + */ + +#include "drm_v4l2_buffer.h" + +namespace XCam { + +DrmV4l2Buffer::~DrmV4l2Buffer () +{ + XCAM_ASSERT (_display.ptr()); + int handle = _display->get_drm_handle (); + if (handle > 0) { + struct drm_mode_destroy_dumb gem; + xcam_mem_clear (gem); + gem.handle = _gem_handle; + xcam_device_ioctl (handle, DRM_IOCTL_MODE_DESTROY_DUMB, &gem); + } +} + +}; diff --git a/xcore/drm_v4l2_buffer.h b/xcore/drm_v4l2_buffer.h new file mode 100644 index 0000000..15021cf --- /dev/null +++ b/xcore/drm_v4l2_buffer.h @@ -0,0 +1,59 @@ +/* + * drm_v4l2_buffer.h - drm v4l2 buffer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: John Ye <john.ye@intel.com> + */ + +#ifndef XCAM_DRM_V4L2_BUFFER_H +#define XCAM_DRM_V4L2_BUFFER_H + +#include <xcam_std.h> +#include <v4l2_buffer_proxy.h> +#include <drm_display.h> + +namespace XCam { + +class AtomispDevice; + +class DrmV4l2Buffer + : public V4l2Buffer +{ +public: + explicit DrmV4l2Buffer ( + uint32_t gem_handle, + const struct v4l2_buffer &buf, + const struct v4l2_format &format, + SmartPtr<DrmDisplay> &display + ) + : V4l2Buffer (buf, format) + , _gem_handle (gem_handle) + , _display (display) + {} + ~DrmV4l2Buffer (); + +private: + XCAM_DEAD_COPY (DrmV4l2Buffer); + +private: + uint32_t _gem_handle; + SmartPtr<DrmDisplay> _display; +}; + +}; + +#endif // XCAM_DRM_V4L2_BUFFER_H diff --git a/xcore/dynamic_analyzer.cpp b/xcore/dynamic_analyzer.cpp new file mode 100644 index 0000000..4ca553a --- /dev/null +++ b/xcore/dynamic_analyzer.cpp @@ -0,0 +1,215 @@ +/* + * analyzer_loader.cpp - analyzer loader + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Jia Meng <jia.meng@intel.com> + */ + +#include "dynamic_analyzer.h" + +namespace XCam { + +DynamicAnalyzer::DynamicAnalyzer (XCam3ADescription *desc, SmartPtr<AnalyzerLoader> &loader, const char *name) + : X3aAnalyzer (name) + , _desc (desc) + , _context (NULL) + , _loader (loader) +{ +} + +DynamicAnalyzer::~DynamicAnalyzer () +{ + destroy_context (); +} + +XCamReturn +DynamicAnalyzer::create_context () +{ + XCam3AContext *context = NULL; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + XCAM_ASSERT (!_context); + if ((ret = _desc->create_context (&context)) != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("dynamic 3a lib create context failed"); + return ret; + } + _context = context; + return XCAM_RETURN_NO_ERROR; +} + +void +DynamicAnalyzer::destroy_context () +{ + if (_context && _desc && _desc->destroy_context) { + _desc->destroy_context (_context); + _context = NULL; + } +} + +XCamReturn +DynamicAnalyzer::analyze_ae (XCamAeParam ¶m) +{ + XCAM_ASSERT (_context); + return _desc->analyze_ae (_context, ¶m); +} + +XCamReturn +DynamicAnalyzer::analyze_awb (XCamAwbParam ¶m) +{ + XCAM_ASSERT (_context); + return _desc->analyze_awb (_context, ¶m); +} + +XCamReturn +DynamicAnalyzer::analyze_af (XCamAfParam ¶m) +{ + XCAM_ASSERT (_context); + return _desc->analyze_af (_context, ¶m); +} + +SmartPtr<AeHandler> +DynamicAnalyzer::create_ae_handler () +{ + return new DynamicAeHandler (this); +} + +SmartPtr<AwbHandler> +DynamicAnalyzer::create_awb_handler () +{ + return new DynamicAwbHandler (this); +} + +SmartPtr<AfHandler> +DynamicAnalyzer::create_af_handler () +{ + return new DynamicAfHandler (this); +} + +SmartPtr<CommonHandler> +DynamicAnalyzer::create_common_handler () +{ + if (_common_handler.ptr()) + return _common_handler; + + _common_handler = new DynamicCommonHandler (this); + return _common_handler; +} + +XCamReturn +DynamicAnalyzer::internal_init (uint32_t width, uint32_t height, double framerate) +{ + XCAM_UNUSED (width); + XCAM_UNUSED (height); + XCAM_UNUSED (framerate); + return create_context (); +} + +XCamReturn +DynamicAnalyzer::internal_deinit () +{ + destroy_context (); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +DynamicAnalyzer::configure_3a () +{ + uint32_t width = get_width (); + uint32_t height = get_height (); + double framerate = get_framerate (); + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (_context); + + ret = _desc->configure_3a (_context, width, height, framerate); + XCAM_FAIL_RETURN (WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "dynamic analyzer configure 3a failed"); + set_manual_brightness(_brightness_level_param); + + return XCAM_RETURN_NO_ERROR; +} +XCamReturn +DynamicAnalyzer::pre_3a_analyze (SmartPtr<X3aStats> &stats) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + XCamCommonParam common_params = _common_handler->get_params_unlock (); + + XCAM_ASSERT (_context); + _cur_stats = stats; + ret = _desc->set_3a_stats (_context, stats->get_stats (), stats->get_timestamp ()); + XCAM_FAIL_RETURN (WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "dynamic analyzer set_3a_stats failed"); + + ret = _desc->update_common_params (_context, &common_params); + XCAM_FAIL_RETURN (WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "dynamic analyzer update common params failed"); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +DynamicAnalyzer::post_3a_analyze (X3aResultList &results) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + XCam3aResultHead *res_array[XCAM_3A_MAX_RESULT_COUNT]; + uint32_t res_count = XCAM_3A_MAX_RESULT_COUNT; + + xcam_mem_clear (res_array); + XCAM_ASSERT (_context); + ret = _desc->combine_analyze_results (_context, res_array, &res_count); + XCAM_FAIL_RETURN (WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "dynamic analyzer combine_analyze_results failed"); + + _cur_stats.release (); + + if (res_count) { + ret = convert_results (res_array, res_count, results); + XCAM_FAIL_RETURN (WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "dynamic analyzer convert_results failed"); + _desc->free_results (res_array, res_count); + } + + return XCAM_RETURN_NO_ERROR; +} + +const XCamCommonParam +DynamicAnalyzer::get_common_params () +{ + return _common_handler->get_params_unlock (); +} + +XCamReturn +DynamicAnalyzer::convert_results (XCam3aResultHead *from[], uint32_t from_count, X3aResultList &to) +{ + for (uint32_t i = 0; i < from_count; ++i) { + SmartPtr<X3aResult> standard_res = + X3aResultFactory::instance ()->create_3a_result (from[i]); + to.push_back (standard_res); + } + + return XCAM_RETURN_NO_ERROR; +} +} diff --git a/xcore/dynamic_analyzer.h b/xcore/dynamic_analyzer.h new file mode 100644 index 0000000..3835fd3 --- /dev/null +++ b/xcore/dynamic_analyzer.h @@ -0,0 +1,155 @@ +/* + * dynamic_analyzer.h - dynamic analyzer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Jia Meng <jia.meng@intel.com> + */ +#ifndef XCAM_DYNAMIC_ANALYZER_H +#define XCAM_DYNAMIC_ANALYZER_H + +#include <xcam_std.h> +#include <base/xcam_3a_description.h> +#include <x3a_analyzer.h> +#include <x3a_stats_pool.h> +#include <handler_interface.h> +#include <x3a_result_factory.h> +#include <analyzer_loader.h> + +namespace XCam { + +class DynamicAeHandler; +class DynamicAwbHandler; +class DynamicAfHandler; +class DynamicCommonHandler; + +class DynamicAnalyzer + : public X3aAnalyzer +{ +public: + DynamicAnalyzer (XCam3ADescription *desc, SmartPtr<AnalyzerLoader> &loader, const char *name = "DynamicAnalyzer"); + ~DynamicAnalyzer (); + + virtual XCamReturn configure_3a (); + virtual XCamReturn analyze_ae (XCamAeParam ¶m); + virtual XCamReturn analyze_awb (XCamAwbParam ¶m); + virtual XCamReturn analyze_af (XCamAfParam ¶m); + +protected: + virtual SmartPtr<AeHandler> create_ae_handler (); + virtual SmartPtr<AwbHandler> create_awb_handler (); + virtual SmartPtr<AfHandler> create_af_handler (); + virtual SmartPtr<CommonHandler> create_common_handler (); + virtual XCamReturn internal_init (uint32_t width, uint32_t height, double framerate); + virtual XCamReturn internal_deinit (); + + virtual XCamReturn pre_3a_analyze (SmartPtr<X3aStats> &stats); + virtual XCamReturn post_3a_analyze (X3aResultList &results); + + XCamReturn create_context (); + void destroy_context (); + + const XCamCommonParam get_common_params (); + SmartPtr<X3aStats> get_cur_stats () const { + return _cur_stats; + } + XCamReturn convert_results (XCam3aResultHead *from[], uint32_t from_count, X3aResultList &to); + +private: + XCAM_DEAD_COPY (DynamicAnalyzer); + +private: + XCam3ADescription *_desc; + XCam3AContext *_context; + SmartPtr<X3aStats> _cur_stats; + SmartPtr<DynamicCommonHandler> _common_handler; + SmartPtr<AnalyzerLoader> _loader; +}; + +class DynamicAeHandler + : public AeHandler +{ +public: + explicit DynamicAeHandler (DynamicAnalyzer *analyzer) + : _analyzer (analyzer) + {} + virtual XCamReturn analyze (X3aResultList &output) { + XCAM_UNUSED (output); + AnalyzerHandler::HandlerLock lock(this); + XCamAeParam param = this->get_params_unlock (); + return _analyzer->analyze_ae (param); + } + +private: + DynamicAnalyzer *_analyzer; +}; + +class DynamicAwbHandler + : public AwbHandler +{ +public: + explicit DynamicAwbHandler (DynamicAnalyzer *analyzer) + : _analyzer (analyzer) + {} + virtual XCamReturn analyze (X3aResultList &output) { + XCAM_UNUSED (output); + AnalyzerHandler::HandlerLock lock(this); + XCamAwbParam param = this->get_params_unlock (); + return _analyzer->analyze_awb (param); + } + +private: + DynamicAnalyzer *_analyzer; +}; + +class DynamicAfHandler + : public AfHandler +{ +public: + explicit DynamicAfHandler (DynamicAnalyzer *analyzer) + : _analyzer (analyzer) + {} + virtual XCamReturn analyze (X3aResultList &output) { + XCAM_UNUSED (output); + AnalyzerHandler::HandlerLock lock(this); + XCamAfParam param = this->get_params_unlock (); + return _analyzer->analyze_af (param); + } + +private: + DynamicAnalyzer *_analyzer; +}; + +class DynamicCommonHandler + : public CommonHandler +{ + friend class DynamicAnalyzer; +public: + explicit DynamicCommonHandler (DynamicAnalyzer *analyzer) + : _analyzer (analyzer) + {} + virtual XCamReturn analyze (X3aResultList &output) { + XCAM_UNUSED (output); + AnalyzerHandler::HandlerLock lock(this); + return XCAM_RETURN_NO_ERROR; + } + +private: + DynamicAnalyzer *_analyzer; +}; +} + +#endif //XCAM_DYNAMIC_ANALYZER_H diff --git a/xcore/dynamic_analyzer_loader.cpp b/xcore/dynamic_analyzer_loader.cpp new file mode 100644 index 0000000..ca97ace --- /dev/null +++ b/xcore/dynamic_analyzer_loader.cpp @@ -0,0 +1,89 @@ +/* + * dynamic_analyzer_loader.cpp - dynamic analyzer loader + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Zong Wei <wei.zong@intel.com> + */ + +#include "dynamic_analyzer_loader.h" +#include "dynamic_analyzer.h" +#include "handler_interface.h" +#include <dlfcn.h> + +namespace XCam { + +DynamicAnalyzerLoader::DynamicAnalyzerLoader (const char *lib_path, const char *symbol) + : AnalyzerLoader (lib_path, symbol) +{ +} + +DynamicAnalyzerLoader::~DynamicAnalyzerLoader () +{ +} + +SmartPtr<X3aAnalyzer> +DynamicAnalyzerLoader::load_analyzer (SmartPtr<AnalyzerLoader> &self) +{ + XCAM_ASSERT (self.ptr () == this); + + SmartPtr<X3aAnalyzer> analyzer; + XCam3ADescription *desc = (XCam3ADescription*)load_library (get_lib_path ()); + + analyzer = new DynamicAnalyzer (desc, self); + if (!analyzer.ptr ()) { + XCAM_LOG_WARNING ("create DynamicAnalyzer from lib failed"); + close_handle (); + return NULL; + } + + XCAM_LOG_INFO ("analyzer(%s) created from 3a lib", XCAM_STR (analyzer->get_name())); + return analyzer; +} + +void * +DynamicAnalyzerLoader::load_symbol (void* handle) +{ + XCam3ADescription *desc = NULL; + + desc = (XCam3ADescription *)AnalyzerLoader::get_symbol (handle); + if (!desc) { + XCAM_LOG_DEBUG ("get symbol failed from lib"); + return NULL; + } + if (desc->version < xcam_version ()) { + XCAM_LOG_DEBUG ("get symbolfailed. version is:0x%04x, but expect:0x%04x", + desc->version, xcam_version ()); + return NULL; + } + if (desc->size < sizeof (XCam3ADescription)) { + XCAM_LOG_DEBUG ("get symbol failed, XCam3ADescription size is:%" PRIu32 ", but expect:%" PRIuS, + desc->size, sizeof (XCam3ADescription)); + return NULL; + } + + if (!desc->create_context || !desc->destroy_context || + !desc->configure_3a || !desc->set_3a_stats || + !desc->analyze_awb || !desc->analyze_ae || + !desc->analyze_af || !desc->combine_analyze_results || + !desc->free_results) { + XCAM_LOG_DEBUG ("some functions in symbol not set from lib"); + return NULL; + } + return (void*)desc; +} + +}; diff --git a/xcore/dynamic_analyzer_loader.h b/xcore/dynamic_analyzer_loader.h new file mode 100644 index 0000000..63c8fbb --- /dev/null +++ b/xcore/dynamic_analyzer_loader.h @@ -0,0 +1,50 @@ +/* + * dynamic_analyzer_loader.h - dynamic analyzer loader + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Zong Wei <wei.zong@intel.com> + */ + +#ifndef XCAM_DYNAMIC_ANALYZER_LOADER_H +#define XCAM_DYNAMIC_ANALYZER_LOADER_H + +#include <xcam_std.h> +#include <base/xcam_3a_description.h> +#include <analyzer_loader.h> + +namespace XCam { +class X3aAnalyzer; + +class DynamicAnalyzerLoader + : public AnalyzerLoader +{ +public: + DynamicAnalyzerLoader (const char *lib_path, const char *symbol = XCAM_3A_LIB_DESCRIPTION); + virtual ~DynamicAnalyzerLoader (); + + virtual SmartPtr<X3aAnalyzer> load_analyzer (SmartPtr<AnalyzerLoader> &self); + +protected: + virtual void *load_symbol (void* handle); + +private: + XCAM_DEAD_COPY(DynamicAnalyzerLoader); +}; + +}; + +#endif // XCAM_DYNAMIC_ANALYZER_LOADER_H
\ No newline at end of file diff --git a/xcore/fake_poll_thread.cpp b/xcore/fake_poll_thread.cpp new file mode 100644 index 0000000..612a697 --- /dev/null +++ b/xcore/fake_poll_thread.cpp @@ -0,0 +1,159 @@ +/* + * fake_poll_thread.cpp - poll thread for raw image + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Jia Meng <jia.meng@intel.com> + */ + +#include "fake_poll_thread.h" +#if HAVE_LIBDRM +#include "drm_bo_buffer.h" +#endif + +#define DEFAULT_FPT_BUF_COUNT 4 + +namespace XCam { + +FakePollThread::FakePollThread (const char *raw_path) + : _raw_path (NULL) + , _raw (NULL) +{ + XCAM_ASSERT (raw_path); + + if (raw_path) + _raw_path = strndup (raw_path, XCAM_MAX_STR_SIZE); +} + +FakePollThread::~FakePollThread () +{ + if (_raw_path) + xcam_free (_raw_path); + + if (_raw) + fclose (_raw); +} + +XCamReturn +FakePollThread::start() +{ + XCAM_FAIL_RETURN( + ERROR, + _raw_path, + XCAM_RETURN_ERROR_FILE, + "FakePollThread failed due to raw path NULL"); + + _raw = fopen (_raw_path, "rb"); + XCAM_FAIL_RETURN( + ERROR, + _raw, + XCAM_RETURN_ERROR_FILE, + "FakePollThread failed to open file:%s", XCAM_STR (_raw_path)); + + return PollThread::start (); +} + +XCamReturn +FakePollThread::stop () +{ + if (_buf_pool.ptr ()) + _buf_pool->stop (); + + return PollThread::stop ();; +} + +XCamReturn +FakePollThread::read_buf (SmartPtr<VideoBuffer> &buf) +{ + uint8_t *dst = buf->map (); + const VideoBufferInfo info = buf->get_video_info (); + VideoBufferPlanarInfo planar; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + for (uint32_t index = 0; index < info.components; index++) { + info.get_planar_info(planar, index); + uint32_t line_bytes = planar.width * planar.pixel_bytes; + + for (uint32_t i = 0; i < planar.height; i++) { + if (fread (dst + info.offsets [index] + i * info.strides [index], 1, line_bytes, _raw) < line_bytes) { + if (feof (_raw)) { + fseek (_raw, 0, SEEK_SET); + ret = XCAM_RETURN_BYPASS; + } else { + XCAM_LOG_ERROR ("poll_buffer_loop failed to read file"); + ret = XCAM_RETURN_ERROR_FILE; + } + goto done; + } + } + } + +done: + buf->unmap (); + return ret; +} + +XCamReturn +FakePollThread::poll_buffer_loop () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + if (!_buf_pool.ptr () && init_buffer_pool () != XCAM_RETURN_NO_ERROR) + return XCAM_RETURN_ERROR_MEM; + + SmartPtr<VideoBuffer> buf = _buf_pool->get_buffer (_buf_pool); + if (!buf.ptr ()) { + XCAM_LOG_WARNING ("FakePollThread get buffer failed"); + return XCAM_RETURN_ERROR_MEM; + } + + ret = read_buf (buf); + if (ret == XCAM_RETURN_BYPASS) { + ret = read_buf (buf); + } + + SmartPtr<VideoBuffer> video_buf = buf; + if (ret == XCAM_RETURN_NO_ERROR && _poll_callback) + return _poll_callback->poll_buffer_ready (video_buf); + + return ret; +} + +XCamReturn +FakePollThread::init_buffer_pool () +{ + struct v4l2_format format; + if (!_capture_dev.ptr () || + _capture_dev->get_format (format) != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("Can't init buffer pool without format"); + return XCAM_RETURN_ERROR_PARAM; + } + VideoBufferInfo info; + info.init(format.fmt.pix.pixelformat, + format.fmt.pix.width, + format.fmt.pix.height, 0, 0, 0); +#if HAVE_LIBDRM + SmartPtr<DrmDisplay> drm_disp = DrmDisplay::instance (); + _buf_pool = new DrmBoBufferPool (drm_disp); + XCAM_ASSERT (_buf_pool.ptr ()); + + if (_buf_pool->set_video_info (info) && _buf_pool->reserve (DEFAULT_FPT_BUF_COUNT)) + return XCAM_RETURN_NO_ERROR; +#endif + + return XCAM_RETURN_ERROR_MEM; +} + +}; diff --git a/xcore/fake_poll_thread.h b/xcore/fake_poll_thread.h new file mode 100644 index 0000000..ee40a86 --- /dev/null +++ b/xcore/fake_poll_thread.h @@ -0,0 +1,59 @@ +/* + * fake_poll_thread.h - poll thread for raw image + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Jia Meng <jia.meng@intel.com> + */ + +#ifndef XCAM_FAKE_POLL_THREAD_H +#define XCAM_FAKE_POLL_THREAD_H + +#include <xcam_std.h> +#include <poll_thread.h> + +namespace XCam { + +class FakePollThread + : public PollThread +{ +public: + explicit FakePollThread (const char *raw_path); + ~FakePollThread (); + + virtual XCamReturn start(); + virtual XCamReturn stop (); + +protected: + virtual XCamReturn poll_buffer_loop (); + +private: + XCAM_DEAD_COPY (FakePollThread); + + virtual XCamReturn init_3a_stats_pool () { + return XCAM_RETURN_ERROR_UNKNOWN; + } + XCamReturn init_buffer_pool (); + XCamReturn read_buf (SmartPtr<VideoBuffer> &buf); + +private: + char *_raw_path; + FILE *_raw; + SmartPtr<BufferPool> _buf_pool; +}; + +}; + +#endif //XCAM_FAKE_POLL_THREAD_H diff --git a/xcore/fake_v4l2_device.h b/xcore/fake_v4l2_device.h new file mode 100644 index 0000000..f679c19 --- /dev/null +++ b/xcore/fake_v4l2_device.h @@ -0,0 +1,53 @@ +/* + * fake_v4l2_device.h - fake v4l2 device + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Jia Meng <jia.meng@intel.com> + */ + +#ifndef XCAM_FAKE_V4L2_DEVICE_H +#define XCAM_FAKE_V4L2_DEVICE_H + +#include <v4l2_device.h> + +namespace XCam { + +class FakeV4l2Device + : public V4l2Device +{ +public: + FakeV4l2Device () + : V4l2Device ("/dev/null") + {} + + int io_control (int cmd, void *arg) + { + XCAM_UNUSED (arg); + + int ret = 0; + switch (cmd) { + case VIDIOC_ENUM_FMT: + ret = -1; + break; + default: + break; + } + return ret; + } +}; + +}; +#endif // XCAM_FAKE_V4L2_DEVICE_H diff --git a/xcore/file_handle.cpp b/xcore/file_handle.cpp new file mode 100644 index 0000000..e7c8ed0 --- /dev/null +++ b/xcore/file_handle.cpp @@ -0,0 +1,161 @@ +/* + * file_handle.cpp - File handle + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "file_handle.h" + +#define INVALID_SIZE (size_t)(-1) + +namespace XCam { + +FileHandle::FileHandle () + : _fp (NULL) + , _file_name (NULL) + , _file_size (INVALID_SIZE) +{} + +FileHandle::FileHandle (const char *name, const char *option) + : _fp (NULL) + , _file_name (NULL) + , _file_size (INVALID_SIZE) +{ + open (name, option); +} + +FileHandle::~FileHandle () +{ + close (); +} + +bool +FileHandle::end_of_file() +{ + if (!is_valid ()) + return true; + + return feof (_fp); +} + +XCamReturn +FileHandle::open (const char *name, const char *option) +{ + XCAM_ASSERT (name); + if (!name) + return XCAM_RETURN_ERROR_FILE; + + close (); + XCAM_ASSERT (!_file_name && !_fp); + _fp = fopen (name, option); + + if (!_fp) + return XCAM_RETURN_ERROR_FILE; + _file_name = strndup (name, 512); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +FileHandle::close () +{ + if (_fp) { + fclose (_fp); + _fp = NULL; + } + + if (_file_name) { + xcam_free (_file_name); + _file_name = NULL; + } + + _file_size = INVALID_SIZE; + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +FileHandle::rewind () +{ + if (!is_valid ()) + return XCAM_RETURN_ERROR_FILE; + return (fseek (_fp, 0L, SEEK_SET) == 0) ? XCAM_RETURN_NO_ERROR : XCAM_RETURN_ERROR_FILE; +} + +XCamReturn +FileHandle::get_file_size (size_t &size) +{ + if (_file_size != INVALID_SIZE) { + size = _file_size; + return XCAM_RETURN_NO_ERROR; + } + + fpos_t cur_pos; + long file_size; + + if (fgetpos (_fp, &cur_pos) < 0) + goto read_error; + + if (fseek (_fp, 0L, SEEK_END) != 0) + goto read_error; + + if ((file_size = ftell (_fp)) <= 0) + goto read_error; + + if (fsetpos (_fp, &cur_pos) < 0) + goto read_error; + + _file_size = file_size; + size = file_size; + return XCAM_RETURN_NO_ERROR; + +read_error: + XCAM_LOG_ERROR ("get file size failed with errno:%d", errno); + return XCAM_RETURN_ERROR_FILE; +} + +XCamReturn +FileHandle::read_file (void *buf, const size_t &size) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + if (fread (buf, 1, size, _fp) != size) { + if (end_of_file ()) { + ret = XCAM_RETURN_BYPASS; + } else { + XCAM_LOG_ERROR ("read file failed, size doesn't match"); + ret = XCAM_RETURN_ERROR_FILE; + } + } + + return ret; +} + +XCamReturn +FileHandle::write_file (const void *buf, const size_t &size) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + if (fwrite (buf, 1, size, _fp) != size) { + XCAM_LOG_ERROR ("write file failed, size doesn't match"); + ret = XCAM_RETURN_ERROR_FILE; + } + + return ret; +} + +} diff --git a/xcore/file_handle.h b/xcore/file_handle.h new file mode 100644 index 0000000..9435d49 --- /dev/null +++ b/xcore/file_handle.h @@ -0,0 +1,62 @@ +/* + * file_handle.h - File handle + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Yinhang Liu <yinhangx.liu@intel.com> + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_FILE_HANDLE_H +#define XCAM_FILE_HANDLE_H + +#include <xcam_std.h> + +namespace XCam { + +class FileHandle { +public: + FileHandle (); + explicit FileHandle (const char *name, const char *option); + virtual ~FileHandle (); + + bool is_valid () const { + return (_fp ? true : false); + } + bool end_of_file (); + XCamReturn open (const char *name, const char *option); + XCamReturn close (); + XCamReturn rewind (); + XCamReturn get_file_size (size_t &size); + const char* get_file_name () const { + return _file_name; + } + XCamReturn read_file (void *buf, const size_t &size); + XCamReturn write_file (const void *buf, const size_t &size); + +private: + XCAM_DEAD_COPY (FileHandle); + +protected: + FILE *_fp; + +private: + char *_file_name; + size_t _file_size; +}; + +} + +#endif //XCAM_FILE_HANDLE_H
\ No newline at end of file diff --git a/xcore/handler_interface.cpp b/xcore/handler_interface.cpp new file mode 100644 index 0000000..bd58b5c --- /dev/null +++ b/xcore/handler_interface.cpp @@ -0,0 +1,599 @@ +/* + * handler_interface.cpp - handler interface + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "handler_interface.h" + +namespace XCam { + +AeHandler::AeHandler() +{ + reset_parameters (); +} + +void +AeHandler::reset_parameters () +{ + // in case missing any parameters + xcam_mem_clear (_params); + + _params.mode = XCAM_AE_MODE_AUTO; + _params.metering_mode = XCAM_AE_METERING_MODE_AUTO; + _params.flicker_mode = XCAM_AE_FLICKER_MODE_AUTO; + _params.speed = 1.0; + _params.exposure_time_min = UINT64_C(0); + _params.exposure_time_max = UINT64_C(0); + _params.max_analog_gain = 0.0; + _params.manual_exposure_time = UINT64_C (0); + _params.manual_analog_gain = 0.0; + _params.aperture_fn = 0.0; + _params.ev_shift = 0.0; + + _params.window.x_start = 0; + _params.window.y_start = 0; + _params.window.x_end = 0; + _params.window.y_end = 0; + _params.window.weight = 0; + + xcam_mem_clear (_params.window_list); +} + +bool +AeHandler::set_mode (XCamAeMode mode) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.mode = mode; + + XCAM_LOG_DEBUG ("ae set mode [%d]", mode); + return true; +} + +bool +AeHandler::set_metering_mode (XCamAeMeteringMode mode) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.metering_mode = mode; + + XCAM_LOG_DEBUG ("ae set metering mode [%d]", mode); + return true; +} + +bool +AeHandler::set_window (XCam3AWindow *window) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.window = *window; + + XCAM_LOG_DEBUG ("ae set metering mode window [x:%d, y:%d, x_end:%d, y_end:%d, weight:%d]", + window->x_start, + window->y_start, + window->x_end, + window->y_end, + window->weight); + return true; +} + +bool +AeHandler::set_window (XCam3AWindow *window, uint8_t count) +{ + if (0 == count) { + XCAM_LOG_WARNING ("invalid input parameter, window count = %d, reset to default value", count); + XCam3AWindow defaultWindow = {0, 0, 1000, 1000, 15}; + set_window(&defaultWindow); + _params.window_list[0] = defaultWindow; + return true; + } + + if (XCAM_AE_MAX_METERING_WINDOW_COUNT < count) { + XCAM_LOG_WARNING ("invalid input parameter, window count = %d, reset count to maximum", count); + count = XCAM_AE_MAX_METERING_WINDOW_COUNT; + } + + AnalyzerHandler::HandlerLock lock(this); + + _params.window = *window; + + for (int i = 0; i < count; i++) { + XCAM_LOG_DEBUG ("window start point(%d, %d), end point(%d, %d), weight = %d", + window[i].x_start, window[i].y_start, window[i].x_end, window[i].y_end, window[i].weight); + + _params.window_list[i] = window[i]; + if (_params.window.weight < window[i].weight) { + _params.window.weight = window[i].weight; + _params.window.x_start = window[i].x_start; + _params.window.y_start = window[i].y_start; + _params.window.x_end = window[i].x_end; + _params.window.y_end = window[i].y_end; + } + } + + XCAM_LOG_DEBUG ("ae set metering mode window [x:%d, y:%d, x_end:%d, y_end:%d, weight:%d]", + _params.window.x_start, + _params.window.y_start, + _params.window.x_end, + _params.window.y_end, + _params.window.weight); + + return true; +} + +bool +AeHandler::set_ev_shift (double ev_shift) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.ev_shift = ev_shift; + + XCAM_LOG_DEBUG ("ae set ev shift:%.03f", ev_shift); + return true; +} + +bool +AeHandler::set_speed (double speed) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.speed = speed; + + XCAM_LOG_DEBUG ("ae set speed:%.03f", speed); + return true; +} + +bool +AeHandler::set_flicker_mode (XCamFlickerMode flicker) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.flicker_mode = flicker; + + XCAM_LOG_DEBUG ("ae set flicker:%d", flicker); + return true; +} + +XCamFlickerMode +AeHandler::get_flicker_mode () +{ + AnalyzerHandler::HandlerLock lock(this); + return _params.flicker_mode; +} + +int64_t +AeHandler::get_current_exposure_time () +{ + AnalyzerHandler::HandlerLock lock(this); + if (_params.mode == XCAM_AE_MODE_MANUAL) + return _params.manual_exposure_time; + return INT64_C(-1); +} + +double +AeHandler::get_current_analog_gain () +{ + AnalyzerHandler::HandlerLock lock(this); + if (_params.mode == XCAM_AE_MODE_MANUAL) + return _params.manual_analog_gain; + return 0.0; +} + +bool +AeHandler::set_manual_exposure_time (int64_t time_in_us) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.manual_exposure_time = time_in_us; + + XCAM_LOG_DEBUG ("ae set manual exposure time: %" PRId64 "us", time_in_us); + return true; +} + +bool +AeHandler::set_manual_analog_gain (double gain) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.manual_analog_gain = gain; + + XCAM_LOG_DEBUG ("ae set manual analog gain: %.03f", gain); + return true; +} + +bool +AeHandler::set_aperture (double fn) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.aperture_fn = fn; + + XCAM_LOG_DEBUG ("ae set aperture fn: %.03f", fn); + return true; +} + +bool +AeHandler::set_max_analog_gain (double max_gain) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.max_analog_gain = max_gain; + + XCAM_LOG_DEBUG ("ae set max analog_gain: %.03f", max_gain); + return true; +} + +double AeHandler::get_max_analog_gain () +{ + AnalyzerHandler::HandlerLock lock(this); + return _params.max_analog_gain; +} + +bool AeHandler::set_exposure_time_range (int64_t min_time_in_us, int64_t max_time_in_us) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.exposure_time_min = min_time_in_us; + _params.exposure_time_max = max_time_in_us; + + XCAM_LOG_DEBUG ("ae set exposrue range[%" PRId64 "us, %" PRId64 "us]", min_time_in_us, max_time_in_us); + return true; +} + +bool +AeHandler::update_parameters (const XCamAeParam ¶ms) +{ + { + AnalyzerHandler::HandlerLock lock (this); + _params = params; + } + XCAM_LOG_DEBUG ("ae parameters updated"); + return true; +} + +bool +AeHandler::get_exposure_time_range (int64_t *min_time_in_us, int64_t *max_time_in_us) +{ + XCAM_ASSERT (min_time_in_us && max_time_in_us); + + AnalyzerHandler::HandlerLock lock(this); + *min_time_in_us = _params.exposure_time_min; + *max_time_in_us = _params.exposure_time_max; + + return true; +} + +AwbHandler::AwbHandler() +{ + reset_parameters (); +} + +void +AwbHandler::reset_parameters () +{ + xcam_mem_clear (_params); + _params.mode = XCAM_AWB_MODE_AUTO; + _params.speed = 1.0; + _params.cct_min = 0; + _params.cct_max = 0; + _params.gr_gain = 0.0; + _params.r_gain = 0.0; + _params.b_gain = 0.0; + _params.gb_gain = 0.0; + + _params.window.x_start = 0; + _params.window.y_start = 0; + _params.window.x_end = 0; + _params.window.y_end = 0; + _params.window.weight = 0; +} + +bool +AwbHandler::set_mode (XCamAwbMode mode) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.mode = mode; + + XCAM_LOG_DEBUG ("awb set mode [%d]", mode); + return true; +} + +bool +AwbHandler::set_speed (double speed) +{ + XCAM_FAIL_RETURN ( + ERROR, + (0.0 < speed) && (speed <= 1.0), + false, + "awb speed(%f) is out of range, suggest (0.0, 1.0]", speed); + + AnalyzerHandler::HandlerLock lock(this); + _params.speed = speed; + + XCAM_LOG_DEBUG ("awb set speed [%f]", speed); + return true; +} + +bool +AwbHandler::set_color_temperature_range (uint32_t cct_min, uint32_t cct_max) +{ + XCAM_FAIL_RETURN ( + ERROR, + (cct_min <= cct_max), + false, + "awb set wrong cct(%u, %u) parameters", cct_min, cct_max); + + AnalyzerHandler::HandlerLock lock(this); + _params.cct_min = cct_min; + _params.cct_max = cct_max; + + XCAM_LOG_DEBUG ("awb set cct range [%u, %u]", cct_min, cct_max); + return true; +} + +bool +AwbHandler::set_manual_gain (double gr, double r, double b, double gb) +{ + XCAM_FAIL_RETURN ( + ERROR, + gr >= 0.0 && r >= 0.0 && b >= 0.0 && gb >= 0.0, + false, + "awb manual gain value must >= 0.0"); + + AnalyzerHandler::HandlerLock lock(this); + _params.gr_gain = gr; + _params.r_gain = r; + _params.b_gain = b; + _params.gb_gain = gb; + XCAM_LOG_DEBUG ("awb set manual gain value(gr:%.03f, r:%.03f, b:%.03f, gb:%.03f)", gr, r, b, gb); + return true; +} + +bool +AwbHandler::update_parameters (const XCamAwbParam ¶ms) +{ + { + AnalyzerHandler::HandlerLock lock (this); + _params = params; + } + XCAM_LOG_DEBUG ("awb parameters updated"); + return true; +} + +uint32_t +AwbHandler::get_current_estimate_cct () +{ + AnalyzerHandler::HandlerLock lock(this); + if (_params.mode == XCAM_AWB_MODE_MANUAL) + return (_params.cct_max + _params.cct_min) / 2; + return 0.0; +} + +bool +AfHandler::update_parameters (const XCamAfParam ¶ms) +{ + { + AnalyzerHandler::HandlerLock lock (this); + _params = params; + } + XCAM_LOG_DEBUG ("af parameters updated"); + return true; +} + +CommonHandler::CommonHandler() +{ + reset_parameters (); +} + +void +CommonHandler::reset_parameters () +{ + xcam_mem_clear (_params); + + _params.is_manual_gamma = false; + _params.nr_level = 0.0; + _params.tnr_level = 0.0; + _params.brightness = 0.0; + _params.contrast = 0.0; + _params.hue = 0.0; + _params.saturation = 0.0; + _params.sharpness = 0.0; + _params.enable_dvs = false; + _params.enable_gbce = false; + _params.enable_night_mode = false; +} + +bool CommonHandler::set_dvs (bool enable) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.enable_dvs = enable; + + XCAM_LOG_DEBUG ("common 3A enable dvs:%s", XCAM_BOOL2STR(enable)); + return true; +} + +bool +CommonHandler::set_gbce (bool enable) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.enable_gbce = enable; + + XCAM_LOG_DEBUG ("common 3A enable gbce:%s", XCAM_BOOL2STR(enable)); + return true; +} + +bool +CommonHandler::set_night_mode (bool enable) +{ + AnalyzerHandler::HandlerLock lock(this); + _params.enable_night_mode = enable; + + XCAM_LOG_DEBUG ("common 3A enable night mode:%s", XCAM_BOOL2STR(enable)); + return true; +} + +/* Picture quality */ +bool +CommonHandler::set_noise_reduction_level (double level) +{ + XCAM_FAIL_RETURN ( + ERROR, + level >= -1.0 && level < 1.0, + false, + "set NR levlel(%.03f) out of range[-1.0, 1.0]", level); + + AnalyzerHandler::HandlerLock lock(this); + _params.nr_level = level; + + XCAM_LOG_DEBUG ("common 3A set NR level:%.03f", level); + return true; +} + +bool +CommonHandler::set_temporal_noise_reduction_level (double level) +{ + XCAM_FAIL_RETURN ( + ERROR, + level >= -1.0 && level < 1.0, + false, + "set TNR levlel(%.03f) out of range[-1.0, 1.0]", level); + + AnalyzerHandler::HandlerLock lock(this); + _params.tnr_level = level; + + XCAM_LOG_DEBUG ("common 3A set TNR level:%.03f", level); + return true; +} + +bool +CommonHandler::set_manual_brightness (double level) +{ + XCAM_FAIL_RETURN ( + ERROR, + level >= -1.0 && level < 1.0, + false, + "set brightness levlel(%.03f) out of range[-1.0, 1.0]", level); + + AnalyzerHandler::HandlerLock lock(this); + _params.brightness = level; + + XCAM_LOG_DEBUG ("common 3A set brightness level:%.03f", level); + return true; +} + +bool CommonHandler::set_manual_contrast (double level) +{ + XCAM_FAIL_RETURN ( + ERROR, + level >= -1.0 && level < 1.0, + false, + "set contrast levlel(%.03f) out of range[-1.0, 1.0]", level); + + AnalyzerHandler::HandlerLock lock(this); + _params.contrast = level; + + XCAM_LOG_DEBUG ("common 3A set contrast level:%.03f", level); + return true; +} + +bool CommonHandler::set_manual_hue (double level) +{ + XCAM_FAIL_RETURN ( + ERROR, + level >= -1.0 && level < 1.0, + false, + "set hue levlel(%.03f) out of range[-1.0, 1.0]", level); + + AnalyzerHandler::HandlerLock lock(this); + _params.hue = level; + + XCAM_LOG_DEBUG ("common 3A set hue level:%.03f", level); + return true; +} + +bool +CommonHandler::set_manual_saturation (double level) +{ + XCAM_FAIL_RETURN ( + ERROR, + level >= -1.0 && level < 1.0, + false, + "set saturation levlel(%.03f) out of range[-1.0, 1.0]", level); + + AnalyzerHandler::HandlerLock lock(this); + _params.saturation = level; + + XCAM_LOG_DEBUG ("common 3A set saturation level:%.03f", level); + return true; +} + +bool CommonHandler::set_manual_sharpness (double level) +{ + XCAM_FAIL_RETURN ( + ERROR, + level >= -1.0 && level < 1.0, + false, + "set sharpness levlel(%.03f) out of range[-1.0, 1.0]", level); + + AnalyzerHandler::HandlerLock lock(this); + _params.sharpness = level; + + XCAM_LOG_DEBUG ("common 3A set sharpness level:%.03f", level); + return true; +} + +bool +CommonHandler::set_gamma_table (double *r_table, double *g_table, double *b_table) +{ + AnalyzerHandler::HandlerLock lock(this); + if (!r_table && ! g_table && !b_table) { + _params.is_manual_gamma = false; + XCAM_LOG_DEBUG ("common 3A disabled gamma"); + return true; + } + + if (!r_table || !g_table || !b_table) { + XCAM_LOG_ERROR ("common 3A gamma table parameters wrong"); + return false; + } + + for (uint32_t i = 0; i < XCAM_GAMMA_TABLE_SIZE; ++i) { + _params.r_gamma [i] = r_table [i]; + _params.g_gamma [i] = g_table [i]; + _params.b_gamma [i] = b_table [i]; + } + _params.is_manual_gamma = true; + + XCAM_LOG_DEBUG ("common 3A enabled RGB gamma"); + return true; +} + +bool +CommonHandler::set_color_effect (XCamColorEffect effect) +{ + // TODO validate the input + + AnalyzerHandler::HandlerLock lock(this); + + _params.color_effect = effect; + + XCAM_LOG_DEBUG ("common 3A set color effect"); + return true; +} + +bool +CommonHandler::update_parameters (const XCamCommonParam ¶ms) +{ + { + AnalyzerHandler::HandlerLock lock (this); + _params = params; + } + XCAM_LOG_DEBUG ("common parameters updated"); + return true; +} + +}; diff --git a/xcore/handler_interface.h b/xcore/handler_interface.h new file mode 100644 index 0000000..a2b7865 --- /dev/null +++ b/xcore/handler_interface.h @@ -0,0 +1,280 @@ +/* + * handler_interface.h - handler interface + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_HANDLER_INTERFACE_H +#define XCAM_HANDLER_INTERFACE_H + +#include <base/xcam_common.h> +#include <base/xcam_3a_types.h> +#include <base/xcam_params.h> + +#include <xcam_std.h> +#include <xcam_mutex.h> +#include <x3a_result.h> + +namespace XCam { + +class AnalyzerHandler { + friend class HandlerLock; +public: + explicit AnalyzerHandler() {} + virtual ~AnalyzerHandler () {} + + virtual XCamReturn analyze (X3aResultList &output) = 0; + +protected: + class HandlerLock + : public SmartLock + { + public: + HandlerLock(AnalyzerHandler *handler) + : SmartLock (handler->_mutex) + {} + ~HandlerLock() {} + }; + + // members + Mutex _mutex; +}; + +class AeHandler + : public AnalyzerHandler +{ +public: + explicit AeHandler(); + virtual ~AeHandler() {} + + bool set_mode (XCamAeMode mode); + bool set_metering_mode (XCamAeMeteringMode mode); + bool set_window (XCam3AWindow *window); + bool set_window (XCam3AWindow *window, uint8_t count); + bool set_ev_shift (double ev_shift); + bool set_speed (double speed); + bool set_flicker_mode (XCamFlickerMode flicker); + bool set_manual_exposure_time (int64_t time_in_us); + bool set_manual_analog_gain (double gain); + bool set_aperture (double fn); + bool set_max_analog_gain (double max_gain); + bool set_exposure_time_range (int64_t min_time_in_us, int64_t max_time_in_us); + + bool update_parameters (const XCamAeParam ¶ms); + + bool get_exposure_time_range (int64_t *min_time_in_us, int64_t *max_time_in_us); + + XCamAeMeteringMode get_metering_mode() const { + return _params.metering_mode; + } + + //virtual functions + virtual XCamFlickerMode get_flicker_mode (); + virtual int64_t get_current_exposure_time (); + virtual double get_current_analog_gain (); + virtual double get_max_analog_gain (); + +protected: + const XCamAeParam &get_params_unlock () const { + return _params; + } + + XCamAeMode get_mode_unlock() const { + return _params.mode; + } + XCamAeMeteringMode get_metering_mode_unlock() const { + return _params.metering_mode; + } + const XCam3AWindow &get_window_unlock() const { + return _params.window; + } + XCamFlickerMode get_flicker_mode_unlock() const { + return _params.flicker_mode; + } + double get_speed_unlock() const { + return _params.speed; + } + double get_ev_shift_unlock() const { + return _params.ev_shift; + } + + uint64_t get_manual_exposure_time_unlock () const { + return _params.manual_exposure_time; + } + double get_manual_analog_gain_unlock () const { + return _params.manual_analog_gain; + } + + double get_aperture_fn_unlock () const { + return _params.aperture_fn; + } + + void get_exposure_time_range_unlock (uint64_t &min, uint64_t &max) const { + min = _params.exposure_time_min; + max = _params.exposure_time_max; + } + + double get_max_analog_gain_unlock () const { + return _params.max_analog_gain; + } + +private: + void reset_parameters (); + XCAM_DEAD_COPY (AeHandler); + +protected: + XCamAeParam _params; +}; + +class AwbHandler + : public AnalyzerHandler +{ +public: + explicit AwbHandler(); + virtual ~AwbHandler() {} + + bool set_mode (XCamAwbMode mode); + bool set_speed (double speed); + bool set_color_temperature_range (uint32_t cct_min, uint32_t cct_max); + bool set_manual_gain (double gr, double r, double b, double gb); + + bool update_parameters (const XCamAwbParam ¶ms); + + //virtual functions + virtual uint32_t get_current_estimate_cct (); + +protected: + const XCamAwbParam &get_params_unlock () const { + return _params; + } + + XCamAwbMode get_mode_unlock() const { + return _params.mode; + } + double get_speed_unlock () const { + return _params.speed; + } + + const XCam3AWindow &get_window_unlock () const { + return _params.window; + } + + void get_cct_range_unlock (uint32_t &cct_min, uint32_t &cct_max) const { + cct_min = _params.cct_min; + cct_max = _params.cct_max; + } + +private: + void reset_parameters (); + XCAM_DEAD_COPY (AwbHandler); + +protected: + XCamAwbParam _params; +}; + +class AfHandler + : public AnalyzerHandler +{ +public: + explicit AfHandler() {} + virtual ~AfHandler() {} + + bool update_parameters (const XCamAfParam ¶ms); + +private: + XCAM_DEAD_COPY (AfHandler); + +protected: + const XCamAfParam &get_params_unlock () const { + return _params; + } + +protected: + XCamAfParam _params; +}; + +class CommonHandler + : public AnalyzerHandler +{ +public: + explicit CommonHandler(); + virtual ~CommonHandler() {} + + bool set_dvs (bool enable); + bool set_gbce (bool enable); + bool set_night_mode (bool enable); + + /* Picture quality */ + bool set_noise_reduction_level (double level); + bool set_temporal_noise_reduction_level (double level); + bool set_manual_brightness (double level); + bool set_manual_contrast (double level); + bool set_manual_hue (double level); + bool set_manual_saturation (double level); + bool set_manual_sharpness (double level); + bool set_gamma_table (double *r_table, double *g_table, double *b_table); + bool set_color_effect(XCamColorEffect effect); + + bool update_parameters (const XCamCommonParam ¶ms); + +protected: + const XCamCommonParam &get_params_unlock () const { + return _params; + } + bool has_gbce_unlock () const { + return _params.enable_gbce; + } + bool has_dvs_unlock () const { + return _params.enable_dvs; + } + bool has_night_mode_unlock () const { + return _params.enable_night_mode; + } + + double get_nr_level_unlock () const { + return _params.nr_level; + } + double get_tnr_level_unlock () const { + return _params.tnr_level; + } + double get_brightness_unlock () const { + return _params.brightness; + } + double get_contrast_unlock () const { + return _params.contrast; + } + double get_hue_unlock () const { + return _params.hue; + } + double get_saturation_unlock () const { + return _params.saturation; + } + double get_sharpness_unlock () const { + return _params.sharpness; + } + +private: + void reset_parameters (); + XCAM_DEAD_COPY (CommonHandler); + +protected: + XCamCommonParam _params; +}; + +}; + +#endif // XCAM_HANDLER_INTERFACE_H diff --git a/xcore/image_file_handle.cpp b/xcore/image_file_handle.cpp new file mode 100644 index 0000000..a901b1f --- /dev/null +++ b/xcore/image_file_handle.cpp @@ -0,0 +1,96 @@ +/* + * image_file_handle.cpp - Image file handle + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include "image_file_handle.h" + +namespace XCam { + +ImageFileHandle::ImageFileHandle () +{ +} + +ImageFileHandle::ImageFileHandle (const char *name, const char *option) + : FileHandle (name, option) +{ +} + +ImageFileHandle::~ImageFileHandle () +{ + close (); +} + +XCamReturn +ImageFileHandle::read_buf (const SmartPtr<VideoBuffer> &buf) +{ + const VideoBufferInfo info = buf->get_video_info (); + VideoBufferPlanarInfo planar; + uint8_t *memory = NULL; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (is_valid ()); + + memory = buf->map (); + for (uint32_t index = 0; index < info.components; index++) { + info.get_planar_info (planar, index); + uint32_t line_bytes = planar.width * planar.pixel_bytes; + + for (uint32_t i = 0; i < planar.height; i++) { + if (fread (memory + info.offsets [index] + i * info.strides [index], 1, line_bytes, _fp) != line_bytes) { + if (end_of_file ()) + ret = XCAM_RETURN_BYPASS; + else { + XCAM_LOG_ERROR ("read file failed, size doesn't match"); + ret = XCAM_RETURN_ERROR_FILE; + } + } + } + } + buf->unmap (); + return ret; +} + +XCamReturn +ImageFileHandle::write_buf (const SmartPtr<VideoBuffer> &buf) +{ + const VideoBufferInfo info = buf->get_video_info (); + VideoBufferPlanarInfo planar; + uint8_t *memory = NULL; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (is_valid ()); + + memory = buf->map (); + for (uint32_t index = 0; index < info.components; index++) { + info.get_planar_info (planar, index); + uint32_t line_bytes = planar.width * planar.pixel_bytes; + + for (uint32_t i = 0; i < planar.height; i++) { + if (fwrite (memory + info.offsets [index] + i * info.strides [index], 1, line_bytes, _fp) != line_bytes) { + XCAM_LOG_ERROR ("write file failed, size doesn't match"); + ret = XCAM_RETURN_ERROR_FILE; + } + } + } + buf->unmap (); + return ret; +} + +} diff --git a/xcore/image_file_handle.h b/xcore/image_file_handle.h new file mode 100644 index 0000000..444356d --- /dev/null +++ b/xcore/image_file_handle.h @@ -0,0 +1,47 @@ +/* + * image_file_handle.h - Image file handle + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_IMAGE_FILE_HANDLE_H +#define XCAM_IMAGE_FILE_HANDLE_H + +#include <xcam_std.h> +#include <file_handle.h> +#include <video_buffer.h> + +namespace XCam { + +class ImageFileHandle + : public FileHandle +{ +public: + ImageFileHandle (); + explicit ImageFileHandle (const char *name, const char *option); + virtual ~ImageFileHandle (); + + XCamReturn read_buf (const SmartPtr<VideoBuffer> &buf); + XCamReturn write_buf (const SmartPtr<VideoBuffer> &buf); + +private: + XCAM_DEAD_COPY (ImageFileHandle); +}; + +} + +#endif //XCAM_IMAGE_FILE_HANDLE_H diff --git a/xcore/image_handler.cpp b/xcore/image_handler.cpp new file mode 100644 index 0000000..6e47a62 --- /dev/null +++ b/xcore/image_handler.cpp @@ -0,0 +1,96 @@ +/* + * image_handler.cpp - image handler implementation + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "image_handler.h" + +namespace XCam { + +ImageHandler::ImageHandler (const char* name) + : _name (NULL) +{ + if (name) + _name = strndup (name, XCAM_MAX_STR_SIZE); +} + +ImageHandler::~ImageHandler() +{ + xcam_mem_clear (_name); +} + +bool +ImageHandler::set_allocator (const SmartPtr<BufferPool> &allocator) +{ + XCAM_FAIL_RETURN ( + ERROR, allocator.ptr (), false, + "softhandler(%s) set allocator(is NULL)", XCAM_STR(get_name ())); + _allocator = allocator; + return true; +} + +XCamReturn +ImageHandler::finish () +{ + return XCAM_RETURN_NO_ERROR; +} + + +XCamReturn +ImageHandler::terminate () +{ + if (_allocator.ptr ()) + _allocator->stop (); + + return XCAM_RETURN_NO_ERROR; +} + +void +ImageHandler::execute_status_check (const SmartPtr<ImageHandler::Parameters> ¶ms, const XCamReturn error) +{ + if (_callback.ptr ()) + _callback->execute_status (this, params, error); +} + +XCamReturn +ImageHandler::reserve_buffers (const VideoBufferInfo &info, uint32_t count) +{ + XCAM_FAIL_RETURN ( + ERROR, _allocator.ptr (), XCAM_RETURN_ERROR_PARAM, + "softhandler(%s) reserve buffers failed, alloctor was not set", XCAM_STR(get_name ())); + + _allocator->set_video_info (info); + + XCAM_FAIL_RETURN ( + ERROR, _allocator->reserve (count), XCAM_RETURN_ERROR_MEM, + "softhandler(%s) reserve buffers(%d) failed", XCAM_STR(get_name ()), count); + + return XCAM_RETURN_NO_ERROR; +} + +SmartPtr<VideoBuffer> +ImageHandler::get_free_buf () +{ + XCAM_FAIL_RETURN ( + ERROR, _allocator.ptr (), NULL, + "softhandler(%s) get free buffer failed since allocator was not initilized", XCAM_STR(get_name ())); + + return _allocator->get_buffer (_allocator); +} + +} diff --git a/xcore/image_handler.h b/xcore/image_handler.h new file mode 100644 index 0000000..2c3fba8 --- /dev/null +++ b/xcore/image_handler.h @@ -0,0 +1,138 @@ +/* + * image_handler.h - image image handler class + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_IMAGE_HANDLER_H +#define XCAM_IMAGE_HANDLER_H + +#include <xcam_std.h> +#include <meta_data.h> +#include <buffer_pool.h> +#include <worker.h> + +#define DECLARE_HANDLER_CALLBACK(CbClass, Next, mem_func) \ + class CbClass : public ::XCam::ImageHandler::Callback { \ + private: ::XCam::SmartPtr<Next> _h; \ + public: CbClass (const ::XCam::SmartPtr<Next> &h) { _h = h;} \ + protected: void execute_status ( \ + const ::XCam::SmartPtr<::XCam::ImageHandler> &handler, \ + const ::XCam::SmartPtr<::XCam::ImageHandler::Parameters> ¶ms, \ + const XCamReturn error) { \ + _h->mem_func (handler, params, error); } \ + } + +namespace XCam { + +class ImageHandler; + +class ImageHandler + : public RefObj +{ +public: + struct Parameters { + SmartPtr<VideoBuffer> in_buf; + SmartPtr<VideoBuffer> out_buf; + + Parameters (const SmartPtr<VideoBuffer> &in = NULL, const SmartPtr<VideoBuffer> &out = NULL) + : in_buf (in), out_buf (out) + {} + virtual ~Parameters() {} + bool add_meta (const SmartPtr<MetaBase> &meta); + template <typename MType> SmartPtr<MType> find_meta (); + + private: + MetaBaseList _metas; + }; + + class Callback { + public: + Callback () {} + virtual ~Callback () {} + virtual void execute_status ( + const SmartPtr<ImageHandler> &handler, const SmartPtr<Parameters> ¶ms, const XCamReturn error) = 0; + + private: + XCAM_DEAD_COPY (Callback); + }; + +public: + explicit ImageHandler (const char* name); + virtual ~ImageHandler (); + + bool set_callback (SmartPtr<Callback> cb) { + _callback = cb; + return true; + } + const SmartPtr<Callback> & get_callback () const { + return _callback; + } + const char *get_name () const { + return _name; + } + + // virtual functions + // execute_buffer params should NOT be const + virtual XCamReturn execute_buffer (const SmartPtr<Parameters> ¶ms, bool sync) = 0; + virtual XCamReturn finish (); + virtual XCamReturn terminate (); + +protected: + virtual void execute_status_check (const SmartPtr<Parameters> ¶ms, const XCamReturn error); + + bool set_allocator (const SmartPtr<BufferPool> &allocator); + const SmartPtr<BufferPool> &get_allocator () const { + return _allocator; + } + XCamReturn reserve_buffers (const VideoBufferInfo &info, uint32_t count); + SmartPtr<VideoBuffer> get_free_buf (); + +private: + XCAM_DEAD_COPY (ImageHandler); + +private: + SmartPtr<Callback> _callback; + SmartPtr<BufferPool> _allocator; + char *_name; +}; + +inline bool +ImageHandler::Parameters::add_meta (const SmartPtr<MetaBase> &meta) +{ + if (!meta.ptr ()) + return false; + + _metas.push_back (meta); + return true; +} + +template <typename MType> +SmartPtr<MType> +ImageHandler::Parameters::find_meta () +{ + for (MetaBaseList::iterator i = _metas.begin (); i != _metas.end (); ++i) { + SmartPtr<MType> m = (*i).dynamic_cast_ptr<MType> (); + if (m.ptr ()) + return m; + } + return NULL; +} + +}; + +#endif //XCAM_IMAGE_HANDLER_H diff --git a/xcore/image_processor.cpp b/xcore/image_processor.cpp new file mode 100644 index 0000000..928cbcc --- /dev/null +++ b/xcore/image_processor.cpp @@ -0,0 +1,358 @@ +/* + * image_processor.h - 3a image processor + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "image_processor.h" +#include "xcam_thread.h" + +namespace XCam { + +void +ImageProcessCallback::process_buffer_done (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf) { + XCAM_UNUSED (processor); + XCAM_ASSERT (buf.ptr() && processor); + + int64_t ts = buf->get_timestamp(); + XCAM_UNUSED (ts); + XCAM_LOG_DEBUG ( + "processor(%s) handled buffer(" XCAM_TIMESTAMP_FORMAT ") successfully", + XCAM_STR(processor->get_name()), + XCAM_TIMESTAMP_ARGS (ts)); +} + +void +ImageProcessCallback::process_buffer_failed (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf) +{ + XCAM_ASSERT (buf.ptr() && processor); + + int64_t ts = buf->get_timestamp(); + XCAM_UNUSED (ts); + XCAM_LOG_WARNING ( + "processor(%s) handled buffer(" XCAM_TIMESTAMP_FORMAT ") failed", + XCAM_STR(processor->get_name()), + XCAM_TIMESTAMP_ARGS (ts)); +} + +void +ImageProcessCallback::process_image_result_done (ImageProcessor *processor, const SmartPtr<X3aResult> &result) +{ + XCAM_UNUSED (processor); + XCAM_ASSERT (result.ptr() && processor); + + int64_t ts = result->get_timestamp(); + XCAM_UNUSED (ts); + + XCAM_LOG_DEBUG ( + "processor(%s) processed result(type:%d, timestamp:" XCAM_TIMESTAMP_FORMAT ") done", + XCAM_STR(processor->get_name()), + (int)result->get_type(), + XCAM_TIMESTAMP_ARGS (ts)); +} + +class ImageProcessorThread + : public Thread +{ +public: + ImageProcessorThread (ImageProcessor *processor) + : Thread ("image_processor") + , _processor (processor) + {} + ~ImageProcessorThread () {} + + virtual bool loop (); + +private: + ImageProcessor *_processor; +}; + +bool ImageProcessorThread::loop () +{ + XCamReturn ret = _processor->buffer_process_loop (); + if (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_ERROR_TIMEOUT) + return true; + return false; +} + +class X3aResultsProcessThread + : public Thread +{ + typedef SafeList<X3aResult> ResultQueue; +public: + X3aResultsProcessThread (ImageProcessor *processor) + : Thread ("x3a_results_process_thread") + , _processor (processor) + {} + ~X3aResultsProcessThread () {} + + XCamReturn push_result (SmartPtr<X3aResult> &result) { + _queue.push (result); + return XCAM_RETURN_NO_ERROR; + } + + void triger_stop () { + _queue.pause_pop (); + } + + virtual bool loop (); + +private: + ImageProcessor *_processor; + ResultQueue _queue; +}; + +bool X3aResultsProcessThread::loop () +{ + X3aResultList result_list; + SmartPtr<X3aResult> result; + + result = _queue.pop (-1); + if (!result.ptr ()) + return false; + + result_list.push_back (result); + while ((result = _queue.pop (0)).ptr ()) { + result_list.push_back (result); + } + + XCamReturn ret = _processor->process_3a_results (result_list); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_DEBUG ("processing 3a result failed"); + } + + return true; +} +ImageProcessor::ImageProcessor (const char* name) + : _name (NULL) + , _callback (NULL) +{ + if (name) + _name = strndup (name, XCAM_MAX_STR_SIZE); + + _processor_thread = new ImageProcessorThread (this); + _results_thread = new X3aResultsProcessThread (this); +} + +ImageProcessor::~ImageProcessor () +{ + if (_name) + xcam_free (_name); +} + +bool +ImageProcessor::set_callback (ImageProcessCallback *callback) +{ + XCAM_ASSERT (!_callback); + _callback = callback; + return true; +} + +XCamReturn +ImageProcessor::start() +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + if (!_results_thread->start ()) { + return XCAM_RETURN_ERROR_THREAD; + } + if (!_processor_thread->start ()) { + return XCAM_RETURN_ERROR_THREAD; + } + ret = emit_start (); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("ImageProcessor(%s) emit start failed", XCAM_STR (_name)); + _video_buf_queue.pause_pop (); + _results_thread->triger_stop (); + _processor_thread->stop (); + _results_thread->stop (); + return ret; + } + XCAM_LOG_INFO ("ImageProcessor(%s) started", XCAM_STR (_name)); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +ImageProcessor::stop() +{ + _video_buf_queue.pause_pop (); + _results_thread->triger_stop (); + + emit_stop (); + + _processor_thread->stop (); + _results_thread->stop (); + XCAM_LOG_DEBUG ("ImageProcessor(%s) stopped", XCAM_STR (_name)); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +ImageProcessor::push_buffer (SmartPtr<VideoBuffer> &buf) +{ + if (_video_buf_queue.push (buf)) + return XCAM_RETURN_NO_ERROR; + + XCAM_LOG_DEBUG ("processor push buffer failed"); + return XCAM_RETURN_ERROR_UNKNOWN; +} + +XCamReturn +ImageProcessor::push_3a_results (X3aResultList &results) +{ + XCAM_ASSERT (!results.empty ()); + XCamReturn ret = XCAM_RETURN_NO_ERROR; + for (X3aResultList::iterator i_res = results.begin(); + i_res != results.end(); ++i_res) { + SmartPtr<X3aResult> &res = *i_res; + + ret = _results_thread->push_result (res); + if (ret != XCAM_RETURN_NO_ERROR) + break; + } + + XCAM_FAIL_RETURN( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "processor(%s) push 3a results failed", XCAM_STR(get_name())); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +ImageProcessor::push_3a_result (SmartPtr<X3aResult> &result) +{ + XCamReturn ret = _results_thread->push_result (result); + XCAM_FAIL_RETURN( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "processor(%s) push 3a result failed", XCAM_STR(get_name())); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +ImageProcessor::process_3a_results (X3aResultList &results) +{ + X3aResultList valid_results; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + filter_valid_results (results, valid_results); + if (valid_results.empty()) + return XCAM_RETURN_BYPASS; + + ret = apply_3a_results (valid_results); + + if (ret != XCAM_RETURN_NO_ERROR && ret != XCAM_RETURN_BYPASS) { + XCAM_LOG_WARNING ("processor(%s) apply results failed", XCAM_STR(get_name())); + return ret; + } + + if (_callback) { + for (X3aResultList::iterator i_res = valid_results.begin(); + i_res != valid_results.end(); ++i_res) { + SmartPtr<X3aResult> &res = *i_res; + _callback->process_image_result_done (this, res); + } + } + + return ret; +} + +XCamReturn +ImageProcessor::process_3a_result (SmartPtr<X3aResult> &result) +{ + X3aResultList valid_results; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + if (!can_process_result(result)) + return XCAM_RETURN_BYPASS; + + ret = apply_3a_result (result); + + if (ret != XCAM_RETURN_NO_ERROR && ret != XCAM_RETURN_BYPASS) { + XCAM_LOG_WARNING ("processor(%s) apply result failed", XCAM_STR(get_name())); + return ret; + } + + if (_callback) { + _callback->process_image_result_done (this, result); + } + + return ret; +} + +void +ImageProcessor::filter_valid_results (X3aResultList &input, X3aResultList &valid_results) +{ + for (X3aResultList::iterator i_res = input.begin(); i_res != input.end(); ) { + SmartPtr<X3aResult> &res = *i_res; + if (can_process_result(res)) { + valid_results.push_back (res); + input.erase (i_res++); + } else + ++i_res; + } +} + +void +ImageProcessor::notify_process_buffer_done (const SmartPtr<VideoBuffer> &buf) +{ + if (_callback) + _callback->process_buffer_done (this, buf); +} + +void +ImageProcessor::notify_process_buffer_failed (const SmartPtr<VideoBuffer> &buf) +{ + if (_callback) + _callback->process_buffer_failed (this, buf); +} + +XCamReturn +ImageProcessor::buffer_process_loop () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<VideoBuffer> new_buf; + SmartPtr<VideoBuffer> buf = _video_buf_queue.pop(); + + if (!buf.ptr()) + return XCAM_RETURN_ERROR_MEM; + + ret = this->process_buffer (buf, new_buf); + if (ret < XCAM_RETURN_NO_ERROR) { + XCAM_LOG_DEBUG ("processing buffer failed"); + notify_process_buffer_failed (buf); + return ret; + } + + if (new_buf.ptr ()) + notify_process_buffer_done (new_buf); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +ImageProcessor::emit_start () +{ + return XCAM_RETURN_NO_ERROR; +} + +void +ImageProcessor::emit_stop () +{ +} + +}; diff --git a/xcore/image_processor.h b/xcore/image_processor.h new file mode 100644 index 0000000..bb7bd4f --- /dev/null +++ b/xcore/image_processor.h @@ -0,0 +1,106 @@ +/* + * image_processor.h - 3a image processor + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_IMAGE_PROCESSOR_H +#define XCAM_IMAGE_PROCESSOR_H + +#include <xcam_std.h> +#include <video_buffer.h> +#include <x3a_result.h> +#include <safe_list.h> + +namespace XCam { + +class ImageProcessor; + +/* callback interface */ +class ImageProcessCallback { +public: + ImageProcessCallback () {} + virtual ~ImageProcessCallback () {} + virtual void process_buffer_done (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf); + virtual void process_buffer_failed (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf); + virtual void process_image_result_done (ImageProcessor *processor, const SmartPtr<X3aResult> &result); + +private: + XCAM_DEAD_COPY (ImageProcessCallback); +}; + +class ImageProcessorThread; +class X3aResultsProcessThread; + +/* base class, ImageProcessor */ +class ImageProcessor +{ + friend class ImageProcessorThread; + friend class X3aResultsProcessThread; + + typedef SafeList<VideoBuffer> VideoBufQueue; + +public: + explicit ImageProcessor (const char* name); + virtual ~ImageProcessor (); + + const char *get_name () const { + return _name; + } + + bool set_callback (ImageProcessCallback *callback); + XCamReturn start(); + XCamReturn stop (); + + XCamReturn push_buffer (SmartPtr<VideoBuffer> &buf); + XCamReturn push_3a_results (X3aResultList &results); + XCamReturn push_3a_result (SmartPtr<X3aResult> &result); + +protected: + virtual bool can_process_result (SmartPtr<X3aResult> &result) = 0; + virtual XCamReturn apply_3a_results (X3aResultList &results) = 0; + virtual XCamReturn apply_3a_result (SmartPtr<X3aResult> &result) = 0; + // buffer runs in another thread + virtual XCamReturn process_buffer(SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) = 0; + virtual XCamReturn emit_start (); + virtual void emit_stop (); + + + void notify_process_buffer_done (const SmartPtr<VideoBuffer> &buf); + void notify_process_buffer_failed (const SmartPtr<VideoBuffer> &buf); + +private: + void filter_valid_results (X3aResultList &input, X3aResultList &valid_results); + XCamReturn buffer_process_loop (); + + XCamReturn process_3a_results (X3aResultList &results); + XCamReturn process_3a_result (SmartPtr<X3aResult> &result); + +private: + XCAM_DEAD_COPY (ImageProcessor); + +protected: + char *_name; + ImageProcessCallback *_callback; + SmartPtr<ImageProcessorThread> _processor_thread; + VideoBufQueue _video_buf_queue; + SmartPtr<X3aResultsProcessThread> _results_thread; +}; + +}; + +#endif //XCAM_IMAGE_PROCESSOR_H diff --git a/xcore/image_projector.cpp b/xcore/image_projector.cpp new file mode 100644 index 0000000..2e4eaa2 --- /dev/null +++ b/xcore/image_projector.cpp @@ -0,0 +1,330 @@ +/* + * image_projector.cpp - Calculate 2D image projective matrix + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include "image_projector.h" + +namespace XCam { + +ImageProjector::ImageProjector (CalibrationParams ¶ms) + : _calib_params (params) +{ + set_camera_intrinsics( + params.focal_x, + params.focal_y, + params.offset_x, + params.offset_y, + params.skew); +} + +ImageProjector::ImageProjector ( + double focal_x, + double focal_y, + double offset_x, + double offset_y, + double skew) +{ + set_camera_intrinsics( + focal_x, + focal_y, + offset_x, + offset_y, + skew); +} + +Quaternd +ImageProjector::interp_orientation ( + int64_t frame_ts, + const std::vector<Vec4d> &orientation, + const std::vector<int64_t> &orient_ts, + int& index) +{ + if (orientation.empty () || orient_ts.empty ()) { + return Quaternd (); + } + + int count = orient_ts.size (); + if (count == 1) { + return Quaternd(orientation[0]); + } + + int i = index; + XCAM_ASSERT(0 <= i && i < count); + + while (i >= 0 && orient_ts[i] > frame_ts) { + i--; + } + if (i < 0) return Quaternd (orientation[0]); + + while (i + 1 < count && orient_ts[i + 1] < frame_ts) { + i++; + } + if (i >= count) return Quaternd (orientation[count - 1]); + + index = i; + + double weight_start = (orient_ts[i + 1] - frame_ts) / (orient_ts[i + 1] - orient_ts[i]); + double weight_end = 1.0f - weight_start; + XCAM_ASSERT (weight_start >= 0 && weight_start <= 1.0); + XCAM_ASSERT (weight_end >= 0 && weight_end <= 1.0); + + return Quaternd (orientation[i] * weight_start + orientation[i + 1] * weight_end); + //return Quaternd (quat[i]).slerp(weight_start, Quaternd (quat[i + 1])); +} + +// rotate coordinate system keeps the handedness of original coordinate system unchanged +// +// axis_to_x: defines the axis of the new cooridinate system that +// coincide with the X axis of the original coordinate system. +// axis_to_y: defines the axis of the new cooridinate system that +// coincide with the Y axis of the original coordinate system. +// +Mat3d +ImageProjector::rotate_coordinate_system ( + CoordinateAxisType axis_to_x, + CoordinateAxisType axis_to_y) +{ + Mat3d t_mat; + if (axis_to_x == AXIS_X && axis_to_y == AXIS_MINUS_Z) { + t_mat = Mat3d (Vec3d (1, 0, 0), + Vec3d (0, 0, -1), + Vec3d (0, 1, 0)); + } else if (axis_to_x == AXIS_X && axis_to_y == AXIS_MINUS_Y) { + t_mat = Mat3d (Vec3d (1, 0, 0), + Vec3d (0, -1, 0), + Vec3d (0, 0, -1)); + } else if (axis_to_x == AXIS_X && axis_to_y == AXIS_Z) { + t_mat = Mat3d (Vec3d (1, 0, 0), + Vec3d (0, 0, 1), + Vec3d (0, -1, 0)); + } else if (axis_to_x == AXIS_MINUS_Z && axis_to_y == AXIS_Y) { + t_mat = Mat3d (Vec3d (0, 0, -1), + Vec3d (0, 1, 0), + Vec3d (1, 0, 0)); + } else if (axis_to_x == AXIS_MINUS_X && axis_to_y == AXIS_Y) { + t_mat = Mat3d (Vec3d (-1, 0, 0), + Vec3d (0, 1, 0), + Vec3d (0, 0, -1)); + } else if (axis_to_x == AXIS_Z && axis_to_y == AXIS_Y) { + t_mat = Mat3d (Vec3d (0, 0, 1), + Vec3d (0, 1, 0), + Vec3d (-1, 0, 0)); + } else if (axis_to_x == AXIS_MINUS_Y && axis_to_y == AXIS_X) { + t_mat = Mat3d (Vec3d (0, -1, 0), + Vec3d (1, 0, 0), + Vec3d (0, 0, 1)); + } else if (axis_to_x == AXIS_MINUS_X && axis_to_y == AXIS_MINUS_Y) { + t_mat = Mat3d (Vec3d (-1, 0, 0), + Vec3d (0, -1, 0), + Vec3d (0, 0, 1)); + } else if (axis_to_x == AXIS_Y && axis_to_y == AXIS_MINUS_X) { + t_mat = Mat3d (Vec3d (0, 1, 0), + Vec3d (-1, 0, 0), + Vec3d (0, 0, 1)); + } else { + t_mat = Mat3d (); + } + return t_mat; +} + +// mirror coordinate system will change the handedness of original coordinate system +// +// axis_mirror: defines the axis that coordinate system mirror on +// +Mat3d +ImageProjector::mirror_coordinate_system (CoordinateAxisType axis_mirror) +{ + Mat3d t_mat; + + switch (axis_mirror) { + case AXIS_X: + case AXIS_MINUS_X: + t_mat = Mat3d (Vec3d (-1, 0, 0), + Vec3d (0, 1, 0), + Vec3d (0, 0, 1)); + break; + case AXIS_Y: + case AXIS_MINUS_Y: + t_mat = Mat3d (Vec3d (1, 0, 0), + Vec3d (0, -1, 0), + Vec3d (0, 0, 1)); + break; + case AXIS_Z: + case AXIS_MINUS_Z: + t_mat = Mat3d (Vec3d (1, 0, 0), + Vec3d (0, 1, 0), + Vec3d (0, 0, -1)); + break; + default: + t_mat = Mat3d (); + break; + } + + return t_mat; +} + +// transform coordinate system will change the handedness of original coordinate system +// +// axis_to_x: defines the axis of the new cooridinate system that +// coincide with the X axis of the original coordinate system. +// axis_to_y: defines the axis of the new cooridinate system that +// coincide with the Y axis of the original coordinate system. +// axis_mirror: defines the axis that coordinate system mirror on +Mat3d +ImageProjector::transform_coordinate_system (CoordinateSystemConv &transform) +{ + return mirror_coordinate_system (transform.axis_mirror) * + rotate_coordinate_system (transform.axis_to_x, transform.axis_to_y); +} + +Mat3d +ImageProjector::align_coordinate_system ( + CoordinateSystemConv &world_to_device, + Mat3d &extrinsics, + CoordinateSystemConv &device_to_image) +{ + return transform_coordinate_system (world_to_device) + * extrinsics + * transform_coordinate_system (device_to_image); +} + +XCamReturn +ImageProjector::set_sensor_calibration (CalibrationParams ¶ms) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + _calib_params = params; + set_camera_intrinsics ( + params.focal_x, + params.focal_y, + params.offset_x, + params.offset_y, + params.skew); + + return ret; +} + +XCamReturn +ImageProjector::set_camera_intrinsics ( + double focal_x, + double focal_y, + double offset_x, + double offset_y, + double skew) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + _intrinsics = Mat3d (Vec3d (focal_x, skew, offset_x), + Vec3d (0, focal_y, offset_y), + Vec3d (0, 0, 1)); + + XCAM_LOG_DEBUG("Intrinsic Matrix(3x3) \n"); + XCAM_LOG_DEBUG("intrinsic = [ %lf, %lf, %lf ; %lf, %lf, %lf ; %lf, %lf, %lf ] \n", + _intrinsics(0, 0), _intrinsics(0, 1), _intrinsics(0, 2), + _intrinsics(1, 0), _intrinsics(1, 1), _intrinsics(1, 2), + _intrinsics(2, 0), _intrinsics(2, 1), _intrinsics(2, 2)); + return ret; +} + +Mat3d +ImageProjector::calc_camera_extrinsics ( + const int64_t frame_ts, + const std::vector<int64_t> &pose_ts, + const std::vector<Vec4d> &orientation, + const std::vector<Vec3d> &translation) +{ + if (pose_ts.empty () || orientation.empty () || translation.empty ()) { + return Mat3d (); + } + + int index = 0; + const double ts = frame_ts + _calib_params.gyro_delay; + Quaternd quat = interp_orientation (ts, orientation, pose_ts, index) + + Quaternd (_calib_params.gyro_drift); + + Mat3d extrinsics = quat.rotation_matrix (); + + XCAM_LOG_DEBUG("Extrinsic Matrix(3x3) \n"); + XCAM_LOG_DEBUG("extrinsic = [ %lf, %lf, %lf; %lf, %lf, %lf; %lf, %lf, %lf ] \n", + extrinsics(0, 0), extrinsics(0, 1), extrinsics(0, 2), + extrinsics(1, 0), extrinsics(1, 1), extrinsics(1, 2), + extrinsics(2, 0), extrinsics(2, 1), extrinsics(2, 2)); + + return extrinsics; +} + +Mat3d +ImageProjector::calc_camera_extrinsics ( + const int64_t frame_ts, + DevicePoseList &pose_list) +{ + if (pose_list.empty ()) { + return Mat3d (); + } + + int index = 0; + + std::vector<Vec4d> orientation; + std::vector<int64_t> orient_ts; + std::vector<Vec3d> translation; + + for (DevicePoseList::iterator iter = pose_list.begin (); iter != pose_list.end (); ++iter) + { + SmartPtr<DevicePose> pose = *iter; + + orientation.push_back (Vec4d (pose->orientation[0], + pose->orientation[1], + pose->orientation[2], + pose->orientation[3])); + + orient_ts.push_back (pose->timestamp); + + translation.push_back (Vec3d (pose->translation[0], + pose->translation[1], + pose->translation[2])); + + } + + const int64_t ts = frame_ts + _calib_params.gyro_delay; + Quaternd quat = interp_orientation (ts, orientation, orient_ts, index) + + Quaternd (_calib_params.gyro_drift); + + Mat3d extrinsics = quat.rotation_matrix (); + + XCAM_LOG_DEBUG("Extrinsic Matrix(3x3) \n"); + XCAM_LOG_DEBUG("extrinsic = [ %lf, %lf, %lf; %lf, %lf, %lf; %lf, %lf, %lf ] \n", + extrinsics(0, 0), extrinsics(0, 1), extrinsics(0, 2), + extrinsics(1, 0), extrinsics(1, 1), extrinsics(1, 2), + extrinsics(2, 0), extrinsics(2, 1), extrinsics(2, 2)); + + return extrinsics; +} + +Mat3d +ImageProjector::calc_projective ( + Mat3d &extrinsic0, + Mat3d &extrinsic1) +{ + Mat3d intrinsic = get_camera_intrinsics (); + + return intrinsic * extrinsic0 * extrinsic1.transpose () * intrinsic.inverse (); +} + +} + diff --git a/xcore/image_projector.h b/xcore/image_projector.h new file mode 100644 index 0000000..ff1c8bf --- /dev/null +++ b/xcore/image_projector.h @@ -0,0 +1,157 @@ +/* + * image_projector.h - Calculate 2D image projective matrix + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#ifndef XCAM_IMAGE_PROJECTIVE_2D_H +#define XCAM_IMAGE_PROJECTIVE_2D_H + +#include <xcam_std.h> +#include <meta_data.h> +#include <vec_mat.h> +#include <vector> + +namespace XCam { + +struct CalibrationParams { + double focal_x; //Focal length, x axis, in pixels + double focal_y; //Focal length, y axis, in pixels + double offset_x; //Principal point x coordinate on the image, in pixels + double offset_y; //Principal point y coordinate on the image, in pixels + double skew; //in case if the image coordinate axes u and v are not orthogonal to each other + double readout_time; + double gyro_delay; + Vec4d gyro_drift; + + CalibrationParams () + : focal_x (0) + , focal_y (0) + , offset_x (0) + , offset_y (0) + , skew (0) + , readout_time (0) + , gyro_delay (0) + { + gyro_drift.zeros(); + } +}; + +enum CoordinateAxisType { + AXIS_X = 0, + AXIS_MINUS_X, + AXIS_Y, + AXIS_MINUS_Y, + AXIS_Z, + AXIS_MINUS_Z, + AXIS_NONE, +}; + +struct CoordinateSystemConv { + CoordinateAxisType axis_to_x; + CoordinateAxisType axis_to_y; + CoordinateAxisType axis_mirror; + + CoordinateSystemConv () + { + axis_to_x = AXIS_X; + axis_to_y = AXIS_Y; + axis_mirror = AXIS_NONE; + } + + CoordinateSystemConv ( + CoordinateAxisType to_x, + CoordinateAxisType to_y, + CoordinateAxisType mirror) + { + axis_to_x = to_x; + axis_to_y = to_y; + axis_mirror = mirror; + } +}; + +class ImageProjector +{ +public: + explicit ImageProjector () {}; + explicit ImageProjector (CalibrationParams ¶ms); + explicit ImageProjector ( + double focal_x, + double focal_y, + double offset_x, + double offset_y, + double skew); + + virtual ~ImageProjector () {}; + + XCamReturn set_sensor_calibration (CalibrationParams ¶ms); + XCamReturn set_camera_intrinsics ( + double focal_x, + double focal_y, + double offset_x, + double offset_y, + double skew); + + Mat3d get_camera_intrinsics () { + return _intrinsics; + } + + Mat3d calc_camera_extrinsics ( + const int64_t frame_ts, + const std::vector<int64_t> &pose_ts, + const std::vector<Vec4d> &orientation, + const std::vector<Vec3d> &translation); + + Mat3d calc_camera_extrinsics ( + const int64_t frame_ts, + DevicePoseList &pose_list); + + Mat3d calc_projective ( + Mat3d &extrinsic0, + Mat3d &extrinsic1); + + Mat3d align_coordinate_system ( + CoordinateSystemConv &world_to_device, + Mat3d &extrinsics, + CoordinateSystemConv &device_to_image); + +protected: + Quaternd interp_orientation ( + int64_t ts, + const std::vector<Vec4d> &orientation, + const std::vector<int64_t> &orient_ts, + int& index); + + Mat3d rotate_coordinate_system ( + CoordinateAxisType axis_to_x, + CoordinateAxisType axis_to_y); + + Mat3d mirror_coordinate_system (CoordinateAxisType axis_mirror); + + Mat3d transform_coordinate_system (CoordinateSystemConv &transform); + +private: + XCAM_DEAD_COPY (ImageProjector); + +private: + Mat3d _intrinsics; + CalibrationParams _calib_params; +}; + +} + +#endif //XCAM_IMAGE_PROJECTIVE_2D_H
\ No newline at end of file diff --git a/xcore/interface/blender.cpp b/xcore/interface/blender.cpp new file mode 100644 index 0000000..7ddc19f --- /dev/null +++ b/xcore/interface/blender.cpp @@ -0,0 +1,122 @@ +/* + * blender.h - blender interface + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "blender.h" + +namespace XCam { + +Blender::Blender (uint32_t alignment_x, uint32_t alignment_y) + : _alignment_x (alignment_x) + , _alignment_y (alignment_y) + , _out_width (0) + , _out_height (0) +{ +} + +Blender::~Blender () +{ +} + +void +Blender::set_output_size (uint32_t width, uint32_t height) { + _out_width = XCAM_ALIGN_UP (width, get_alignment_x ()); + _out_height = XCAM_ALIGN_UP (height, get_alignment_y ()); +} + +bool +Blender::set_merge_window (const Rect &window) { + uint32_t alignmend_x = get_alignment_x (); + + _merge_window = window; + _merge_window.pos_x = XCAM_ALIGN_AROUND (_merge_window.pos_x, alignmend_x); + _merge_window.width = XCAM_ALIGN_AROUND (_merge_window.width, alignmend_x); + XCAM_ASSERT (_merge_window.width >= (int32_t)alignmend_x); + XCAM_LOG_DEBUG( + "Blender merge window:(x:%d, width:%d), blend_width:%d", + _merge_window.pos_x, _merge_window.width, _out_width); + return true; +} + +bool +Blender::set_input_valid_area (const Rect &area, uint32_t index) +{ + XCAM_ASSERT (index < XCAM_BLENDER_IMAGE_NUM); + _input_valid_area[index] = area; + + uint32_t alignmend_x = get_alignment_x (); + _input_valid_area[index].pos_x = XCAM_ALIGN_DOWN (_input_valid_area[index].pos_x, alignmend_x); + _input_valid_area[index].width = XCAM_ALIGN_UP (_input_valid_area[index].width, alignmend_x); + + XCAM_LOG_DEBUG( + "Blender buf(%d) valid area:(x:%d, width:%d)", + index, _input_valid_area[index].pos_x, _input_valid_area[index].width); + return true; +} + +bool +Blender::set_input_merge_area (const Rect &area, uint32_t index) +{ + XCAM_ASSERT (index < XCAM_BLENDER_IMAGE_NUM); + if (!is_merge_window_set ()) { + XCAM_LOG_ERROR ("set_input_merge_area(idx:%d) failed, need set merge window first", index); + return false; + } + + _input_merge_area[index] = area; + _input_merge_area[index].pos_x = XCAM_ALIGN_AROUND (_input_merge_area[index].pos_x, get_alignment_x ()); + _input_merge_area[index].pos_y = XCAM_ALIGN_AROUND (_input_merge_area[index].pos_y, get_alignment_y ()); + + XCAM_LOG_DEBUG( + "Blender buf(%d) merge area:(x:%d, width:%d)", + index, _input_merge_area[index].pos_x, _input_merge_area[index].width); + + return true; +} + +bool +Blender::auto_calc_merge_window ( + uint32_t width0, uint32_t width1, uint32_t blend_width, + Rect &out_window) +{ + out_window.pos_x = blend_width - width1; + out_window.width = (width0 + width1 - blend_width) / 2; + + out_window.pos_x = XCAM_ALIGN_AROUND (out_window.pos_x, get_alignment_x ()); + out_window.width = XCAM_ALIGN_AROUND (out_window.width, get_alignment_x ()); + if ((int)blend_width < out_window.pos_x + out_window.width) + out_window.width = blend_width - out_window.pos_x; + + XCAM_ASSERT (out_window.width > 0 && out_window.width <= (int)blend_width); + XCAM_ASSERT (out_window.pos_x >= 0 && out_window.pos_x <= (int)blend_width); + + return true; +} + +XCamReturn +Blender::blend ( + const SmartPtr<VideoBuffer> &, + const SmartPtr<VideoBuffer> &, + SmartPtr<VideoBuffer> &) +{ + XCAM_LOG_ERROR ("Blender interface blend must be derived."); + return XCAM_RETURN_ERROR_UNKNOWN; +} + +} diff --git a/xcore/interface/blender.h b/xcore/interface/blender.h new file mode 100644 index 0000000..93b5fbe --- /dev/null +++ b/xcore/interface/blender.h @@ -0,0 +1,97 @@ +/* + * blender.h - blender interface + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_INTERFACE_BLENDER_H +#define XCAM_INTERFACE_BLENDER_H + +#include <xcam_std.h> +#include <video_buffer.h> +#include <interface/data_types.h> + +#define XCAM_BLENDER_IMAGE_NUM 2 + +namespace XCam { + +class Blender; + +class Blender +{ +public: + explicit Blender (uint32_t alignment_x, uint32_t alignment_y); + virtual ~Blender (); + static SmartPtr<Blender> create_ocl_blender (); + static SmartPtr<Blender> create_soft_blender (); + + void set_output_size (uint32_t width, uint32_t height); + void get_output_size (uint32_t &width, uint32_t &height) const { + width = _out_width; + height = _out_height; + } + bool set_input_valid_area (const Rect &area, uint32_t index); + bool set_merge_window (const Rect &window); + virtual bool set_input_merge_area (const Rect &area, uint32_t index); + + const Rect &get_merge_window () const { + return _merge_window; + } + + const Rect &get_input_merge_area (uint32_t index) const { + return _input_merge_area[index]; + } + const Rect &get_input_valid_area (uint32_t index) const { + return _input_valid_area[index]; + } + + bool is_merge_window_set () const { + return _merge_window.pos_x || _merge_window.width; + } + + uint32_t get_alignment_x () const { + return _alignment_x; + } + uint32_t get_alignment_y () const { + return _alignment_y; + } + + virtual XCamReturn blend ( + const SmartPtr<VideoBuffer> &in0, + const SmartPtr<VideoBuffer> &in1, + SmartPtr<VideoBuffer> &out_buf); + +protected: + bool auto_calc_merge_window ( + uint32_t width0, uint32_t width1, uint32_t blend_width, Rect &out_window); + +private: + XCAM_DEAD_COPY (Blender); + +private: + uint32_t _alignment_x, _alignment_y; + uint32_t _out_width, _out_height; + Rect _input_valid_area[XCAM_BLENDER_IMAGE_NUM]; + Rect _merge_window; // for output buffer + +protected: + Rect _input_merge_area[XCAM_BLENDER_IMAGE_NUM]; +}; + +} + +#endif //XCAM_INTERFACE_BLENDER_H diff --git a/xcore/interface/data_types.h b/xcore/interface/data_types.h new file mode 100644 index 0000000..a4d6f4e --- /dev/null +++ b/xcore/interface/data_types.h @@ -0,0 +1,159 @@ +/* + * data_types.h - data types in interface + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#ifndef XCAM_INTERFACE_DATA_TYPES_H +#define XCAM_INTERFACE_DATA_TYPES_H + +#include <xcam_std.h> + +namespace XCam { + +enum SurroundMode { + SphereView = 0, + BowlView = 1 +}; + +struct Rect { + int32_t pos_x, pos_y; + int32_t width, height; + + Rect () : pos_x (0), pos_y (0), width (0), height (0) {} + Rect (int32_t x, int32_t y, int32_t w, int32_t h) : pos_x (x), pos_y (y), width (w), height (h) {} +}; + +struct ImageCropInfo { + uint32_t left; + uint32_t right; + uint32_t top; + uint32_t bottom; + + ImageCropInfo () : left (0), right (0), top (0), bottom (0) {} +}; + +struct FisheyeInfo { + float center_x; + float center_y; + float wide_angle; + float radius; + float rotate_angle; // clockwise + + FisheyeInfo () + : center_x (0.0f), center_y (0.0f), wide_angle (0.0f) + , radius (0.0f), rotate_angle (0.0f) + {} + bool is_valid () const { + return wide_angle >= 1.0f && radius >= 1.0f; + } +}; + +#define XCAM_INTRINSIC_MAX_POLY_SIZE 16 + +// current intrinsic parameters definition from Scaramuzza's approach +struct IntrinsicParameter { + float xc; + float yc; + float c; + float d; + float e; + uint32_t poly_length; + + float poly_coeff[XCAM_INTRINSIC_MAX_POLY_SIZE]; + + IntrinsicParameter () + : xc (0.0f), yc (0.0f), c(0.0f), d (0.0f), e (0.0f), poly_length (0) + { + xcam_mem_clear (poly_coeff); + } +}; + +struct ExtrinsicParameter { + float trans_x; + float trans_y; + float trans_z; + + // angle degree + float roll; + float pitch; + float yaw; + + ExtrinsicParameter () + : trans_x (0.0f), trans_y (0.0f), trans_z (0.0f) + , roll (0.0f), pitch (0.0f), yaw (0.0f) + {} +}; + +template <typename T> +struct Point2DT { + T x, y; + Point2DT () : x (0), y(0) {} + Point2DT (const T px, const T py) : x (px), y(py) {} +}; + +template <typename T> +struct Point3DT { + T x, y, z; + Point3DT () : x (0), y(0), z(0) {} + Point3DT (const T px, const T py, const T pz) : x (px), y(py), z(pz) {} +}; + +typedef Point2DT<int32_t> PointInt2; +typedef Point2DT<float> PointFloat2; + +typedef Point3DT<int32_t> PointInt3; +typedef Point3DT<float> PointFloat3; + +/* + * Ellipsoid model + * x^2 / a^2 + y^2 / b^2 + (z-center_z)^2 / c^2 = 1 + * ground : z = 0 + * x_axis : front direction + * y_axis : left direction + * z_axis : up direction + * wall_height : bowl height inside of view + * ground_length: left direction distance from ellipsoid bottom edge to nearest side of the car in the view + */ +struct BowlDataConfig { + float a, b, c; + float angle_start, angle_end; // angle degree + + // unit mm + float center_z; + float wall_height; + float ground_length; + + BowlDataConfig () + : a (6060.0f), b (4388.0f), c (3003.4f) + , angle_start (90.0f), angle_end (270.0f) + , center_z (1500.0f) + , wall_height (3000.0f) + , ground_length (2801.0f) + { + XCAM_ASSERT (fabs(center_z) <= c); + XCAM_ASSERT (a > 0.0f && b > 0.0f && c > 0.0f); + XCAM_ASSERT (wall_height >= 0.0f && ground_length >= 0.0f); + XCAM_ASSERT (ground_length <= b * sqrt(1.0f - center_z * center_z / (c * c))); + XCAM_ASSERT (wall_height <= center_z + c); + } +}; + +} + +#endif //XCAM_INTERFACE_DATA_TYPES_H diff --git a/xcore/interface/feature_match.cpp b/xcore/interface/feature_match.cpp new file mode 100644 index 0000000..4a6a428 --- /dev/null +++ b/xcore/interface/feature_match.cpp @@ -0,0 +1,143 @@ +/* + * feature_match.cpp - optical flow feature match + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include "feature_match.h" + +#define XCAM_FM_DEBUG 0 + +namespace XCam { + +FeatureMatch::FeatureMatch () + : _x_offset (0.0f) + , _mean_offset (0.0f) + , _valid_count (0) + , _fm_idx (-1) + , _frame_num (0) +{ +} + +void +FeatureMatch::set_config (CVFMConfig config) +{ + _config = config; +} + +CVFMConfig +FeatureMatch::get_config () +{ + return _config; +} + +void +FeatureMatch::set_fm_index (int idx) +{ + _fm_idx = idx; +} + +void +FeatureMatch::reset_offsets () +{ + _x_offset = 0.0f; + _mean_offset = 0.0f; +} + +bool +FeatureMatch::get_mean_offset (std::vector<float> &offsets, float sum, int &count, float &mean_offset) +{ + if (count < _config.min_corners) + return false; + + mean_offset = sum / count; + +#if XCAM_FM_DEBUG + XCAM_LOG_INFO ( + "FeatureMatch(idx:%d): X-axis mean offset:%.2f, pre_mean_offset:%.2f (%d times, count:%d)", + _fm_idx, mean_offset, 0.0f, 0, count); +#endif + + bool ret = true; + float delta = 20.0f;//mean_offset; + float pre_mean_offset = mean_offset; + for (int try_times = 1; try_times < 4; ++try_times) { + int recur_count = 0; + sum = 0.0f; + + for (size_t i = 0; i < offsets.size (); ++i) { + if (fabs (offsets[i] - mean_offset) >= _config.recur_offset_error) + continue; + sum += offsets[i]; + ++recur_count; + } + + if (recur_count < _config.min_corners) { + ret = false; + break; + } + + mean_offset = sum / recur_count; +#if XCAM_FM_DEBUG + XCAM_LOG_INFO ( + "FeatureMatch(idx:%d): X-axis mean_offset:%.2f, pre_mean_offset:%.2f (%d times, count:%d)", + _fm_idx, mean_offset, pre_mean_offset, try_times, recur_count); +#endif + + if (mean_offset == pre_mean_offset && recur_count == count) + return true; + + if (fabs (mean_offset - pre_mean_offset) > fabs (delta) * 1.2f) { + ret = false; + break; + } + + delta = mean_offset - pre_mean_offset; + pre_mean_offset = mean_offset; + count = recur_count; + } + + return ret; +} + +void +FeatureMatch::adjust_stitch_area (int dst_width, float &x_offset, Rect &stitch0, Rect &stitch1) +{ + if (fabs (x_offset) < 5.0f) + return; + + int last_overlap_width = stitch1.pos_x + stitch1.width + (dst_width - (stitch0.pos_x + stitch0.width)); + // int final_overlap_width = stitch1.pos_x + stitch1.width + (dst_width - (stitch0.pos_x - x_offset + stitch0.width)); + if ((stitch0.pos_x - x_offset + stitch0.width) > dst_width) + x_offset = dst_width - (stitch0.pos_x + stitch0.width); + int final_overlap_width = last_overlap_width + x_offset; + final_overlap_width = XCAM_ALIGN_AROUND (final_overlap_width, 8); + XCAM_ASSERT (final_overlap_width >= _config.sitch_min_width); + int center = final_overlap_width / 2; + XCAM_ASSERT (center >= _config.sitch_min_width / 2); + + stitch1.pos_x = XCAM_ALIGN_AROUND (center - _config.sitch_min_width / 2, 8); + stitch1.width = _config.sitch_min_width; + stitch0.pos_x = dst_width - final_overlap_width + stitch1.pos_x; + stitch0.width = _config.sitch_min_width; + + float delta_offset = final_overlap_width - last_overlap_width; + x_offset -= delta_offset; +} + +} diff --git a/xcore/interface/feature_match.h b/xcore/interface/feature_match.h new file mode 100644 index 0000000..06c0b7b --- /dev/null +++ b/xcore/interface/feature_match.h @@ -0,0 +1,98 @@ +/* + * feature_match.h - optical flow feature match + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#ifndef XCAM_FEATURE_MATCH_H +#define XCAM_FEATURE_MATCH_H + +#include <xcam_std.h> +#include <video_buffer.h> +#include <interface/data_types.h> + +namespace XCam { + +struct CVFMConfig { + int sitch_min_width; + int min_corners; // number of minimum efficient corners + float offset_factor; // last_offset * offset_factor + cur_offset * (1.0f - offset_factor) + float delta_mean_offset; // cur_mean_offset - last_mean_offset + float recur_offset_error; // cur_offset - mean_offset + float max_adjusted_offset; // maximum offset of each adjustment + float max_valid_offset_y; // valid maximum offset in vertical direction + float max_track_error; // maximum track error + + CVFMConfig () + : sitch_min_width (56) + , min_corners (8) + , offset_factor (0.8f) + , delta_mean_offset (5.0f) + , recur_offset_error (8.0f) + , max_adjusted_offset (12.0f) + , max_valid_offset_y (8.0f) + , max_track_error (24.0f) + {} +}; + +class FeatureMatch +{ +public: + explicit FeatureMatch (); + virtual ~FeatureMatch () {}; + + void set_config (CVFMConfig config); + CVFMConfig get_config (); + + void set_fm_index (int idx); + + void reset_offsets (); + + virtual void optical_flow_feature_match ( + const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf, + Rect &left_crop_rect, Rect &right_crop_rect, int dst_width) = 0; + + float get_current_left_offset_x () const { + return _x_offset; + } + + virtual void set_ocl (bool use_ocl) = 0; + virtual bool is_ocl_path () = 0; + +protected: + bool get_mean_offset (std::vector<float> &offsets, float sum, int &count, float &mean_offset); + + void adjust_stitch_area (int dst_width, float &x_offset, Rect &stitch0, Rect &stitch1); + +private: + XCAM_DEAD_COPY (FeatureMatch); + +protected: + float _x_offset; + float _mean_offset; + int _valid_count; + CVFMConfig _config; + + // debug parameters + int _fm_idx; + uint _frame_num; +}; + +} + +#endif // XCAM_FEATURE_MATCH_H diff --git a/xcore/interface/geo_mapper.cpp b/xcore/interface/geo_mapper.cpp new file mode 100644 index 0000000..75031d8 --- /dev/null +++ b/xcore/interface/geo_mapper.cpp @@ -0,0 +1,79 @@ +/* + * geo_mapper.cpp - geometry mapper implementation + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "geo_mapper.h" + +namespace XCam { + +GeoMapper::GeoMapper () + : _out_width (0) + , _out_height (0) + , _factor_x (0.0f) + , _factor_y (0.0f) +{} + +GeoMapper::~GeoMapper () +{ +} + +bool +GeoMapper::set_factors (float x, float y) +{ + XCAM_FAIL_RETURN ( + ERROR, !XCAM_DOUBLE_EQUAL_AROUND (x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (y, 0.0f), false, + "GeoMapper set factors failed. (x:%.3f, h:%.3f)", x, y); + _factor_x = x; + _factor_y = y; + + return true; +} + +bool +GeoMapper::set_output_size (uint32_t width, uint32_t height) +{ + XCAM_FAIL_RETURN ( + ERROR, width && height, false, + "GeoMapper set output size failed. (w:%d, h:%d)", + width, height); + + _out_width = width; + _out_height = height; + return true; +} + +bool +GeoMapper::auto_calculate_factors (uint32_t lut_w, uint32_t lut_h) +{ + XCAM_FAIL_RETURN ( + ERROR, _out_width > 1 && _out_height > 1, false, + "GeoMapper auto calculate factors failed. output size was not set. (w:%d, h:%d)", + _out_width, _out_height); + XCAM_FAIL_RETURN ( + ERROR, lut_w > 1 && lut_w > 1, false, + "GeoMapper auto calculate factors failed. lookuptable size need > 1. but set with (w:%d, h:%d)", + lut_w, lut_h); + + XCAM_ASSERT (lut_w && lut_h); + _factor_x = (_out_width - 1.0f) / (lut_w - 1.0f); + _factor_y = (_out_height - 1.0f) / (lut_h - 1.0f); + return true; +} + +} diff --git a/xcore/interface/geo_mapper.h b/xcore/interface/geo_mapper.h new file mode 100644 index 0000000..0ddd495 --- /dev/null +++ b/xcore/interface/geo_mapper.h @@ -0,0 +1,64 @@ +/* + * geo_mapper.h - geometry mapper interface + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_INTERFACE_GEO_MAPPER_H +#define XCAM_INTERFACE_GEO_MAPPER_H + +#include <xcam_std.h> +#include <video_buffer.h> +#include <interface/data_types.h> + +namespace XCam { + +class GeoMapper +{ +public: + GeoMapper (); + virtual ~GeoMapper (); + static SmartPtr<GeoMapper> create_ocl_geo_mapper (); + static SmartPtr<GeoMapper> create_soft_geo_mapper (); + + //2D table + virtual bool set_lookup_table (const PointFloat2 *data, uint32_t width, uint32_t height) = 0; + bool set_factors (float x, float y); + void get_factors (float &x, float &y) const { + x = _factor_x; + y = _factor_y; + } + bool set_output_size (uint32_t width, uint32_t height); + void get_output_size (uint32_t &width, uint32_t &height) const { + width = _out_width; + height = _out_height; + } + + virtual XCamReturn remap ( + const SmartPtr<VideoBuffer> &in, + SmartPtr<VideoBuffer> &out_buf) = 0; + +protected: + bool auto_calculate_factors (uint32_t lut_w, uint32_t lut_h); + +private: + uint32_t _out_width, _out_height; + float _factor_x, _factor_y; +}; + +} +#endif //XCAM_INTERFACE_GEO_MAPPER_H diff --git a/xcore/interface/stitcher.cpp b/xcore/interface/stitcher.cpp new file mode 100644 index 0000000..70da11f --- /dev/null +++ b/xcore/interface/stitcher.cpp @@ -0,0 +1,667 @@ +/* + * stitcher.cpp - stitcher base + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include "stitcher.h" +#include "xcam_utils.h" + +// angle to position, output range [-180, 180] +#define OUT_WINDOWS_START 0.0f + +#define constraint_margin (2 * _alignment_x) + +#define XCAM_GL_RESTART_FIXED_INDEX 0xFFFF + +namespace XCam { + +static inline bool +merge_neighbor_area ( + const Stitcher::CopyArea ¤t, + const Stitcher::CopyArea &next, + Stitcher::CopyArea &merged) +{ + if (current.in_idx == next.in_idx && + current.in_area.pos_x + current.in_area.width == next.in_area.pos_x && + current.out_area.pos_x + current.out_area.width == next.out_area.pos_x) + { + merged = current; + merged.in_area.pos_x = current.in_area.pos_x; + merged.in_area.width = current.in_area.width + next.in_area.width; + merged.out_area.pos_x = current.out_area.pos_x; + merged.out_area.width = current.out_area.width + next.out_area.width; + return true; + } + return false; +} + +static inline bool +split_area_by_out ( + const Stitcher::CopyArea &area, const uint32_t round_width, + Stitcher::CopyArea &split_a, Stitcher::CopyArea &split_b) +{ + XCAM_ASSERT (area.out_area.pos_x >= 0 && area.out_area.pos_x < (int32_t)round_width); + XCAM_ASSERT (area.out_area.width > 0 && area.out_area.width < (int32_t)round_width); + if (area.out_area.pos_x + area.out_area.width > (int32_t)round_width) { + split_a = area; + split_a.out_area.width = round_width - area.out_area.pos_x; + split_a.in_area.width = split_a.out_area.width; + + split_b = area; + split_b.in_area.pos_x = area.in_area.pos_x + split_a.in_area.width; + split_b.in_area.width = area.in_area.width - split_a.in_area.width; + split_b.out_area.pos_x = 0; + split_b.out_area.width = split_b.in_area.width; + XCAM_ASSERT (split_b.out_area.width == area.out_area.pos_x + area.out_area.width - (int32_t)round_width); + return true; + + } + XCAM_ASSERT (area.out_area.width == area.in_area.width); + return false; +} + +Stitcher::Stitcher (uint32_t align_x, uint32_t align_y) + : _is_crop_set (false) + , _alignment_x (align_x) + , _alignment_y (align_y) + , _output_width (0) + , _output_height (0) + , _out_start_angle (OUT_WINDOWS_START) + , _camera_num (0) + , _is_round_view_set (false) + , _is_overlap_set (false) + , _is_center_marked (false) +{ + XCAM_ASSERT (align_x >= 1); + XCAM_ASSERT (align_y >= 1); +} + +Stitcher::~Stitcher () +{ +} + +bool +Stitcher::set_bowl_config (const BowlDataConfig &config) +{ + _bowl_config = config; + return true; +} + +bool +Stitcher::set_camera_num (uint32_t num) +{ + XCAM_FAIL_RETURN ( + ERROR, num <= XCAM_STITCH_MAX_CAMERAS, false, + "stitcher: set camera count failed, num(%d) is larger than max value(%d)", + num, XCAM_STITCH_MAX_CAMERAS); + _camera_num = num; + return true; +} + +bool +Stitcher::set_camera_info (uint32_t index, const CameraInfo &info) +{ + XCAM_FAIL_RETURN ( + ERROR, index < _camera_num, false, + "stitcher: set camera info failed, index(%d) exceed max camera num(%d)", + index, _camera_num); + _camera_info[index] = info; + return true; +} + +bool +Stitcher::set_crop_info (uint32_t index, const ImageCropInfo &info) +{ + XCAM_FAIL_RETURN ( + ERROR, index < _camera_num, false, + "stitcher: set camera info failed, index(%d) exceed max camera num(%d)", + index, _camera_num); + _crop_info[index] = info; + _is_crop_set = true; + return true; +} + +bool +Stitcher::get_crop_info (uint32_t index, ImageCropInfo &info) const +{ + XCAM_FAIL_RETURN ( + ERROR, index < _camera_num, false, + "stitcher: get crop info failed, index(%d) exceed camera num(%d)", + index, _camera_num); + info = _crop_info[index]; + return true; +} + +#if 0 +bool +Stitcher::set_overlap_info (uint32_t index, const ImageOverlapInfo &info) +{ + XCAM_FAIL_RETURN ( + ERROR, index < _camera_num, false, + "stitcher: set overlap info failed, index(%d) exceed max camera num(%d)", + index, _camera_num); + _overlap_info[index] = info; + _is_overlap_set = true; + return true; +} + +bool +Stitcher::get_overlap_info (uint32_t index, ImageOverlapInfo &info) const +{ + XCAM_FAIL_RETURN ( + ERROR, index < _camera_num, false, + "stitcher: get overlap info failed, index(%d) exceed camera num(%d)", + index, _camera_num); + info = _overlap_info[index]; + return true; +} +#endif + +bool +Stitcher::get_camera_info (uint32_t index, CameraInfo &info) const +{ + XCAM_FAIL_RETURN ( + ERROR, index < XCAM_STITCH_MAX_CAMERAS, false, + "stitcher: get camera info failed, index(%d) exceed max camera value(%d)", + index, XCAM_STITCH_MAX_CAMERAS); + info = _camera_info[index]; + return true; +} + +XCamReturn +Stitcher::estimate_round_slices () +{ + if (_is_round_view_set) + return XCAM_RETURN_NO_ERROR; + + XCAM_FAIL_RETURN ( + ERROR, _camera_num && _camera_num < XCAM_STITCH_MAX_CAMERAS, XCAM_RETURN_ERROR_PARAM, + "stitcher: camera num was not set, or camera num(%d) exceed max camera value(%d)", + _camera_num, XCAM_STITCH_MAX_CAMERAS); + + for (uint32_t i = 0; i < _camera_num; ++i) { + CameraInfo &cam_info = _camera_info[i]; + RoundViewSlice &view_slice = _round_view_slices[i]; + + view_slice.width = cam_info.angle_range / 360.0f * (float)_output_width; + view_slice.width = XCAM_ALIGN_UP (view_slice.width, _alignment_x); + view_slice.height = _output_height; + view_slice.hori_angle_range = view_slice.width * 360.0f / (float)_output_width; + + uint32_t aligned_start = format_angle (cam_info.round_angle_start) / 360.0f * (float)_output_width; + aligned_start = XCAM_ALIGN_AROUND (aligned_start, _alignment_x); + if (_output_width <= constraint_margin + aligned_start || aligned_start <= constraint_margin) + aligned_start = 0; + view_slice.hori_angle_start = format_angle((float)aligned_start / (float)_output_width * 360.0f); + if (XCAM_DOUBLE_EQUAL_AROUND (view_slice.hori_angle_start, 0.0001f)) + view_slice.hori_angle_start = 0.0f; + + cam_info.round_angle_start = view_slice.hori_angle_start; + cam_info.angle_range = view_slice.hori_angle_range; + } + + _is_round_view_set = true; + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +Stitcher::estimate_coarse_crops () +{ + if (_is_crop_set) + return XCAM_RETURN_NO_ERROR; + + XCAM_FAIL_RETURN ( + ERROR, _camera_num > 0 && _is_round_view_set, XCAM_RETURN_ERROR_ORDER, + "stitcher mark_centers failed, need set camera info and round_slices first"); + + for (uint32_t i = 0; i < _camera_num; ++i) { + _crop_info[i].left = 0; + _crop_info[i].right = 0; + _crop_info[i].top = 0; + _crop_info[i].bottom = 0; + } + _is_crop_set = true; + return XCAM_RETURN_NO_ERROR; +} + +// after crop done +XCamReturn +Stitcher::mark_centers () +{ + if (_is_center_marked) + return XCAM_RETURN_NO_ERROR; + + XCAM_FAIL_RETURN ( + ERROR, _camera_num > 0 && _is_round_view_set, XCAM_RETURN_ERROR_ORDER, + "stitcher mark_centers failed, need set camera info and round_view slices first"); + + for (uint32_t i = 0; i < _camera_num; ++i) { + const RoundViewSlice &slice = _round_view_slices[i]; + + //calcuate final output postion + float center_angle = i * 360.0f / _camera_num; + uint32_t out_pos = format_angle (center_angle - _out_start_angle) / 360.0f * _output_width; + XCAM_ASSERT (out_pos < _output_width); + if (_output_width <= constraint_margin + out_pos || out_pos <= constraint_margin) + out_pos = 0; + + // get slice center angle + center_angle = XCAM_ALIGN_AROUND (out_pos, _alignment_x) / (float)_output_width * 360.0f - _out_start_angle; + center_angle = format_angle (center_angle); + + float center_in_slice = center_angle - slice.hori_angle_start; + center_in_slice = format_angle (center_in_slice); + XCAM_FAIL_RETURN ( + ERROR, center_in_slice < slice.hori_angle_range, + XCAM_RETURN_ERROR_PARAM, + "stitcher mark center failed, slice:%d calculated center-angle:%.2f is out of slice angle(start:%.2f, range:%.2f)", + center_angle, slice.hori_angle_start, slice.hori_angle_range); + + uint32_t slice_pos = (uint32_t)(center_in_slice / slice.hori_angle_range * slice.width); + slice_pos = XCAM_ALIGN_AROUND (slice_pos, _alignment_x); + XCAM_ASSERT (slice_pos > _crop_info[i].left && slice_pos < slice.width - _crop_info[i].right); + + _center_marks[i].slice_center_x = slice_pos; + _center_marks[i].out_center_x = out_pos; + } + _is_center_marked = true; + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +Stitcher::estimate_overlap () +{ + if (_is_overlap_set) + return XCAM_RETURN_NO_ERROR; + + XCAM_FAIL_RETURN ( + ERROR, _is_round_view_set && _is_crop_set && _is_center_marked, XCAM_RETURN_ERROR_ORDER, + "stitcher estimate_coarse_seam failed, need set round_view slices, crop info and mark centers first"); + + for (uint32_t idx = 0; idx < _camera_num; ++idx) { + uint32_t next_idx = (idx + 1) % _camera_num; + const RoundViewSlice &left = _round_view_slices[idx]; + const RoundViewSlice &right = _round_view_slices[next_idx]; + const CenterMark &left_center = _center_marks[idx]; + const CenterMark &right_center = _center_marks[next_idx]; + const ImageCropInfo &left_img_crop = _crop_info[idx]; + const ImageCropInfo &right_img_crop = _crop_info[next_idx]; + +#if 0 + XCAM_FAIL_RETURN ( + ERROR, + (format_angle (right.hori_angle_start - left.hori_angle_start) < left.hori_angle_range) + XCAM_RETURN_ERROR_UNKNOWN, + "stitcher estimate_coarse_seam failed and there is no seam between slice %d and slice %d", idx, next_idx); + + float seam_angle_start = right.hori_angle_start; + float seam_angle_range = + format_angle (left.hori_angle_start + left.hori_angle_range - right.hori_angle_start); + + XCAM_FAIL_RETURN ( + ERROR, seam_angle_range < right.hori_angle_range, XCAM_RETURN_ERROR_UNKNOWN, + "stitcher estimate_coarse_seam failed and left slice(%d)over covered right slice(%d)", idx, next_idx); + + XCAM_ASSERT (!XCAM_DOUBLE_EQUAL_AROUND (left.hori_angle_range, 0.0f)); + XCAM_ASSERT (!XCAM_DOUBLE_EQUAL_AROUND (right.hori_angle_range, 0.0f)); +#endif + uint32_t out_right_center_x = right_center.out_center_x; + if (out_right_center_x == 0) + out_right_center_x = _output_width; + + Rect valid_left_img, valid_right_img; + valid_left_img.pos_x = left_center.slice_center_x; + valid_left_img.width = left.width - left_img_crop.right - valid_left_img.pos_x; + valid_left_img.pos_y = left_img_crop.top; + valid_left_img.height = left.height - left_img_crop.top - left_img_crop.bottom; + + valid_right_img.width = right_center.slice_center_x - right_img_crop.left; + valid_right_img.pos_x = right_center.slice_center_x - valid_right_img.width; + valid_right_img.pos_y = right_img_crop.top; + valid_right_img.height = right.height - right_img_crop.top - right_img_crop.bottom; + + uint32_t merge_width = out_right_center_x - left_center.out_center_x; + XCAM_FAIL_RETURN ( + ERROR, + valid_left_img.width + valid_right_img.width > (int32_t)merge_width, + XCAM_RETURN_ERROR_UNKNOWN, + "stitcher estimate_overlap failed and there is no overlap area between slice %d and slice %d", idx, next_idx); + + uint32_t overlap_width = valid_left_img.width + valid_right_img.width - merge_width; + + Rect left_img_overlap, right_img_overlap; + left_img_overlap.pos_x = valid_left_img.pos_x + valid_left_img.width - overlap_width; + left_img_overlap.width = overlap_width; + left_img_overlap.pos_y = valid_left_img.pos_y; + left_img_overlap.height = valid_left_img.height; + XCAM_ASSERT (left_img_overlap.pos_x >= (int32_t)left_center.slice_center_x && left_img_overlap.pos_x < (int32_t)left.width); + + right_img_overlap.pos_x = valid_right_img.pos_x; + right_img_overlap.width = overlap_width; + right_img_overlap.pos_y = valid_right_img.pos_y; + right_img_overlap.height = valid_right_img.height; + XCAM_ASSERT (right_img_overlap.pos_x >= (int32_t)right_img_crop.left && right_img_overlap.pos_x < (int32_t)right_center.slice_center_x); + + Rect out_overlap; + out_overlap.pos_x = left_center.out_center_x + valid_left_img.width - overlap_width; + out_overlap.width = overlap_width; + // out_overlap.pos_y/height not useful by now + out_overlap.pos_y = valid_left_img.pos_y; + out_overlap.height = valid_left_img.height; + +#if 0 + left_img_seam.pos_x = + left.width * format_angle (seam_angle_start - left.hori_angle_start) / left.hori_angle_range; + left_img_seam.pos_y = _crop_info[idx].top; + left_img_seam.width = left.width * seam_angle_range / left.hori_angle_range; + left_img_seam.height = left.height - _crop_info[idx].top - _crop_info[idx].bottom; + + //consider crop + XCAM_ASSERT (left_img_seam.pos_x < left.width - _crop_info[idx].right); + if (left_img_seam.pos_x + left_img_seam.width > left.width - _crop_info[idx].right) + left_img_seam.width = left.width - _crop_info[idx].right; + + right_img_seam.pos_x = 0; + right_img_seam.pos_y = _crop_info[next_idx].top; + right_img_seam.width = right.width * (seam_angle_range / right.hori_angle_range); + right_img_seam.height = right.height - _crop_info[next_idx].top - _crop_info[next_idx].bottom; + + //consider crop + XCAM_ASSERT (right_img_seam.pos_x + right_img_seam.width > _crop_info[next_idx].left); + if (_crop_info[next_idx].left) { + right_img_seam.pos_x = _crop_info[next_idx].left; + right_img_seam.width -= _crop_info[next_idx].left; + left_img_seam.pos_x += _crop_info[next_idx].left; + left_img_seam.width -= _crop_info[next_idx].left; + } + + XCAM_ASSERT (abs (left_img_seam.width - right_img_seam.width) < 16); + left_img_seam.pos_x = XCAM_ALIGN_DOWN (left_img_seam.pos_x, _alignment_x); + right_img_seam.pos_x = XCAM_ALIGN_DOWN (right_img_seam.pos_x, _alignment_x); + + //find max seam width + uint32_t seam_width, seam_height; + seam_width = XCAM_MAX (left_img_seam.width, right_img_seam.width); + if (left_img_seam.pos_x + seam_width > left.width) + seam_width = left.width - left_img_seam.pos_x; + if (right_img_seam.pos_x + seam_width > right.width) + seam_width = right.width - right_img_seam.pos_x; + + XCAM_FAIL_RETURN ( + ERROR, seam_width >= XCAM_STITCH_MIN_SEAM_WIDTH, XCAM_RETURN_ERROR_UNKNOWN, + "stitcher estimate_coarse_seam failed, the seam(w:%d) is very narrow between(slice %d and %d)", + seam_width, idx, next_idx); + left_img_seam.width = right_img_seam.width = XCAM_ALIGN_DOWN (seam_width, _alignment_x); + + // min height + uint32_t top = XCAM_MAX (left_img_seam.pos_y, right_img_seam.pos_y); + uint32_t bottom0 = left_img_seam.pos_y + left_img_seam.height; + uint32_t bottom1 = right_img_seam.pos_y + right_img_seam.height; + uint32_t bottom = XCAM_MIN (bottom0, bottom1); + top = XCAM_ALIGN_UP (top, _alignment_y); + left_img_seam.pos_y = right_img_seam.pos_y = top; + left_img_seam.height = right_img_seam.height = XCAM_ALIGN_DOWN (bottom - top, _alignment_y); +#endif + // set overlap info + _overlap_info[idx].left = left_img_overlap; + _overlap_info[idx].right = right_img_overlap; + _overlap_info[idx].out_area = out_overlap; + } + + _is_overlap_set = true; + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +Stitcher::update_copy_areas () +{ + XCAM_FAIL_RETURN ( + ERROR, _camera_num > 1 && _is_round_view_set && _is_crop_set && _is_overlap_set, XCAM_RETURN_ERROR_ORDER, + "stitcher update_copy_areas failed, check orders, need" + "camera_info, round_view slices, crop_info and overlap_info set first."); + + CopyAreaArray tmp_areas; + uint32_t i = 0; + uint32_t next_i = 0; + for (i = 0; i < _camera_num; ++i) { + next_i = (i + 1 ) % _camera_num; + const CenterMark &mark_left = _center_marks[i]; + const CenterMark &mark_right = _center_marks[next_i]; + const ImageOverlapInfo &overlap = _overlap_info[i]; + + CopyArea split_a, split_b; + + CopyArea left; + left.in_idx = i; + left.in_area.pos_x = mark_left.slice_center_x; + left.in_area.width = overlap.left.pos_x - left.in_area.pos_x; + XCAM_ASSERT (left.in_area.width > 0); + left.in_area.pos_y = _crop_info[i].top; + left.in_area.height = _round_view_slices[i].height - _crop_info[i].top - _crop_info[i].bottom; + XCAM_ASSERT (left.in_area.height > 0); + + left.out_area.pos_x = mark_left.out_center_x; + left.out_area.width = left.in_area.width; + left.out_area.pos_y = 0; + left.out_area.height = left.in_area.height; + + if (split_area_by_out (left, _output_width, split_a, split_b)) { + tmp_areas.push_back (split_a); + tmp_areas.push_back (split_b); + } else { + tmp_areas.push_back (left); + } + + CopyArea right; + right.in_idx = next_i; + right.in_area.pos_x = _overlap_info[i].right.pos_x + _overlap_info[i].right.width; + right.in_area.width = (int32_t)mark_right.slice_center_x - right.in_area.pos_x; + XCAM_ASSERT (right.in_area.width > 0); + right.in_area.pos_y = _crop_info[next_i].top; + right.in_area.height = _round_view_slices[next_i].height - _crop_info[next_i].top - _crop_info[next_i].bottom; + XCAM_ASSERT (right.in_area.height > 0); + + uint32_t out_right_center_x = mark_right.out_center_x; + if (out_right_center_x == 0) + out_right_center_x = _output_width; + right.out_area.width = right.in_area.width; + right.out_area.pos_x = out_right_center_x - right.out_area.width; + right.out_area.pos_y = 0; + right.out_area.height = right.in_area.height; + + if (split_area_by_out (right, _output_width, split_a, split_b)) { + tmp_areas.push_back (split_a); + tmp_areas.push_back (split_b); + } else { + tmp_areas.push_back (right); + } + } + XCAM_ASSERT (tmp_areas.size () > _camera_num && _camera_num >= 2); + + CopyArea merged; + int32_t start = 0; + int32_t end = tmp_areas.size () - 1; + if (tmp_areas.size () > 2) { + const CopyArea &first = tmp_areas[0]; + const CopyArea &last = tmp_areas[end]; + // merge first and last + if (merge_neighbor_area (last, first, merged)) { + _copy_areas.push_back (merged); + ++start; + --end; + } + } + + // merge areas + for (i = (uint32_t)start; (int32_t)i <= end; ) { + const CopyArea ¤t = tmp_areas[i]; + if (i == (uint32_t)end) { + _copy_areas.push_back (current); + break; + } + + const CopyArea &next = tmp_areas[i + 1]; + if (merge_neighbor_area (current, next, merged)) { + _copy_areas.push_back (merged); + i += 2; + } else { + _copy_areas.push_back (current); + i += 1; + } + } + + XCAM_ASSERT (_copy_areas.size() >= _camera_num); + + return XCAM_RETURN_NO_ERROR; +} + +BowlModel::BowlModel (const BowlDataConfig &config, const uint32_t image_width, const uint32_t image_height) + : _config (config) + , _bowl_img_width (image_width) + , _bowl_img_height (image_height) +{ + //max area => x/a = y/b + XCAM_ASSERT (fabs(_config.center_z) < _config.c); + float mid = sqrt ((1.0f - _config.center_z * _config.center_z / (_config.c * _config.c)) / 2.0f); + _max_topview_length_mm = mid * _config.a * 2.0f; + _max_topview_width_mm = mid * _config.b * 2.0f; +} + +bool +BowlModel::get_max_topview_area_mm (float &length_mm, float &width_mm) +{ + if (_max_topview_width_mm <= 0.0f || _max_topview_length_mm <= 0.0f) + return false; + length_mm = _max_topview_length_mm; + width_mm = _max_topview_width_mm; + return true; +} + +bool +BowlModel::get_topview_rect_map ( + PointMap &texture_points, + uint32_t res_width, uint32_t res_height, + float length_mm, float width_mm) +{ + if (XCAM_DOUBLE_EQUAL_AROUND (length_mm, 0.0f) || + XCAM_DOUBLE_EQUAL_AROUND (width_mm, 0.0f)) { + get_max_topview_area_mm (length_mm, width_mm); + } + + XCAM_FAIL_RETURN ( + ERROR, + length_mm * length_mm / (_config.a * _config.a) / 4.0f + width_mm * width_mm / (_config.b * _config.b) / 4.0f + + _config.center_z * _config.center_z / (_config.c * _config.c) <= 1.0f + 0.001f, + false, + "bowl model topview input area(L:%.2fmm, W:%.2fmm) is larger than max area", length_mm, width_mm); + + float center_pos_x = res_width / 2.0f; + float center_pos_y = res_height / 2.0f; + float mm_per_pixel_x = length_mm / res_width; + float mm_per_pixel_y = width_mm / res_height; + + texture_points.resize (res_width * res_height); + + for(uint32_t row = 0; row < res_height; row++) { + for(uint32_t col = 0; col < res_width; col++) { + PointFloat3 world_pos ( + (col - center_pos_x) * mm_per_pixel_x, + (center_pos_y - row) * mm_per_pixel_y, + 0.0f); + + PointFloat2 texture_pos = bowl_view_coords_to_image ( + _config, world_pos, _bowl_img_width, _bowl_img_height); + + texture_points [res_width * row + col] = texture_pos; + } + } + return true; +} + +bool +BowlModel::get_stitch_image_vertex_model ( + VertexMap &vertices, PointMap &texture_points, IndexVector &indeices, + uint32_t res_width, uint32_t res_height, float vertex_height) +{ + vertices.reserve (2 * (res_width + 1) * (res_height + 1)); + texture_points.reserve (2 * (res_width + 1) * (res_height + 1)); + indeices.reserve (2 * (res_width + 1) * (res_height + 1) + (res_height + 1)); + + float step_x = (float)_bowl_img_width / res_width; + float step_y = vertex_height / res_height; + float offset_y = (float)_bowl_img_height - vertex_height; + + int32_t indicator = 0; + + for (uint32_t row = 0; row < res_height - 1; row++) { + PointFloat2 texture_pos0; + texture_pos0.y = row * step_y + offset_y; + + PointFloat2 texture_pos1; + texture_pos1.y = (row + 1) * step_y + offset_y; + + for (uint32_t col = 0; col <= res_width; col++) { + + texture_pos0.x = col * step_x; + texture_pos1.x = col * step_x; + + PointFloat3 world_pos0 = + bowl_view_image_to_world ( + _config, _bowl_img_width, _bowl_img_height, texture_pos0); + + vertices.push_back (PointFloat3(world_pos0.x / _config.a, world_pos0.y / _config.b, world_pos0.z / _config.c)); + indeices.push_back (indicator++); + texture_points.push_back (PointFloat2(texture_pos0.x / _bowl_img_width, (_bowl_img_height - texture_pos0.y) / _bowl_img_height)); + + PointFloat3 world_pos1 = + bowl_view_image_to_world ( + _config, _bowl_img_width, _bowl_img_height, texture_pos1); + + vertices.push_back (PointFloat3(world_pos1.x / _config.a, world_pos1.y / _config.b, world_pos1.z / _config.c)); + indeices.push_back (indicator++); + texture_points.push_back (PointFloat2(texture_pos1.x / _bowl_img_width, (_bowl_img_height - texture_pos1.y) / _bowl_img_height)); + } + } + return true; +} + + +bool +BowlModel::get_bowlview_vertex_model ( + VertexMap &vertices, PointMap &texture_points, IndexVector &indeices, + uint32_t res_width, uint32_t res_height) +{ + return get_stitch_image_vertex_model (vertices, texture_points, indeices, res_width, res_height, (float)_bowl_img_height); +} + +bool +BowlModel::get_topview_vertex_model ( + VertexMap &vertices, PointMap &texture_points, IndexVector &indeices, + uint32_t res_width, uint32_t res_height) +{ + float wall_image_height = _config.wall_height / (float)(_config.wall_height + _config.ground_length) * (float)_bowl_img_height; + float ground_image_height = (float)_bowl_img_height - wall_image_height; + + return get_stitch_image_vertex_model (vertices, texture_points, indeices, res_width, res_height, ground_image_height); +} + + +} diff --git a/xcore/interface/stitcher.h b/xcore/interface/stitcher.h new file mode 100644 index 0000000..e38a98e --- /dev/null +++ b/xcore/interface/stitcher.h @@ -0,0 +1,249 @@ +/* + * stitcher.h - stitcher interface + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#ifndef XCAM_INTERFACE_STITCHER_H +#define XCAM_INTERFACE_STITCHER_H + +#include <xcam_std.h> +#include <interface/data_types.h> +#include <vector> +#include <video_buffer.h> + +#define XCAM_STITCH_FISHEYE_MAX_NUM 6 +#define XCAM_STITCH_MAX_CAMERAS XCAM_STITCH_FISHEYE_MAX_NUM +#define XCAM_STITCH_MIN_SEAM_WIDTH 56 + +#define INVALID_INDEX (uint32_t)(-1) + +namespace XCam { + +enum StitchResMode { + StitchRes1080P, + StitchRes1080P4, + StitchRes4K +}; + +struct StitchInfo { + uint32_t merge_width[XCAM_STITCH_FISHEYE_MAX_NUM]; + + ImageCropInfo crop[XCAM_STITCH_FISHEYE_MAX_NUM]; + FisheyeInfo fisheye_info[XCAM_STITCH_FISHEYE_MAX_NUM]; + + StitchInfo () { + xcam_mem_clear (merge_width); + } +}; + +struct ImageMergeInfo { + Rect left; + Rect right; +}; + +class Stitcher; + +struct CalibrationInfo { + ExtrinsicParameter extrinsic; + IntrinsicParameter intrinsic; +}; + +struct CameraInfo { + CalibrationInfo calibration; + float round_angle_start; + float angle_range;; +}; + +class Stitcher +{ +public: + struct RoundViewSlice { + float hori_angle_start; + float hori_angle_range; + uint32_t width; + uint32_t height; + + RoundViewSlice () + : hori_angle_start (0.0f), hori_angle_range (0.0f) + , width (0), height (0) + {} + }; + + struct CenterMark { + uint32_t slice_center_x; + uint32_t out_center_x; + CenterMark () + : slice_center_x (0) + , out_center_x (0) + {} + }; + + struct ScaleFactor { + float left_scale; + float right_scale; + + ScaleFactor () + : left_scale (1.0f) + , right_scale (1.0f) + {} + }; + + struct ImageOverlapInfo { + Rect left; + Rect right; + Rect out_area; + }; + + struct CopyArea { + uint32_t in_idx; + Rect in_area; + Rect out_area; + + CopyArea () + : in_idx (INVALID_INDEX) + {} + }; + typedef std::vector<CopyArea> CopyAreaArray; + +public: + explicit Stitcher (uint32_t align_x, uint32_t align_y = 1); + virtual ~Stitcher (); + static SmartPtr<Stitcher> create_ocl_stitcher (); + static SmartPtr<Stitcher> create_soft_stitcher (); + + bool set_bowl_config (const BowlDataConfig &config); + const BowlDataConfig &get_bowl_config () { + return _bowl_config; + } + bool set_camera_num (uint32_t num); + uint32_t get_camera_num () const { + return _camera_num; + } + bool set_camera_info (uint32_t index, const CameraInfo &info); + bool get_camera_info (uint32_t index, CameraInfo &info) const; + + bool set_crop_info (uint32_t index, const ImageCropInfo &info); + bool get_crop_info (uint32_t index, ImageCropInfo &info) const; + bool is_crop_info_set () const { + return _is_crop_set; + } + //bool set_overlap_info (uint32_t index, const ImageOverlapInfo &info); + bool is_overlap_info_set () const { + return _is_overlap_set; + } + + //bool set_stitch_info (const StitchInfo &stitch_info); + void set_output_size (uint32_t width, uint32_t height) { + _output_width = width; //XCAM_ALIGN_UP (width, XCAM_BLENDER_ALIGNED_WIDTH); + _output_height = height; + } + + void get_output_size (uint32_t &width, uint32_t &height) const { + width = _output_width; + height = _output_height; + } + virtual XCamReturn stitch_buffers (const VideoBufferList &in_bufs, SmartPtr<VideoBuffer> &out_buf) = 0; + +protected: + XCamReturn estimate_round_slices (); + virtual XCamReturn estimate_coarse_crops (); + XCamReturn mark_centers (); + XCamReturn estimate_overlap (); + XCamReturn update_copy_areas (); + + const CenterMark &get_center (uint32_t idx) const { + return _center_marks[idx]; + } + const RoundViewSlice &get_round_view_slice (uint32_t idx) const { + return _round_view_slices[idx]; + } + const ImageOverlapInfo &get_overlap (uint32_t idx) const { + return _overlap_info[idx]; + } + const ImageCropInfo &get_crop (uint32_t idx) const { + return _crop_info[idx]; + } + const CopyAreaArray &get_copy_area () const { + return _copy_areas; + } + +private: + XCAM_DEAD_COPY (Stitcher); + +protected: + ImageCropInfo _crop_info[XCAM_STITCH_MAX_CAMERAS]; + bool _is_crop_set; + //update after each feature match + ScaleFactor _scale_factors[XCAM_STITCH_MAX_CAMERAS]; + +private: + uint32_t _alignment_x, _alignment_y; + uint32_t _output_width, _output_height; + float _out_start_angle; + uint32_t _camera_num; + CameraInfo _camera_info[XCAM_STITCH_MAX_CAMERAS]; + RoundViewSlice _round_view_slices[XCAM_STITCH_MAX_CAMERAS]; + bool _is_round_view_set; + + ImageOverlapInfo _overlap_info[XCAM_STITCH_MAX_CAMERAS]; + BowlDataConfig _bowl_config; + bool _is_overlap_set; + + //auto calculation + CenterMark _center_marks[XCAM_STITCH_MAX_CAMERAS]; + bool _is_center_marked; + CopyAreaArray _copy_areas; +}; + +class BowlModel { +public: + typedef std::vector<PointFloat3> VertexMap; + typedef std::vector<PointFloat2> PointMap; + typedef std::vector<int32_t> IndexVector; + +public: + BowlModel (const BowlDataConfig &config, const uint32_t image_width, const uint32_t image_height); + bool get_max_topview_area_mm (float &length_mm, float &width_mm); + bool get_topview_rect_map ( + PointMap &texture_points, + uint32_t res_width, uint32_t res_height, + float length_mm = 0.0f, float width_mm = 0.0f); + + bool get_stitch_image_vertex_model ( + VertexMap &vertices, PointMap &texture_points, IndexVector &indeices, + uint32_t res_width, uint32_t res_height, float vertex_height); + + bool get_bowlview_vertex_model ( + VertexMap &vertices, PointMap &texture_points, IndexVector &indeices, + uint32_t res_width, uint32_t res_height); + + bool get_topview_vertex_model ( + VertexMap &vertices, PointMap &texture_points, IndexVector &indeices, + uint32_t res_width, uint32_t res_height); + +private: + BowlDataConfig _config; + uint32_t _bowl_img_width, _bowl_img_height; + float _max_topview_width_mm; + float _max_topview_length_mm; +}; + +} + +#endif //XCAM_INTERFACE_STITCHER_H diff --git a/xcore/meta_data.h b/xcore/meta_data.h new file mode 100644 index 0000000..2bfd6c4 --- /dev/null +++ b/xcore/meta_data.h @@ -0,0 +1,71 @@ +/* + * meta_data.h - meta data struct + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#ifndef XCAM_META_DATA_H +#define XCAM_META_DATA_H + +#include <xcam_std.h> +#include <list> + +namespace XCam { + +struct MetaBase +{ + MetaBase () {} + virtual ~MetaBase() {}; +private: + XCAM_DEAD_COPY (MetaBase); +}; + +struct MetaData + : MetaBase +{ + int64_t timestamp; // in microseconds + + MetaData () { + timestamp = 0; + }; + virtual ~MetaData () {}; +private: + XCAM_DEAD_COPY (MetaData); +}; + +struct DevicePose + : MetaData +{ + double orientation[4]; + double translation[3]; + uint32_t confidence; + + DevicePose () + { + xcam_mem_clear (orientation); + xcam_mem_clear (translation); + confidence = 1; + } +}; + +typedef std::list<SmartPtr<MetaBase>> MetaBaseList; +typedef std::list<SmartPtr<MetaData>> MetaDataList; +typedef std::list<SmartPtr<DevicePose>> DevicePoseList; + +}; + +#endif //XCAM_META_DATA_H diff --git a/xcore/pipe_manager.cpp b/xcore/pipe_manager.cpp new file mode 100644 index 0000000..4dae722 --- /dev/null +++ b/xcore/pipe_manager.cpp @@ -0,0 +1,180 @@ +/* + * pipe_manager.cpp - pipe manager + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include "pipe_manager.h" + +#define XCAM_FAILED_STOP(exp, msg, ...) \ + if ((exp) != XCAM_RETURN_NO_ERROR) { \ + XCAM_LOG_ERROR (msg, ## __VA_ARGS__); \ + stop (); \ + return ret; \ + } + +namespace XCam { + +PipeManager::PipeManager () + : _is_running (false) +{ + _processor_center = new X3aImageProcessCenter; + XCAM_LOG_DEBUG ("PipeManager construction"); +} + +PipeManager::~PipeManager () +{ + XCAM_LOG_DEBUG ("PipeManager destruction"); +} + +bool +PipeManager::set_smart_analyzer (SmartPtr<SmartAnalyzer> analyzer) +{ + if (is_running ()) + return false; + + XCAM_ASSERT (analyzer.ptr () && !_smart_analyzer.ptr ()); + _smart_analyzer = analyzer; + + return true; +} + +bool +PipeManager::add_image_processor (SmartPtr<ImageProcessor> processor) +{ + if (is_running ()) + return false; + + XCAM_ASSERT (processor.ptr ()); + return _processor_center->insert_processor (processor); +} + +XCamReturn +PipeManager::start () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + if (_smart_analyzer.ptr ()) { + if (_smart_analyzer->prepare_handlers () != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_INFO ("prepare smart analyzer handler failed"); + } + + _smart_analyzer->set_results_callback (this); + if (_smart_analyzer->init (1920, 1080, 25) != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_INFO ("initialize smart analyzer failed"); + } + if (_smart_analyzer->start () != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_INFO ("start smart analyzer failed"); + } + } + + if (!_processor_center->has_processors ()) { + XCAM_LOG_ERROR ("image processors empty"); + } + _processor_center->set_image_callback (this); + XCAM_FAILED_STOP (ret = _processor_center->start (), "3A process center start failed"); + + _is_running = true; + + XCAM_LOG_DEBUG ("pipe manager started"); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +PipeManager::stop () +{ + _is_running = false; + + if (_smart_analyzer.ptr ()) { + _smart_analyzer->stop (); + _smart_analyzer->deinit (); + } + + if (_processor_center.ptr ()) + _processor_center->stop (); + + XCAM_LOG_DEBUG ("pipe manager stopped"); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +PipeManager::push_buffer (SmartPtr<VideoBuffer> &buf) +{ + // need to add sync mode later + + if (_processor_center->put_buffer (buf) == false) { + XCAM_LOG_WARNING ("push buffer failed"); + return XCAM_RETURN_ERROR_UNKNOWN; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +PipeManager::scaled_image_ready (const SmartPtr<VideoBuffer> &buffer) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + if (!_smart_analyzer.ptr ()) { + return XCAM_RETURN_NO_ERROR; + } + + ret = _smart_analyzer->push_buffer (buffer); + XCAM_FAIL_RETURN ( + ERROR, ret == XCAM_RETURN_NO_ERROR, + ret, "push scaled buffer failed"); + + return XCAM_RETURN_NO_ERROR; +} + +void +PipeManager::x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results) +{ + XCamReturn ret = _processor_center->put_3a_results (results); + if (ret != XCAM_RETURN_NO_ERROR && ret != XCAM_RETURN_BYPASS) { + XCAM_LOG_WARNING ("apply 3a results failed"); + return; + } + AnalyzerCallback::x3a_calculation_done (analyzer, results); +} + +void +PipeManager::x3a_calculation_failed (XAnalyzer *analyzer, int64_t timestamp, const char *msg) +{ + AnalyzerCallback::x3a_calculation_failed (analyzer, timestamp, msg); +} + +void +PipeManager::process_buffer_done (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf) +{ + ImageProcessCallback::process_buffer_done (processor, buf); + post_buffer (buf); +} + +void +PipeManager::process_buffer_failed (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf) +{ + ImageProcessCallback::process_buffer_failed (processor, buf); +} + +void +PipeManager::process_image_result_done (ImageProcessor *processor, const SmartPtr<X3aResult> &result) +{ + ImageProcessCallback::process_image_result_done (processor, result); +} + +}; diff --git a/xcore/pipe_manager.h b/xcore/pipe_manager.h new file mode 100644 index 0000000..8bba7d3 --- /dev/null +++ b/xcore/pipe_manager.h @@ -0,0 +1,79 @@ +/* + * pipe_manager.h - pipe manager + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#ifndef XCAM_PIPE_MANAGER_H +#define XCAM_PIPE_MANAGER_H + +#include <xcam_std.h> +#include <smart_analyzer.h> +#include <x3a_image_process_center.h> +#include <stats_callback_interface.h> + +namespace XCam { + +class PipeManager + : public StatsCallback + , public AnalyzerCallback + , public ImageProcessCallback +{ +public: + PipeManager (); + virtual ~PipeManager (); + + bool set_smart_analyzer (SmartPtr<SmartAnalyzer> analyzer); + bool add_image_processor (SmartPtr<ImageProcessor> processor); + + bool is_running () const { + return _is_running; + } + + XCamReturn start (); + XCamReturn stop (); + + virtual XCamReturn push_buffer (SmartPtr<VideoBuffer> &buf); + +protected: + virtual void post_buffer (const SmartPtr<VideoBuffer> &buf) = 0; + + // virtual functions derived from PollCallback + virtual XCamReturn scaled_image_ready (const SmartPtr<VideoBuffer> &buffer); + + // virtual functions derived from AnalyzerCallback + virtual void x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results); + virtual void x3a_calculation_failed (XAnalyzer *analyzer, int64_t timestamp, const char *msg); + + // virtual functions derived from ImageProcessCallback + virtual void process_buffer_done (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf); + virtual void process_buffer_failed (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf); + virtual void process_image_result_done (ImageProcessor *processor, const SmartPtr<X3aResult> &result); + +private: + XCAM_DEAD_COPY (PipeManager); + +protected: + bool _is_running; + SmartPtr<SmartAnalyzer> _smart_analyzer; + SmartPtr<X3aImageProcessCenter> _processor_center; +}; + +}; + +#endif // XCAM_PIPE_MANAGER_H diff --git a/xcore/poll_thread.cpp b/xcore/poll_thread.cpp new file mode 100644 index 0000000..dcb778b --- /dev/null +++ b/xcore/poll_thread.cpp @@ -0,0 +1,261 @@ +/* + * poll_thread.cpp - poll thread for event and buffer + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "poll_thread.h" +#include "xcam_thread.h" +#include <unistd.h> + +namespace XCam { + +class PollThread; + +class EventPollThread + : public Thread +{ +public: + EventPollThread (PollThread *poll) + : Thread ("event_poll") + , _poll (poll) + {} + +protected: + virtual bool started () { + XCamReturn ret = _poll->init_3a_stats_pool (); + if (ret != XCAM_RETURN_NO_ERROR) + return false; + return true; + } + virtual bool loop () { + XCamReturn ret = _poll->poll_subdev_event_loop (); + + if (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_ERROR_TIMEOUT) + return true; + return false; + } + +private: + PollThread *_poll; +}; + +class CapturePollThread + : public Thread +{ +public: + CapturePollThread (PollThread *poll) + : Thread ("capture_poll") + , _poll (poll) + {} + +protected: + virtual bool loop () { + XCamReturn ret = _poll->poll_buffer_loop (); + + if (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_ERROR_TIMEOUT) + return true; + return false; + } + +private: + PollThread *_poll; +}; + +const int PollThread::default_subdev_event_timeout = 100; // ms +const int PollThread::default_capture_event_timeout = 100; // ms + +PollThread::PollThread () + : _poll_callback (NULL) + , _stats_callback (NULL) +{ + _event_loop = new EventPollThread(this); + _capture_loop = new CapturePollThread (this); + + XCAM_LOG_DEBUG ("PollThread constructed"); +} + +PollThread::~PollThread () +{ + stop(); + + XCAM_LOG_DEBUG ("~PollThread destructed"); +} + +bool +PollThread::set_capture_device (SmartPtr<V4l2Device> &dev) +{ + XCAM_ASSERT (!_capture_dev.ptr()); + _capture_dev = dev; + return true; +} + +bool +PollThread::set_event_device (SmartPtr<V4l2SubDevice> &dev) +{ + XCAM_ASSERT (!_event_dev.ptr()); + _event_dev = dev; + return true; +} + +bool +PollThread::set_poll_callback (PollCallback *callback) +{ + XCAM_ASSERT (!_poll_callback); + _poll_callback = callback; + return true; +} + +bool +PollThread::set_stats_callback (StatsCallback *callback) +{ + XCAM_ASSERT (!_stats_callback); + _stats_callback = callback; + return true; +} + +XCamReturn PollThread::start () +{ + if (_event_dev.ptr () && !_event_loop->start ()) { + return XCAM_RETURN_ERROR_THREAD; + } + if (!_capture_loop->start ()) { + return XCAM_RETURN_ERROR_THREAD; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn PollThread::stop () +{ + _event_loop->stop (); + _capture_loop->stop (); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +PollThread::init_3a_stats_pool () +{ + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +PollThread::capture_3a_stats (SmartPtr<X3aStats> &stats) +{ + XCAM_UNUSED (stats); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +PollThread::handle_events (struct v4l2_event &event) +{ + XCAM_UNUSED (event); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +PollThread::handle_3a_stats_event (struct v4l2_event &event) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + SmartPtr<X3aStats> stats; + + ret = capture_3a_stats (stats); + if (ret != XCAM_RETURN_NO_ERROR || !stats.ptr()) { + XCAM_LOG_WARNING ("capture 3a stats failed"); + return ret; + } + stats->set_timestamp (XCAM_TIMESPEC_2_USEC (event.timestamp)); + + if (_stats_callback) + return _stats_callback->x3a_stats_ready (stats); + + return ret; +} + +XCamReturn +PollThread::poll_subdev_event_loop () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + struct v4l2_event event; + int poll_ret = 0; + + poll_ret = _event_dev->poll_event (PollThread::default_subdev_event_timeout); + + if (poll_ret < 0) { + XCAM_LOG_WARNING ("poll event failed but continue"); + ::usleep (100000); // 100ms + return XCAM_RETURN_ERROR_TIMEOUT; + } + + /* timeout */ + if (poll_ret == 0) { + XCAM_LOG_DEBUG ("poll event timeout and continue"); + return XCAM_RETURN_ERROR_TIMEOUT; + } + + xcam_mem_clear (event); + ret = _event_dev->dequeue_event (event); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("dequeue event failed on dev:%s", XCAM_STR(_event_dev->get_device_name())); + return XCAM_RETURN_ERROR_IOCTL; + } + + ret = handle_events (event); + return ret; +} + +XCamReturn +PollThread::poll_buffer_loop () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + int poll_ret = 0; + SmartPtr<V4l2Buffer> buf; + + poll_ret = _capture_dev->poll_event (PollThread::default_capture_event_timeout); + + if (poll_ret < 0) { + XCAM_LOG_DEBUG ("poll buffer event got error but continue"); + ::usleep (100000); // 100ms + return XCAM_RETURN_ERROR_TIMEOUT; + } + + /* timeout */ + if (poll_ret == 0) { + XCAM_LOG_DEBUG ("poll buffer timeout and continue"); + return XCAM_RETURN_ERROR_TIMEOUT; + } + + ret = _capture_dev->dequeue_buffer (buf); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("capture buffer failed"); + return ret; + } + XCAM_ASSERT (buf.ptr()); + XCAM_ASSERT (_poll_callback); + + SmartPtr<VideoBuffer> video_buf = new V4l2BufferProxy (buf, _capture_dev); + + if (_poll_callback) + return _poll_callback->poll_buffer_ready (video_buf); + + return ret; +} + +}; diff --git a/xcore/poll_thread.h b/xcore/poll_thread.h new file mode 100644 index 0000000..0cdd34d --- /dev/null +++ b/xcore/poll_thread.h @@ -0,0 +1,99 @@ +/* + * poll_thread.h - poll thread for event and buffer + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_POLL_THREAD_H +#define XCAM_POLL_THREAD_H + +#include <xcam_std.h> +#include <xcam_mutex.h> +#include <x3a_event.h> +#include <v4l2_buffer_proxy.h> +#include <x3a_stats_pool.h> +#include <v4l2_device.h> +#include <stats_callback_interface.h> + +namespace XCam { + +class PollCallback +{ +public: + PollCallback () {} + virtual ~PollCallback() {} + virtual XCamReturn poll_buffer_ready (SmartPtr<VideoBuffer> &buf) = 0; + virtual XCamReturn poll_buffer_failed (int64_t timestamp, const char *msg) = 0; + +private: + XCAM_DEAD_COPY (PollCallback); + +}; + +class V4l2Device; +class V4l2SubDevice; +class EventPollThread; +class CapturePollThread; + +class PollThread +{ + friend class EventPollThread; + friend class CapturePollThread; + friend class FakePollThread; +public: + explicit PollThread (); + virtual ~PollThread (); + + bool set_capture_device (SmartPtr<V4l2Device> &dev); + bool set_event_device (SmartPtr<V4l2SubDevice> &sub_dev); + bool set_poll_callback (PollCallback *callback); + bool set_stats_callback (StatsCallback *callback); + + virtual XCamReturn start(); + virtual XCamReturn stop (); + +protected: + XCamReturn poll_subdev_event_loop (); + virtual XCamReturn poll_buffer_loop (); + + virtual XCamReturn handle_events (struct v4l2_event &event); + XCamReturn handle_3a_stats_event (struct v4l2_event &event); + +private: + virtual XCamReturn init_3a_stats_pool (); + virtual XCamReturn capture_3a_stats (SmartPtr<X3aStats> &stats); + +private: + XCAM_DEAD_COPY (PollThread); + +private: + static const int default_subdev_event_timeout; + static const int default_capture_event_timeout; + + SmartPtr<EventPollThread> _event_loop; + SmartPtr<CapturePollThread> _capture_loop; + + SmartPtr<V4l2SubDevice> _event_dev; + SmartPtr<V4l2Device> _capture_dev; + + PollCallback *_poll_callback; + StatsCallback *_stats_callback; +}; + +}; + +#endif //XCAM_POLL_THREAD_H diff --git a/xcore/safe_list.h b/xcore/safe_list.h new file mode 100644 index 0000000..36263e6 --- /dev/null +++ b/xcore/safe_list.h @@ -0,0 +1,162 @@ +/* + * safe_list.h - safe list template + * + * Copyright (c) 2014 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_SAFE_LIST_H +#define XCAM_SAFE_LIST_H + +#include <base/xcam_defs.h> +#include <base/xcam_common.h> +#include <errno.h> +#include <list> +#include <xcam_mutex.h> + +namespace XCam { + +template<class OBj> +class SafeList { +public: + typedef SmartPtr<OBj> ObjPtr; + typedef std::list<ObjPtr> ObjList; + typedef typename std::list<typename SafeList<OBj>::ObjPtr>::iterator ObjIter; + + SafeList () + : _pop_paused (false) + {} + ~SafeList () { + } + + /* + * timeout, -1, wait until wakeup + * >=0, wait for @timeout microsseconds + */ + inline ObjPtr pop (int32_t timeout = -1); + inline bool push (const ObjPtr &obj); + inline bool erase (const ObjPtr &obj); + inline ObjPtr front (); + uint32_t size () { + SmartLock lock(_mutex); + return _obj_list.size(); + } + bool is_empty () { + SmartLock lock(_mutex); + return _obj_list.empty(); + } + void wakeup () { + _new_obj_cond.broadcast (); + } + void pause_pop () { + SmartLock lock(_mutex); + _pop_paused = true; + wakeup (); + } + void resume_pop () { + SmartLock lock(_mutex); + _pop_paused = false; + } + inline void clear (); + +protected: + ObjList _obj_list; + Mutex _mutex; + XCam::Cond _new_obj_cond; + volatile bool _pop_paused; +}; + + +template<class OBj> +typename SafeList<OBj>::ObjPtr +SafeList<OBj>::pop (int32_t timeout) +{ + SmartLock lock (_mutex); + int code = 0; + + while (!_pop_paused && _obj_list.empty() && code == 0) { + if (timeout < 0) + code = _new_obj_cond.wait(_mutex); + else + code = _new_obj_cond.timedwait(_mutex, timeout); + } + + if (_pop_paused) + return NULL; + + if (_obj_list.empty()) { + if (code == ETIMEDOUT) { + XCAM_LOG_DEBUG ("safe list pop timeout"); + } else { + XCAM_LOG_ERROR ("safe list pop failed, code:%d", code); + } + return NULL; + } + + SafeList<OBj>::ObjPtr obj = *_obj_list.begin (); + _obj_list.erase (_obj_list.begin ()); + return obj; +} + +template<class OBj> +bool +SafeList<OBj>::push (const SafeList<OBj>::ObjPtr &obj) +{ + SmartLock lock (_mutex); + _obj_list.push_back (obj); + _new_obj_cond.signal (); + return true; +} + +template<class OBj> +bool +SafeList<OBj>::erase (const SafeList<OBj>::ObjPtr &obj) +{ + XCAM_ASSERT (obj.ptr ()); + SmartLock lock (_mutex); + for (SafeList<OBj>::ObjIter i_obj = _obj_list.begin (); + i_obj != _obj_list.end (); ++i_obj) { + if ((*i_obj).ptr () == obj.ptr ()) { + _obj_list.erase (i_obj); + return true; + } + } + return false; +} + +template<class OBj> +typename SafeList<OBj>::ObjPtr +SafeList<OBj>::front () +{ + SmartLock lock (_mutex); + SafeList<OBj>::ObjIter i = _obj_list.begin (); + if (i == _obj_list.end ()) + return NULL; + return *i; +} + +template<class OBj> +void SafeList<OBj>::clear () +{ + SmartLock lock (_mutex); + SafeList<OBj>::ObjIter i_obj = _obj_list.begin (); + while (i_obj != _obj_list.end ()) { + _obj_list.erase (i_obj++); + } +} + +}; +#endif //XCAM_SAFE_LIST_H diff --git a/xcore/smart_analysis_handler.cpp b/xcore/smart_analysis_handler.cpp new file mode 100644 index 0000000..221c70a --- /dev/null +++ b/xcore/smart_analysis_handler.cpp @@ -0,0 +1,198 @@ +/* + * smart_analysis_handler.cpp - smart analysis handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + * Wind Yuan <feng.yuan@intel.com> + */ + +#include "smart_analysis_handler.h" +#include "smart_analyzer_loader.h" +#include "smart_analyzer.h" +#include "video_buffer.h" + +namespace XCam { + +SmartAnalysisHandler::SmartHandlerMap SmartAnalysisHandler::_handler_map; +Mutex SmartAnalysisHandler::_handler_map_lock; + +SmartAnalysisHandler::SmartAnalysisHandler (XCamSmartAnalysisDescription *desc, SmartPtr<SmartAnalyzerLoader> &loader, const char *name) + : _desc (desc) + , _loader (loader) + , _analyzer (NULL) + , _name (NULL) + , _context (NULL) + , _async_mode (false) +{ + if (name) + _name = strndup (name, XCAM_MAX_STR_SIZE); +} + +SmartAnalysisHandler::~SmartAnalysisHandler () +{ + if (is_valid ()) + destroy_context (); + + if (_name) + xcam_free (_name); +} + +XCamReturn +SmartAnalysisHandler::create_context (SmartPtr<SmartAnalysisHandler> &self) +{ + XCamSmartAnalysisContext *context = NULL; + XCamReturn ret = XCAM_RETURN_NO_ERROR; + uint32_t async_mode = 0; + XCAM_ASSERT (!_context); + XCAM_ASSERT (self.ptr () == this); + if ((ret = _desc->create_context (&context, &async_mode, NULL)) != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("smart handler(%s) lib create context failed", XCAM_STR(get_name())); + return ret; + } + if (!context) { + XCAM_LOG_WARNING ("smart handler(%s) lib create context failed with NULL context", XCAM_STR(get_name())); + return XCAM_RETURN_ERROR_UNKNOWN; + } + _async_mode = async_mode; + + XCAM_LOG_INFO ("create smart analysis context(%s)", XCAM_STR(get_name())); + + SmartLock locker (_handler_map_lock); + _handler_map[context] = self; + _context = context; + return XCAM_RETURN_NO_ERROR; +} + +void +SmartAnalysisHandler::destroy_context () +{ + XCamSmartAnalysisContext *context; + { + SmartLock locker (_handler_map_lock); + context = _context; + _context = NULL; + if (context) + _handler_map.erase (context); + } + + if (context && _desc && _desc->destroy_context) { + _desc->destroy_context (context); + XCAM_LOG_INFO ("destroy smart analysis context(%s)", XCAM_STR(get_name())); + } +} + +XCamReturn +SmartAnalysisHandler::post_aync_results ( + XCamSmartAnalysisContext *context, + const XCamVideoBuffer *buffer, + XCam3aResultHead *results[], uint32_t res_count) +{ + SmartPtr<SmartAnalysisHandler> handler = NULL; + XCAM_ASSERT (context); + { + SmartLock locker (_handler_map_lock); + SmartHandlerMap::iterator i_h = _handler_map.find (context); + if (i_h != _handler_map.end ()) + handler = i_h->second; + } + + if (!handler.ptr ()) { + XCAM_LOG_WARNING ("can't find a proper smart analyzer handler, please check context pointer"); + return XCAM_RETURN_ERROR_PARAM; + } + + return handler->post_smart_results (buffer, results, res_count); +} + +XCamReturn +SmartAnalysisHandler::post_smart_results (const XCamVideoBuffer *buffer, XCam3aResultHead *results[], uint32_t res_count) +{ + X3aResultList result_list; + XCamReturn ret = convert_results (results, res_count, result_list); + XCAM_FAIL_RETURN ( + WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "smart handler convert results failed in async mode"); + + if (_analyzer) + _analyzer->post_smart_results (result_list, (buffer ? buffer->timestamp : InvalidTimestamp)); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +SmartAnalysisHandler::update_params (XCamSmartAnalysisParam ¶ms) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (_context); + ret = _desc->update_params (_context, ¶ms); + XCAM_FAIL_RETURN (WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "smart handler(%s) update parameters failed", XCAM_STR(get_name())); + + return ret; +} + +XCamReturn +SmartAnalysisHandler::analyze (const SmartPtr<VideoBuffer> &buffer, X3aResultList &results) +{ + XCAM_LOG_DEBUG ("smart handler(%s) analyze", XCAM_STR(get_name())); + XCamReturn ret = XCAM_RETURN_NO_ERROR; + XCamVideoBuffer *video_buffer = convert_to_external_buffer (buffer); + XCam3aResultHead *res_array[XCAM_3A_MAX_RESULT_COUNT]; + uint32_t res_count = XCAM_3A_MAX_RESULT_COUNT; + + XCAM_ASSERT (buffer.ptr ()); + XCAM_ASSERT (_context); + XCAM_ASSERT (video_buffer); + xcam_mem_clear (res_array); + + ret = _desc->analyze (_context, video_buffer, res_array, &res_count); + XCAM_ASSERT (video_buffer->unref); + video_buffer->unref (video_buffer); + XCAM_FAIL_RETURN (WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "smart handler(%s) calculation failed", XCAM_STR(get_name())); + + if (res_count > 0 && res_array[0]) { + ret = convert_results (res_array, res_count, results); + XCAM_FAIL_RETURN (WARNING, + ret == XCAM_RETURN_NO_ERROR, + ret, + "smart handler(%s) convert_results failed", XCAM_STR(get_name())); + _desc->free_results (_context, res_array, res_count); + } + + return ret; +} + +XCamReturn +SmartAnalysisHandler::convert_results (XCam3aResultHead *from[], uint32_t from_count, X3aResultList &to) +{ + for (uint32_t i = 0; i < from_count; ++i) { + SmartPtr<X3aResult> standard_res = + X3aResultFactory::instance ()->create_3a_result (from[i]); + to.push_back (standard_res); + } + + return XCAM_RETURN_NO_ERROR; +} + +} diff --git a/xcore/smart_analysis_handler.h b/xcore/smart_analysis_handler.h new file mode 100644 index 0000000..8e0748c --- /dev/null +++ b/xcore/smart_analysis_handler.h @@ -0,0 +1,93 @@ +/* + * smart_analysis_handler.h - smart analysis handler + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + * Wind Yuan <feng.yuan@intel.com> + */ +#ifndef XCAM_SMART_ANALYSIS_HANDLER_H +#define XCAM_SMART_ANALYSIS_HANDLER_H + +#include <xcam_std.h> +#include <base/xcam_smart_description.h> +#include <map> +#include <x3a_result_factory.h> + +namespace XCam { + +class VideoBuffer; +class SmartAnalysisHandler; +class SmartAnalyzerLoader; +class SmartAnalyzer; + +typedef std::list<SmartPtr<SmartAnalysisHandler>> SmartHandlerList; + +class SmartAnalysisHandler +{ + typedef std::map<XCamSmartAnalysisContext*, SmartPtr<SmartAnalysisHandler>> SmartHandlerMap; + +public: + SmartAnalysisHandler (XCamSmartAnalysisDescription *desc, SmartPtr<SmartAnalyzerLoader> &loader, const char *name = "SmartHandler"); + ~SmartAnalysisHandler (); + void set_analyzer (SmartAnalyzer *analyzer) { + _analyzer = analyzer; + } + + XCamReturn create_context (SmartPtr<SmartAnalysisHandler> &self); + void destroy_context (); + bool is_valid () const { + return (_context != NULL); + } + + XCamReturn update_params (XCamSmartAnalysisParam ¶ms); + XCamReturn analyze (const SmartPtr<VideoBuffer> &buffer, X3aResultList &results); + const char * get_name () const { + return _name; + } + uint32_t get_priority () const { + if (_desc) + return _desc->priority; + return 0; + } + +protected: + XCamReturn post_smart_results (const XCamVideoBuffer *buffer, XCam3aResultHead *results[], uint32_t res_count); + static XCamReturn post_aync_results ( + XCamSmartAnalysisContext *context, + const XCamVideoBuffer *buffer, + XCam3aResultHead *results[], uint32_t res_count); + +private: + XCamReturn convert_results (XCam3aResultHead *from[], uint32_t from_count, X3aResultList &to); + XCAM_DEAD_COPY (SmartAnalysisHandler); + +// +private: + static SmartHandlerMap _handler_map; + static Mutex _handler_map_lock; + +private: + XCamSmartAnalysisDescription *_desc; + SmartPtr<SmartAnalyzerLoader> _loader; + SmartAnalyzer *_analyzer; + char *_name; + XCamSmartAnalysisContext *_context; + bool _async_mode; +}; + +} + +#endif //XCAM_SMART_ANALYSIS_HANDLER_H diff --git a/xcore/smart_analyzer.cpp b/xcore/smart_analyzer.cpp new file mode 100644 index 0000000..690c1ea --- /dev/null +++ b/xcore/smart_analyzer.cpp @@ -0,0 +1,178 @@ +/* + * smart_analyzer.cpp - smart analyzer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include "smart_analyzer_loader.h" +#include "smart_analyzer.h" +#include "smart_analysis_handler.h" + +#include "xcam_obj_debug.h" + +namespace XCam { + +SmartAnalyzer::SmartAnalyzer (const char *name) + : XAnalyzer (name) +{ + XCAM_OBJ_PROFILING_INIT; +} + +SmartAnalyzer::~SmartAnalyzer () +{ +} + +XCamReturn +SmartAnalyzer::add_handler (SmartPtr<SmartAnalysisHandler> handler) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + if (!handler.ptr ()) { + return XCAM_RETURN_ERROR_PARAM; + } + + _handlers.push_back (handler); + handler->set_analyzer (this); + return ret; +} + +XCamReturn +SmartAnalyzer::create_handlers () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + if (_handlers.empty ()) { + ret = XCAM_RETURN_ERROR_PARAM; + } + return ret; +} + +XCamReturn +SmartAnalyzer::release_handlers () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + return ret; +} + +XCamReturn +SmartAnalyzer::internal_init (uint32_t width, uint32_t height, double framerate) +{ + XCAM_UNUSED (width); + XCAM_UNUSED (height); + XCAM_UNUSED (framerate); + SmartHandlerList::iterator i_handler = _handlers.begin (); + for (; i_handler != _handlers.end (); ++i_handler) + { + SmartPtr<SmartAnalysisHandler> handler = *i_handler; + XCamReturn ret = handler->create_context (handler); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("smart analyzer initialize handler(%s) context failed", XCAM_STR(handler->get_name())); + } + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +SmartAnalyzer::internal_deinit () +{ + SmartHandlerList::iterator i_handler = _handlers.begin (); + for (; i_handler != _handlers.end (); ++i_handler) + { + SmartPtr<SmartAnalysisHandler> handler = *i_handler; + if (handler->is_valid ()) + handler->destroy_context (); + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +SmartAnalyzer::configure () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + return ret; +} + +XCamReturn +SmartAnalyzer::update_params (XCamSmartAnalysisParam ¶ms) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + SmartHandlerList::iterator i_handler = _handlers.begin (); + for (; i_handler != _handlers.end (); ++i_handler) + { + SmartPtr<SmartAnalysisHandler> handler = *i_handler; + if (!handler->is_valid ()) + continue; + + ret = handler->update_params (params); + + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("smart analyzer update handler(%s) context failed", XCAM_STR(handler->get_name())); + handler->destroy_context (); + } + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +SmartAnalyzer::analyze (const SmartPtr<VideoBuffer> &buffer) +{ + XCAM_OBJ_PROFILING_START; + + XCamReturn ret = XCAM_RETURN_NO_ERROR; + X3aResultList results; + + if (!buffer.ptr ()) { + XCAM_LOG_DEBUG ("SmartAnalyzer::analyze got NULL buffer!"); + return XCAM_RETURN_ERROR_PARAM; + } + + SmartHandlerList::iterator i_handler = _handlers.begin (); + for (; i_handler != _handlers.end (); ++i_handler) + { + SmartPtr<SmartAnalysisHandler> handler = *i_handler; + if (!handler->is_valid ()) + continue; + + ret = handler->analyze (buffer, results); + if (ret != XCAM_RETURN_NO_ERROR && ret != XCAM_RETURN_BYPASS) { + XCAM_LOG_WARNING ("smart analyzer analyze handler(%s) context failed", XCAM_STR(handler->get_name())); + handler->destroy_context (); + } + } + + if (!results.empty ()) { + set_results_timestamp (results, buffer->get_timestamp ()); + notify_calculation_done (results); + } + + XCAM_OBJ_PROFILING_END ("smart analysis", XCAM_OBJ_DUR_FRAME_NUM); + + return XCAM_RETURN_NO_ERROR; +} + +void +SmartAnalyzer::post_smart_results (X3aResultList &results, int64_t timestamp) +{ + if (!results.empty ()) { + set_results_timestamp (results, timestamp); + notify_calculation_done (results); + } +} + +} diff --git a/xcore/smart_analyzer.h b/xcore/smart_analyzer.h new file mode 100644 index 0000000..6e9851b --- /dev/null +++ b/xcore/smart_analyzer.h @@ -0,0 +1,64 @@ +/* + * smart_analyzer.h - smart analyzer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ +#ifndef XCAM_SMART_ANALYZER_H +#define XCAM_SMART_ANALYZER_H + +#include <xcam_std.h> +#include <xcam_analyzer.h> +#include <smart_analysis_handler.h> +#include <x3a_result_factory.h> + +namespace XCam { + +class VideoBuffer; + +class SmartAnalyzer + : public XAnalyzer +{ +public: + SmartAnalyzer (const char *name = "SmartAnalyzer"); + ~SmartAnalyzer (); + + XCamReturn add_handler (SmartPtr<SmartAnalysisHandler> handler); + XCamReturn update_params (XCamSmartAnalysisParam ¶ms); + void post_smart_results (X3aResultList &results, int64_t timestamp); + +protected: + virtual XCamReturn create_handlers (); + virtual XCamReturn release_handlers (); + virtual XCamReturn internal_init (uint32_t width, uint32_t height, double framerate); + virtual XCamReturn internal_deinit (); + virtual XCamReturn configure (); + virtual XCamReturn analyze (const SmartPtr<VideoBuffer> &buffer); + +private: + XCAM_DEAD_COPY (SmartAnalyzer); + +private: + SmartHandlerList _handlers; + X3aResultList _results; + + XCAM_OBJ_PROFILING_DEFINES; + +}; + +} + +#endif //XCAM_SMART_ANALYZER_H diff --git a/xcore/smart_analyzer_loader.cpp b/xcore/smart_analyzer_loader.cpp new file mode 100644 index 0000000..ab3187d --- /dev/null +++ b/xcore/smart_analyzer_loader.cpp @@ -0,0 +1,151 @@ +/* + * smart_analyzer_loader.cpp - smart analyzer loader + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#include "smart_analyzer_loader.h" +#include "analyzer_loader.h" +#include "smart_analyzer.h" +#include "smart_analysis_handler.h" +#include <dirent.h> + +namespace XCam { + +#define MAX_PLUGIN_LIB_COUNT 10 + +SmartAnalyzerLoader::SmartAnalyzerLoader (const char *lib_path, const char *name, const char *symbol) + : AnalyzerLoader (lib_path, symbol) + , _name (NULL) +{ + if (name) + _name = strndup (name, XCAM_MAX_STR_SIZE); +} + +SmartAnalyzerLoader::~SmartAnalyzerLoader () +{ + if (_name) + xcam_free (_name); +} + +SmartHandlerList + +SmartAnalyzerLoader::load_smart_handlers (const char *dir_path) +{ + SmartHandlerList ret_handers; + AnalyzerLoaderList loaders = create_analyzer_loader (dir_path); + for (AnalyzerLoaderList::iterator i_loader = loaders.begin (); + i_loader != loaders.end (); ++i_loader) + { + SmartPtr<SmartAnalysisHandler> handler = (*i_loader)->load_smart_handler(*i_loader); + if (!handler.ptr ()) + continue; + + SmartHandlerList::iterator i_pos = ret_handers.begin (); + for (; i_pos != ret_handers.end (); ++i_pos) + { + if (handler->get_priority() < (*i_pos)->get_priority ()) + break; + } + ret_handers.insert (i_pos, handler); + } + return ret_handers; +} + +AnalyzerLoaderList +SmartAnalyzerLoader::create_analyzer_loader (const char *dir_path) +{ + XCAM_ASSERT (dir_path); + + char lib_path[512]; + DIR *lib_dir = NULL; + struct dirent *dirent_lib = NULL; + SmartPtr<SmartAnalyzerLoader> loader; + AnalyzerLoaderList loader_list; + uint8_t count = 0; + + lib_dir = opendir (dir_path); + if (lib_dir) { + while ((count < MAX_PLUGIN_LIB_COUNT) && (dirent_lib = readdir (lib_dir)) != NULL) { + if (dirent_lib->d_type != DT_LNK && + dirent_lib->d_type != DT_REG) + continue; + snprintf (lib_path, sizeof(lib_path), "%s/%s", dir_path, dirent_lib->d_name); + loader = new SmartAnalyzerLoader (lib_path, dirent_lib->d_name); + if (loader.ptr ()) { + loader_list.push_back (loader); + } + } + } + if (lib_dir) + closedir (lib_dir); + return loader_list; +} + +SmartPtr<SmartAnalysisHandler> +SmartAnalyzerLoader::load_smart_handler (SmartPtr<SmartAnalyzerLoader> &self) +{ + XCAM_ASSERT (self.ptr () == this); + + SmartPtr<SmartAnalysisHandler> handler; + XCamSmartAnalysisDescription *desc = (XCamSmartAnalysisDescription*)load_library (get_lib_path ()); + if (NULL == desc) { + XCAM_LOG_WARNING ("load smart handler lib symbol failed"); + return NULL; + } + + handler = new SmartAnalysisHandler (desc, self, (desc->name ? desc->name : _name)); + if (!handler.ptr ()) { + XCAM_LOG_WARNING ("create smart handler failed"); + close_handle (); + return NULL; + } + + XCAM_LOG_INFO ("smart handler(%s) created from lib", XCAM_STR (handler->get_name())); + return handler; +} + +void * +SmartAnalyzerLoader::load_symbol (void* handle) +{ + XCamSmartAnalysisDescription *desc = NULL; + + desc = (XCamSmartAnalysisDescription *)AnalyzerLoader::get_symbol (handle); + if (!desc) { + XCAM_LOG_DEBUG ("get symbol failed from lib"); + return NULL; + } + if (desc->version < xcam_version ()) { + XCAM_LOG_WARNING ("get symbol version is:0x%04x, but expect:0x%04x", + desc->version, xcam_version ()); + } + if (desc->size < sizeof (XCamSmartAnalysisDescription)) { + XCAM_LOG_DEBUG ("get symbol failed, XCamSmartAnalysisDescription size is:%" PRIu32 ", but expect:%" PRIuS, + desc->size, sizeof (XCamSmartAnalysisDescription)); + return NULL; + } + + if (!desc->create_context || !desc->destroy_context || + !desc->update_params || !desc->analyze || + !desc->free_results) { + XCAM_LOG_DEBUG ("some functions in symbol not set from lib"); + return NULL; + } + return (void*)desc; +} + +}; diff --git a/xcore/smart_analyzer_loader.h b/xcore/smart_analyzer_loader.h new file mode 100644 index 0000000..dd79d89 --- /dev/null +++ b/xcore/smart_analyzer_loader.h @@ -0,0 +1,63 @@ +/* + * smart_analyzer_loader.h - smart analyzer loader + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#ifndef XCAM_SMART_ANALYZER_LOADER_H +#define XCAM_SMART_ANALYZER_LOADER_H + +#include <xcam_std.h> +#include <analyzer_loader.h> +#include <smart_analysis_handler.h> +#include <base/xcam_smart_description.h> +#include <list> + +namespace XCam { + +class SmartAnalyzer; +class SmartAnalysisHandler; +class SmartAnalyzerLoader; + +typedef std::list<SmartPtr<SmartAnalyzerLoader>> AnalyzerLoaderList; + +class SmartAnalyzerLoader + : public AnalyzerLoader +{ + +public: + SmartAnalyzerLoader (const char *lib_path, const char *name = NULL, const char *symbol = XCAM_SMART_ANALYSIS_LIB_DESCRIPTION); + virtual ~SmartAnalyzerLoader (); + + static SmartHandlerList load_smart_handlers (const char *dir_path); + +protected: + static AnalyzerLoaderList create_analyzer_loader (const char *dir_path); + SmartPtr<SmartAnalysisHandler> load_smart_handler (SmartPtr<SmartAnalyzerLoader> &self); + +protected: + virtual void *load_symbol (void* handle); + +private: + XCAM_DEAD_COPY (SmartAnalyzerLoader); + +private: + char *_name; +}; + +}; +#endif //XCAM_SMART_ANALYZER_LOADER_H diff --git a/xcore/smart_buffer_priv.cpp b/xcore/smart_buffer_priv.cpp new file mode 100644 index 0000000..d9f9522 --- /dev/null +++ b/xcore/smart_buffer_priv.cpp @@ -0,0 +1,168 @@ +/* + * smart_buffer_priv.cpp - smart buffer for XCamVideoBuffer + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include <xcam_std.h> +#include "base/xcam_buffer.h" +#include "video_buffer.h" +#if HAVE_LIBDRM +#include "drm_bo_buffer.h" +#endif + +namespace XCam { + +class SmartBufferPriv + : public XCamVideoBufferIntel +{ +public: + SmartBufferPriv (const SmartPtr<VideoBuffer> &buf); + ~SmartBufferPriv (); + + bool is_valid () const { + return _buf_ptr.ptr (); + } + + static void buf_ref (XCamVideoBuffer *data); + static void buf_unref (XCamVideoBuffer *data); + static uint8_t *buf_map (XCamVideoBuffer *data); + static void buf_unmap (XCamVideoBuffer *data); + static int buf_get_fd (XCamVideoBuffer *data); + static void *buf_get_bo (XCamVideoBufferIntel *data); + +private: + XCAM_DEAD_COPY (SmartBufferPriv); + +private: + mutable RefCount *_ref; + SmartPtr<VideoBuffer> _buf_ptr; +}; + +SmartBufferPriv::SmartBufferPriv (const SmartPtr<VideoBuffer> &buf) + : _ref (NULL) +{ + XCAM_ASSERT (buf.ptr ()); + this->_buf_ptr = buf; + + if (!buf.ptr ()) { + return; + } + + _ref = new RefCount (); + + const VideoBufferInfo& video_info = buf->get_video_info (); + + this->base.info = *((const XCamVideoBufferInfo*)&video_info); + this->base.mem_type = XCAM_MEM_TYPE_PRIVATE_BO; + this->base.timestamp = buf->get_timestamp (); + + this->base.ref = SmartBufferPriv::buf_ref; + this->base.unref = SmartBufferPriv::buf_unref; + this->base.map = SmartBufferPriv::buf_map; + this->base.unmap = SmartBufferPriv::buf_unmap; + this->base.get_fd = SmartBufferPriv::buf_get_fd; + this->get_bo = SmartBufferPriv::buf_get_bo; +} + +SmartBufferPriv::~SmartBufferPriv () +{ + delete _ref; +} + +void +SmartBufferPriv::buf_ref (XCamVideoBuffer *data) +{ + SmartBufferPriv *buf = (SmartBufferPriv*) data; + XCAM_ASSERT (buf->_ref); + if (buf->_ref) + buf->_ref->ref (); +} + +void +SmartBufferPriv::buf_unref (XCamVideoBuffer *data) +{ + SmartBufferPriv *buf = (SmartBufferPriv*) data; + XCAM_ASSERT (buf->_ref); + if (buf->_ref) { + if (!buf->_ref->unref()) { + delete buf; + } + } +} + +uint8_t * +SmartBufferPriv::buf_map (XCamVideoBuffer *data) +{ + SmartBufferPriv *buf = (SmartBufferPriv*) data; + XCAM_ASSERT (buf->_buf_ptr.ptr ()); + return buf->_buf_ptr->map (); +} + +void +SmartBufferPriv::buf_unmap (XCamVideoBuffer *data) +{ + SmartBufferPriv *buf = (SmartBufferPriv*) data; + XCAM_ASSERT (buf->_buf_ptr.ptr ()); + buf->_buf_ptr->unmap (); +} + +int +SmartBufferPriv::buf_get_fd (XCamVideoBuffer *data) +{ + SmartBufferPriv *buf = (SmartBufferPriv*) data; + XCAM_ASSERT (buf->_buf_ptr.ptr ()); + return buf->_buf_ptr->get_fd (); +} + +void * +SmartBufferPriv::buf_get_bo (XCamVideoBufferIntel *data) +{ +#if HAVE_LIBDRM + SmartBufferPriv *buf = (SmartBufferPriv*) data; + XCAM_ASSERT (buf->_buf_ptr.ptr ()); + + SmartPtr<DrmBoBuffer> bo_buf = buf->_buf_ptr.dynamic_cast_ptr<DrmBoBuffer> (); + XCAM_FAIL_RETURN ( + ERROR, + bo_buf.ptr (), + NULL, + "get DrmBoBuffer failed"); + + return bo_buf->get_bo (); +#else + XCAM_LOG_ERROR ("VideoBuffer doesn't support DrmBoBuffer"); + + XCAM_UNUSED (data); + return NULL; +#endif +} + +XCamVideoBuffer * +convert_to_external_buffer (const SmartPtr<VideoBuffer> &buf) +{ + SmartBufferPriv *priv_buf = new SmartBufferPriv (buf); + XCAM_ASSERT (priv_buf); + + if (priv_buf->is_valid ()) + return (XCamVideoBuffer *)(priv_buf); + + delete priv_buf; + return NULL; +} + +} diff --git a/xcore/smartptr.h b/xcore/smartptr.h new file mode 100644 index 0000000..5495372 --- /dev/null +++ b/xcore/smartptr.h @@ -0,0 +1,220 @@ +/* + * xcam_SmartPtr.h - start pointer + * + * Copyright (c) 2014 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ +#ifndef XCAM_SMARTPTR_H +#define XCAM_SMARTPTR_H + +#include <stdint.h> +#include <atomic> +#include <type_traits> +#include <base/xcam_defs.h> + +namespace XCam { + +class RefCount; + +class RefObj { + friend class RefCount; +public: + RefObj (): _ref_count(0) {} // derived class must set to SmartPtr at birth + virtual ~RefObj () {} + + void ref() const { + ++_ref_count; + } + uint32_t unref() const { + return --_ref_count; + } + virtual bool is_a_object () const { + return true; + } + +private: + explicit RefObj (uint32_t i) : _ref_count (i) {} + XCAM_DEAD_COPY (RefObj); + +private: + mutable std::atomic<uint32_t> _ref_count; +}; + +class RefCount + : public RefObj +{ +public: + RefCount () : RefObj (1) {} + virtual bool is_a_object () const { + return false; + } +}; + +template<typename Obj> +RefObj* generate_ref_count (Obj *obj, std::true_type) +{ + XCAM_ASSERT (obj); + obj->ref (); + return obj; +} + +template<typename Obj> +RefCount* generate_ref_count (Obj *, std::false_type) +{ + return new RefCount; +} + +template <typename Obj> +class SmartPtr { +private: + template<typename ObjDerive> friend class SmartPtr; +public: + SmartPtr (Obj *obj = NULL) + : _ptr (obj), _ref(NULL) + { + if (obj) + init_ref (obj); + } + + template <typename ObjDerive> + SmartPtr (ObjDerive *obj) + : _ptr (obj), _ref(NULL) + { + if (obj) + init_ref (obj); + } + + // copy from pointer + SmartPtr (const SmartPtr<Obj> &obj) + : _ptr(obj._ptr), _ref(obj._ref) + { + if (_ref) { + _ref->ref(); + XCAM_ASSERT (_ptr); + } + } + + template <typename ObjDerive> + SmartPtr (const SmartPtr<ObjDerive> &obj) + : _ptr(obj._ptr), _ref(obj._ref) + { + if (_ref) { + _ref->ref(); + XCAM_ASSERT (_ptr); + } + } + + ~SmartPtr () { + release(); + } + + /* operator = */ + SmartPtr<Obj> & operator = (Obj *obj) { + release (); + set_pointer (obj, NULL); + return *this; + } + + template <typename ObjDerive> + SmartPtr<Obj> & operator = (ObjDerive *obj) { + release (); + set_pointer (obj, NULL); + return *this; + } + + SmartPtr<Obj> & operator = (const SmartPtr<Obj> &obj) { + release (); + set_pointer (obj._ptr, obj._ref); + return *this; + } + + template <typename ObjDerive> + SmartPtr<Obj> & operator = (const SmartPtr<ObjDerive> &obj) { + release (); + set_pointer (obj._ptr, obj._ref); + return *this; + } + + Obj *operator -> () const { + return _ptr; + } + + Obj *ptr() const { + return _ptr; + } + + void release() { + if (!_ptr) + return; + + XCAM_ASSERT (_ref); + if (!_ref->unref()) { + if (!_ref->is_a_object ()) { + XCAM_ASSERT (dynamic_cast<RefCount*>(_ref)); + delete _ref; + } else { + XCAM_ASSERT (dynamic_cast<Obj*>(_ref) == _ptr); + } + delete _ptr; + } + _ptr = NULL; + _ref = NULL; + } + + template <typename ObjDerive> + SmartPtr<ObjDerive> dynamic_cast_ptr () const { + SmartPtr<ObjDerive> ret(NULL); + ObjDerive *obj_derive(NULL); + if (!_ref) + return ret; + obj_derive = dynamic_cast<ObjDerive*>(_ptr); + if (!obj_derive) + return ret; + ret.set_pointer (obj_derive, _ref); + return ret; + } + +private: + template <typename ObjD> + void set_pointer (ObjD *obj, RefObj *ref) { + if (!obj) + return; + + _ptr = obj; + if (ref) { + _ref = ref; + _ref->ref(); + } else { + init_ref (obj); + } + } + + template <typename ObjD> + void init_ref (ObjD *obj) + { + // consider is_base_of or dynamic_cast ? + typedef std::is_base_of<RefObj, ObjD> BaseCheck; + _ref = generate_ref_count (obj, BaseCheck()); + XCAM_ASSERT (_ref); + } + +private: + Obj *_ptr; + mutable RefObj *_ref; +}; + +}; // end namespace +#endif //XCAM_SMARTPTR_H
\ No newline at end of file diff --git a/xcore/stats_callback_interface.h b/xcore/stats_callback_interface.h new file mode 100644 index 0000000..0054c05 --- /dev/null +++ b/xcore/stats_callback_interface.h @@ -0,0 +1,51 @@ +/* + * stats_callback_interface.h - statistics callback interface + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_STATS_CALLBACK_H +#define XCAM_STATS_CALLBACK_H + +#include <xcam_std.h> +#include <xcam_mutex.h> + + +namespace XCam { + +class X3aStats; +class VideoBuffer; + +class StatsCallback { +public: + StatsCallback () {} + virtual ~StatsCallback() {} + virtual XCamReturn x3a_stats_ready (const SmartPtr<X3aStats> &stats) { + XCAM_UNUSED (stats); + return XCAM_RETURN_NO_ERROR; + } + virtual XCamReturn dvs_stats_ready () { + return XCAM_RETURN_NO_ERROR; + } + virtual XCamReturn scaled_image_ready (const SmartPtr<VideoBuffer> &buffer) = 0; + +private: + XCAM_DEAD_COPY (StatsCallback); +}; + +} +#endif //XCAM_STATS_CALLBACK_H diff --git a/xcore/surview_fisheye_dewarp.cpp b/xcore/surview_fisheye_dewarp.cpp new file mode 100644 index 0000000..6c0830c --- /dev/null +++ b/xcore/surview_fisheye_dewarp.cpp @@ -0,0 +1,180 @@ +/* + * surview_fisheye_dewarp.cpp - dewarp fisheye image of surround view + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Junkai Wu <junkai.wu@intel.com> + */ + +#include "surview_fisheye_dewarp.h" +#include "xcam_utils.h" + +namespace XCam { + +SurViewFisheyeDewarp::SurViewFisheyeDewarp () +{ +} +SurViewFisheyeDewarp::~SurViewFisheyeDewarp () +{ +} + +PolyFisheyeDewarp::PolyFisheyeDewarp() + : SurViewFisheyeDewarp() +{ +} + +void +SurViewFisheyeDewarp::set_intrinsic_param(const IntrinsicParameter &intrinsic_param) +{ + _intrinsic_param = intrinsic_param; +} + +void +SurViewFisheyeDewarp::set_extrinsic_param(const ExtrinsicParameter &extrinsic_param) +{ + _extrinsic_param = extrinsic_param; +} + +IntrinsicParameter +SurViewFisheyeDewarp::get_intrinsic_param() +{ + return _intrinsic_param; +} + +ExtrinsicParameter +SurViewFisheyeDewarp::get_extrinsic_param() +{ + return _extrinsic_param; +} + +void +SurViewFisheyeDewarp::fisheye_dewarp(MapTable &map_table, uint32_t table_w, uint32_t table_h, uint32_t image_w, uint32_t image_h, const BowlDataConfig &bowl_config) +{ + PointFloat3 world_coord; + PointFloat3 cam_coord; + PointFloat3 cam_world_coord; + PointFloat2 image_coord; + + XCAM_LOG_DEBUG ("fisheye-dewarp:\n table(%dx%d), out_size(%dx%d)" + "bowl(start:%.1f, end:%.1f, ground:%.2f, wall:%.2f, a:%.2f, b:%.2f, c:%.2f, center_z:%.2f )", + table_w, table_h, image_w, image_h, + bowl_config.angle_start, bowl_config.angle_end, + bowl_config.wall_height, bowl_config.ground_length, + bowl_config.a, bowl_config.b, bowl_config.c, bowl_config.center_z); + + float scale_factor_w = (float)image_w / table_w; + float scale_factor_h = (float)image_h / table_h; + + for(uint32_t row = 0; row < table_h; row++) { + for(uint32_t col = 0; col < table_w; col++) { + PointFloat2 out_pos (col * scale_factor_w, row * scale_factor_h); + world_coord = bowl_view_image_to_world (bowl_config, image_w, image_h, out_pos); + cal_cam_world_coord(world_coord, cam_world_coord); + world_coord2cam(cam_world_coord, cam_coord); + cal_image_coord(cam_coord, image_coord); + + map_table[row * table_w + col] = image_coord; + } + } +} + +void +SurViewFisheyeDewarp::cal_cam_world_coord(const PointFloat3 &world_coord, PointFloat3 &cam_world_coord) +{ + Mat4f rotation_mat = generate_rotation_matrix( degree2radian (_extrinsic_param.roll), + degree2radian (_extrinsic_param.pitch), + degree2radian (_extrinsic_param.yaw)); + Mat4f rotation_tran_mat = rotation_mat; + rotation_tran_mat(0, 3) = _extrinsic_param.trans_x; + rotation_tran_mat(1, 3) = _extrinsic_param.trans_y; + rotation_tran_mat(2, 3) = _extrinsic_param.trans_z; + + Mat4f world_coord_mat(Vec4f(1.0f, 0.0f, 0.0f, world_coord.x), + Vec4f(0.0f, 1.0f, 0.0f, world_coord.y), + Vec4f(0.0f, 0.0f, 1.0f, world_coord.z), + Vec4f(0.0f, 0.0f, 0.0f, 1.0f)); + + Mat4f cam_world_coord_mat = rotation_tran_mat.inverse() * world_coord_mat; + + cam_world_coord.x = cam_world_coord_mat(0, 3); + cam_world_coord.y = cam_world_coord_mat(1, 3); + cam_world_coord.z = cam_world_coord_mat(2, 3); +} + +Mat4f +SurViewFisheyeDewarp::generate_rotation_matrix(float roll, float pitch, float yaw) +{ + Mat4f matrix_x(Vec4f(1.0f, 0.0f, 0.0f, 0.0f), + Vec4f(0.0f, cos(roll), -sin(roll), 0.0f), + Vec4f(0.0f, sin(roll), cos(roll), 0.0f), + Vec4f(0.0f, 0.0f, 0.0f, 1.0f)); + + Mat4f matrix_y(Vec4f(cos(pitch), 0.0f, sin(pitch), 0.0f), + Vec4f(0.0f, 1.0f, 0.0f, 0.0f), + Vec4f(-sin(pitch), 0.0f, cos(pitch), 0.0f), + Vec4f(0.0f, 0.0f, 0.0f, 1.0f)); + + Mat4f matrix_z(Vec4f(cos(yaw), -sin(yaw), 0.0f, 0.0f), + Vec4f(sin(yaw), cos(yaw), 0.0f, 0.0f), + Vec4f(0.0f, 0.0f, 1.0f, 0.0f), + Vec4f(0.0f, 0.0f, 0.0f, 1.0f)); + + return matrix_z * matrix_y * matrix_x; +} + +void +SurViewFisheyeDewarp::world_coord2cam(const PointFloat3 &cam_world_coord, PointFloat3 &cam_coord) +{ + cam_coord.x = -cam_world_coord.y; + cam_coord.y = -cam_world_coord.z; + cam_coord.z = -cam_world_coord.x; +} + +void +SurViewFisheyeDewarp::cal_image_coord(const PointFloat3 &cam_coord, PointFloat2 &image_coord) +{ + image_coord.x = cam_coord.x; + image_coord.y = cam_coord.y; +} + +void +PolyFisheyeDewarp::cal_image_coord(const PointFloat3 &cam_coord, PointFloat2 &image_coord) +{ + float dist2center = sqrt(cam_coord.x * cam_coord.x + cam_coord.y * cam_coord.y); + float angle = atan(cam_coord.z / dist2center); + + float p = 1; + float poly_sum = 0; + + IntrinsicParameter intrinsic_param = get_intrinsic_param(); + + if (dist2center != 0) { + for (uint32_t i = 0; i < intrinsic_param.poly_length; i++) { + poly_sum += intrinsic_param.poly_coeff[i] * p; + p = p * angle; + } + + float image_x = cam_coord.x * poly_sum / dist2center; + float image_y = cam_coord.y * poly_sum / dist2center; + + image_coord.x = image_x * intrinsic_param.c + image_y * intrinsic_param.d + intrinsic_param.xc; + image_coord.y = image_x * intrinsic_param.e + image_y + intrinsic_param.yc; + } else { + image_coord.x = intrinsic_param.xc; + image_coord.y = intrinsic_param.yc; + } +} // Adopt Scaramuzza's approach to calculate image coordinates from camera coordinates + +} diff --git a/xcore/surview_fisheye_dewarp.h b/xcore/surview_fisheye_dewarp.h new file mode 100644 index 0000000..571b02a --- /dev/null +++ b/xcore/surview_fisheye_dewarp.h @@ -0,0 +1,75 @@ +/* + * surview_fisheye_dewarp.h - dewarp fisheye image for surround view + * + * Copyright (c) 2016-2017 Intel Corporation + * + * 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. + * + * Author: Junkai Wu <junkai.wu@intel.com> + */ + +#ifndef XCAM_SURVIEW_FISHEYE_DEWARP_H +#define XCAM_SURVIEW_FISHEYE_DEWARP_H + +#include <xcam_std.h> +#include <vec_mat.h> +#include <interface/data_types.h> + +namespace XCam { + +class SurViewFisheyeDewarp +{ + +public: + typedef std::vector<PointFloat2> MapTable; + + explicit SurViewFisheyeDewarp (); + virtual ~SurViewFisheyeDewarp (); + + void fisheye_dewarp(MapTable &map_table, uint32_t table_w, uint32_t table_h, uint32_t image_w, uint32_t image_h, const BowlDataConfig &bowl_config); + + void set_intrinsic_param(const IntrinsicParameter &intrinsic_param); + void set_extrinsic_param(const ExtrinsicParameter &extrinsic_param); + + IntrinsicParameter get_intrinsic_param(); + ExtrinsicParameter get_extrinsic_param(); + +private: + XCAM_DEAD_COPY (SurViewFisheyeDewarp); + + virtual void cal_image_coord (const PointFloat3 &cam_coord, PointFloat2 &image_coord); + + void cal_cam_world_coord (const PointFloat3 &world_coord, PointFloat3 &cam_world_coord); + void world_coord2cam (const PointFloat3 &cam_world_coord, PointFloat3 &cam_coord); + + Mat4f generate_rotation_matrix(float roll, float pitch, float yaw); + +private: + IntrinsicParameter _intrinsic_param; + ExtrinsicParameter _extrinsic_param; +}; + +class PolyFisheyeDewarp : public SurViewFisheyeDewarp +{ + +public: + explicit PolyFisheyeDewarp (); + +private: + void cal_image_coord (const PointFloat3 &cam_coord, PointFloat2 &image_coord); + +}; + +} // Adopt Scaramuzza's approach to calculate image coordinates from camera coordinates + +#endif // XCAM_SURVIEW_FISHEYE_DEWARP_H diff --git a/xcore/swapped_buffer.cpp b/xcore/swapped_buffer.cpp new file mode 100644 index 0000000..a740959 --- /dev/null +++ b/xcore/swapped_buffer.cpp @@ -0,0 +1,115 @@ +/* + * swapped_buffer.cpp - swapped buffer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include <xcam_std.h> +#include "swapped_buffer.h" + +namespace XCam { + +SwappedBuffer::SwappedBuffer ( + const VideoBufferInfo &info, const SmartPtr<BufferData> &data) + : BufferProxy (info, data) + , _swap_flags (SwappedBuffer::SwapNone) +{ + xcam_mem_clear (_swap_offsets); +} + +SwappedBuffer::~SwappedBuffer () +{ +} + +void +SwappedBuffer::set_swap_info (uint32_t flags, uint32_t* offsets) +{ + _swap_flags = flags; + XCAM_ASSERT (offsets); + memcpy(_swap_offsets, offsets, sizeof (_swap_offsets)); +} + +bool SwappedBuffer::swap_new_buffer_info( + const VideoBufferInfo &in, uint32_t flags, VideoBufferInfo &out) +{ + out = in; + if (flags & (uint32_t)(SwapY)) { + if (in.offsets[0] == _swap_offsets[SwapYOffset0]) { + out.offsets[0] = _swap_offsets[SwapYOffset1]; + } else { + XCAM_ASSERT (in.offsets[0] == _swap_offsets[SwapYOffset1]); + out.offsets[0] = _swap_offsets[SwapYOffset0]; + } + } + if (flags & (uint32_t)(SwapUV)) { + if (in.offsets[1] == _swap_offsets[SwapUVOffset0]) { + out.offsets[1] = _swap_offsets[SwapUVOffset1]; + } else { + XCAM_ASSERT (in.offsets[1] == _swap_offsets[SwapUVOffset1]); + out.offsets[1] = _swap_offsets[SwapUVOffset0]; + } + } + return true; +} + +SmartPtr<SwappedBuffer> +SwappedBuffer::create_new_swap_buffer ( + const VideoBufferInfo &info, SmartPtr<BufferData> &data) +{ + XCAM_ASSERT (false); + SmartPtr<SwappedBuffer> out = new SwappedBuffer (info, data); + return out; +} + +SmartPtr<SwappedBuffer> +SwappedBuffer::swap_clone (SmartPtr<SwappedBuffer> self, uint32_t flags) +{ + XCAM_ASSERT (self.ptr () && self.ptr () == (SwappedBuffer*)(this)); + XCAM_FAIL_RETURN( + WARNING, + flags && (flags & _swap_flags) == flags, + NULL, + "SwappedBuffer swap_clone failed since flags doesn't match"); + + const VideoBufferInfo &cur_info = this->get_video_info (); + VideoBufferInfo out_info; + XCAM_FAIL_RETURN( + WARNING, + swap_new_buffer_info (cur_info, flags, out_info), + NULL, + "SwappedBuffer swap_clone failed on out buffer info"); + + SmartPtr<BufferData> data = get_buffer_data (); + XCAM_FAIL_RETURN( + WARNING, + data.ptr (), + NULL, + "SwappedBuffer swap_clone failed to get buffer data"); + + SmartPtr<SwappedBuffer> out = create_new_swap_buffer (out_info, data); + XCAM_FAIL_RETURN( + WARNING, + out.ptr (), + NULL, + "SwappedBuffer swap_clone failed to create new swap buffer"); + out->_swap_flags = _swap_flags; + memcpy (out->_swap_offsets, _swap_offsets, sizeof (_swap_offsets)); + out->set_parent (self); + return out; +} + +}; diff --git a/xcore/swapped_buffer.h b/xcore/swapped_buffer.h new file mode 100644 index 0000000..bd29923 --- /dev/null +++ b/xcore/swapped_buffer.h @@ -0,0 +1,83 @@ +/* + * swapped_buffer.h - swapped buffer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_SWAPPED_BUFFER_H +#define XCAM_SWAPPED_BUFFER_H + +#include <xcam_std.h> +#include <buffer_pool.h> + +namespace XCam { + +class SwappedBuffer + : public virtual BufferProxy +{ +public: + enum SwapFlags { + SwapNone = 0, + SwapY = 1, + SwapUV = 2, + }; + + enum SwapOffsets { + SwapYOffset0 = 0, + SwapYOffset1 = 1, + SwapUVOffset0 = 2, + SwapUVOffset1 = 3, + }; + + enum InitOrder { + OrderYMask = 0x000F, + OrderY0Y1 = 0x0001, + OrderY1Y0 = 0x0002, + OrderUVMask = 0x0F00, + OrderUV0UV1 = 0x0100, + OrderUV1UV0 = 0x0200, + }; + +protected: + explicit SwappedBuffer ( + const VideoBufferInfo &info, const SmartPtr<BufferData> &data); + +public: + virtual ~SwappedBuffer (); + void set_swap_info (uint32_t flags, uint32_t* offsets); + + SmartPtr<SwappedBuffer> swap_clone ( + SmartPtr<SwappedBuffer> self, uint32_t flags); + +protected: + virtual SmartPtr<SwappedBuffer> create_new_swap_buffer ( + const VideoBufferInfo &info, SmartPtr<BufferData> &data); + + bool swap_new_buffer_info ( + const VideoBufferInfo &in, uint32_t flags, VideoBufferInfo &out); + +private: + XCAM_DEAD_COPY (SwappedBuffer); + +protected: + uint32_t _swap_flags; + uint32_t _swap_offsets[XCAM_VIDEO_MAX_COMPONENTS * 2]; +}; + +} + +#endif //XCAM_SWAPPED_BUFFER_H diff --git a/xcore/thread_pool.cpp b/xcore/thread_pool.cpp new file mode 100644 index 0000000..5774eaf --- /dev/null +++ b/xcore/thread_pool.cpp @@ -0,0 +1,273 @@ +/* + * thread_pool.cpp - Thread Pool + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "thread_pool.h" + +#define XCAM_POOL_MIN_THREADS 2 +#define XCAM_POOL_MAX_THREADS 1024 + +namespace XCam { + +class UserThread + : public Thread +{ +public: + UserThread (const SmartPtr<ThreadPool> &pool, const char *name) + : Thread (name) + , _pool (pool) + {} + +protected: + virtual bool started (); + virtual void stopped (); + virtual bool loop (); + +private: + SmartPtr<ThreadPool> _pool; +}; + +bool +UserThread::started () +{ + XCAM_ASSERT (_pool.ptr ()); + SmartLock lock (_pool->_mutex); + return true; +} + +void +UserThread::stopped () +{ + XCAM_LOG_DEBUG ("thread(%s, %p) stopped", XCAM_STR(get_name ()), this); +} + +bool +UserThread::loop () +{ + XCAM_ASSERT (_pool.ptr ()); + { + SmartLock lock (_pool->_mutex); + if (!_pool->_running) + return false; + } + + SmartPtr<ThreadPool::UserData> data = _pool->_data_queue.pop (); + if (!data.ptr ()) { + XCAM_LOG_DEBUG ("user thread(%s) get null data, need stop", XCAM_STR (_pool->get_name ())); + return false; + } + + { + SmartLock lock (_pool->_mutex); + XCAM_ASSERT (_pool->_free_threads > 0); + --_pool->_free_threads; + } + + bool ret = _pool->dispatch (data); + + if (ret) { + SmartLock lock (_pool->_mutex); + ++_pool->_free_threads; + } + return ret; +} + +bool +ThreadPool::dispatch (const SmartPtr<ThreadPool::UserData> &data) +{ + XCAM_FAIL_RETURN ( + ERROR, data.ptr(), true, + "ThreadPool(%s) dispatch NULL data", XCAM_STR (get_name ())); + XCamReturn err = data->run (); + data->done (err); + return true; +} + +ThreadPool::ThreadPool (const char *name) + : _name (NULL) + , _min_threads (XCAM_POOL_MIN_THREADS) + , _max_threads (XCAM_POOL_MIN_THREADS) + , _allocated_threads (0) + , _free_threads (0) + , _running (false) +{ + if (name) + _name = strndup (name, XCAM_MAX_STR_SIZE); +} + +ThreadPool::~ThreadPool () +{ + stop (); + + xcam_mem_clear (_name); +} + +bool +ThreadPool::set_threads (uint32_t min, uint32_t max) +{ + XCAM_FAIL_RETURN ( + ERROR, !_running, false, + "ThreadPool(%s) set threads failed, need stop the pool first", XCAM_STR(get_name ())); + + if (min < XCAM_POOL_MIN_THREADS) + min = XCAM_POOL_MIN_THREADS; + if (max > XCAM_POOL_MAX_THREADS) + max = XCAM_POOL_MAX_THREADS; + + if (min > max) + min = max; + + _min_threads = min; + _max_threads = max; + return true; +} + +bool +ThreadPool::is_running () +{ + SmartLock locker(_mutex); + return _running; +} + +XCamReturn +ThreadPool::start () +{ + SmartLock locker(_mutex); + if (_running) + return XCAM_RETURN_NO_ERROR; + + _free_threads = 0; + _allocated_threads = 0; + _data_queue.resume_pop (); + + for (uint32_t i = 0; i < _min_threads; ++i) { + XCamReturn ret = create_user_thread_unsafe (); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), ret, + "thread pool(%s) start failed by creating user thread", XCAM_STR (get_name())); + } + + XCAM_ASSERT (_allocated_threads == _min_threads); + + _running = true; + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +ThreadPool::stop () +{ + UserThreadList threads; + { + SmartLock locker(_mutex); + if (!_running) + return XCAM_RETURN_NO_ERROR; + + _running = false; + threads = _thread_list; + _thread_list.clear (); + } + + for (UserThreadList::iterator i = threads.begin (); i != threads.end (); ++i) + { + SmartPtr<UserThread> t = *i; + XCAM_ASSERT (t.ptr ()); + t->emit_stop (); + } + + _data_queue.pause_pop (); + _data_queue.clear (); + + for (UserThreadList::iterator i = threads.begin (); i != threads.end (); ++i) + { + SmartPtr<UserThread> t = *i; + XCAM_ASSERT (t.ptr ()); + t->stop (); + } + + { + SmartLock locker(_mutex); + _free_threads = 0; + _allocated_threads = 0; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +ThreadPool::create_user_thread_unsafe () +{ + char name[256]; + snprintf (name, 255, "%s-%d", XCAM_STR (get_name()), _allocated_threads); + SmartPtr<UserThread> thread = new UserThread (this, name); + XCAM_ASSERT (thread.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, thread.ptr () && thread->start (), XCAM_RETURN_ERROR_THREAD, + "ThreadPool(%s) create user thread failed by starting error", XCAM_STR (get_name())); + + _thread_list.push_back (thread); + + ++_allocated_threads; + ++_free_threads; + XCAM_ASSERT (_free_threads <= _allocated_threads); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +ThreadPool::queue (const SmartPtr<UserData> &data) +{ + XCAM_ASSERT (data.ptr ()); + { + SmartLock locker (_mutex); + if (!_running) + return XCAM_RETURN_ERROR_THREAD; + } + + if (!_data_queue.push (data)) + return XCAM_RETURN_ERROR_THREAD; + + do { + SmartLock locker(_mutex); + if (!_running) { + _data_queue.erase (data); + return XCAM_RETURN_ERROR_THREAD; + } + + if (_allocated_threads >= _max_threads) + break; + + if (!_free_threads) + break; + + XCamReturn err = create_user_thread_unsafe (); + if (!xcam_ret_is_ok (err) && _allocated_threads) { + XCAM_LOG_WARNING ("thread pool(%s) create new thread failed but queue data can continue"); + break; + } + + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (err), err, + "thread pool(%s) queue data failed by creating user thread", XCAM_STR (get_name())); + + } while (0); + + return XCAM_RETURN_NO_ERROR; +} + +} diff --git a/xcore/thread_pool.h b/xcore/thread_pool.h new file mode 100644 index 0000000..4e808d9 --- /dev/null +++ b/xcore/thread_pool.h @@ -0,0 +1,84 @@ +/* + * thread_pool.h - Thread Pool + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_THREAD_POOL_H +#define XCAM_THREAD_POOL_H + +#include <xcam_std.h> +#include <safe_list.h> +#include <xcam_thread.h> + +namespace XCam { + +class UserThread; + +class ThreadPool + : public RefObj +{ + friend class UserThread; + typedef std::list<SmartPtr<UserThread> > UserThreadList; + +public: + class UserData { + public: + UserData () {} + virtual ~UserData () {} + virtual XCamReturn run () = 0; + virtual void done (XCamReturn) {} + private: + XCAM_DEAD_COPY (UserData); + }; + +public: + explicit ThreadPool (const char *name); + virtual ~ThreadPool (); + bool set_threads (uint32_t min, uint32_t max); + const char *get_name () const { + return _name; + } + bool is_running (); + + XCamReturn start (); + XCamReturn stop (); + XCamReturn queue (const SmartPtr<UserData> &data); + +protected: + bool dispatch (const SmartPtr<UserData> &data); + XCamReturn create_user_thread_unsafe (); + +private: + XCAM_DEAD_COPY (ThreadPool); + +private: + char *_name; + uint32_t _min_threads; + uint32_t _max_threads; + uint32_t _allocated_threads; + uint32_t _free_threads; + bool _running; + UserThreadList _thread_list; + Mutex _mutex; + + SafeList<UserData> _data_queue; +}; + +} + +#endif // XCAM_THREAD_POOL_H diff --git a/xcore/uvc_device.cpp b/xcore/uvc_device.cpp new file mode 100644 index 0000000..4507baf --- /dev/null +++ b/xcore/uvc_device.cpp @@ -0,0 +1,60 @@ +/* + * uvc_device.cpp - uvc device + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Sameer Kibey <sameer.kibey@intel.com> + */ + +#include "uvc_device.h" +#include "v4l2_buffer_proxy.h" +#include <linux/v4l2-subdev.h> + +namespace XCam { + +UVCDevice::UVCDevice (const char *name) + : V4l2Device (name) +{ +} + +UVCDevice::~UVCDevice () +{ +} + +XCamReturn +UVCDevice::allocate_buffer ( + SmartPtr<V4l2Buffer> &buf, + const struct v4l2_format &format, + const uint32_t index) +{ +#if HAVE_LIBDRM + if (!_drm_disp.ptr()) { + _drm_disp = DrmDisplay::instance (); + } + + if (get_mem_type () == V4L2_MEMORY_DMABUF && _drm_disp.ptr () != NULL) { + buf = _drm_disp->create_drm_buf (format, index, get_capture_buf_type ()); + if (!buf.ptr()) { + XCAM_LOG_WARNING ("uvc device(%s) allocate buffer failed", XCAM_STR (get_device_name())); + return XCAM_RETURN_ERROR_MEM; + } + return XCAM_RETURN_NO_ERROR; + } +#endif + + return V4l2Device::allocate_buffer (buf, format, index); +} + +}; diff --git a/xcore/uvc_device.h b/xcore/uvc_device.h new file mode 100644 index 0000000..bec14fc --- /dev/null +++ b/xcore/uvc_device.h @@ -0,0 +1,68 @@ +/* + * uvc_device.h - uvc device + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Sameer Kibey <sameer.kibey@intel.com> + */ + +#ifndef XCAM_UVC_DEVICE_H +#define XCAM_UVC_DEVICE_H + +#include <xcam_std.h> +#include <v4l2_device.h> +#if HAVE_LIBDRM +#include <drm_display.h> +#endif + +namespace XCam { + +#if HAVE_LIBDRM +class DrmDisplay; +#endif + +class UVCDevice + : public V4l2Device +{ + friend class DrmV4l2Buffer; + +public: + explicit UVCDevice (const char *name = NULL); + ~UVCDevice (); + +#if HAVE_LIBDRM + void set_drm_display(SmartPtr<DrmDisplay> &drm_disp) { + _drm_disp = drm_disp; + }; +#endif + +protected: + virtual XCamReturn allocate_buffer ( + SmartPtr<V4l2Buffer> &buf, + const struct v4l2_format &format, + const uint32_t index); + +private: + XCAM_DEAD_COPY (UVCDevice); + +#if HAVE_LIBDRM +private: + SmartPtr<DrmDisplay> _drm_disp; +#endif +}; + +}; + +#endif //XCAM_UVC_DEVICE_H diff --git a/xcore/v4l2_buffer_proxy.cpp b/xcore/v4l2_buffer_proxy.cpp new file mode 100644 index 0000000..0d87a80 --- /dev/null +++ b/xcore/v4l2_buffer_proxy.cpp @@ -0,0 +1,155 @@ +/* + * v4l2_buffer_proxy.cpp - v4l2 buffer proxy + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "v4l2_buffer_proxy.h" +#include "v4l2_device.h" + +namespace XCam { +V4l2Buffer::V4l2Buffer (const struct v4l2_buffer &buf, const struct v4l2_format &format) +{ + _buf = buf; + _format = format; +} + +V4l2Buffer::~V4l2Buffer () +{ +} + +uint8_t * +V4l2Buffer::map () +{ + if (_buf.memory == V4L2_MEMORY_DMABUF) + return NULL; + return (uint8_t *)(_buf.m.userptr); +} + +bool +V4l2Buffer::unmap () +{ + return true; +} + +int +V4l2Buffer::get_fd () +{ + if (_buf.memory == V4L2_MEMORY_MMAP) + return -1; + return _buf.m.fd; +} + +V4l2BufferProxy::V4l2BufferProxy (SmartPtr<V4l2Buffer> &buf, SmartPtr<V4l2Device> &device) + : BufferProxy (buf) + , _device (device) +{ + VideoBufferInfo info; + struct timeval ts = buf->get_buf().timestamp; + + v4l2_format_to_video_info (buf->get_format(), info); + set_video_info (info); + set_timestamp (XCAM_TIMEVAL_2_USEC (ts)); +} + +V4l2BufferProxy::~V4l2BufferProxy () +{ + SmartPtr<BufferData> data = get_buffer_data (); + SmartPtr<V4l2Buffer> v4l2_data = data.dynamic_cast_ptr<V4l2Buffer> (); + if (_device.ptr () && v4l2_data.ptr ()) + _device->queue_buffer (v4l2_data); + XCAM_LOG_DEBUG ("v4l2 buffer released"); +} + +void +V4l2BufferProxy::v4l2_format_to_video_info ( + const struct v4l2_format &format, VideoBufferInfo &info) +{ + info.format = format.fmt.pix.pixelformat; + info.color_bits = 8; + info.width = format.fmt.pix.width; + info.height = format.fmt.pix.height; + info.aligned_width = 0; + info.aligned_height = 0; + info.size = format.fmt.pix.sizeimage; + switch (format.fmt.pix.pixelformat) { + case V4L2_PIX_FMT_NV12: // 420 + case V4L2_PIX_FMT_NV21: + info.components = 2; + info.strides [0] = format.fmt.pix.bytesperline * 2 / 3; + info.strides [1] = info.strides [0]; + info.offsets[0] = 0; + info.offsets[1] = info.strides [0] * format.fmt.pix.height; + break; + case V4L2_PIX_FMT_YUV422P: // 422 Planar + info.components = 3; + info.strides [0] = format.fmt.pix.bytesperline / 2; + info.strides [1] = info.strides [0] / 2 ; + info.strides [2] = info.strides [0] / 2 ; + info.offsets[0] = 0; + info.offsets[1] = info.strides [0] * format.fmt.pix.height; + info.offsets[2] = info.offsets[1] + info.strides [1] * format.fmt.pix.height; + break; + case V4L2_PIX_FMT_YUYV: // 422 + info.components = 1; + info.strides [0] = format.fmt.pix.bytesperline; + info.offsets[0] = 0; + info.aligned_width = info.strides [0] / 2; + break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + info.color_bits = 10; + info.components = 1; + info.strides [0] = format.fmt.pix.bytesperline; + info.offsets[0] = 0; + break; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + info.color_bits = 12; + info.components = 1; + info.strides [0] = format.fmt.pix.bytesperline; + info.offsets[0] = 0; + break; + default: + XCAM_LOG_WARNING ( + "unknown v4l2 format(%s) to video info", + xcam_fourcc_to_string (format.fmt.pix.pixelformat)); + break; + } + + if (!info.aligned_width) + info.aligned_width = info.strides [0]; + + if (!info.aligned_height) + info.aligned_height = info.height; + +} + +const struct v4l2_buffer & +V4l2BufferProxy::get_v4l2_buf () +{ + SmartPtr<BufferData> &data = get_buffer_data (); + SmartPtr<V4l2Buffer> v4l2_data = data.dynamic_cast_ptr<V4l2Buffer> (); + XCAM_ASSERT (v4l2_data.ptr ()); + return v4l2_data->get_buf (); +} + +}; diff --git a/xcore/v4l2_buffer_proxy.h b/xcore/v4l2_buffer_proxy.h new file mode 100644 index 0000000..94bd397 --- /dev/null +++ b/xcore/v4l2_buffer_proxy.h @@ -0,0 +1,124 @@ +/* + * v4l2_buffer_proxy.h - v4l2 buffer proxy + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_V4L2_BUFFER_PROXY_H +#define XCAM_V4L2_BUFFER_PROXY_H + +#include <xcam_std.h> +#include <buffer_pool.h> +#include <linux/videodev2.h> + +namespace XCam { + +class V4l2Device; + +class V4l2Buffer + : public BufferData +{ +public: + explicit V4l2Buffer (const struct v4l2_buffer &buf, const struct v4l2_format &format); + virtual ~V4l2Buffer (); + + const struct v4l2_buffer & get_buf () const { + return _buf; + } + + void set_timestamp (const struct timeval &time) { + _buf.timestamp = time; + } + + void set_timecode (const struct v4l2_timecode &code) { + _buf.timecode = code; + } + + void set_sequence (const uint32_t sequence) { + _buf.sequence = sequence; + } + + void set_length (const uint32_t value) { + _buf.length = value; + } + + void reset () { + xcam_mem_clear (_buf.timestamp); + xcam_mem_clear (_buf.timecode); + _buf.sequence = 0; + //_buf.length = 0; + } + + const struct v4l2_format & get_format () const { + return _format; + } + + // derived from BufferData + virtual uint8_t *map (); + virtual bool unmap (); + virtual int get_fd (); + +private: + XCAM_DEAD_COPY (V4l2Buffer); + +private: + struct v4l2_buffer _buf; + struct v4l2_format _format; +}; + +class V4l2BufferProxy + : public BufferProxy +{ +public: + explicit V4l2BufferProxy (SmartPtr<V4l2Buffer> &buf, SmartPtr<V4l2Device> &device); + + ~V4l2BufferProxy (); + + int get_v4l2_buf_index () { + return get_v4l2_buf().index; + } + + enum v4l2_memory get_v4l2_mem_type () { + return (enum v4l2_memory)(get_v4l2_buf().memory); + } + + int get_v4l2_buf_length () { + return get_v4l2_buf().length; + } + + int get_v4l2_dma_fd () { + return get_v4l2_buf().m.fd; + } + + uintptr_t get_v4l2_userptr () { + return get_v4l2_buf().m.userptr; + } + +private: + const struct v4l2_buffer & get_v4l2_buf (); + + void v4l2_format_to_video_info ( + const struct v4l2_format &format, VideoBufferInfo &info); + + XCAM_DEAD_COPY (V4l2BufferProxy); + +private: + SmartPtr<V4l2Device> _device; +}; +}; + +#endif //XCAM_V4L2_BUFFER_PROXY_H diff --git a/xcore/v4l2_device.cpp b/xcore/v4l2_device.cpp new file mode 100644 index 0000000..395461e --- /dev/null +++ b/xcore/v4l2_device.cpp @@ -0,0 +1,710 @@ +/* + * v4l2_device.cpp - v4l2 device + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: John Ye <john.ye@intel.com> + */ + +#include "v4l2_device.h" +#include <sys/ioctl.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <poll.h> +#include <errno.h> +#include <sys/mman.h> + +#include "v4l2_buffer_proxy.h" + +namespace XCam { + +#define XCAM_V4L2_DEFAULT_BUFFER_COUNT 6 + +V4l2Device::V4l2Device (const char *name) + : _name (NULL) + , _fd (-1) + , _sensor_id (0) + , _capture_mode (0) + , _capture_buf_type (V4L2_BUF_TYPE_VIDEO_CAPTURE) + , _memory_type (V4L2_MEMORY_MMAP) + , _fps_n (0) + , _fps_d (0) + , _active (false) + , _buf_count (XCAM_V4L2_DEFAULT_BUFFER_COUNT) +{ + if (name) + _name = strndup (name, XCAM_MAX_STR_SIZE); + xcam_mem_clear (_format); +} + +V4l2Device::~V4l2Device () +{ + close(); + if (_name) + xcam_free (_name); +} + +bool +V4l2Device::set_device_name (const char *name) +{ + XCAM_ASSERT (name); + + if (is_opened()) { + XCAM_LOG_WARNING ("can't set device name since device opened"); + return false; + } + if (_name) + xcam_free (_name); + _name = strndup (name, XCAM_MAX_STR_SIZE); + return true; +} + +bool +V4l2Device::set_sensor_id (int id) +{ + if (is_opened()) { + XCAM_LOG_WARNING ("can't set sensor id since device opened"); + return false; + } + _sensor_id = id; + return true; +} + +bool +V4l2Device::set_capture_mode (uint32_t capture_mode) +{ + if (is_opened()) { + XCAM_LOG_WARNING ("can't set sensor id since device opened"); + return false; + } + _capture_mode = capture_mode; + return true; +} + +bool +V4l2Device::set_framerate (uint32_t n, uint32_t d) +{ + if (_format.fmt.pix.pixelformat) { + XCAM_LOG_WARNING ("device(%s) set framerate failed since formatted was already set.", XCAM_STR(_name)); + return false; + } + + _fps_n = n; + _fps_d = d; + + return true; +} + +void +V4l2Device::get_framerate (uint32_t &n, uint32_t &d) +{ + n = _fps_n; + d = _fps_d; +} + +bool +V4l2Device::set_mem_type (enum v4l2_memory type) { + if (is_activated ()) { + XCAM_LOG_WARNING ("device(%s) set mem type failed", XCAM_STR (_name)); + return false; + } + _memory_type = type; + return true; +} + +bool +V4l2Device::set_buffer_count (uint32_t buf_count) +{ + if (is_activated ()) { + XCAM_LOG_WARNING ("device(%s) set buffer count failed", XCAM_STR (_name)); + return false; + } + _buf_count = buf_count; + return true; +} + + +XCamReturn +V4l2Device::open () +{ + struct v4l2_streamparm param; + + if (is_opened()) { + XCAM_LOG_DEBUG ("device(%s) was already opened", XCAM_STR(_name)); + return XCAM_RETURN_NO_ERROR; + } + + if (!_name) { + XCAM_LOG_DEBUG ("v4l2 device open failed, there's no device name"); + return XCAM_RETURN_ERROR_PARAM; + } + _fd = ::open (_name, O_RDWR); + if (_fd == -1) { + XCAM_LOG_DEBUG ("open device(%s) failed", _name); + return XCAM_RETURN_ERROR_IOCTL; + } + + // set sensor id + if (io_control (VIDIOC_S_INPUT, &_sensor_id) < 0) { + XCAM_LOG_WARNING ("set sensor id(%d) failed but continue", _sensor_id); + } + + // set capture mode + xcam_mem_clear (param); + param.type = _capture_buf_type; + param.parm.capture.capturemode = _capture_mode; + if (io_control (VIDIOC_S_PARM, ¶m) < 0) { + XCAM_LOG_WARNING ("set capture mode(0x%08x) failed but continue", _capture_mode); + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +V4l2Device::close () +{ + if (!is_opened()) + return XCAM_RETURN_NO_ERROR; + ::close (_fd); + _fd = -1; + return XCAM_RETURN_NO_ERROR; +} + +int +V4l2Device::io_control (int cmd, void *arg) + +{ + if (_fd <= 0) + return -1; + + return xcam_device_ioctl (_fd, cmd, arg); +} + +int +V4l2Device::poll_event (int timeout_msec) +{ + struct pollfd poll_fd; + int ret = 0; + + XCAM_ASSERT (_fd > 0); + + xcam_mem_clear (poll_fd); + poll_fd.fd = _fd; + poll_fd.events = (POLLPRI | POLLIN | POLLERR | POLLNVAL | POLLHUP); + + ret = poll (&poll_fd, 1, timeout_msec); + if (ret > 0 && (poll_fd.revents & (POLLERR | POLLNVAL | POLLHUP))) { + XCAM_LOG_DEBUG ("v4l2 subdev(%s) polled error", XCAM_STR(_name)); + return -1; + } + return ret; + +} + +XCamReturn +V4l2Device::set_format (struct v4l2_format &format) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_FAIL_RETURN (ERROR, !is_activated (), XCAM_RETURN_ERROR_PARAM, + "Cannot set format to v4l2 device while it is active."); + + XCAM_FAIL_RETURN (ERROR, is_opened (), XCAM_RETURN_ERROR_FILE, + "Cannot set format to v4l2 device while it is closed."); + + struct v4l2_format tmp_format = format; + + ret = pre_set_format (format); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("device(%s) pre_set_format failed", XCAM_STR (_name)); + return ret; + } + + if (io_control (VIDIOC_S_FMT, &format) < 0) { + if (errno == EBUSY) { + // TODO log device name + XCAM_LOG_ERROR("Video device is busy, fail to set format."); + } else { + // TODO log format details and errno + XCAM_LOG_ERROR("Fail to set format: %s", strerror(errno)); + } + + return XCAM_RETURN_ERROR_IOCTL; + } + + if (tmp_format.fmt.pix.width != format.fmt.pix.width || tmp_format.fmt.pix.height != format.fmt.pix.height) { + XCAM_LOG_ERROR ( + "device(%s) set v4l2 format failed, supported format: width:%d, height:%d", + XCAM_STR (_name), + format.fmt.pix.width, + format.fmt.pix.height); + + return XCAM_RETURN_ERROR_PARAM; + } + + while (_fps_n && _fps_d) { + struct v4l2_streamparm param; + xcam_mem_clear (param); + param.type = _capture_buf_type; + if (io_control (VIDIOC_G_PARM, ¶m) < 0) { + XCAM_LOG_WARNING ("device(%s) set framerate failed on VIDIOC_G_PARM but continue", XCAM_STR (_name)); + break; + } + + if (!(param.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)) + break; + + param.parm.capture.timeperframe.numerator = _fps_d; + param.parm.capture.timeperframe.denominator = _fps_n; + + if (io_control (VIDIOC_S_PARM, ¶m) < 0) { + XCAM_LOG_WARNING ("device(%s) set framerate failed on VIDIOC_S_PARM but continue", XCAM_STR (_name)); + break; + } + _fps_n = param.parm.capture.timeperframe.denominator; + _fps_d = param.parm.capture.timeperframe.numerator; + XCAM_LOG_INFO ("device(%s) set framerate(%d/%d)", XCAM_STR (_name), _fps_n, _fps_d); + + // exit here, otherwise it is an infinite loop + break; + } + + ret = post_set_format (format); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("device(%s) post_set_format failed", XCAM_STR (_name)); + return ret; + } + + _format = format; + XCAM_LOG_INFO ( + "device(%s) set format(w:%d, h:%d, pixelformat:%s, bytesperline:%d,image_size:%d)", + XCAM_STR (_name), + format.fmt.pix.width, format.fmt.pix.height, + xcam_fourcc_to_string (format.fmt.pix.pixelformat), + format.fmt.pix.bytesperline, + format.fmt.pix.sizeimage); + + return XCAM_RETURN_NO_ERROR; +} + +/*! \brief v4l2 set format + * + * \param[in] width format width + * \param[in] height format height + * \param[in] pixelformat fourcc + * \param[in] field V4L2_FIELD_INTERLACED or V4L2_FIELD_NONE + */ +XCamReturn +V4l2Device::set_format ( + uint32_t width, uint32_t height, + uint32_t pixelformat, enum v4l2_field field, uint32_t bytes_perline) +{ + + struct v4l2_format format; + xcam_mem_clear (format); + + format.type = _capture_buf_type; + format.fmt.pix.width = width; + format.fmt.pix.height = height; + format.fmt.pix.pixelformat = pixelformat; + format.fmt.pix.field = field; + + if (bytes_perline != 0) + format.fmt.pix.bytesperline = bytes_perline; + return set_format (format); +} + +XCamReturn +V4l2Device::pre_set_format (struct v4l2_format &format) +{ + XCAM_UNUSED (format); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +V4l2Device::post_set_format (struct v4l2_format &format) +{ + XCAM_UNUSED (format); + return XCAM_RETURN_NO_ERROR; +} + +std::list<struct v4l2_fmtdesc> +V4l2Device::enum_formats () +{ + std::list<struct v4l2_fmtdesc> formats; + struct v4l2_fmtdesc format; + uint32_t i = 0; + + while (1) { + xcam_mem_clear (format); + format.index = i++; + format.type = _capture_buf_type; + if (this->io_control (VIDIOC_ENUM_FMT, &format) < 0) { + if (errno == EINVAL) + break; + else { // error + XCAM_LOG_DEBUG ("enum formats failed"); + return formats; + } + } + formats.push_back (format); + } + + return formats; +} + +XCamReturn +V4l2Device::get_format (struct v4l2_format &format) +{ + if (is_activated ()) { + format = _format; + return XCAM_RETURN_NO_ERROR; + } + + if (!is_opened ()) + return XCAM_RETURN_ERROR_IOCTL; + + xcam_mem_clear (format); + format.type = _capture_buf_type; + + if (this->io_control (VIDIOC_G_FMT, &format) < 0) { + // FIXME: also log the device name? + XCAM_LOG_ERROR("Fail to get format via ioctl VIDVIO_G_FMT."); + return XCAM_RETURN_ERROR_IOCTL; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +V4l2Device::start () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + // request buffer first + ret = request_buffer (); + XCAM_FAIL_RETURN ( + ERROR, ret == XCAM_RETURN_NO_ERROR, ret, + "device(%s) start failed", XCAM_STR (_name)); + + //alloc buffers + ret = init_buffer_pool (); + XCAM_FAIL_RETURN ( + ERROR, ret == XCAM_RETURN_NO_ERROR, ret, + "device(%s) start failed", XCAM_STR (_name)); + + //queue all buffers + for (uint32_t i = 0; i < _buf_count; ++i) { + SmartPtr<V4l2Buffer> &buf = _buf_pool [i]; + XCAM_ASSERT (buf.ptr()); + XCAM_ASSERT (buf->get_buf().index == i); + ret = queue_buffer (buf); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ( + "device(%s) start failed on queue index:%d", + XCAM_STR (_name), i); + stop (); + return ret; + } + } + + // stream on + if (io_control (VIDIOC_STREAMON, &_capture_buf_type) < 0) { + XCAM_LOG_ERROR ( + "device(%s) start failed on VIDIOC_STREAMON", + XCAM_STR (_name)); + stop (); + return XCAM_RETURN_ERROR_IOCTL; + } + _active = true; + XCAM_LOG_INFO ("device(%s) started successfully", XCAM_STR (_name)); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +V4l2Device::stop () +{ + // stream off + if (_active) { + if (io_control (VIDIOC_STREAMOFF, &_capture_buf_type) < 0) { + XCAM_LOG_WARNING ("device(%s) steamoff failed", XCAM_STR (_name)); + } + _active = false; + } + + fini_buffer_pool (); + + XCAM_LOG_INFO ("device(%s) stopped", XCAM_STR (_name)); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +V4l2Device::request_buffer () +{ + struct v4l2_requestbuffers request_buf; + + XCAM_ASSERT (!is_activated()); + + xcam_mem_clear (request_buf); + request_buf.type = _capture_buf_type; + request_buf.count = _buf_count; + request_buf.memory = _memory_type; + + if (io_control (VIDIOC_REQBUFS, &request_buf) < 0) { + XCAM_LOG_INFO ("device(%s) starts failed on VIDIOC_REQBUFS", XCAM_STR (_name)); + return XCAM_RETURN_ERROR_IOCTL; + } + + if (request_buf.count != _buf_count) { + XCAM_LOG_DEBUG ( + "device(%s) request buffer count doesn't match user settings, reset buffer count to %d", + XCAM_STR (_name), request_buf.count); + _buf_count = request_buf.count; + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +V4l2Device::allocate_buffer ( + SmartPtr<V4l2Buffer> &buf, + const struct v4l2_format &format, + const uint32_t index) +{ + struct v4l2_buffer v4l2_buf; + + xcam_mem_clear (v4l2_buf); + v4l2_buf.index = index; + v4l2_buf.type = _capture_buf_type; + v4l2_buf.memory = _memory_type; + + switch (_memory_type) { + case V4L2_MEMORY_DMABUF: + { + struct v4l2_exportbuffer expbuf; + xcam_mem_clear (expbuf); + expbuf.type = _capture_buf_type; + expbuf.index = index; + expbuf.flags = O_CLOEXEC; + if (io_control (VIDIOC_EXPBUF, &expbuf) < 0) { + XCAM_LOG_WARNING ("device(%s) get dma buf(%d) failed", XCAM_STR (_name), index); + return XCAM_RETURN_ERROR_MEM; + } + v4l2_buf.m.fd = expbuf.fd; + v4l2_buf.length = format.fmt.pix.sizeimage; + } + break; + case V4L2_MEMORY_MMAP: + { + void *pointer; + int map_flags = MAP_SHARED; +#ifdef NEED_MAP_32BIT + map_flags |= MAP_32BIT; +#endif + if (io_control (VIDIOC_QUERYBUF, &v4l2_buf) < 0) { + XCAM_LOG_WARNING("device(%s) query MMAP buf(%d) failed", XCAM_STR(_name), index); + return XCAM_RETURN_ERROR_MEM; + } + pointer = mmap (0, v4l2_buf.length, PROT_READ | PROT_WRITE, map_flags, _fd, v4l2_buf.m.offset); + if (pointer == MAP_FAILED) { + XCAM_LOG_WARNING("device(%s) mmap buf(%d) failed", XCAM_STR(_name), index); + return XCAM_RETURN_ERROR_MEM; + } + v4l2_buf.m.userptr = (uintptr_t) pointer; + } + break; + case V4L2_MEMORY_USERPTR: + default: + XCAM_ASSERT (false); + XCAM_LOG_WARNING ( + "device(%s) allocated buffer mem_type(%d) doesn't support", + XCAM_STR (_name), _memory_type); + return XCAM_RETURN_ERROR_MEM; + } + + buf = new V4l2Buffer (v4l2_buf, _format); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +V4l2Device::init_buffer_pool () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + uint32_t i = 0; + + _buf_pool.clear (); + _buf_pool.reserve (_buf_count); + + for (; i < _buf_count; i++) { + SmartPtr<V4l2Buffer> new_buf; + ret = allocate_buffer (new_buf, _format, i); + if (ret != XCAM_RETURN_NO_ERROR) { + break; + } + _buf_pool.push_back (new_buf); + } + + if (_buf_pool.empty()) { + XCAM_LOG_ERROR ("No bufer allocated in device(%s)", XCAM_STR (_name)); + return XCAM_RETURN_ERROR_MEM; + } + + if (i != _buf_count) { + XCAM_LOG_WARNING ( + "device(%s) allocate buffer count:%d failback to %d", + XCAM_STR (_name), _buf_count, i); + _buf_count = i; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +V4l2Device::fini_buffer_pool() +{ + _buf_pool.clear (); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +V4l2Device::dequeue_buffer(SmartPtr<V4l2Buffer> &buf) +{ + struct v4l2_buffer v4l2_buf; + + if (!is_activated()) { + XCAM_LOG_DEBUG ( + "device(%s) dequeue buffer failed since not activated", XCAM_STR (_name)); + return XCAM_RETURN_ERROR_PARAM; + } + + xcam_mem_clear (v4l2_buf); + v4l2_buf.type = _capture_buf_type; + v4l2_buf.memory = _memory_type; + + if (this->io_control (VIDIOC_DQBUF, &v4l2_buf) < 0) { + XCAM_LOG_ERROR ("device(%s) fail to dequeue buffer.", XCAM_STR (_name)); + return XCAM_RETURN_ERROR_IOCTL; + } + + XCAM_LOG_DEBUG ("device(%s) dequeue buffer index:%d", XCAM_STR (_name), v4l2_buf.index); + + if (v4l2_buf.index > _buf_count) { + XCAM_LOG_ERROR ( + "device(%s) dequeue wrong buffer index:%d", + XCAM_STR (_name), v4l2_buf.index); + return XCAM_RETURN_ERROR_ISP; + } + buf = _buf_pool [v4l2_buf.index]; + buf->set_timestamp (v4l2_buf.timestamp); + buf->set_timecode (v4l2_buf.timecode); + buf->set_sequence (v4l2_buf.sequence); + //buf.set_length (v4l2_buf.length); // not necessary to set length + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +V4l2Device::queue_buffer (SmartPtr<V4l2Buffer> &buf) +{ + XCAM_ASSERT (buf.ptr()); + buf->reset (); + + struct v4l2_buffer v4l2_buf = buf->get_buf (); + XCAM_ASSERT (v4l2_buf.index < _buf_count); + + XCAM_LOG_DEBUG ("device(%s) queue buffer index:%d", XCAM_STR (_name), v4l2_buf.index); + if (io_control (VIDIOC_QBUF, &v4l2_buf) < 0) { + XCAM_LOG_ERROR("fail to enqueue buffer index:%d.", v4l2_buf.index); + return XCAM_RETURN_ERROR_IOCTL; + } + return XCAM_RETURN_NO_ERROR; +} + +V4l2SubDevice::V4l2SubDevice (const char *name) + : V4l2Device (name) +{ +} + +XCamReturn +V4l2SubDevice::subscribe_event (int event) +{ + struct v4l2_event_subscription sub; + int ret = 0; + + XCAM_ASSERT (is_opened()); + + xcam_mem_clear (sub); + sub.type = event; + + ret = this->io_control (VIDIOC_SUBSCRIBE_EVENT, &sub); + if (ret < 0) { + XCAM_LOG_DEBUG ("subdev(%s) subscribe event(%d) failed", XCAM_STR(_name), event); + return XCAM_RETURN_ERROR_IOCTL; + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +V4l2SubDevice::unsubscribe_event (int event) +{ + struct v4l2_event_subscription sub; + int ret = 0; + + XCAM_ASSERT (is_opened()); + + xcam_mem_clear (sub); + sub.type = event; + + ret = this->io_control (VIDIOC_UNSUBSCRIBE_EVENT, &sub); + if (ret < 0) { + XCAM_LOG_DEBUG ("subdev(%s) unsubscribe event(%d) failed", XCAM_STR(_name), event); + return XCAM_RETURN_ERROR_IOCTL; + } + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +V4l2SubDevice::dequeue_event (struct v4l2_event &event) +{ + int ret = 0; + XCAM_ASSERT (is_opened()); + + ret = this->io_control (VIDIOC_DQEVENT, &event); + if (ret < 0) { + XCAM_LOG_DEBUG ("subdev(%s) dequeue event failed", XCAM_STR(_name)); + return XCAM_RETURN_ERROR_IOCTL; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn V4l2SubDevice::start () +{ + if (!is_opened()) + return XCAM_RETURN_ERROR_PARAM; + + _active = true; + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn V4l2SubDevice::stop () +{ + if (_active) + _active = false; + + return XCAM_RETURN_NO_ERROR; +} + +}; diff --git a/xcore/v4l2_device.h b/xcore/v4l2_device.h new file mode 100644 index 0000000..b4ad7ad --- /dev/null +++ b/xcore/v4l2_device.h @@ -0,0 +1,167 @@ +/* + * v4l2_device.h - v4l2 device + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_V4L2_DEVICE_H +#define XCAM_V4L2_DEVICE_H + +#include <xcam_std.h> +#include <linux/videodev2.h> +#include <list> +#include <vector> + +extern "C" { + struct v4l2_event; + struct v4l2_format; + struct v4l2_fmtdesc; + struct v4l2_frmsizeenum; +} + +namespace XCam { + +class V4l2Buffer; + +class V4l2Device { + friend class V4l2BufferProxy; + typedef std::vector<SmartPtr<V4l2Buffer>> BufferPool; + +public: + V4l2Device (const char *name = NULL); + virtual ~V4l2Device (); + + // before device open + bool set_device_name (const char *name); + bool set_sensor_id (int id); + bool set_capture_mode (uint32_t capture_mode); + + int get_fd () const { + return _fd; + } + const char *get_device_name () const { + return _name; + } + bool is_opened () const { + return (_fd != -1); + } + bool is_activated () const { + return _active; + } + + // set_mem_type must before set_format + bool set_mem_type (enum v4l2_memory type); + enum v4l2_memory get_mem_type () const { + return _memory_type; + } + enum v4l2_buf_type get_capture_buf_type () const { + return _capture_buf_type; + } + void get_size (uint32_t &width, uint32_t &height) const { + width = _format.fmt.pix.width; + height = _format.fmt.pix.height; + } + uint32_t get_pixel_format () const { + return _format.fmt.pix.pixelformat; + } + + bool set_buffer_count (uint32_t buf_count); + + // set_framerate must before set_format + bool set_framerate (uint32_t n, uint32_t d); + void get_framerate (uint32_t &n, uint32_t &d); + + XCamReturn open (); + XCamReturn close (); + // set_format + XCamReturn get_format (struct v4l2_format &format); + XCamReturn set_format (struct v4l2_format &format); + XCamReturn set_format ( + uint32_t width, uint32_t height, uint32_t pixelformat, + enum v4l2_field field = V4L2_FIELD_NONE, uint32_t bytes_perline = 0); + + std::list<struct v4l2_fmtdesc> enum_formats (); + + virtual XCamReturn start (); + virtual XCamReturn stop (); + + int poll_event (int timeout_msec); + XCamReturn dequeue_buffer (SmartPtr<V4l2Buffer> &buf); + XCamReturn queue_buffer (SmartPtr<V4l2Buffer> &buf); + + // use as less as possible + virtual int io_control (int cmd, void *arg); + +protected: + + //virtual functions, handle private actions on set_format + virtual XCamReturn pre_set_format (struct v4l2_format &format); + virtual XCamReturn post_set_format (struct v4l2_format &format); + virtual XCamReturn allocate_buffer ( + SmartPtr<V4l2Buffer> &buf, + const struct v4l2_format &format, + const uint32_t index); + +private: + XCamReturn request_buffer (); + XCamReturn init_buffer_pool (); + XCamReturn fini_buffer_pool (); + + XCAM_DEAD_COPY (V4l2Device); + +protected: + char *_name; + int _fd; + int32_t _sensor_id; + uint32_t _capture_mode; + enum v4l2_buf_type _capture_buf_type; + enum v4l2_memory _memory_type; + + struct v4l2_format _format; + uint32_t _fps_n; + uint32_t _fps_d; + + bool _active; + + // buffer pool + BufferPool _buf_pool; + uint32_t _buf_count; + + XCamReturn buffer_new(); + XCamReturn buffer_del(); +}; + +class V4l2SubDevice + : public V4l2Device +{ +public: + explicit V4l2SubDevice (const char *name = NULL); + + XCamReturn subscribe_event (int event); + XCamReturn unsubscribe_event (int event); + XCamReturn dequeue_event (struct v4l2_event &event); + + virtual XCamReturn start (); + virtual XCamReturn stop (); + +private: + XCAM_DEAD_COPY (V4l2SubDevice); +}; + +}; +#endif // XCAM_V4L2_DEVICE_H + diff --git a/xcore/vec_mat.h b/xcore/vec_mat.h new file mode 100644 index 0000000..51add21 --- /dev/null +++ b/xcore/vec_mat.h @@ -0,0 +1,1200 @@ +/* + * vec_mat.h - vector and matrix defination & calculation + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Zong Wei <wei.zong@intel.com> + */ + +#ifndef XCAM_VECTOR_MATRIX_H +#define XCAM_VECTOR_MATRIX_H + +#include <xcam_std.h> +#include <cmath> + + +namespace XCam { + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +#ifndef FLT_EPSILON +#define FLT_EPSILON 1.19209290e-07F // float +#endif + +#ifndef DBL_EPSILON +#define DBL_EPSILON 2.2204460492503131e-16 // double +#endif + +#ifndef DEGREE_2_RADIANS +#define DEGREE_2_RADIANS(x) (((x) * PI) / 180.0) +#endif + +#ifndef RADIANS_2_DEGREE +#define RADIANS_2_DEGREE(x) (((x) * 180.0) / PI) +#endif + +#define XCAM_VECT2_OPERATOR_VECT2(op) \ + Vector2<T> operator op (const Vector2<T>& b) const { \ + return Vector2<T>(x op b.x, y op b.y); \ + } \ + Vector2<T> &operator op##= (const Vector2<T>& b) { \ + x op##= b.x; y op##= b.y; return *this; \ + } + +#define XCAM_VECT2_OPERATOR_SCALER(op) \ + Vector2<T> operator op (const T& b) const { \ + return Vector2<T>(x op b, y op b); \ + } \ + Vector2<T> &operator op##= (const T& b) { \ + x op##= b; y op##= b; return *this; \ + } + +template<class T> +class Vector2 +{ +public: + + T x; + T y; + + Vector2 () : x(0), y(0) {}; + Vector2 (T _x, T _y) : x(_x), y(_y) {}; + + template <typename New> + Vector2<New> convert_to () const { + Vector2<New> ret((New)(this->x), (New)(this->y)); + return ret; + } + + Vector2<T>& operator = (const Vector2<T>& rhs) + { + x = rhs.x; + y = rhs.y; + return *this; + } + + template <typename Other> + Vector2<T>& operator = (const Vector2<Other>& rhs) + { + x = rhs.x; + y = rhs.y; + return *this; + } + + Vector2<T> operator - () const { + return Vector2<T>(-x, -y); + } + + XCAM_VECT2_OPERATOR_VECT2 (+) + XCAM_VECT2_OPERATOR_VECT2 (-) + XCAM_VECT2_OPERATOR_VECT2 (*) + XCAM_VECT2_OPERATOR_VECT2 ( / ) + XCAM_VECT2_OPERATOR_SCALER (+) + XCAM_VECT2_OPERATOR_SCALER (-) + XCAM_VECT2_OPERATOR_SCALER (*) + XCAM_VECT2_OPERATOR_SCALER ( / ) + + bool operator == (const Vector2<T>& rhs) const { + return (x == rhs.x) && (y == rhs.y); + } + + void reset () { + this->x = (T) 0; + this->y = (T) 0; + } + + void set (T _x, T _y) { + this->x = _x; + this->y = _y; + } + + T magnitude () const { + return (T) sqrtf(x * x + y * y); + } + + float distance (const Vector2<T>& vec) const { + return sqrtf((vec.x - x) * (vec.x - x) + (vec.y - y) * (vec.y - y)); + } + + T dot (const Vector2<T>& vec) const { + return (x * vec.x + y * vec.y); + } + + inline Vector2<T> lerp (T weight, const Vector2<T>& vec) const { + return (*this) + (vec - (*this)) * weight; + } + +}; + +template<class T, uint32_t N> +class VectorN +{ +public: + + VectorN (); + VectorN (T x); + VectorN (T x, T y); + VectorN (T x, T y, T z); + VectorN (T x, T y, T z, T w); + VectorN (VectorN<T, 3> vec3, T w); + + inline VectorN<T, N>& operator = (const VectorN<T, N>& rhs); + inline VectorN<T, N> operator - () const; + inline bool operator == (const VectorN<T, N>& rhs) const; + + inline T& operator [] (uint32_t index) { + XCAM_ASSERT(index >= 0 && index < N); + return data[index]; + } + inline const T& operator [] (uint32_t index) const { + XCAM_ASSERT(index >= 0 && index < N); + return data[index]; + } + + inline VectorN<T, N> operator + (const T rhs) const; + inline VectorN<T, N> operator - (const T rhs) const; + inline VectorN<T, N> operator * (const T rhs) const; + inline VectorN<T, N> operator / (const T rhs) const; + inline VectorN<T, N> operator += (const T rhs); + inline VectorN<T, N> operator -= (const T rhs); + inline VectorN<T, N> operator *= (const T rhs); + inline VectorN<T, N> operator /= (const T rhs); + + inline VectorN<T, N> operator + (const VectorN<T, N>& rhs) const; + inline VectorN<T, N> operator - (const VectorN<T, N>& rhs) const; + inline VectorN<T, N> operator * (const VectorN<T, N>& rhs) const; + inline VectorN<T, N> operator / (const VectorN<T, N>& rhs) const; + inline VectorN<T, N> operator += (const VectorN<T, N>& rhs); + inline VectorN<T, N> operator -= (const VectorN<T, N>& rhs); + inline VectorN<T, N> operator *= (const VectorN<T, N>& rhs); + inline VectorN<T, N> operator /= (const VectorN<T, N>& rhs); + + template <typename NEW> inline + VectorN<NEW, N> convert_to () const; + + inline void zeros (); + inline void set (T x, T y); + inline void set (T x, T y, T z); + inline void set (T x, T y, T z, T w); + inline T magnitude () const; + inline float distance (const VectorN<T, N>& vec) const; + inline T dot (const VectorN<T, N>& vec) const; + inline VectorN<T, N> lerp (T weight, const VectorN<T, N>& vec) const; + +private: + T data[N]; + +}; + + +template<class T, uint32_t N> inline +VectorN<T, N>::VectorN () +{ + for (uint32_t i = 0; i < N; i++) { + data[i] = 0; + } +} + +template<class T, uint32_t N> inline +VectorN<T, N>::VectorN (T x) { + data[0] = x; +} + +template<class T, uint32_t N> inline +VectorN<T, N>::VectorN (T x, T y) { + if (N >= 2) { + data[0] = x; + data[1] = y; + } +} + +template<class T, uint32_t N> inline +VectorN<T, N>::VectorN (T x, T y, T z) { + if (N >= 3) { + data[0] = x; + data[1] = y; + data[2] = z; + } +} + +template<class T, uint32_t N> inline +VectorN<T, N>::VectorN (T x, T y, T z, T w) { + if (N >= 4) { + data[0] = x; + data[1] = y; + data[2] = z; + data[3] = w; + } +} + +template<class T, uint32_t N> inline +VectorN<T, N>::VectorN (VectorN<T, 3> vec3, T w) { + if (N >= 4) { + data[0] = vec3.data[0]; + data[1] = vec3.data[1]; + data[2] = vec3.data[2]; + data[3] = w; + } +} + +template<class T, uint32_t N> inline +VectorN<T, N>& VectorN<T, N>::operator = (const VectorN<T, N>& rhs) { + for (uint32_t i = 0; i < N; i++) { + data[i] = rhs.data[i]; + } + + return *this; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator - () const { + for (uint32_t i = 0; i < N; i++) { + data[i] = -data[i]; + } + + return *this; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator + (const T rhs) const { + VectorN<T, N> result; + + for (uint32_t i = 0; i < N; i++) { + result.data[i] = data[i] + rhs; + } + return result; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator - (const T rhs) const { + VectorN<T, N> result; + + for (uint32_t i = 0; i < N; i++) { + result.data[i] = data[i] - rhs; + } + return result; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator * (const T rhs) const { + VectorN<T, N> result; + + for (uint32_t i = 0; i < N; i++) { + result.data[i] = data[i] * rhs; + } + return result; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator / (const T rhs) const { + VectorN<T, N> result; + + for (uint32_t i = 0; i < N; i++) { + result.data[i] = data[i] / rhs; + } + return result; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator += (const T rhs) { + for (uint32_t i = 0; i < N; i++) { + data[i] += rhs; + } + return *this; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator -= (const T rhs) { + for (uint32_t i = 0; i < N; i++) { + data[i] -= rhs; + } + return *this; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator *= (const T rhs) { + for (uint32_t i = 0; i < N; i++) { + data[i] *= rhs; + } + return *this; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator /= (const T rhs) { + for (uint32_t i = 0; i < N; i++) { + data[i] /= rhs; + } + return *this; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator + (const VectorN<T, N>& rhs) const { + VectorN<T, N> result; + + for (uint32_t i = 0; i < N; i++) { + result.data[i] = data[i] + rhs.data[i]; + } + return result; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator - (const VectorN<T, N>& rhs) const { + VectorN<T, N> result; + + for (uint32_t i = 0; i < N; i++) { + result.data[i] = data[i] - rhs.data[i]; + } + return result; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator * (const VectorN<T, N>& rhs) const { + VectorN<T, N> result; + + for (uint32_t i = 0; i < N; i++) { + result.data[i] = data[i] * rhs.data[i]; + } + return result; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator / (const VectorN<T, N>& rhs) const { + VectorN<T, N> result; + + for (uint32_t i = 0; i < N; i++) { + result.data[i] = data[i] / rhs.data[i]; + } + return result; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator += (const VectorN<T, N>& rhs) { + + for (uint32_t i = 0; i < N; i++) { + data[i] += rhs.data[i]; + } + return *this; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator -= (const VectorN<T, N>& rhs) { + + for (uint32_t i = 0; i < N; i++) { + data[i] -= rhs.data[i]; + } + return *this; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator *= (const VectorN<T, N>& rhs) { + + for (uint32_t i = 0; i < N; i++) { + data[i] *= rhs.data[i]; + } + return *this; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::operator /= (const VectorN<T, N>& rhs) { + + for (uint32_t i = 0; i < N; i++) { + data[i] /= rhs.data[i]; + } + return *this; +} + +template<class T, uint32_t N> inline +bool VectorN<T, N>::operator == (const VectorN<T, N>& rhs) const { + for (uint32_t i = 0; i < N; i++) { + if (data[i] != rhs[i]) { + return false; + } + } + return true; +} + +template <class T, uint32_t N> +template <typename NEW> +VectorN<NEW, N> VectorN<T, N>::convert_to () const { + VectorN<NEW, N> result; + + for (uint32_t i = 0; i < N; i++) { + result[i] = (NEW)(this->data[i]); + } + return result; +} + +template <class T, uint32_t N> inline +void VectorN<T, N>::zeros () { + for (uint32_t i = 0; i < N; i++) { + data[i] = (T)(0); + } +} + +template<class T, uint32_t N> inline +void VectorN<T, N>::set (T x, T y) { + if (N >= 2) { + data[0] = x; + data[1] = y; + } +} + +template<class T, uint32_t N> inline +void VectorN<T, N>::set (T x, T y, T z) { + if (N >= 3) { + data[0] = x; + data[1] = y; + data[2] = z; + } +} + +template<class T, uint32_t N> inline +void VectorN<T, N>::set (T x, T y, T z, T w) { + if (N >= 4) { + data[0] - x; + data[1] = y; + data[2] = z; + data[3] = w; + } +} + +template<class T, uint32_t N> inline +T VectorN<T, N>::magnitude () const { + T result = 0; + + for (uint32_t i = 0; i < N; i++) { + result += (data[i] * data[i]); + } + return (T) sqrtf(result); +} + +template<class T, uint32_t N> inline +float VectorN<T, N>::distance (const VectorN<T, N>& vec) const { + T result = 0; + + for (uint32_t i = 0; i < N; i++) { + result += (vec.data[i] - data[i]) * (vec.data[i] - data[i]); + } + return sqrtf(result); +} + +template<class T, uint32_t N> inline +T VectorN<T, N>::dot (const VectorN<T, N>& vec) const { + T result = 0; + + for (uint32_t i = 0; i < N; i++) { + result += (vec.data[i] * data[i]); + } + return result; +} + +template<class T, uint32_t N> inline +VectorN<T, N> VectorN<T, N>::lerp (T weight, const VectorN<T, N>& vec) const { + return (*this) + (vec - (*this)) * weight; +} + +// NxN matrix in row major order +template<class T, uint32_t N> +class MatrixN +{ +public: + MatrixN (); + MatrixN (VectorN<T, 2> a, VectorN<T, 2> b); + MatrixN (VectorN<T, 3> a, VectorN<T, 3> b, VectorN<T, 3> c); + MatrixN (VectorN<T, 4> a, VectorN<T, 4> b, VectorN<T, 4> c, VectorN<T, 4> d); + + inline void zeros (); + inline void eye (); + + inline T& at (uint32_t row, uint32_t col) { + XCAM_ASSERT(row >= 0 && row < N); + XCAM_ASSERT(col >= 0 && col < N); + + return data[row * N + col]; + }; + inline const T& at (uint32_t row, uint32_t col) const { + XCAM_ASSERT(row >= 0 && row < N); + XCAM_ASSERT(col >= 0 && col < N); + + return data[row * N + col]; + }; + + inline T& operator () (uint32_t row, uint32_t col) { + return at (row, col); + }; + inline const T& operator () (uint32_t row, uint32_t col) const { + return at (row, col); + }; + + inline MatrixN<T, N>& operator = (const MatrixN<T, N>& rhs); + inline MatrixN<T, N> operator - () const; + inline MatrixN<T, N> operator + (const MatrixN<T, N>& rhs) const; + inline MatrixN<T, N> operator - (const MatrixN<T, N>& rhs) const; + inline MatrixN<T, N> operator * (const T a) const; + inline MatrixN<T, N> operator / (const T a) const; + inline VectorN<T, N> operator * (const VectorN<T, N>& rhs) const; + inline MatrixN<T, N> operator * (const MatrixN<T, N>& rhs) const; + inline MatrixN<T, N> transpose (); + inline MatrixN<T, N> inverse (); + inline T trace (); + +private: + inline MatrixN<T, 2> inverse (const MatrixN<T, 2>& mat); + inline MatrixN<T, 3> inverse (const MatrixN<T, 3>& mat); + inline MatrixN<T, 4> inverse (const MatrixN<T, 4>& mat); + +private: + T data[N * N]; + +}; + +// NxN matrix in row major order +template<class T, uint32_t N> +MatrixN<T, N>::MatrixN () { + eye (); +} + +template<class T, uint32_t N> +MatrixN<T, N>::MatrixN (VectorN<T, 2> a, VectorN<T, 2> b) { + if (N == 2) { + data[0] = a[0]; + data[1] = a[1]; + data[2] = b[0]; + data[3] = b[1]; + } else { + eye (); + } +} + +template<class T, uint32_t N> +MatrixN<T, N>::MatrixN (VectorN<T, 3> a, VectorN<T, 3> b, VectorN<T, 3> c) { + if (N == 3) { + data[0] = a[0]; + data[1] = a[1]; + data[2] = a[2]; + data[3] = b[0]; + data[4] = b[1]; + data[5] = b[2]; + data[6] = c[0]; + data[7] = c[1]; + data[8] = c[2]; + } else { + eye (); + } +} + +template<class T, uint32_t N> +MatrixN<T, N>::MatrixN (VectorN<T, 4> a, VectorN<T, 4> b, VectorN<T, 4> c, VectorN<T, 4> d) { + if (N == 4) { + data[0] = a[0]; + data[1] = a[1]; + data[2] = a[2]; + data[3] = a[3]; + data[4] = b[0]; + data[5] = b[1]; + data[6] = b[2]; + data[7] = b[3]; + data[8] = c[0]; + data[9] = c[1]; + data[10] = c[2]; + data[11] = c[3]; + data[12] = d[0]; + data[13] = d[1]; + data[14] = d[2]; + data[15] = d[3]; + } else { + eye (); + } +} + +template<class T, uint32_t N> inline +void MatrixN<T, N>::zeros () { + for (uint32_t i = 0; i < N * N; i++) { + data[i] = 0; + } +} + +template<class T, uint32_t N> inline +void MatrixN<T, N>::eye () { + zeros (); + for (uint32_t i = 0; i < N; i++) { + data[i * N + i] = 1; + } +} + +template<class T, uint32_t N> inline +MatrixN<T, N>& MatrixN<T, N>::operator = (const MatrixN<T, N>& rhs) { + for (uint32_t i = 0; i < N * N; i++) { + data[i] = rhs.data[i]; + } + return *this; +} + +template<class T, uint32_t N> inline +MatrixN<T, N> MatrixN<T, N>::operator - () const { + MatrixN<T, N> result; + for (uint32_t i = 0; i < N * N; i++) { + result.data[i] = -data[i]; + } + return result; +} + +template<class T, uint32_t N> inline +MatrixN<T, N> MatrixN<T, N>::operator + (const MatrixN<T, N>& rhs) const { + MatrixN<T, N> result; + for (uint32_t i = 0; i < N * N; i++) { + result.data[i] = data[i] + rhs.data[i]; + } + return result; +} + +template<class T, uint32_t N> inline +MatrixN<T, N> MatrixN<T, N>::operator - (const MatrixN<T, N>& rhs) const { + MatrixN<T, N> result; + for (uint32_t i = 0; i < N * N; i++) { + result.data[i] = data[i] - rhs.data[i]; + } + return result; +} + +template<class T, uint32_t N> inline +MatrixN<T, N> MatrixN<T, N>::operator * (const T a) const { + MatrixN<T, N> result; + for (uint32_t i = 0; i < N * N; i++) { + result.data[i] = data[i] * a; + } + return result; +} + +template<class T, uint32_t N> inline +MatrixN<T, N> MatrixN<T, N>::operator / (const T a) const { + MatrixN<T, N> result; + for (uint32_t i = 0; i < N * N; i++) { + result.data[i] = data[i] / a; + } + return result; +} + +template<class T, uint32_t N> inline +MatrixN<T, N> MatrixN<T, N>::operator * (const MatrixN<T, N>& rhs) const { + MatrixN<T, N> result; + result.zeros (); + + for (uint32_t i = 0; i < N; i++) { + for (uint32_t j = 0; j < N; j++) { + T element = 0; + for (uint32_t k = 0; k < N; k++) { + element += at(i, k) * rhs(k, j); + } + result(i, j) = element; + } + } + return result; +} + +template<class T, uint32_t N> inline +VectorN<T, N> MatrixN<T, N>::operator * (const VectorN<T, N>& rhs) const { + VectorN<T, N> result; + for (uint32_t i = 0; i < N; i++) { // row + for (uint32_t j = 0; j < N; j++) { // col + result.data[i] = data[i * N + j] * rhs.data[j]; + } + } + return result; +} + +template<class T, uint32_t N> inline +MatrixN<T, N> MatrixN<T, N>::transpose () { + MatrixN<T, N> result; + for (uint32_t i = 0; i < N; i++) { + for (uint32_t j = 0; j <= N; j++) { + result.data[i * N + j] = data[j * N + i]; + } + } + return result; +} + +// if the matrix is non-invertible, return identity matrix +template<class T, uint32_t N> inline +MatrixN<T, N> MatrixN<T, N>::inverse () { + MatrixN<T, N> result; + + result = inverse (*this); + return result; +} + +template<class T, uint32_t N> inline +T MatrixN<T, N>::trace () { + T t = 0; + for ( uint32_t i = 0; i < N; i++ ) { + t += data(i, i); + } + return t; +} + +template<class T, uint32_t N> inline +MatrixN<T, 2> MatrixN<T, N>::inverse (const MatrixN<T, 2>& mat) +{ + MatrixN<T, 2> result; + + T det = mat(0, 0) * mat(1, 1) - mat(0, 1) * mat(1, 0); + + if (det == (T)0) { + return result; + } + + result(0, 0) = mat(1, 1); + result(0, 1) = -mat(0, 1); + result(1, 0) = -mat(1, 0); + result(1, 1) = mat(0, 0); + + return result * (1.0f / det); +} + +template<class T, uint32_t N> inline +MatrixN<T, 3> MatrixN<T, N>::inverse (const MatrixN<T, 3>& mat) +{ + MatrixN<T, 3> result; + + T det = mat(0, 0) * mat(1, 1) * mat(2, 2) + + mat(1, 0) * mat(2, 1) * mat(0, 2) + + mat(2, 0) * mat(0, 1) * mat(1, 2) - + mat(0, 0) * mat(2, 1) * mat(1, 2) - + mat(1, 0) * mat(0, 1) * mat(2, 2) - + mat(2, 0) * mat(1, 1) * mat(0, 2); + + if (det == (T)0) { + return result; + } + + result(0, 0) = mat(1, 1) * mat(2, 2) - mat(1, 2) * mat(2, 1); + result(1, 0) = mat(1, 2) * mat(2, 0) - mat(1, 0) * mat(2, 2); + result(2, 0) = mat(1, 0) * mat(2, 1) - mat(1, 1) * mat(2, 0); + result(0, 1) = mat(0, 2) * mat(2, 1) - mat(0, 1) * mat(2, 2); + result(1, 1) = mat(0, 0) * mat(2, 2) - mat(0, 2) * mat(2, 0); + result(2, 1) = mat(0, 1) * mat(2, 0) - mat(0, 0) * mat(2, 1); + result(0, 2) = mat(0, 1) * mat(1, 2) - mat(0, 2) * mat(1, 1); + result(1, 2) = mat(0, 2) * mat(1, 0) - mat(0, 0) * mat(1, 2); + result(2, 2) = mat(0, 0) * mat(1, 1) - mat(0, 1) * mat(1, 0); + + return result * (1.0f / det); +} + +template<class T, uint32_t N> inline +MatrixN<T, 4> MatrixN<T, N>::inverse (const MatrixN<T, 4>& mat) +{ + MatrixN<T, 4> result; + + T det = mat(0, 3) * mat(1, 2) * mat(2, 1) * mat(3, 1) - + mat(0, 2) * mat(1, 3) * mat(2, 1) * mat(3, 1) - + mat(0, 3) * mat(1, 1) * mat(2, 2) * mat(3, 1) + + mat(0, 1) * mat(1, 3) * mat(2, 2) * mat(3, 1) + + mat(0, 2) * mat(1, 1) * mat(2, 3) * mat(3, 1) - + mat(0, 1) * mat(1, 2) * mat(2, 3) * mat(3, 1) - + mat(0, 3) * mat(1, 2) * mat(2, 0) * mat(3, 1) + + mat(0, 2) * mat(1, 3) * mat(2, 0) * mat(3, 1) + + mat(0, 3) * mat(1, 0) * mat(2, 2) * mat(3, 1) - + mat(0, 0) * mat(1, 3) * mat(2, 2) * mat(3, 1) - + mat(0, 2) * mat(1, 0) * mat(2, 3) * mat(3, 1) + + mat(0, 0) * mat(1, 2) * mat(2, 3) * mat(3, 1) + + mat(0, 3) * mat(1, 1) * mat(2, 0) * mat(3, 2) - + mat(0, 1) * mat(1, 3) * mat(2, 0) * mat(3, 2) - + mat(0, 3) * mat(1, 0) * mat(2, 1) * mat(3, 2) + + mat(0, 0) * mat(1, 3) * mat(2, 1) * mat(3, 2) + + mat(0, 1) * mat(1, 0) * mat(2, 3) * mat(3, 2) - + mat(0, 0) * mat(1, 1) * mat(2, 3) * mat(3, 2) - + mat(0, 2) * mat(1, 1) * mat(2, 0) * mat(3, 3) + + mat(0, 1) * mat(1, 2) * mat(2, 0) * mat(3, 3) + + mat(0, 2) * mat(1, 0) * mat(2, 1) * mat(3, 3) - + mat(0, 0) * mat(1, 2) * mat(2, 1) * mat(3, 3) - + mat(0, 1) * mat(1, 0) * mat(2, 2) * mat(3, 3) + + mat(0, 0) * mat(1, 1) * mat(2, 2) * mat(3, 3); + + if (det == (T)0) { + return result; + } + + result(0, 0) = mat(1, 2) * mat(2, 3) * mat(3, 1) - + mat(1, 3) * mat(2, 2) * mat(3, 1) + + mat(1, 3) * mat(2, 1) * mat(3, 2) - + mat(1, 1) * mat(2, 3) * mat(3, 2) - + mat(1, 2) * mat(2, 1) * mat(3, 3) + + mat(1, 1) * mat(2, 2) * mat(3, 3); + + result(0, 1) = mat(0, 3) * mat(2, 2) * mat(3, 1) - + mat(0, 2) * mat(2, 3) * mat(3, 1) - + mat(0, 3) * mat(2, 1) * mat(3, 2) + + mat(0, 1) * mat(2, 3) * mat(3, 2) + + mat(0, 2) * mat(2, 1) * mat(3, 3) - + mat(0, 1) * mat(2, 2) * mat(3, 3); + + result(0, 2) = mat(0, 2) * mat(1, 3) * mat(3, 1) - + mat(0, 3) * mat(1, 2) * mat(3, 1) + + mat(0, 3) * mat(1, 1) * mat(3, 2) - + mat(0, 1) * mat(1, 3) * mat(3, 2) - + mat(0, 2) * mat(1, 1) * mat(3, 3) + + mat(0, 1) * mat(1, 2) * mat(3, 3); + + result(0, 3) = mat(0, 3) * mat(1, 2) * mat(2, 1) - + mat(0, 2) * mat(1, 3) * mat(2, 1) - + mat(0, 3) * mat(1, 1) * mat(2, 2) + + mat(0, 1) * mat(1, 3) * mat(2, 2) + + mat(0, 2) * mat(1, 1) * mat(2, 3) - + mat(0, 1) * mat(1, 2) * mat(2, 3); + + result(1, 0) = mat(1, 3) * mat(2, 2) * mat(3, 0) - + mat(1, 2) * mat(2, 3) * mat(3, 0) - + mat(1, 3) * mat(2, 0) * mat(3, 2) + + mat(1, 0) * mat(2, 3) * mat(3, 2) + + mat(1, 2) * mat(2, 0) * mat(3, 3) - + mat(1, 0) * mat(2, 2) * mat(3, 3); + + result(1, 1) = mat(0, 2) * mat(2, 3) * mat(3, 0) - + mat(0, 3) * mat(2, 2) * mat(3, 0) + + mat(0, 3) * mat(2, 0) * mat(3, 2) - + mat(0, 0) * mat(2, 3) * mat(3, 2) - + mat(0, 2) * mat(2, 0) * mat(3, 3) + + mat(0, 0) * mat(2, 2) * mat(3, 3); + + result(1, 2) = mat(0, 3) * mat(1, 2) * mat(3, 0) - + mat(0, 2) * mat(1, 3) * mat(3, 0) - + mat(0, 3) * mat(1, 0) * mat(3, 2) + + mat(0, 0) * mat(1, 3) * mat(3, 2) + + mat(0, 2) * mat(1, 0) * mat(3, 3) - + mat(0, 0) * mat(1, 2) * mat(3, 3); + + result(1, 3) = mat(0, 2) * mat(1, 3) * mat(2, 0) - + mat(0, 3) * mat(1, 2) * mat(2, 0) + + mat(0, 3) * mat(1, 0) * mat(2, 2) - + mat(0, 0) * mat(1, 3) * mat(2, 2) - + mat(0, 2) * mat(1, 0) * mat(2, 3) + + mat(0, 0) * mat(1, 2) * mat(2, 3); + + result(2, 0) = mat(1, 1) * mat(2, 3) * mat(3, 0) - + mat(1, 3) * mat(2, 1) * mat(3, 0) + + mat(1, 3) * mat(2, 0) * mat(3, 1) - + mat(1, 0) * mat(2, 3) * mat(3, 1) - + mat(1, 1) * mat(2, 0) * mat(3, 3) + + mat(1, 0) * mat(2, 1) * mat(3, 3); + + result(2, 1) = mat(0, 3) * mat(2, 1) * mat(3, 0) - + mat(0, 1) * mat(2, 3) * mat(3, 0) - + mat(0, 3) * mat(2, 0) * mat(3, 1) + + mat(0, 0) * mat(2, 3) * mat(3, 1) + + mat(0, 1) * mat(2, 0) * mat(3, 3) - + mat(0, 0) * mat(2, 1) * mat(3, 3); + + result(2, 2) = mat(0, 1) * mat(1, 3) * mat(3, 0) - + mat(0, 3) * mat(1, 1) * mat(3, 0) + + mat(0, 3) * mat(1, 0) * mat(3, 1) - + mat(0, 0) * mat(1, 3) * mat(3, 1) - + mat(0, 1) * mat(1, 0) * mat(3, 3) + + mat(0, 0) * mat(1, 1) * mat(3, 3); + + result(2, 3) = mat(0, 3) * mat(1, 1) * mat(2, 0) - + mat(0, 1) * mat(1, 3) * mat(2, 0) - + mat(0, 3) * mat(1, 0) * mat(2, 1) + + mat(0, 0) * mat(1, 3) * mat(2, 1) + + mat(0, 1) * mat(1, 0) * mat(2, 3) - + mat(0, 0) * mat(1, 1) * mat(2, 3); + + result(3, 0) = mat(1, 2) * mat(2, 1) * mat(3, 0) - + mat(1, 1) * mat(2, 2) * mat(3, 0) - + mat(1, 2) * mat(2, 0) * mat(3, 1) + + mat(1, 0) * mat(2, 2) * mat(3, 1) + + mat(1, 1) * mat(2, 0) * mat(3, 2) - + mat(1, 0) * mat(2, 1) * mat(3, 2); + + result(3, 1) = mat(1, 1) * mat(2, 2) * mat(3, 0) - + mat(1, 2) * mat(2, 1) * mat(3, 0) + + mat(1, 2) * mat(2, 0) * mat(3, 1) - + mat(1, 0) * mat(2, 2) * mat(3, 1) - + mat(1, 1) * mat(2, 0) * mat(3, 2) + + mat(1, 0) * mat(2, 1) * mat(3, 2); + + result(3, 2) = mat(0, 2) * mat(1, 1) * mat(3, 0) - + mat(0, 1) * mat(1, 2) * mat(3, 0) - + mat(0, 2) * mat(1, 0) * mat(3, 1) + + mat(0, 0) * mat(1, 2) * mat(3, 1) + + mat(0, 1) * mat(1, 0) * mat(3, 2) - + mat(0, 0) * mat(1, 1) * mat(3, 2); + + result(3, 3) = mat(0, 1) * mat(1, 2) * mat(2, 0) - + mat(0, 2) * mat(1, 1) * mat(2, 0) + + mat(0, 2) * mat(1, 0) * mat(2, 1) - + mat(0, 0) * mat(1, 2) * mat(2, 1) - + mat(0, 1) * mat(1, 0) * mat(2, 2) + + mat(0, 0) * mat(1, 1) * mat(2, 2); + + return result * (1.0f / det); +} + +typedef VectorN<double, 2> Vec2d; +typedef VectorN<double, 3> Vec3d; +typedef VectorN<double, 4> Vec4d; +typedef MatrixN<double, 2> Mat2d; +typedef MatrixN<double, 3> Mat3d; +typedef MatrixN<double, 4> Mat4d; + +typedef VectorN<float, 2> Vec2f; +typedef VectorN<float, 3> Vec3f; +typedef VectorN<float, 4> Vec4f; +typedef MatrixN<float, 3> Mat3f; +typedef MatrixN<float, 4> Mat4f; + +template<class T> +class Quaternion +{ +public: + + Vec3d v; + T w; + + Quaternion () : v(0, 0, 0), w(0) {}; + Quaternion (const Quaternion<T>& q) : v(q.v), w(q.w) {}; + + Quaternion (const Vec3d& vec, T _w) : v(vec), w(_w) {}; + Quaternion (const Vec4d& vec) : v(vec[0], vec[1], vec[2]), w(vec[3]) {}; + Quaternion (T _x, T _y, T _z, T _w) : v(_x, _y, _z), w(_w) {}; + + inline void reset () { + v.zeros(); + w = (T) 0; + } + + inline Quaternion<T>& operator = (const Quaternion<T>& rhs) { + v = rhs.v; + w = rhs.w; + return *this; + } + + inline Quaternion<T> operator + (const Quaternion<T>& rhs) const { + const Quaternion<T>& lhs = *this; + return Quaternion<T>(lhs.v + rhs.v, lhs.w + rhs.w); + } + + inline Quaternion<T> operator - (const Quaternion<T>& rhs) const { + const Quaternion<T>& lhs = *this; + return Quaternion<T>(lhs.v - rhs.v, lhs.w - rhs.w); + } + + inline Quaternion<T> operator * (T rhs) const { + return Quaternion<T>(v * rhs, w * rhs); + } + + inline Quaternion<T> operator * (const Quaternion<T>& rhs) const { + const Quaternion<T>& lhs = *this; + return Quaternion<T>(lhs.w * rhs.v[0] + lhs.v[0] * rhs.w + lhs.v[1] * rhs.v[2] - lhs.v[2] * rhs.v[1], + lhs.w * rhs.v[1] - lhs.v[0] * rhs.v[2] + lhs.v[1] * rhs.w + lhs.v[2] * rhs.v[0], + lhs.w * rhs.v[2] + lhs.v[0] * rhs.v[1] - lhs.v[1] * rhs.v[0] + lhs.v[2] * rhs.w, + lhs.w * rhs.w - lhs.v[0] * rhs.v[0] - lhs.v[1] * rhs.v[1] - lhs.v[2] * rhs.v[2]); + } + + /* + -------- + / -- + |Qr| = \/ Qr.Qr + */ + inline T magnitude () const { + return (T) sqrtf(w * w + v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + } + + inline void normalize () + { + T length = magnitude (); + w = w / length; + v = v / length; + } + + inline Quaternion<T> conjugate (const Quaternion<T>& quat) const { + return Quaternion<T>(-quat.v, quat.w); + } + + inline Quaternion<T> inverse (const Quaternion<T>& quat) const { + return conjugate(quat) * ( 1.0f / magnitude(quat)); + } + + inline Quaternion<T> lerp (T weight, const Quaternion<T>& quat) const { + return Quaternion<T>(v.lerp(weight, quat.v), (1 - weight) * w + weight * quat.w); + } + + inline Quaternion<T> slerp(T r, const Quaternion<T>& quat) const { + Quaternion<T> ret; + T cos_theta = w * quat.w + v[0] * quat.v[0] + v[1] * quat.v[1] + v[2] * quat.v[2]; + T theta = (T) acos(cos_theta); + if (fabs(theta) < FLT_EPSILON) + { + ret = *this; + } + else + { + T sin_theta = (T) sqrt(1.0 - cos_theta * cos_theta); + if (fabs(sin_theta) < FLT_EPSILON) + { + ret.w = 0.5 * w + 0.5 * quat.w; + ret.v = v.lerp(0.5, quat.v); + } + else + { + T r0 = (T) sin((1.0 - r) * theta) / sin_theta; + T r1 = (T) sin(r * theta) / sin_theta; + + ret.w = w * r0 + quat.w * r1; + ret.v[0] = v[0] * r0 + quat.v[0] * r1; + ret.v[1] = v[1] * r0 + quat.v[1] * r1; + ret.v[2] = v[2] * r0 + quat.v[2] * r1; + } + } + return ret; + } + + static Quaternion<T> create_quaternion (Vec3d axis, T angle_rad) { + T theta_over_two = angle_rad / (T) 2.0; + T sin_theta_over_two = std::sin(theta_over_two); + T cos_theta_over_two = std::cos(theta_over_two); + return Quaternion<T>(axis * sin_theta_over_two, cos_theta_over_two); + } + + static Quaternion<T> create_quaternion (Vec3d euler) { + return create_quaternion(Vec3d(1, 0, 0), euler[0]) * + create_quaternion(Vec3d(0, 1, 0), euler[1]) * + create_quaternion(Vec3d(0, 0, 1), euler[2]); + } + + static Quaternion<T> create_quaternion (const Mat3d& mat) { + Quaternion<T> q; + + T trace, s; + T diag1 = mat(0, 0); + T diag2 = mat(1, 1); + T diag3 = mat(2, 2); + + trace = diag1 + diag2 + diag3; + + if (trace >= FLT_EPSILON) + { + s = 2.0 * (T) sqrt(trace + 1.0); + q.w = 0.25 * s; + q.v[0] = (mat(2, 1) - mat(1, 2)) / s; + q.v[1] = (mat(0, 2) - mat(2, 0)) / s; + q.v[2] = (mat(1, 0) - mat(0, 1)) / s; + } + else + { + char max_diag = (diag1 > diag2) ? ((diag1 > diag3) ? 1 : 3) : ((diag2 > diag3) ? 2 : 3); + + if (max_diag == 1) + { + s = 2.0 * (T) sqrt(1.0 + mat(0, 0) - mat(1, 1) - mat(2, 2)); + q.w = (mat(2, 1) - mat(1, 2)) / s; + q.v[0] = 0.25 * s; + q.v[1] = (mat(0, 1) + mat(1, 0)) / s; + q.v[2] = (mat(0, 2) + mat(2, 0)) / s; + } + else if (max_diag == 2) + { + s = 2.0 * (T) sqrt(1.0 + mat(1, 1) - mat(0, 0) - mat(2, 2)); + q.w = (mat(0, 2) - mat(2, 0)) / s; + q.v[0] = (mat(0, 1) + mat(1, 0)) / s; + q.v[1] = 0.25 * s; + q.v[2] = (mat(1, 2) + mat(2, 1)) / s; + } + else + { + s = 2.0 * (T) sqrt(1.0 + mat(2, 2) - mat(0, 0) - mat(1, 1)); + q.w = (mat(1, 0) - mat(0, 1)) / s; + q.v[0] = (mat(0, 2) + mat(2, 0)) / s; + q.v[1] = (mat(1, 2) + mat(2, 1)) / s; + q.v[2] = 0.25 * s; + } + } + + return q; + } + + inline Vec4d rotation_axis () { + Vec4d rot_axis; + + T cos_theta_over_two = w; + rot_axis[4] = (T) std::acos( cos_theta_over_two ) * 2.0f; + + T sin_theta_over_two = (T) sqrt( 1.0 - cos_theta_over_two * cos_theta_over_two ); + if ( fabs( sin_theta_over_two ) < 0.0005 ) sin_theta_over_two = 1; + rot_axis[0] = v[0] / sin_theta_over_two; + rot_axis[1] = v[1] / sin_theta_over_two; + rot_axis[2] = v[2] / sin_theta_over_two; + + return rot_axis; + } + + /* + psi=atan2(2.*(Q(:,1).*Q(:,4)-Q(:,2).*Q(:,3)),(Q(:,4).^2-Q(:,1).^2-Q(:,2).^2+Q(:,3).^2)); + theta=asin(2.*(Q(:,1).*Q(:,3)+Q(:,2).*Q(:,4))); + phi=atan2(2.*(Q(:,3).*Q(:,4)-Q(:,1).*Q(:,2)),(Q(:,4).^2+Q(:,1).^2-Q(:,2).^2-Q(:,3).^2)); + */ + inline Vec3d euler_angles () { + Vec3d euler; + + // atan2(2*(qx*qw-qy*qz) , qw2-qx2-qy2+qz2) + euler[0] = atan2(2 * (v[0] * w - v[1] * v[2]), + w * w - v[0] * v[0] - v[1] * v[1] + v[2] * v[2]); + + // asin(2*(qx*qz + qy*qw) + euler[1] = asin(2 * (v[0] * v[2] + v[1] * w)); + + // atan2(2*(qz*qw- qx*qy) , qw2 + qx2 - qy2 - qz2) + euler[2] = atan2(2 * (v[2] * w - v[0] * v[1]), + w * w + v[0] * v[0] - v[1] * v[1] - v[2] * v[2]); + + return euler; + } + + inline Mat3d rotation_matrix () { + Mat3d mat; + + T xx = v[0] * v[0]; + T xy = v[0] * v[1]; + T xz = v[0] * v[2]; + T xw = v[0] * w; + + T yy = v[1] * v[1]; + T yz = v[1] * v[2]; + T yw = v[1] * w; + + T zz = v[2] * v[2]; + T zw = v[2] * w; + + mat(0, 0) = 1 - 2 * (yy + zz); + mat(0, 1) = 2 * (xy - zw); + mat(0, 2) = 2 * (xz + yw); + mat(1, 0) = 2 * (xy + zw); + mat(1, 1) = 1 - 2 * (xx + zz); + mat(1, 2) = 2 * (yz - xw); + mat(2, 0) = 2 * (xz - yw); + mat(2, 1) = 2 * (yz + xw); + mat(2, 2) = 1 - 2 * (xx + yy); + + return mat; + } +}; + + +typedef Quaternion<double> Quaternd; + +} + +#endif //XCAM_VECTOR_MATRIX_H diff --git a/xcore/video_buffer.cpp b/xcore/video_buffer.cpp new file mode 100644 index 0000000..65e923a --- /dev/null +++ b/xcore/video_buffer.cpp @@ -0,0 +1,149 @@ +/* + * video_buffer.cpp - video buffer base + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "video_buffer.h" +#include <linux/videodev2.h> + +namespace XCam { + +VideoBufferPlanarInfo::VideoBufferPlanarInfo () +{ + width = 0; + height = 0; + pixel_bytes = 0; +} + +VideoBufferInfo::VideoBufferInfo () +{ + format = 0; + color_bits = 8; + width = 0; + height = 0; + aligned_width = 0; + aligned_height = 0; + size = 0; + components = 0; + xcam_mem_clear (strides); + xcam_mem_clear (offsets); +} + +bool +VideoBufferInfo::init ( + uint32_t format, + uint32_t width, uint32_t height, + uint32_t aligned_width, uint32_t aligned_height, + uint32_t size) +{ + + XCamVideoBufferInfo *info = this; + + return (xcam_video_buffer_info_reset ( + info, format, width, height, aligned_width, aligned_height, size) == XCAM_RETURN_NO_ERROR); +} + +bool +VideoBufferInfo::is_valid () const +{ + return format && aligned_width && aligned_height && size; +} + +bool +VideoBufferInfo::get_planar_info ( + VideoBufferPlanarInfo &planar, const uint32_t index) const +{ + const XCamVideoBufferInfo *info = this; + XCamVideoBufferPlanarInfo *planar_info = &planar; + return (xcam_video_buffer_get_planar_info (info, planar_info, index) == XCAM_RETURN_NO_ERROR); +} + +VideoBuffer::~VideoBuffer () +{ + clear_attached_buffers (); + clear_all_metadata (); + _parent.release (); +} + +bool +VideoBuffer::attach_buffer (const SmartPtr<VideoBuffer>& buf) +{ + _attached_bufs.push_back (buf); + return true; +} + +bool +VideoBuffer::detach_buffer (const SmartPtr<VideoBuffer>& buf) +{ + for (VideoBufferList::iterator iter = _attached_bufs.begin (); + iter != _attached_bufs.end (); ++iter) { + SmartPtr<VideoBuffer>& current = *iter; + if (current.ptr () == buf.ptr ()) { + _attached_bufs.erase (iter); + return true; + } + } + + //not found + return false; +} + +bool +VideoBuffer::copy_attaches (const SmartPtr<VideoBuffer>& buf) +{ + _attached_bufs.insert ( + _attached_bufs.end (), buf->_attached_bufs.begin (), buf->_attached_bufs.end ()); + return true; +} + +void +VideoBuffer::clear_attached_buffers () +{ + _attached_bufs.clear (); +} + +bool +VideoBuffer::add_metadata (const SmartPtr<MetaData>& data) +{ + _metadata_list.push_back (data); + return true; +} + +bool +VideoBuffer::remove_metadata (const SmartPtr<MetaData>& data) +{ + for (MetaDataList::iterator iter = _metadata_list.begin (); + iter != _metadata_list.end (); ++iter) { + SmartPtr<MetaData>& current = *iter; + if (current.ptr () == data.ptr ()) { + _metadata_list.erase (iter); + return true; + } + } + + //not found + return false; +} + +void +VideoBuffer::clear_all_metadata () +{ + _metadata_list.clear (); +} + +}; diff --git a/xcore/video_buffer.h b/xcore/video_buffer.h new file mode 100644 index 0000000..f740c87 --- /dev/null +++ b/xcore/video_buffer.h @@ -0,0 +1,152 @@ +/* + * video_buffer.h - video buffer base + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_VIDEO_BUFFER_H +#define XCAM_VIDEO_BUFFER_H + +#include <xcam_std.h> +#include <meta_data.h> +#include <base/xcam_buffer.h> +#include <list> + +namespace XCam { + +class VideoBuffer; +typedef std::list<SmartPtr<VideoBuffer>> VideoBufferList; + +struct VideoBufferPlanarInfo + : XCamVideoBufferPlanarInfo +{ + VideoBufferPlanarInfo (); +}; + +struct VideoBufferInfo + : XCamVideoBufferInfo +{ + VideoBufferInfo (); + bool init ( + uint32_t format, + uint32_t width, uint32_t height, + uint32_t aligned_width = 0, uint32_t aligned_height = 0, uint32_t size = 0); + + bool get_planar_info ( + VideoBufferPlanarInfo &planar, const uint32_t index = 0) const; + + bool is_valid () const; +}; + +class VideoBuffer { +public: + explicit VideoBuffer (int64_t timestamp = InvalidTimestamp) + : _timestamp (timestamp) + {} + explicit VideoBuffer (const VideoBufferInfo &info, int64_t timestamp = InvalidTimestamp) + : _videoinfo (info) + , _timestamp (timestamp) + {} + virtual ~VideoBuffer (); + + void set_parent (const SmartPtr<VideoBuffer> &parent) { + _parent = parent; + } + + virtual uint8_t *map () = 0; + virtual bool unmap () = 0; + virtual int get_fd () = 0; + + const VideoBufferInfo & get_video_info () const { + return _videoinfo; + } + int64_t get_timestamp () const { + return _timestamp; + } + + void set_video_info (const VideoBufferInfo &info) { + _videoinfo = info; + } + + void set_timestamp (int64_t timestamp) { + _timestamp = timestamp; + } + + uint32_t get_size () const { + return _videoinfo.size; + } + + bool attach_buffer (const SmartPtr<VideoBuffer>& buf); + bool detach_buffer (const SmartPtr<VideoBuffer>& buf); + bool copy_attaches (const SmartPtr<VideoBuffer>& buf); + void clear_attached_buffers (); + + template <typename BufType> + SmartPtr<BufType> find_typed_attach (); + + bool add_metadata (const SmartPtr<MetaData>& data); + bool remove_metadata (const SmartPtr<MetaData>& data); + void clear_all_metadata (); + + template <typename MetaType> + SmartPtr<MetaType> find_typed_metadata (); + +private: + XCAM_DEAD_COPY (VideoBuffer); + +protected: + VideoBufferList _attached_bufs; + MetaDataList _metadata_list; + +private: + VideoBufferInfo _videoinfo; + int64_t _timestamp; // in microseconds + + SmartPtr<VideoBuffer> _parent; +}; + +template <typename BufType> +SmartPtr<BufType> VideoBuffer::find_typed_attach () +{ + for (VideoBufferList::iterator iter = _attached_bufs.begin (); + iter != _attached_bufs.end (); ++iter) { + SmartPtr<BufType> buf = (*iter).dynamic_cast_ptr<BufType> (); + if (buf.ptr ()) + return buf; + } + + return NULL; +} + +template <typename MetaType> +SmartPtr<MetaType> VideoBuffer::find_typed_metadata () +{ + for (MetaDataList::iterator iter = _metadata_list.begin (); + iter != _metadata_list.end (); ++iter) { + SmartPtr<MetaType> buf = (*iter).dynamic_cast_ptr<MetaType> (); + if (buf.ptr ()) + return buf; + } + + return NULL; +} + +XCamVideoBuffer *convert_to_external_buffer (const SmartPtr<VideoBuffer> &buf); + +}; + +#endif //XCAM_VIDEO_BUFFER_H
\ No newline at end of file diff --git a/xcore/worker.cpp b/xcore/worker.cpp new file mode 100644 index 0000000..6d8a7ab --- /dev/null +++ b/xcore/worker.cpp @@ -0,0 +1,137 @@ +/* + * worker.cpp - worker implementation + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "worker.h" + +namespace XCam { + +Worker::Worker (const char *name, const SmartPtr<Callback> &cb) + : _name (NULL) + , _callback (cb) +{ + if (name) + _name = strndup (name, XCAM_MAX_STR_SIZE); +} + +Worker::~Worker () +{ + xcam_mem_clear (_name); +} + +bool +Worker::set_name (const char *name) +{ + XCAM_FAIL_RETURN ( + ERROR, name, + false, "worker set name failed with parameter NULL"); + + XCAM_FAIL_RETURN ( + ERROR, !_name, false, + "worker(%s) set name(%s) failed, already got a name", XCAM_STR (get_name ()), XCAM_STR (name)); + + _name = strndup (name, XCAM_MAX_STR_SIZE); + return true; +} + +bool +Worker::set_callback (const SmartPtr<Worker::Callback> &callback) +{ + XCAM_ASSERT (!_callback.ptr ()); + XCAM_FAIL_RETURN ( + ERROR, !_callback.ptr (), + false, "worker(%s) callback was already set", XCAM_STR(get_name ())); + + _callback = callback; + return true; +} + +void +Worker::status_check (const SmartPtr<Worker::Arguments> &args, const XCamReturn error) +{ + if (_callback.ptr ()) + _callback->work_status (this, args, error); +} + +#if ENABLE_FUNC_OBJ +bool +Worker::set_func_obj (const SmartPtr<FuncObj> &obj) +{ + XCAM_FAIL_RETURN ( + ERROR, !_func_obj.ptr (), + false, "worker(%s) func_obj was already set", XCAM_STR(get_name ())); + _func_obj = obj; + return true; +} + +XCamReturn +Worker::work (const SmartPtr<Worker::Arguments> &args) +{ + XCamReturn ret = _func_obj->impl(args); + status_check (args, ret); + return ret; +} +#endif +}; + +namespace UnitTestWorker { +using namespace XCam; + +struct UTArguments : Worker::Arguments { + uint32_t data; + UTArguments () : data (5) {} +}; + +class UnitTestWorker: public Worker { +public: + UnitTestWorker () : Worker("UnitTestWorker") {} + XCamReturn work (const SmartPtr<Worker::Arguments> &args) { + SmartPtr<UTArguments> ut_args = args.dynamic_cast_ptr<UTArguments> (); + XCAM_ASSERT (ut_args.ptr ()); + printf ("unit test worker runing on data:%d\n", ut_args->data); + status_check (args, XCAM_RETURN_NO_ERROR); + return XCAM_RETURN_NO_ERROR; + } + XCamReturn stop () { + return XCAM_RETURN_NO_ERROR; + } +}; + +class UintTestHandler { +public: + XCamReturn work_done ( + const SmartPtr<Worker> &w, const SmartPtr<Worker::Arguments> &, + const XCamReturn error) { + printf ("worker(%s) done, error:%d", + XCAM_STR(w->get_name ()), error); + return error; + } +}; + +DECLARE_WORK_CALLBACK (UTCbBridge, UintTestHandler, work_done); + +void test_base_worker() +{ + SmartPtr<UintTestHandler> handler = new UintTestHandler; + SmartPtr<Worker> worker = new UnitTestWorker; + worker->set_callback (new UTCbBridge (handler)); + worker->work (new UTArguments); +} + +}; diff --git a/xcore/worker.h b/xcore/worker.h new file mode 100644 index 0000000..16807c1 --- /dev/null +++ b/xcore/worker.h @@ -0,0 +1,108 @@ +/* + * worker.h - worker class interface + * + * Copyright (c) 2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_WORKER_H +#define XCAM_WORKER_H + +#include <xcam_std.h> + +#define ENABLE_FUNC_OBJ 0 + +#define DECLARE_WORK_CALLBACK(CbClass, Handler, mem_func) \ + class CbClass : public ::XCam::Worker::Callback { \ + private: ::XCam::SmartPtr<Handler> _h; \ + public: CbClass (const ::XCam::SmartPtr<Handler> &h) { _h = h;} \ + protected: void work_status ( \ + const ::XCam::SmartPtr<::XCam::Worker> &worker, \ + const ::XCam::SmartPtr<::XCam::Worker::Arguments> &args, \ + const XCamReturn error) { \ + _h->mem_func (worker, args, error); } \ + } + +namespace XCam { + +class Worker + : public RefObj +{ +public: + struct Arguments + { + Arguments () {} + virtual ~Arguments () {} + + XCAM_DEAD_COPY (Arguments); + }; + + class Callback { + public: + Callback () {} + virtual ~Callback () {} + + virtual void work_status ( + const SmartPtr<Worker> &worker, const SmartPtr<Arguments> &args, const XCamReturn error) = 0; + + private: + XCAM_DEAD_COPY (Callback); + }; + +#if ENABLE_FUNC_OBJ + class FuncObj { + public: + virtual ~FuncObj () {} + virtual XCamReturn impl (const SmartPtr<Arguments> &args) = 0; + + private: + XCAM_DEAD_COPY (FuncObj); + }; +#endif + +protected: + explicit Worker (const char *name, const SmartPtr<Callback> &cb = NULL); + +public: + virtual ~Worker (); + bool set_name (const char *name); + const char *get_name () const { + return _name; + } +#if ENABLE_FUNC_OBJ + bool set_func_obj (const SmartPtr<FuncObj> &obj); +#endif + bool set_callback (const SmartPtr<Callback> &callback); + + virtual XCamReturn work (const SmartPtr<Arguments> &args) = 0; + virtual XCamReturn stop () = 0; + +protected: + virtual void status_check (const SmartPtr<Arguments> &args, const XCamReturn error); + +private: + XCAM_DEAD_COPY (Worker); + +private: + char *_name; + SmartPtr<Callback> _callback; +#if ENABLE_FUNC_OBJ + SmartPtr<FuncObj> _func_obj; +#endif +}; + +} +#endif //XCAM_WORKER_H diff --git a/xcore/x3a_analyzer.cpp b/xcore/x3a_analyzer.cpp new file mode 100644 index 0000000..436d54a --- /dev/null +++ b/xcore/x3a_analyzer.cpp @@ -0,0 +1,423 @@ +/* + * x3a_analyzer.cpp - 3a analyzer + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "xcam_analyzer.h" +#include "x3a_analyzer.h" +#include "x3a_stats_pool.h" + +namespace XCam { + +X3aAnalyzer::X3aAnalyzer (const char *name) + : XAnalyzer (name) + , _brightness_level_param (0.0) + , _ae_handler (NULL) + , _awb_handler (NULL) + , _af_handler (NULL) + , _common_handler (NULL) +{ +} + +X3aAnalyzer::~X3aAnalyzer() +{ +} + +XCamReturn +X3aAnalyzer::create_handlers () +{ + SmartPtr<AeHandler> ae_handler; + SmartPtr<AwbHandler> awb_handler; + SmartPtr<AfHandler> af_handler; + SmartPtr<CommonHandler> common_handler; + + if (_ae_handler.ptr() && _awb_handler.ptr() && + _af_handler.ptr() && _common_handler.ptr()) + return XCAM_RETURN_NO_ERROR; + + ae_handler = create_ae_handler (); + awb_handler = create_awb_handler (); + af_handler = create_af_handler (); + common_handler = create_common_handler (); + + if (!ae_handler.ptr() || !awb_handler.ptr() || !af_handler.ptr() || !common_handler.ptr()) { + XCAM_LOG_WARNING ("create handlers failed"); + return XCAM_RETURN_ERROR_MEM; + } + + _ae_handler = ae_handler; + _awb_handler = awb_handler; + _af_handler = af_handler; + _common_handler = common_handler; + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +X3aAnalyzer::release_handlers () +{ + _ae_handler.release (); + _awb_handler.release (); + _af_handler.release (); + _common_handler.release (); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +X3aAnalyzer::configure () +{ + return configure_3a (); +} + +XCamReturn +X3aAnalyzer::analyze (const SmartPtr<VideoBuffer> &buffer) +{ + SmartPtr<X3aStats> stats = buffer.dynamic_cast_ptr<X3aStats> (); + + return analyze_3a_statistics (stats); +} + +XCamReturn +X3aAnalyzer::push_3a_stats (const SmartPtr<X3aStats> &stats) +{ + return XAnalyzer::push_buffer (stats); +} + + +XCamReturn +X3aAnalyzer::analyze_3a_statistics (SmartPtr<X3aStats> &stats) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + X3aResultList results; + + ret = pre_3a_analyze (stats); + if (ret != XCAM_RETURN_NO_ERROR) { + notify_calculation_failed( + NULL, stats->get_timestamp (), "pre 3a analyze failed"); + return ret; + } + + ret = _ae_handler->analyze (results); + if (ret != XCAM_RETURN_NO_ERROR) { + notify_calculation_failed( + _ae_handler.ptr(), stats->get_timestamp (), "ae calculation failed"); + return ret; + } + + ret = _awb_handler->analyze (results); + if (ret != XCAM_RETURN_NO_ERROR) { + notify_calculation_failed( + _awb_handler.ptr(), stats->get_timestamp (), "awb calculation failed"); + return ret; + } + + ret = _af_handler->analyze (results); + if (ret != XCAM_RETURN_NO_ERROR) { + notify_calculation_failed( + _af_handler.ptr(), stats->get_timestamp (), "af calculation failed"); + return ret; + } + + ret = _common_handler->analyze (results); + if (ret != XCAM_RETURN_NO_ERROR) { + notify_calculation_failed( + _common_handler.ptr(), stats->get_timestamp (), "3a other calculation failed"); + return ret; + } + + ret = post_3a_analyze (results); + if (ret != XCAM_RETURN_NO_ERROR) { + notify_calculation_failed( + NULL, stats->get_timestamp (), "3a collect results failed"); + return ret; + } + + if (!results.empty ()) { + set_results_timestamp(results, stats->get_timestamp ()); + notify_calculation_done (results); + } + + return ret; +} + +/* AWB */ +bool +X3aAnalyzer::set_awb_mode (XCamAwbMode mode) +{ + XCAM_ASSERT (_awb_handler.ptr()); + return _awb_handler->set_mode (mode); +} + +bool +X3aAnalyzer::set_awb_speed (double speed) +{ + XCAM_ASSERT (_awb_handler.ptr()); + return _awb_handler->set_speed (speed); +} + +bool +X3aAnalyzer::set_awb_color_temperature_range (uint32_t cct_min, uint32_t cct_max) +{ + XCAM_ASSERT (_awb_handler.ptr()); + return _awb_handler->set_color_temperature_range (cct_min, cct_max); +} + +bool +X3aAnalyzer::set_awb_manual_gain (double gr, double r, double b, double gb) +{ + XCAM_ASSERT (_awb_handler.ptr()); + return _awb_handler->set_manual_gain (gr, r, b, gb); +} + +/* AE */ +bool +X3aAnalyzer::set_ae_mode (XCamAeMode mode) +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->set_mode (mode); +} + +bool +X3aAnalyzer::set_ae_metering_mode (XCamAeMeteringMode mode) +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->set_metering_mode (mode); +} + +bool +X3aAnalyzer::set_ae_window (XCam3AWindow *window, uint8_t count) +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->set_window (window, count); +} + +bool +X3aAnalyzer::set_ae_ev_shift (double ev_shift) +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->set_ev_shift (ev_shift); +} + +bool +X3aAnalyzer::set_ae_speed (double speed) +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->set_speed (speed); +} + +bool +X3aAnalyzer::set_ae_flicker_mode (XCamFlickerMode flicker) +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->set_flicker_mode (flicker); +} + +XCamFlickerMode +X3aAnalyzer::get_ae_flicker_mode () +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->get_flicker_mode (); +} + +uint64_t +X3aAnalyzer::get_ae_current_exposure_time () +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->get_current_exposure_time(); +} + +double +X3aAnalyzer::get_ae_current_analog_gain () +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->get_current_analog_gain (); +} + +bool +X3aAnalyzer::set_ae_manual_exposure_time (int64_t time_in_us) +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->set_manual_exposure_time (time_in_us); +} + +bool +X3aAnalyzer::set_ae_manual_analog_gain (double gain) +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->set_manual_analog_gain (gain); +} + +bool +X3aAnalyzer::set_ae_aperture (double fn) +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->set_aperture (fn); +} + +bool +X3aAnalyzer::set_ae_max_analog_gain (double max_gain) +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->set_max_analog_gain (max_gain); +} + +double +X3aAnalyzer::get_ae_max_analog_gain () +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->get_max_analog_gain(); +} + +bool +X3aAnalyzer::set_ae_exposure_time_range (int64_t min_time_in_us, int64_t max_time_in_us) +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->set_exposure_time_range (min_time_in_us, max_time_in_us); +} + +bool +X3aAnalyzer::get_ae_exposure_time_range (int64_t *min_time_in_us, int64_t *max_time_in_us) +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->get_exposure_time_range (min_time_in_us, max_time_in_us); +} + +/* DVS */ +bool +X3aAnalyzer::set_dvs (bool enable) +{ + XCAM_ASSERT (_common_handler.ptr()); + return _common_handler->set_dvs (enable); +} + +bool +X3aAnalyzer::set_gbce (bool enable) +{ + XCAM_ASSERT (_common_handler.ptr()); + return _common_handler->set_gbce (enable); +} + +bool +X3aAnalyzer::set_night_mode (bool enable) +{ + XCAM_ASSERT (_common_handler.ptr()); + return _common_handler->set_night_mode (enable); +} + +bool +X3aAnalyzer::set_color_effect (XCamColorEffect type) +{ + + XCAM_ASSERT (_common_handler.ptr()); + return _common_handler->set_color_effect (type); +} + +/* Picture quality */ +bool +X3aAnalyzer::set_noise_reduction_level (double level) +{ + XCAM_ASSERT (_common_handler.ptr()); + return _common_handler->set_noise_reduction_level (level); +} + +bool +X3aAnalyzer::set_temporal_noise_reduction_level (double level) +{ + XCAM_ASSERT (_common_handler.ptr()); + return _common_handler->set_temporal_noise_reduction_level (level); +} + +bool +X3aAnalyzer::set_manual_brightness (double level) +{ + XCAM_ASSERT (_common_handler.ptr()); + return _common_handler->set_manual_brightness (level); +} + +bool +X3aAnalyzer::set_manual_contrast (double level) +{ + XCAM_ASSERT (_common_handler.ptr()); + return _common_handler->set_manual_contrast (level); +} + +bool +X3aAnalyzer::set_manual_hue (double level) +{ + XCAM_ASSERT (_common_handler.ptr()); + return _common_handler->set_manual_hue (level); +} + +bool +X3aAnalyzer::set_manual_saturation (double level) +{ + XCAM_ASSERT (_common_handler.ptr()); + return _common_handler->set_manual_saturation (level); +} + +bool +X3aAnalyzer::set_manual_sharpness (double level) +{ + XCAM_ASSERT (_common_handler.ptr()); + return _common_handler->set_manual_sharpness (level); +} + +bool +X3aAnalyzer::set_gamma_table (double *r_table, double *g_table, double *b_table) +{ + XCAM_ASSERT (_common_handler.ptr()); + return _common_handler->set_gamma_table (r_table, g_table, b_table); +} + +bool +X3aAnalyzer::set_parameter_brightness(double level) +{ + _brightness_level_param = level; + return true; +} + +bool +X3aAnalyzer::update_awb_parameters (const XCamAwbParam ¶ms) +{ + XCAM_ASSERT (_awb_handler.ptr()); + return _awb_handler->update_parameters (params); +} + +bool +X3aAnalyzer::update_common_parameters (const XCamCommonParam ¶ms) +{ + XCAM_ASSERT (_common_handler.ptr()); + return _common_handler->update_parameters (params); +} + +bool +X3aAnalyzer::update_ae_parameters (const XCamAeParam ¶ms) +{ + XCAM_ASSERT (_ae_handler.ptr()); + return _ae_handler->update_parameters (params); +} + +bool +X3aAnalyzer::update_af_parameters (const XCamAfParam ¶ms) +{ + XCAM_ASSERT (_af_handler.ptr()); + return _af_handler->update_parameters (params); +} + +}; diff --git a/xcore/x3a_analyzer.h b/xcore/x3a_analyzer.h new file mode 100644 index 0000000..ab5a62f --- /dev/null +++ b/xcore/x3a_analyzer.h @@ -0,0 +1,144 @@ +/* + * x3a_analyzer.h - 3a analyzer + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_3A_ANALYZER_H +#define XCAM_3A_ANALYZER_H + +#include <xcam_std.h> +#include <xcam_analyzer.h> +#include <handler_interface.h> + +namespace XCam { + +class X3aStats; +class AnalyzerThread; +class VideoBuffer; + +class X3aAnalyzer + : public XAnalyzer +{ + friend class AnalyzerThread; +public: + explicit X3aAnalyzer (const char *name = NULL); + virtual ~X3aAnalyzer (); + + /* analyze 3A statistics */ + XCamReturn push_3a_stats (const SmartPtr<X3aStats> &stats); + + /* AWB */ + bool set_awb_mode (XCamAwbMode mode); + bool set_awb_speed (double speed); + bool set_awb_color_temperature_range (uint32_t cct_min, uint32_t cct_max); + bool set_awb_manual_gain (double gr, double r, double b, double gb); + + /* AE */ + bool set_ae_mode (XCamAeMode mode); + bool set_ae_metering_mode (XCamAeMeteringMode mode); + bool set_ae_window (XCam3AWindow *window, uint8_t count = 1); + bool set_ae_ev_shift (double ev_shift); + bool set_ae_speed (double speed); + bool set_ae_flicker_mode (XCamFlickerMode flicker); + + XCamFlickerMode get_ae_flicker_mode (); + uint64_t get_ae_current_exposure_time (); + double get_ae_current_analog_gain (); + + bool set_ae_manual_exposure_time (int64_t time_in_us); + bool set_ae_manual_analog_gain (double gain); + bool set_ae_aperture (double fn); + bool set_ae_max_analog_gain (double max_gain); + double get_ae_max_analog_gain (); + bool set_ae_exposure_time_range (int64_t min_time_in_us, int64_t max_time_in_us); + bool get_ae_exposure_time_range (int64_t *min_time_in_us, int64_t *max_time_in_us); + + /* DVS */ + bool set_dvs (bool enable); + bool set_gbce (bool enable); + bool set_night_mode (bool enable); + + /* Picture quality */ + bool set_noise_reduction_level (double level); + bool set_temporal_noise_reduction_level (double level); + bool set_manual_brightness (double level); + bool set_manual_contrast (double level); + bool set_manual_hue (double level); + bool set_manual_saturation (double level); + bool set_manual_sharpness (double level); + bool set_gamma_table (double *r_table, double *g_table, double *b_table); + bool set_color_effect(XCamColorEffect effect); + bool set_parameter_brightness (double level); + + // whole update of parameters + bool update_awb_parameters (const XCamAwbParam ¶ms); + bool update_ae_parameters (const XCamAeParam ¶ms); + bool update_af_parameters (const XCamAfParam ¶ms); + bool update_common_parameters (const XCamCommonParam ¶ms); + + SmartPtr<AeHandler> get_ae_handler () { + return _ae_handler; + } + SmartPtr<AwbHandler> get_awb_handler () { + return _awb_handler; + } + SmartPtr<AfHandler> get_af_handler () { + return _af_handler; + } + SmartPtr<CommonHandler> get_common_handler () { + return _common_handler; + } + +protected: + /* virtual function list */ + virtual XCamReturn create_handlers (); + virtual XCamReturn release_handlers (); + virtual XCamReturn configure (); + virtual XCamReturn analyze (const SmartPtr<VideoBuffer> &buffer); + + virtual SmartPtr<AeHandler> create_ae_handler () = 0; + virtual SmartPtr<AwbHandler> create_awb_handler () = 0; + virtual SmartPtr<AfHandler> create_af_handler () = 0; + virtual SmartPtr<CommonHandler> create_common_handler () = 0; + virtual XCamReturn internal_init (uint32_t width, uint32_t height, double framerate) = 0; + virtual XCamReturn internal_deinit () = 0; + + // in 3a stats thread + virtual XCamReturn configure_3a () = 0; + // @param[in] stats, 3a statistics prepared + virtual XCamReturn pre_3a_analyze (SmartPtr<X3aStats> &stats) = 0; + // @param[out] results, new 3a results merged into \c results + virtual XCamReturn post_3a_analyze (X3aResultList &results) = 0; + +private: + XCamReturn analyze_3a_statistics (SmartPtr<X3aStats> &stats); + + XCAM_DEAD_COPY (X3aAnalyzer); + +protected: + double _brightness_level_param; + +private: + SmartPtr<AeHandler> _ae_handler; + SmartPtr<AwbHandler> _awb_handler; + SmartPtr<AfHandler> _af_handler; + SmartPtr<CommonHandler> _common_handler; +}; + +} +#endif //XCAM_3A_ANALYZER_H diff --git a/xcore/x3a_analyzer_manager.cpp b/xcore/x3a_analyzer_manager.cpp new file mode 100644 index 0000000..c716624 --- /dev/null +++ b/xcore/x3a_analyzer_manager.cpp @@ -0,0 +1,113 @@ +/* + * x3a_analyzer_manager.cpp - analyzer manager + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "x3a_analyzer_manager.h" +#include "x3a_analyzer_simple.h" +#include <sys/types.h> +#include <dirent.h> + +namespace XCam { + +#define XCAM_DEFAULT_3A_LIB_DIR "/usr/lib/xcam/plugins/3a" + +SmartPtr<X3aAnalyzerManager> X3aAnalyzerManager::_instance(NULL); +Mutex X3aAnalyzerManager::_mutex; + +SmartPtr<X3aAnalyzerManager> +X3aAnalyzerManager::instance() +{ + SmartLock lock(_mutex); + if (_instance.ptr()) + return _instance; + _instance = new X3aAnalyzerManager; + return _instance; +} + +X3aAnalyzerManager::X3aAnalyzerManager () +{ + XCAM_LOG_DEBUG ("X3aAnalyzerManager construction"); +} +X3aAnalyzerManager::~X3aAnalyzerManager () +{ + XCAM_LOG_DEBUG ("X3aAnalyzerManager destruction"); +} + +SmartPtr<X3aAnalyzer> +X3aAnalyzerManager::create_analyzer() +{ + SmartPtr<X3aAnalyzer> analyzer = find_analyzer(); + if (!analyzer.ptr()) + analyzer = new X3aAnalyzerSimple; + return analyzer; +} + +SmartPtr<X3aAnalyzer> +X3aAnalyzerManager::find_analyzer () +{ + char lib_path[512]; + const char *dir_path = NULL; + DIR *dir_3a = NULL; + struct dirent *dirent_3a = NULL; + SmartPtr<X3aAnalyzer> analyzer; + + dir_path = getenv ("XCAM_3A_LIB"); + if (!dir_path) { + dir_path = XCAM_DEFAULT_3A_LIB_DIR; + XCAM_LOG_INFO ("doesn't find environment=>XCAM_3A_LIB, change to default dir:%s", dir_path); + } + dir_3a = opendir (dir_path); + if (dir_3a) { + while ((dirent_3a = readdir (dir_3a)) != NULL) { + if (dirent_3a->d_type != DT_LNK && + dirent_3a->d_type != DT_REG) + continue; + snprintf (lib_path, sizeof(lib_path), "%s/%s", dir_path, dirent_3a->d_name); + analyzer = load_analyzer_from_binary (lib_path); + if (analyzer.ptr()) + break; + } + } + if (dir_3a) + closedir (dir_3a); + return analyzer; +} + +SmartPtr<X3aAnalyzer> +X3aAnalyzerManager::load_analyzer_from_binary (const char *path) +{ + SmartPtr<X3aAnalyzer> analyzer; + + XCAM_ASSERT (path); + + _loader.release (); + _loader = new DynamicAnalyzerLoader (path); + + SmartPtr<AnalyzerLoader> loader = _loader.dynamic_cast_ptr<AnalyzerLoader> (); + analyzer = _loader->load_analyzer (loader); + + if (analyzer.ptr ()) + return analyzer; + + XCAM_LOG_WARNING ("load 3A analyzer failed from: %s", path); + return NULL; +} + +}; + diff --git a/xcore/x3a_analyzer_manager.h b/xcore/x3a_analyzer_manager.h new file mode 100644 index 0000000..7dedcc8 --- /dev/null +++ b/xcore/x3a_analyzer_manager.h @@ -0,0 +1,57 @@ +/* + * x3a_analyzer_manager.h - analyzer manager + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_3A_ANALYZER_MANAGER_H +#define XCAM_3A_ANALYZER_MANAGER_H + +#include <xcam_std.h> +#include <x3a_analyzer.h> +#include <dynamic_analyzer_loader.h> + +namespace XCam { + +class DynamicAnalyzerLoader; + +class X3aAnalyzerManager +{ +protected: + explicit X3aAnalyzerManager (); +public: + virtual ~X3aAnalyzerManager (); + + static SmartPtr<X3aAnalyzerManager> instance(); + + virtual SmartPtr<X3aAnalyzer> create_analyzer(); + +private: + SmartPtr<X3aAnalyzer> find_analyzer (); + SmartPtr<X3aAnalyzer> load_analyzer_from_binary (const char *path); + +private: + XCAM_DEAD_COPY (X3aAnalyzerManager); + +private: + static SmartPtr<X3aAnalyzerManager> _instance; + static Mutex _mutex; + + SmartPtr<DynamicAnalyzerLoader> _loader; +}; +}; +#endif //XCAM_3A_ANALYZER_MANAGER_H diff --git a/xcore/x3a_analyzer_simple.cpp b/xcore/x3a_analyzer_simple.cpp new file mode 100644 index 0000000..896d2d0 --- /dev/null +++ b/xcore/x3a_analyzer_simple.cpp @@ -0,0 +1,280 @@ +/* + * x3a_analyzer_simple.cpp - a simple 3a analyzer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "x3a_analyzer_simple.h" + +namespace XCam { + +#define SIMPLE_MIN_TARGET_EXPOSURE_TIME 5000 //5ms +#define SIMPLE_MAX_TARGET_EXPOSURE_TIME 33000 //33ms +#define SIMPLE_DEFAULT_BLACK_LEVEL 0.05 + +class SimpleAeHandler + : public AeHandler +{ +public: + SimpleAeHandler (X3aAnalyzerSimple *analyzer) + : _analyzer (analyzer) + {} + ~SimpleAeHandler () {} + + virtual XCamReturn analyze (X3aResultList &output) { + return _analyzer->analyze_ae (output); + } +private: + X3aAnalyzerSimple *_analyzer; +}; + +class SimpleAwbHandler + : public AwbHandler +{ +public: + SimpleAwbHandler (X3aAnalyzerSimple *analyzer) + : _analyzer (analyzer) + {} + ~SimpleAwbHandler () {} + + virtual XCamReturn analyze (X3aResultList &output) { + return _analyzer->analyze_awb (output); + } +private: + X3aAnalyzerSimple *_analyzer; + +}; + +class SimpleAfHandler + : public AfHandler +{ +public: + SimpleAfHandler (X3aAnalyzerSimple *analyzer) + : _analyzer (analyzer) + {} + ~SimpleAfHandler () {} + + virtual XCamReturn analyze (X3aResultList &output) { + return _analyzer->analyze_af (output); + } + +private: + X3aAnalyzerSimple *_analyzer; +}; + +class SimpleCommonHandler + : public CommonHandler +{ +public: + SimpleCommonHandler (X3aAnalyzerSimple *analyzer) + : _analyzer (analyzer) + {} + ~SimpleCommonHandler () {} + + virtual XCamReturn analyze (X3aResultList &output) { + XCAM_UNUSED (output); + return XCAM_RETURN_NO_ERROR; + } + +private: + X3aAnalyzerSimple *_analyzer; +}; + +X3aAnalyzerSimple::X3aAnalyzerSimple () + : X3aAnalyzer ("X3aAnalyzerSimple") + , _last_target_exposure ((double)SIMPLE_MIN_TARGET_EXPOSURE_TIME) + , _is_ae_started (false) + , _ae_calculation_interval (0) +{ +} + +X3aAnalyzerSimple::~X3aAnalyzerSimple () +{ +} + +SmartPtr<AeHandler> +X3aAnalyzerSimple::create_ae_handler () +{ + SimpleAeHandler *handler = new SimpleAeHandler (this); + return handler; +} + +SmartPtr<AwbHandler> +X3aAnalyzerSimple::create_awb_handler () +{ + SimpleAwbHandler *handler = new SimpleAwbHandler (this); + return handler; +} + +SmartPtr<AfHandler> +X3aAnalyzerSimple::create_af_handler () +{ + SimpleAfHandler *handler = new SimpleAfHandler (this); + return handler; +} + +SmartPtr<CommonHandler> +X3aAnalyzerSimple::create_common_handler () +{ + SimpleCommonHandler *handler = new SimpleCommonHandler (this); + return handler; +} + +XCamReturn +X3aAnalyzerSimple::configure_3a () +{ + _is_ae_started = false; + _ae_calculation_interval = 0; + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +X3aAnalyzerSimple::pre_3a_analyze (SmartPtr<X3aStats> &stats) +{ + _current_stats = stats; + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +X3aAnalyzerSimple::post_3a_analyze (X3aResultList &results) +{ + _current_stats.release (); + + XCam3aResultBlackLevel black_level; + SmartPtr<X3aBlackLevelResult> bl_result = new X3aBlackLevelResult (XCAM_3A_RESULT_BLACK_LEVEL); + + xcam_mem_clear (black_level); + black_level.r_level = SIMPLE_DEFAULT_BLACK_LEVEL; + black_level.gr_level = SIMPLE_DEFAULT_BLACK_LEVEL; + black_level.gb_level = SIMPLE_DEFAULT_BLACK_LEVEL; + black_level.b_level = SIMPLE_DEFAULT_BLACK_LEVEL; + bl_result->set_standard_result (black_level); + results.push_back (bl_result); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +X3aAnalyzerSimple::analyze_awb (X3aResultList &output) +{ + const XCam3AStats *stats = _current_stats->get_stats (); + double sum_r = 0.0, sum_gr = 0.0, sum_gb = 0.0, sum_b = 0.0; + double avg_r = 0.0, avg_gr = 0.0, avg_gb = 0.0, avg_b = 0.0; + double target_avg = 0.0; + XCam3aResultWhiteBalance wb; + + xcam_mem_clear (wb); + XCAM_ASSERT (stats); + + // calculate avg r, gr, gb, b + for (uint32_t i = 0; i < stats->info.height; ++i) + for (uint32_t j = 0; j < stats->info.width; ++j) { + sum_r += (double)(stats->stats[i * stats->info.aligned_width + j].avg_r); + sum_gr += (double)(stats->stats[i * stats->info.aligned_width + j].avg_gr); + sum_gb += (double)(stats->stats[i * stats->info.aligned_width + j].avg_gb); + sum_b += (double)(stats->stats[i * stats->info.aligned_width + j].avg_b); + } + + avg_r = sum_r / (stats->info.width * stats->info.height); + avg_gr = sum_gr / (stats->info.width * stats->info.height); + avg_gb = sum_gb / (stats->info.width * stats->info.height); + avg_b = sum_b / (stats->info.width * stats->info.height); + + target_avg = (avg_gr + avg_gb) / 2; + wb.r_gain = target_avg / avg_r; + wb.b_gain = target_avg / avg_b; + wb.gr_gain = 1.0; + wb.gb_gain = 1.0; + + SmartPtr<X3aWhiteBalanceResult> result = new X3aWhiteBalanceResult (XCAM_3A_RESULT_WHITE_BALANCE); + result->set_standard_result (wb); + output.push_back (result); + + XCAM_LOG_DEBUG ("X3aAnalyzerSimple analyze awb, r:%f, gr:%f, gb:%f, b:%f", + wb.r_gain, wb.gr_gain, wb.gb_gain, wb.b_gain); + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +X3aAnalyzerSimple::analyze_ae (X3aResultList &output) +{ + static const uint32_t expect_y_mean = 110; + + const XCam3AStats *stats = _current_stats->get_stats (); + XCAM_FAIL_RETURN( + WARNING, + stats, + XCAM_RETURN_ERROR_UNKNOWN, + "failed to get XCam3AStats"); + + double sum_y = 0.0; + double target_exposure = 1.0; + SmartPtr<X3aExposureResult> result = new X3aExposureResult (XCAM_3A_RESULT_EXPOSURE); + XCam3aResultExposure exposure; + + xcam_mem_clear (exposure); + exposure.digital_gain = 1.0; + + if (!_is_ae_started) { + _last_target_exposure = SIMPLE_MIN_TARGET_EXPOSURE_TIME; + exposure.exposure_time = _last_target_exposure; + exposure.analog_gain = 1.0; + + result->set_standard_result (exposure); + output.push_back (result); + _is_ae_started = true; + return XCAM_RETURN_NO_ERROR; + } + + if (_ae_calculation_interval % 10 == 0) { + for (uint32_t i = 0; i < stats->info.height; ++i) + for (uint32_t j = 0; j < stats->info.width; ++j) { + sum_y += (double)(stats->stats[i * stats->info.aligned_width + j].avg_y); + } + sum_y /= (stats->info.width * stats->info.height); + target_exposure = (expect_y_mean / sum_y) * _last_target_exposure; + target_exposure = XCAM_MAX (target_exposure, SIMPLE_MIN_TARGET_EXPOSURE_TIME); + + if (target_exposure > SIMPLE_MAX_TARGET_EXPOSURE_TIME * 255) + target_exposure = SIMPLE_MAX_TARGET_EXPOSURE_TIME * 255; + + if (target_exposure > SIMPLE_MAX_TARGET_EXPOSURE_TIME) { + exposure.exposure_time = SIMPLE_MAX_TARGET_EXPOSURE_TIME; + exposure.analog_gain = target_exposure / exposure.exposure_time; + } else { + exposure.exposure_time = target_exposure; + exposure.analog_gain = 1.0; + } + + result->set_standard_result (exposure); + output.push_back (result); + _last_target_exposure = target_exposure; + } + + _ae_calculation_interval++; + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn X3aAnalyzerSimple::analyze_af (X3aResultList &output) +{ + XCAM_UNUSED (output); + return XCAM_RETURN_NO_ERROR; +} + +}; diff --git a/xcore/x3a_analyzer_simple.h b/xcore/x3a_analyzer_simple.h new file mode 100644 index 0000000..49cab50 --- /dev/null +++ b/xcore/x3a_analyzer_simple.h @@ -0,0 +1,76 @@ +/* + * x3a_analyzer_simple.h - a simple 3a analyzer + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_3A_ANALYZER_SIMPLE_H +#define XCAM_3A_ANALYZER_SIMPLE_H + +#include <xcam_std.h> +#include <x3a_analyzer.h> +#include <x3a_stats_pool.h> + +namespace XCam { + +class X3aAnalyzerSimple + : public X3aAnalyzer +{ +public: + explicit X3aAnalyzerSimple (); + ~X3aAnalyzerSimple (); + +private: + + XCAM_DEAD_COPY (X3aAnalyzerSimple); + +protected: + virtual SmartPtr<AeHandler> create_ae_handler (); + virtual SmartPtr<AwbHandler> create_awb_handler (); + virtual SmartPtr<AfHandler> create_af_handler (); + virtual SmartPtr<CommonHandler> create_common_handler (); + + virtual XCamReturn internal_init (uint32_t width, uint32_t height, double framerate) { + XCAM_UNUSED (width); + XCAM_UNUSED (height); + XCAM_UNUSED (framerate); + return XCAM_RETURN_NO_ERROR; + } + virtual XCamReturn internal_deinit () { + _is_ae_started = false; + _ae_calculation_interval = 0; + return XCAM_RETURN_NO_ERROR; + } + virtual XCamReturn configure_3a (); + virtual XCamReturn pre_3a_analyze (SmartPtr<X3aStats> &stats); + virtual XCamReturn post_3a_analyze (X3aResultList &results); + +public: + XCamReturn analyze_ae (X3aResultList &output); + XCamReturn analyze_awb (X3aResultList &output); + XCamReturn analyze_af (X3aResultList &output); + +private: + SmartPtr<X3aStats> _current_stats; + double _last_target_exposure; + bool _is_ae_started; + uint32_t _ae_calculation_interval; +}; + +}; +#endif //XCAM_3A_ANALYZER_SIMPLE_H + diff --git a/xcore/x3a_event.h b/xcore/x3a_event.h new file mode 100644 index 0000000..301860b --- /dev/null +++ b/xcore/x3a_event.h @@ -0,0 +1,63 @@ +/* + * x3a_event.h - event + * + * Copyright (c) 2014 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_3A_EVENT_H +#define XCAM_3A_EVENT_H + +#include <xcam_std.h> + +namespace XCam { + +class X3aEvent +//:public ObjectLife +{ +public: + enum Type { + TYPE_ISP_STATISTICS, + TYPE_ISP_FRAME_SYNC, + }; + +protected: + explicit X3aEvent (X3aEvent::Type type, uint64_t timestamp) + : _timestamp (timestamp) + , _type (type) + {} + virtual ~X3aEvent() {} + +public: + uint64_t get_timestamp () const { + return _timestamp; + } + Type get_type () const { + return _type; + } + +private: + XCAM_DEAD_COPY (X3aEvent); + +protected: + uint64_t _timestamp; + X3aEvent::Type _type; +}; + +}; + +#endif //XCAM_3A_EVENT_H + diff --git a/xcore/x3a_image_process_center.cpp b/xcore/x3a_image_process_center.cpp new file mode 100644 index 0000000..5adc912 --- /dev/null +++ b/xcore/x3a_image_process_center.cpp @@ -0,0 +1,237 @@ +/* + * x3a_image_process_center.cpp - 3a process center + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ +#include "x3a_image_process_center.h" + +namespace XCam { + +X3aImageProcessCenter::X3aImageProcessCenter() + : _callback (NULL) +{ + XCAM_LOG_DEBUG ("X3aImageProcessCenter construction"); +} + +X3aImageProcessCenter::~X3aImageProcessCenter() +{ + stop (); + XCAM_LOG_DEBUG ("~X3aImageProcessCenter destruction"); +} + +bool +X3aImageProcessCenter::set_image_callback (ImageProcessCallback *callback) +{ + XCAM_ASSERT (!_callback); + _callback = callback; + return true; +} + +bool +X3aImageProcessCenter::insert_processor (SmartPtr<ImageProcessor> &processor) +{ + _image_processors.push_back (processor); + XCAM_LOG_INFO ("Add processor(%s) into image processor center", XCAM_STR (processor->get_name())); + return true; +} + +bool +X3aImageProcessCenter::has_processors () +{ + return !_image_processors.empty(); +} + +XCamReturn +X3aImageProcessCenter::start () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + if (_image_processors.empty()) { + XCAM_LOG_ERROR ("process center start failed, no processor found"); + return XCAM_RETURN_ERROR_PARAM; + } + + for (ImageProcessorList::iterator i_pro = _image_processors.begin (); + i_pro != _image_processors.end(); ++i_pro) + { + SmartPtr<ImageProcessor> &processor = *i_pro; + XCAM_ASSERT (processor.ptr()); + processor->set_callback (this); + ret = processor->start (); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("processor(%s) start failed", XCAM_STR(processor->get_name())); + break; + } + } + + if (ret != XCAM_RETURN_NO_ERROR) + stop(); + else { + XCAM_LOG_INFO ("3a process center started"); + } + + return ret; +} + +XCamReturn +X3aImageProcessCenter::stop () +{ + for (ImageProcessorList::iterator i_pro = _image_processors.begin (); + i_pro != _image_processors.end(); ++i_pro) + { + SmartPtr<ImageProcessor> &processor = *i_pro; + XCAM_ASSERT (processor.ptr()); + processor->stop (); + } + + XCAM_LOG_INFO ("3a process center stopped"); + + _image_processors.clear(); + return XCAM_RETURN_NO_ERROR; +} + +bool +X3aImageProcessCenter::put_buffer (SmartPtr<VideoBuffer> &buf) +{ + XCAM_ASSERT (!_image_processors.empty()); + if (_image_processors.empty()) + return false; + + ImageProcessorList::iterator i_pro = _image_processors.begin (); + SmartPtr<ImageProcessor> &processor = *i_pro; + if (processor->push_buffer (buf) != XCAM_RETURN_NO_ERROR) + return false; + return true; +} + + +XCamReturn +X3aImageProcessCenter::put_3a_results (X3aResultList &results) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_FAIL_RETURN (ERROR, !results.empty(), XCAM_RETURN_ERROR_PARAM, "results empty"); + + for (ImageProcessorIter i_pro = _image_processors.begin(); + i_pro != _image_processors.end(); i_pro++) { + SmartPtr<ImageProcessor> &processor = *i_pro; + XCAM_ASSERT (processor.ptr()); + ret = processor->push_3a_results (results); + if (ret != XCAM_RETURN_NO_ERROR && ret != XCAM_RETURN_BYPASS) { + XCAM_LOG_WARNING ("processor(%s) gailed on results", XCAM_STR(processor->get_name())); + break; + } + if (results.empty ()) { + XCAM_LOG_DEBUG ("results done"); + return XCAM_RETURN_NO_ERROR; + } + } + + if (!results.empty()) { + XCAM_LOG_DEBUG ("process center: results left without being processed"); + return XCAM_RETURN_BYPASS; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +X3aImageProcessCenter::put_3a_result (SmartPtr<X3aResult> &result) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_FAIL_RETURN (ERROR, !result.ptr(), XCAM_RETURN_ERROR_PARAM, "result empty"); + + for (ImageProcessorIter i_pro = _image_processors.begin(); + i_pro != _image_processors.end(); i_pro++) + { + SmartPtr<ImageProcessor> &processor = *i_pro; + XCAM_ASSERT (processor.ptr()); + ret = processor->push_3a_result (result); + + if (ret == XCAM_RETURN_BYPASS) + continue; + + if (ret == XCAM_RETURN_NO_ERROR) + return XCAM_RETURN_NO_ERROR; + + XCAM_LOG_WARNING ("processor(%s) failed on result", XCAM_STR(processor->get_name())); + return ret; + } + + if (ret == XCAM_RETURN_BYPASS) { + XCAM_LOG_WARNING ("processor center: no processor can handle result()"); + } + + return ret; +} + +void +X3aImageProcessCenter::process_buffer_done (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf) +{ + ImageProcessorIter i_pro = _image_processors.begin(); + for (; i_pro != _image_processors.end(); ++i_pro) + { + SmartPtr<ImageProcessor> &cur_pro = *i_pro; + XCAM_ASSERT (cur_pro.ptr()); + if (cur_pro.ptr() == processor) + break; + } + + XCAM_ASSERT (i_pro != _image_processors.end()); + if (i_pro == _image_processors.end()) { + XCAM_LOG_ERROR ("processor doesn't found from list of image center"); + return; + } + + if (++i_pro != _image_processors.end()) { + SmartPtr<ImageProcessor> &next_processor = *i_pro; + SmartPtr<VideoBuffer> cur_buf = buf; + XCAM_ASSERT (next_processor.ptr()); + XCamReturn ret = next_processor->push_buffer (cur_buf); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("processor(%s) failed in push_buffer", next_processor->get_name()); + } + return; + } + + //all processor done + if (_callback) + _callback->process_buffer_done (processor, buf); + else + ImageProcessCallback::process_buffer_done (processor, buf); +} + +void +X3aImageProcessCenter::process_buffer_failed (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf) +{ + if (_callback) + _callback->process_buffer_failed(processor, buf); + else + ImageProcessCallback::process_buffer_failed (processor, buf); +} + +void +X3aImageProcessCenter::process_image_result_done (ImageProcessor *processor, const SmartPtr<X3aResult> &result) +{ + if (_callback) + _callback->process_image_result_done(processor, result); + else + ImageProcessCallback::process_image_result_done (processor, result); +} + +}; diff --git a/xcore/x3a_image_process_center.h b/xcore/x3a_image_process_center.h new file mode 100644 index 0000000..b72bbb3 --- /dev/null +++ b/xcore/x3a_image_process_center.h @@ -0,0 +1,64 @@ +/* + * x3a_image_process_center.h - 3a process center + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_3A_IMAGE_PROCESS_CENTER_H +#define XCAM_3A_IMAGE_PROCESS_CENTER_H + +#include <xcam_std.h> +#include <image_processor.h> + +namespace XCam { + +class X3aImageProcessCenter + : public ImageProcessCallback +{ + typedef std::list<SmartPtr<ImageProcessor> > ImageProcessorList; + typedef std::list<SmartPtr<ImageProcessor> >::iterator ImageProcessorIter; +public: + explicit X3aImageProcessCenter(); + ~X3aImageProcessCenter(); + + bool insert_processor (SmartPtr<ImageProcessor> &processor); + bool has_processors (); + bool set_image_callback (ImageProcessCallback *callback); + + XCamReturn start (); + XCamReturn stop (); + + bool put_buffer (SmartPtr<VideoBuffer> &buf); + + XCamReturn put_3a_results (X3aResultList &results); + XCamReturn put_3a_result (SmartPtr<X3aResult> &result); + + //derived from ImageProcessCallback + virtual void process_buffer_done (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf); + virtual void process_buffer_failed (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf); + virtual void process_image_result_done (ImageProcessor *processor, const SmartPtr<X3aResult> &result); + +private: + XCAM_DEAD_COPY (X3aImageProcessCenter); + +private: + ImageProcessorList _image_processors; + ImageProcessCallback *_callback; +}; + +}; +#endif //XCAM_3A_IMAGE_PROCESS_CENTER_H diff --git a/xcore/x3a_result.cpp b/xcore/x3a_result.cpp new file mode 100644 index 0000000..add2059 --- /dev/null +++ b/xcore/x3a_result.cpp @@ -0,0 +1,39 @@ +/* + * x3a_result.cpp - 3A calculation result + * + * Copyright (c) 2014 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "x3a_result.h" + +namespace XCam { + +void +x3a_list_remove_result (X3aResultList &list, uint32_t type) +{ + for (X3aResultList::iterator i = list.begin (); i != list.end ();) { + SmartPtr<X3aResult> &result = *i; + XCAM_ASSERT (result.ptr ()); + if (result->get_type () == type) { + list.erase (i++); + continue; + } + ++i; + } +} + +}; diff --git a/xcore/x3a_result.h b/xcore/x3a_result.h new file mode 100644 index 0000000..8fc9284 --- /dev/null +++ b/xcore/x3a_result.h @@ -0,0 +1,168 @@ +/* + * x3a_result.h - 3A calculation result + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_3A_RESULT_H +#define XCAM_3A_RESULT_H + +#include <xcam_std.h> +#include <base/xcam_3a_result.h> +#include <base/xcam_smart_result.h> +#include <list> + +namespace XCam { + +class X3aResult +{ +protected: + explicit X3aResult ( + uint32_t type, + XCamImageProcessType process_type = XCAM_IMAGE_PROCESS_ALWAYS, + int64_t timestamp = XCam::InvalidTimestamp + ) + : _type (type) + , _process_type (process_type) + , _timestamp (timestamp) + , _ptr (NULL) + , _processed (false) + {} + +public: + virtual ~X3aResult() {} + + void *get_ptr () const { + return _ptr; + } + bool is_done() const { + return _processed; + } + void set_done (bool flag) { + _processed = flag; + } + void set_timestamp (int64_t timestamp) { + _timestamp = timestamp; + } + int64_t get_timestamp () const { + return _timestamp; + } + uint32_t get_type () const { + return _type; + } + + void set_process_type (XCamImageProcessType process) { + _process_type = process; + } + XCamImageProcessType get_process_type () const { + return _process_type; + } + +protected: + void set_ptr (void *ptr) { + _ptr = ptr; + } + + //virtual bool to_isp_config (SmartPtr<X3aIspConfig> &config) = 0; + +private: + XCAM_DEAD_COPY (X3aResult); + +protected: + //XCam3aResultType _type; + uint32_t _type; // XCam3aResultType + XCamImageProcessType _process_type; + int64_t _timestamp; + void *_ptr; + bool _processed; +}; + +typedef std::list<SmartPtr<X3aResult>> X3aResultList; + +void x3a_list_remove_result (X3aResultList &list, uint32_t type); + +/* ! + * \template StandardResult must inherited from XCam3aResultHead + */ +template <typename StandardResult> +class X3aStandardResultT + : public X3aResult +{ +public: + explicit X3aStandardResultT (uint32_t type, XCamImageProcessType process_type = XCAM_IMAGE_PROCESS_ALWAYS, uint32_t extra_size = 0) + : X3aResult (type, process_type) + , _result (NULL) + , _extra_size (extra_size) + { + _result = (StandardResult *) xcam_malloc0 (sizeof (StandardResult) + _extra_size); + XCAM_ASSERT (_result); + set_ptr ((void*) _result); + _result->head.type = (XCam3aResultType) type; + _result->head.process_type = _process_type; + _result->head.version = xcam_version (); + } + ~X3aStandardResultT () { + xcam_free (_result); + } + + void set_standard_result (StandardResult &res) { + uint32_t offset = sizeof (XCam3aResultHead); + XCAM_ASSERT (sizeof (StandardResult) >= offset); + + if (_extra_size > 0) { + memcpy ((uint8_t*)(_result) + offset, (uint8_t*)(&res) + offset, _extra_size); + } else { + memcpy ((uint8_t*)(_result) + offset, (uint8_t*)(&res) + offset, sizeof (StandardResult) - offset); + } + } + + StandardResult &get_standard_result () { + return *_result; + } + const StandardResult &get_standard_result () const { + return *_result; + } + StandardResult *get_standard_result_ptr () { + return _result; + } + +private: + StandardResult *_result; + uint32_t _extra_size; +}; + +typedef X3aStandardResultT<XCam3aResultWhiteBalance> X3aWhiteBalanceResult; +typedef X3aStandardResultT<XCam3aResultBlackLevel> X3aBlackLevelResult; +typedef X3aStandardResultT<XCam3aResultColorMatrix> X3aColorMatrixResult; +typedef X3aStandardResultT<XCam3aResultExposure> X3aExposureResult; +typedef X3aStandardResultT<XCam3aResultFocus> X3aFocusResult; +typedef X3aStandardResultT<XCam3aResultDemosaic> X3aDemosaicResult; +typedef X3aStandardResultT<XCam3aResultDefectPixel> X3aDefectPixelResult; +typedef X3aStandardResultT<XCam3aResultNoiseReduction> X3aNoiseReductionResult; +typedef X3aStandardResultT<XCam3aResultEdgeEnhancement> X3aEdgeEnhancementResult; +typedef X3aStandardResultT<XCam3aResultGammaTable> X3aGammaTableResult; +typedef X3aStandardResultT<XCam3aResultMaccMatrix> X3aMaccMatrixResult; +typedef X3aStandardResultT<XCam3aResultChromaToneControl> X3aChromaToneControlResult; +typedef X3aStandardResultT<XCam3aResultBayerNoiseReduction> X3aBayerNoiseReduction; +typedef X3aStandardResultT<XCam3aResultBrightness> X3aBrightnessResult; +typedef X3aStandardResultT<XCam3aResultTemporalNoiseReduction> X3aTemporalNoiseReduction; +typedef X3aStandardResultT<XCam3aResultWaveletNoiseReduction> X3aWaveletNoiseReduction; +typedef X3aStandardResultT<XCamFDResult> X3aFaceDetectionResult; +typedef X3aStandardResultT<XCamDVSResult> X3aDVSResult; +}; + +#endif //XCAM_3A_RESULT_H diff --git a/xcore/x3a_result_factory.cpp b/xcore/x3a_result_factory.cpp new file mode 100644 index 0000000..8e0e12f --- /dev/null +++ b/xcore/x3a_result_factory.cpp @@ -0,0 +1,301 @@ +/* + * x3a_result_factory.cpp - 3A result factory + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "x3a_result_factory.h" + +namespace XCam { + +#define XCAM_3A_RESULT_FACTORY(DataType, res_type, from) \ + DataType *ret = \ + new DataType (res_type); \ + if (from) { \ + uint32_t type = xcam_3a_result_type (from); \ + if (type != XCAM_3A_RESULT_NULL && type != res_type) { \ + XCAM_ASSERT (false); \ + XCAM_LOG_WARNING ("create result from wrong type:%d to type:%d", type, res_type); \ + } \ + ret->set_standard_result (*from); \ + } \ + return ret; + + +Mutex X3aResultFactory::_mutex; +SmartPtr<X3aResultFactory> X3aResultFactory::_instance (NULL); + +SmartPtr<X3aResultFactory> +X3aResultFactory::instance () +{ + SmartLock locker (_mutex); + if (_instance.ptr ()) + return _instance; + + _instance = new X3aResultFactory; + return _instance; +} + +X3aResultFactory::X3aResultFactory () +{ +} + +X3aResultFactory::~X3aResultFactory () +{ +} + +SmartPtr<X3aResult> +X3aResultFactory::create_3a_result (XCam3aResultHead *from) +{ + SmartPtr<X3aResult> result (NULL); + + XCAM_ASSERT (from); + if (!from) + return result; + + uint32_t type = xcam_3a_result_type (from); + + switch (type) { + case XCAM_3A_RESULT_WHITE_BALANCE: + result = create_whitebalance ((XCam3aResultWhiteBalance*)from); + break; + case XCAM_3A_RESULT_BLACK_LEVEL: + result = create_blacklevel ((XCam3aResultBlackLevel*)from); + break; + case XCAM_3A_RESULT_YUV2RGB_MATRIX: + result = create_yuv2rgb_colormatrix ((XCam3aResultColorMatrix*)from); + break; + case XCAM_3A_RESULT_RGB2YUV_MATRIX: + result = create_rgb2yuv_colormatrix ((XCam3aResultColorMatrix*)from); + break; + case XCAM_3A_RESULT_EXPOSURE: + result = create_exposure ((XCam3aResultExposure*)from); + break; + case XCAM_3A_RESULT_FOCUS: + result = create_focus ((XCam3aResultFocus*)from); + break; + case XCAM_3A_RESULT_DEMOSAIC: + result = create_demosaicing ((XCam3aResultDemosaic*)from); + break; + case XCAM_3A_RESULT_DEFECT_PIXEL_CORRECTION: + result = create_defectpixel ((XCam3aResultDefectPixel*)from); + break; + case XCAM_3A_RESULT_NOISE_REDUCTION: + result = create_noise_reduction ((XCam3aResultNoiseReduction*)from); + break; + case XCAM_3A_RESULT_3D_NOISE_REDUCTION: + result = create_3d_noise_reduction ((XCam3aResultTemporalNoiseReduction*)from); + break; + case XCAM_3A_RESULT_TEMPORAL_NOISE_REDUCTION_YUV: + result = create_yuv_temp_noise_reduction ((XCam3aResultTemporalNoiseReduction*)from); + break; + case XCAM_3A_RESULT_EDGE_ENHANCEMENT: + result = create_edge_enhancement ((XCam3aResultEdgeEnhancement*)from); + break; + case XCAM_3A_RESULT_MACC: + result = create_macc ((XCam3aResultMaccMatrix*)from); + break; + case XCAM_3A_RESULT_CHROMA_TONE_CONTROL: + result = create_chroma_tone_control ((XCam3aResultChromaToneControl*)from); + break; + case XCAM_3A_RESULT_Y_GAMMA: + result = create_y_gamma_table ((XCam3aResultGammaTable*)from); + break; + case XCAM_3A_RESULT_R_GAMMA: + result = create_r_gamma_table ((XCam3aResultGammaTable*)from); + break; + case XCAM_3A_RESULT_G_GAMMA: + result = create_g_gamma_table ((XCam3aResultGammaTable*)from); + break; + case XCAM_3A_RESULT_B_GAMMA: + result = create_b_gamma_table ((XCam3aResultGammaTable*)from); + break; + case XCAM_3A_RESULT_BAYER_NOISE_REDUCTION: + result = create_bayer_noise_reduction ((XCam3aResultBayerNoiseReduction*)from); + break; + case XCAM_3A_RESULT_BRIGHTNESS: + result = create_brightness ((XCam3aResultBrightness*)from); + break; + case XCAM_3A_RESULT_WAVELET_NOISE_REDUCTION: + result = create_wavelet_noise_reduction ((XCam3aResultWaveletNoiseReduction*)from); + break; + case XCAM_3A_RESULT_FACE_DETECTION: + result = create_face_detection ((XCamFDResult*)from); + break; + case XCAM_3A_RESULT_DVS: + result = create_digital_video_stabilizer ((XCamDVSResult*)from); + break; + default: + XCAM_LOG_WARNING ("create 3a result with unknown result type:%d", type); + break; + } + + return result; +} + +SmartPtr<X3aWhiteBalanceResult> +X3aResultFactory::create_whitebalance (XCam3aResultWhiteBalance *from) +{ + XCAM_3A_RESULT_FACTORY (X3aWhiteBalanceResult, XCAM_3A_RESULT_WHITE_BALANCE, from); +} + +SmartPtr<X3aBlackLevelResult> +X3aResultFactory::create_blacklevel (XCam3aResultBlackLevel *from) +{ + XCAM_3A_RESULT_FACTORY (X3aBlackLevelResult, XCAM_3A_RESULT_BLACK_LEVEL, from); +} + +SmartPtr<X3aColorMatrixResult> +X3aResultFactory::create_rgb2yuv_colormatrix (XCam3aResultColorMatrix *from) +{ + XCAM_3A_RESULT_FACTORY (X3aColorMatrixResult, XCAM_3A_RESULT_RGB2YUV_MATRIX, from); +} + +SmartPtr<X3aColorMatrixResult> +X3aResultFactory::create_yuv2rgb_colormatrix (XCam3aResultColorMatrix *from) +{ + XCAM_3A_RESULT_FACTORY (X3aColorMatrixResult, XCAM_3A_RESULT_YUV2RGB_MATRIX, from); +} + +SmartPtr<X3aExposureResult> +X3aResultFactory::create_exposure (XCam3aResultExposure *from) +{ + XCAM_3A_RESULT_FACTORY (X3aExposureResult, XCAM_3A_RESULT_EXPOSURE, from); +} + +SmartPtr<X3aFocusResult> +X3aResultFactory::create_focus (XCam3aResultFocus *from) +{ + XCAM_3A_RESULT_FACTORY (X3aFocusResult, XCAM_3A_RESULT_FOCUS, from); +} + +SmartPtr<X3aDemosaicResult> +X3aResultFactory::create_demosaicing (XCam3aResultDemosaic *from) +{ + XCAM_3A_RESULT_FACTORY (X3aDemosaicResult, XCAM_3A_RESULT_DEMOSAIC, from); +} + +SmartPtr<X3aDefectPixelResult> +X3aResultFactory::create_defectpixel (XCam3aResultDefectPixel *from) +{ + XCAM_3A_RESULT_FACTORY (X3aDefectPixelResult, XCAM_3A_RESULT_DEFECT_PIXEL_CORRECTION, from); +} + +SmartPtr<X3aNoiseReductionResult> +X3aResultFactory::create_noise_reduction (XCam3aResultNoiseReduction *from) +{ + XCAM_3A_RESULT_FACTORY (X3aNoiseReductionResult, XCAM_3A_RESULT_NOISE_REDUCTION, from); +} + +SmartPtr<X3aTemporalNoiseReduction> +X3aResultFactory::create_3d_noise_reduction (XCam3aResultTemporalNoiseReduction *from) +{ + XCAM_3A_RESULT_FACTORY (X3aTemporalNoiseReduction, XCAM_3A_RESULT_3D_NOISE_REDUCTION, from); +} + +SmartPtr<X3aTemporalNoiseReduction> +X3aResultFactory::create_yuv_temp_noise_reduction (XCam3aResultTemporalNoiseReduction *from) +{ + XCAM_3A_RESULT_FACTORY (X3aTemporalNoiseReduction, XCAM_3A_RESULT_TEMPORAL_NOISE_REDUCTION_YUV, from); +} + +SmartPtr<X3aEdgeEnhancementResult> +X3aResultFactory::create_edge_enhancement (XCam3aResultEdgeEnhancement *from) +{ + XCAM_3A_RESULT_FACTORY (X3aEdgeEnhancementResult, XCAM_3A_RESULT_EDGE_ENHANCEMENT, from); +} + +SmartPtr<X3aGammaTableResult> +X3aResultFactory::create_y_gamma_table (XCam3aResultGammaTable *from) +{ + XCAM_3A_RESULT_FACTORY (X3aGammaTableResult, XCAM_3A_RESULT_Y_GAMMA, from); +} + +SmartPtr<X3aGammaTableResult> +X3aResultFactory::create_r_gamma_table (XCam3aResultGammaTable *from) +{ + XCAM_3A_RESULT_FACTORY (X3aGammaTableResult, XCAM_3A_RESULT_R_GAMMA, from); +} + +SmartPtr<X3aGammaTableResult> +X3aResultFactory::create_g_gamma_table (XCam3aResultGammaTable *from) +{ + XCAM_3A_RESULT_FACTORY (X3aGammaTableResult, XCAM_3A_RESULT_G_GAMMA, from); +} + +SmartPtr<X3aGammaTableResult> +X3aResultFactory::create_b_gamma_table (XCam3aResultGammaTable *from) +{ + XCAM_3A_RESULT_FACTORY (X3aGammaTableResult, XCAM_3A_RESULT_B_GAMMA, from); +} + +SmartPtr<X3aMaccMatrixResult> +X3aResultFactory::create_macc (XCam3aResultMaccMatrix *from) +{ + XCAM_3A_RESULT_FACTORY (X3aMaccMatrixResult, XCAM_3A_RESULT_MACC, from); +} + +SmartPtr<X3aChromaToneControlResult> +X3aResultFactory::create_chroma_tone_control (XCam3aResultChromaToneControl *from) +{ + XCAM_3A_RESULT_FACTORY (X3aChromaToneControlResult, XCAM_3A_RESULT_CHROMA_TONE_CONTROL, from); +} + +SmartPtr<X3aBayerNoiseReduction> +X3aResultFactory::create_bayer_noise_reduction (XCam3aResultBayerNoiseReduction *from) +{ + XCAM_3A_RESULT_FACTORY (X3aBayerNoiseReduction, XCAM_3A_RESULT_BAYER_NOISE_REDUCTION, from); +} + +SmartPtr<X3aBrightnessResult> +X3aResultFactory::create_brightness (XCam3aResultBrightness *from) +{ + XCAM_3A_RESULT_FACTORY (X3aBrightnessResult, XCAM_3A_RESULT_BRIGHTNESS, from); +} + +SmartPtr<X3aWaveletNoiseReduction> +X3aResultFactory::create_wavelet_noise_reduction (XCam3aResultWaveletNoiseReduction *from) +{ + XCAM_3A_RESULT_FACTORY (X3aWaveletNoiseReduction, XCAM_3A_RESULT_WAVELET_NOISE_REDUCTION, from); +} + +SmartPtr<X3aFaceDetectionResult> +X3aResultFactory::create_face_detection (XCamFDResult *from) +{ + uint32_t type = xcam_3a_result_type (from); + if (type != XCAM_3A_RESULT_FACE_DETECTION) { + XCAM_ASSERT (false); + XCAM_LOG_WARNING ("X3aResultFactory create face detection failed with wrong type"); + } + + X3aFaceDetectionResult *fd_res = new X3aFaceDetectionResult ( + XCAM_3A_RESULT_FACE_DETECTION, + from->head.process_type, + from->face_num * sizeof (XCamFaceInfo)); + fd_res->set_standard_result (*from); + + return fd_res; +} + +SmartPtr<X3aDVSResult> +X3aResultFactory::create_digital_video_stabilizer (XCamDVSResult *from) +{ + XCAM_3A_RESULT_FACTORY (X3aDVSResult, XCAM_3A_RESULT_DVS, from); +} +}; + + diff --git a/xcore/x3a_result_factory.h b/xcore/x3a_result_factory.h new file mode 100644 index 0000000..88a555c --- /dev/null +++ b/xcore/x3a_result_factory.h @@ -0,0 +1,73 @@ +/* + * x3a_result_factory.h - 3A result factory + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_3A_RESULT_FACTORY_H +#define XCAM_3A_RESULT_FACTORY_H + +#include <xcam_std.h> +#include <xcam_mutex.h> +#include <x3a_result.h> + +namespace XCam { + +class X3aResultFactory { +public: + virtual ~X3aResultFactory (); + + static SmartPtr<X3aResultFactory> instance (); + + SmartPtr<X3aResult> create_3a_result (XCam3aResultHead *from); + + SmartPtr<X3aWhiteBalanceResult> create_whitebalance (XCam3aResultWhiteBalance *from = NULL); + SmartPtr<X3aBlackLevelResult> create_blacklevel (XCam3aResultBlackLevel *from = NULL); + SmartPtr<X3aColorMatrixResult> create_rgb2yuv_colormatrix (XCam3aResultColorMatrix *from = NULL); + SmartPtr<X3aColorMatrixResult> create_yuv2rgb_colormatrix (XCam3aResultColorMatrix *from = NULL); + SmartPtr<X3aExposureResult> create_exposure (XCam3aResultExposure *from = NULL); + SmartPtr<X3aFocusResult> create_focus (XCam3aResultFocus *from = NULL); + SmartPtr<X3aDemosaicResult> create_demosaicing (XCam3aResultDemosaic *from = NULL); + SmartPtr<X3aDefectPixelResult> create_defectpixel (XCam3aResultDefectPixel *from = NULL); + SmartPtr<X3aNoiseReductionResult> create_noise_reduction (XCam3aResultNoiseReduction *from = NULL); + SmartPtr<X3aTemporalNoiseReduction> create_3d_noise_reduction (XCam3aResultTemporalNoiseReduction *from = NULL); + SmartPtr<X3aTemporalNoiseReduction> create_yuv_temp_noise_reduction (XCam3aResultTemporalNoiseReduction *from = NULL); + SmartPtr<X3aEdgeEnhancementResult> create_edge_enhancement (XCam3aResultEdgeEnhancement *from = NULL); + SmartPtr<X3aGammaTableResult> create_y_gamma_table (XCam3aResultGammaTable *from = NULL); + SmartPtr<X3aGammaTableResult> create_r_gamma_table (XCam3aResultGammaTable *from = NULL); + SmartPtr<X3aGammaTableResult> create_g_gamma_table (XCam3aResultGammaTable *from = NULL); + SmartPtr<X3aGammaTableResult> create_b_gamma_table (XCam3aResultGammaTable *from = NULL); + SmartPtr<X3aMaccMatrixResult> create_macc (XCam3aResultMaccMatrix *from = NULL); + SmartPtr<X3aChromaToneControlResult> create_chroma_tone_control (XCam3aResultChromaToneControl *from = NULL); + SmartPtr<X3aBayerNoiseReduction> create_bayer_noise_reduction (XCam3aResultBayerNoiseReduction *from = NULL); + SmartPtr<X3aBrightnessResult> create_brightness (XCam3aResultBrightness *from = NULL); + SmartPtr<X3aWaveletNoiseReduction> create_wavelet_noise_reduction (XCam3aResultWaveletNoiseReduction *from = NULL); + SmartPtr<X3aFaceDetectionResult> create_face_detection (XCamFDResult *from = NULL); + SmartPtr<X3aDVSResult> create_digital_video_stabilizer (XCamDVSResult *from = NULL); +protected: + explicit X3aResultFactory (); + + XCAM_DEAD_COPY (X3aResultFactory); + +private: + static Mutex _mutex; + static SmartPtr<X3aResultFactory> _instance; +}; + +}; + +#endif // XCAM_3A_RESULT_FACTORY_H diff --git a/xcore/x3a_stats_pool.cpp b/xcore/x3a_stats_pool.cpp new file mode 100644 index 0000000..3ba4cd4 --- /dev/null +++ b/xcore/x3a_stats_pool.cpp @@ -0,0 +1,127 @@ +/* + * x3a_stats_pool.cpp - 3a stats pool + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "x3a_stats_pool.h" + +#define XCAM_3A_STATS_DEFAULT_BIT_DEPTH 8 + +namespace XCam { + +X3aStatsData::X3aStatsData (XCam3AStats *data) + : _data (data) +{ + XCAM_ASSERT (_data); +} + +X3aStatsData::~X3aStatsData () +{ + if (_data) + xcam_free (_data); +} + +uint8_t * +X3aStatsData::map () +{ + return (uint8_t*)(intptr_t)(_data); +} + +bool +X3aStatsData::unmap () +{ + return true; +} + +X3aStats::X3aStats (const SmartPtr<X3aStatsData> &data) + : BufferProxy (SmartPtr<BufferData>(data)) +{ +} + + +XCam3AStats * +X3aStats::get_stats () +{ + SmartPtr<BufferData> data = get_buffer_data (); + SmartPtr<X3aStatsData> stats = data.dynamic_cast_ptr<X3aStatsData> (); + + XCAM_FAIL_RETURN( + WARNING, + stats.ptr(), + NULL, + "X3aStats get_stats failed with NULL"); + return stats->get_stats (); +} + +X3aStatsPool::X3aStatsPool () + : _bit_depth (XCAM_3A_STATS_DEFAULT_BIT_DEPTH) +{ +} + +void +X3aStatsPool::set_stats_info (const XCam3AStatsInfo &info) +{ + _stats_info = info; +} + +bool +X3aStatsPool::fixate_video_info (VideoBufferInfo &info) +{ + const uint32_t grid = 16; + + _stats_info.aligned_width = (info.width + grid - 1) / grid; + _stats_info.aligned_height = (info.height + grid - 1) / grid; + + _stats_info.width = info.width / grid; + _stats_info.height = info.height / grid; + _stats_info.grid_pixel_size = grid; + _stats_info.bit_depth = _bit_depth; + _stats_info.histogram_bins = (1 << _bit_depth); + return true; +} + +SmartPtr<BufferData> +X3aStatsPool::allocate_data (const VideoBufferInfo &buffer_info) +{ + XCAM_UNUSED (buffer_info); + + XCam3AStats *stats = NULL; + stats = + (XCam3AStats *) xcam_malloc0 ( + sizeof (XCam3AStats) + + sizeof (XCamHistogram) * _stats_info.histogram_bins + + sizeof (uint32_t) * _stats_info.histogram_bins + + sizeof (XCamGridStat) * _stats_info.aligned_width * _stats_info.aligned_height); + XCAM_ASSERT (stats); + stats->info = _stats_info; + stats->hist_rgb = (XCamHistogram *) (stats->stats + + _stats_info.aligned_width * _stats_info.aligned_height); + stats->hist_y = (uint32_t *) (stats->hist_rgb + _stats_info.histogram_bins); + return new X3aStatsData (stats); +} + +SmartPtr<BufferProxy> +X3aStatsPool::create_buffer_from_data (SmartPtr<BufferData> &data) +{ + SmartPtr<X3aStatsData> stats_data = data.dynamic_cast_ptr<X3aStatsData> (); + XCAM_ASSERT (stats_data.ptr ()); + + return new X3aStats (stats_data); +} + +}; diff --git a/xcore/x3a_stats_pool.h b/xcore/x3a_stats_pool.h new file mode 100644 index 0000000..ed50694 --- /dev/null +++ b/xcore/x3a_stats_pool.h @@ -0,0 +1,91 @@ +/* + * x3a_stats_pool.h - 3a stats pool + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_3A_STATS_POOL_H +#define XCAM_3A_STATS_POOL_H + +#include <xcam_std.h> +#include <buffer_pool.h> +#include <base/xcam_3a_stats.h> + +namespace XCam { + +class X3aStatsData + : public BufferData +{ +public: + explicit X3aStatsData (XCam3AStats *data); + ~X3aStatsData (); + XCam3AStats *get_stats () { + return _data; + } + + virtual uint8_t *map (); + virtual bool unmap (); + +private: + XCAM_DEAD_COPY (X3aStatsData); +private: + XCam3AStats *_data; +}; + +class X3aStats + : public BufferProxy +{ + friend class X3aStatsPool; +public: + XCam3AStats *get_stats (); + +protected: + explicit X3aStats (const SmartPtr<X3aStatsData> &data); + XCAM_DEAD_COPY (X3aStats); + +}; + +class X3aStatsPool + : public BufferPool +{ +public: + explicit X3aStatsPool (); + XCam3AStatsInfo &get_stats_info () { + return _stats_info; + } + void set_bit_depth (uint32_t bit_depth) { + _bit_depth = bit_depth; + } + void set_stats_info (const XCam3AStatsInfo &info); + +protected: + virtual bool fixate_video_info (VideoBufferInfo &info); + virtual SmartPtr<BufferData> allocate_data (const VideoBufferInfo &buffer_info); + virtual SmartPtr<BufferProxy> create_buffer_from_data (SmartPtr<BufferData> &data); + +private: + XCAM_DEAD_COPY (X3aStatsPool); + +private: + XCam3AStatsInfo _stats_info; + uint32_t _bit_depth; +}; + +}; + +#endif //XCAM_3A_STATS_POOL_H + diff --git a/xcore/xcam_analyzer.cpp b/xcore/xcam_analyzer.cpp new file mode 100644 index 0000000..8191a79 --- /dev/null +++ b/xcore/xcam_analyzer.cpp @@ -0,0 +1,282 @@ +/* + * xcam_analyzer.cpp - libxcam analyzer + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Zong Wei <wei.zong@intel.com> + * Jia Meng <jia.meng@intel.com> + */ + +#include "xcam_analyzer.h" +#include "x3a_stats_pool.h" + +namespace XCam { + +AnalyzerThread::AnalyzerThread (XAnalyzer *analyzer) + : Thread ("AnalyzerThread") + , _analyzer (analyzer) +{} + +AnalyzerThread::~AnalyzerThread () +{ + _stats_queue.clear (); +} + +bool +AnalyzerThread::push_stats (const SmartPtr<VideoBuffer> &buffer) +{ + _stats_queue.push (buffer); + return true; +} + +bool +AnalyzerThread::started () +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (_analyzer); + ret = _analyzer->configure (); + if (ret != XCAM_RETURN_NO_ERROR) { + _analyzer->notify_calculation_failed (NULL, 0, "configure 3a failed"); + XCAM_LOG_WARNING ("analyzer(%s) configure 3a failed", XCAM_STR(_analyzer->get_name())); + return false; + } + + return true; +} + +bool +AnalyzerThread::loop () +{ + const static int32_t timeout = -1; + SmartPtr<VideoBuffer> latest_stats; + SmartPtr<VideoBuffer> stats = _stats_queue.pop (timeout); + if (!stats.ptr()) { + XCAM_LOG_DEBUG ("analyzer thread got empty stats, stop thread"); + return false; + } + //while ((latest_stats = _stats_queue.pop (0)).ptr ()) { + // stats = latest_stats; + // XCAM_LOG_WARNING ("lost 3a stats since 3a analyzer too slow"); + //} + + XCamReturn ret = _analyzer->analyze (stats); + if (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS) + return true; + + XCAM_LOG_DEBUG ("analyzer(%s) failed to analyze 3a stats", XCAM_STR(_analyzer->get_name())); + return false; +} + +void +AnalyzerCallback::x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results) +{ + XCAM_UNUSED (analyzer); + + for (X3aResultList::iterator i_res = results.begin(); + i_res != results.end(); ++i_res) { + SmartPtr<X3aResult> res = *i_res; + if (res.ptr() == NULL) continue; + XCAM_LOG_DEBUG ( + "calculated 3a result(type:0x%x, timestamp:" XCAM_TIMESTAMP_FORMAT ")", + res->get_type (), XCAM_TIMESTAMP_ARGS (res->get_timestamp ())); + } +} + +void +AnalyzerCallback::x3a_calculation_failed (XAnalyzer *analyzer, int64_t timestamp, const char *msg) +{ + XCAM_UNUSED (analyzer); + + XCAM_LOG_WARNING ( + "Calculate 3a result failed, ts(" XCAM_TIMESTAMP_FORMAT "), msg:%s", + XCAM_TIMESTAMP_ARGS (timestamp), XCAM_STR (msg)); +} + +XAnalyzer::XAnalyzer (const char *name) + : _name (NULL) + , _sync (false) + , _started (false) + , _width (0) + , _height (0) + , _framerate (30.0) + , _callback (NULL) +{ + if (name) + _name = strndup (name, XCAM_MAX_STR_SIZE); + + _analyzer_thread = new AnalyzerThread (this); +} + +XAnalyzer::~XAnalyzer() +{ + if (_name) + xcam_free (_name); +} + +bool +XAnalyzer::set_results_callback (AnalyzerCallback *callback) +{ + XCAM_ASSERT (!_callback); + _callback = callback; + return true; +} + +XCamReturn +XAnalyzer::prepare_handlers () +{ + return create_handlers (); +} + +XCamReturn +XAnalyzer::init (uint32_t width, uint32_t height, double framerate) +{ + XCAM_LOG_DEBUG ("Analyzer(%s) init.", XCAM_STR(get_name())); + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + XCAM_ASSERT (!_width && !_height); + _width = width; + _height = height; + _framerate = framerate; + + ret = internal_init (width, height, _framerate); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_WARNING ("analyzer init failed"); + deinit (); + return ret; + } + + XCAM_LOG_INFO ( + "Analyzer(%s) initialized(w:%d, h:%d).", + XCAM_STR(get_name()), _width, _height); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +XAnalyzer::deinit () +{ + internal_deinit (); + + release_handlers (); + + _width = 0; + _height = 0; + + XCAM_LOG_INFO ("Analyzer(%s) deinited.", XCAM_STR(get_name())); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +XAnalyzer::set_sync_mode (bool sync) +{ + if (_started) { + XCAM_LOG_ERROR ("can't set_sync_mode after analyzer started"); + return XCAM_RETURN_ERROR_PARAM; + } + _sync = sync; + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +XAnalyzer::start () +{ + if (_sync) { + XCamReturn ret = configure (); + if (ret != XCAM_RETURN_NO_ERROR) { + XCAM_LOG_ERROR ("analyzer failed to start in sync mode"); + stop (); + return ret; + } + } else { + if (_analyzer_thread->start () == false) { + XCAM_LOG_WARNING ("analyzer thread start failed"); + stop (); + return XCAM_RETURN_ERROR_THREAD; + } + } + + _started = true; + XCAM_LOG_INFO ("Analyzer(%s) started in %s mode.", XCAM_STR(get_name()), + _sync ? "sync" : "async"); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +XAnalyzer::stop () +{ + if (!_sync) { + _analyzer_thread->triger_stop (); + _analyzer_thread->stop (); + } + + _started = false; + XCAM_LOG_INFO ("Analyzer(%s) stopped.", XCAM_STR(get_name())); + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +XAnalyzer::push_buffer (const SmartPtr<VideoBuffer> &buffer) +{ + XCamReturn ret = XCAM_RETURN_NO_ERROR; + + if (get_sync_mode ()) { + ret = analyze (buffer); + } + else { + if (!_analyzer_thread->is_running()) + return XCAM_RETURN_ERROR_THREAD; + + if (!_analyzer_thread->push_stats (buffer)) + return XCAM_RETURN_ERROR_THREAD; + } + + return ret; +} + +void +XAnalyzer::set_results_timestamp (X3aResultList &results, int64_t timestamp) +{ + if (results.empty ()) + return; + + X3aResultList::iterator i_results = results.begin (); + for (; i_results != results.end (); ++i_results) + { + (*i_results)->set_timestamp(timestamp); + } +} + +void +XAnalyzer::notify_calculation_failed (AnalyzerHandler *handler, int64_t timestamp, const char *msg) +{ + XCAM_UNUSED (handler); + + if (_callback) + _callback->x3a_calculation_failed (this, timestamp, msg); + XCAM_LOG_DEBUG ( + "calculation failed on ts:" XCAM_TIMESTAMP_FORMAT ", reason:%s", + XCAM_TIMESTAMP_ARGS (timestamp), XCAM_STR (msg)); +} + +void +XAnalyzer::notify_calculation_done (X3aResultList &results) +{ + XCAM_ASSERT (!results.empty ()); + if (_callback) + _callback->x3a_calculation_done (this, results); +} + +}; diff --git a/xcore/xcam_analyzer.h b/xcore/xcam_analyzer.h new file mode 100644 index 0000000..086fcc6 --- /dev/null +++ b/xcore/xcam_analyzer.h @@ -0,0 +1,141 @@ +/* + * xcam_analyzer.h - libxcam analyzer + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Zong Wei <wei.zong@intel.com> + */ + +#ifndef XCAM_ANALYZER_H +#define XCAM_ANALYZER_H + +#include <xcam_std.h> +#include <handler_interface.h> +#include <xcam_thread.h> +#include <video_buffer.h> +#include <safe_list.h> + +namespace XCam { + +class XAnalyzer; + +class AnalyzerThread + : public Thread +{ +public: + AnalyzerThread (XAnalyzer *analyzer); + ~AnalyzerThread (); + + void triger_stop() { + _stats_queue.pause_pop (); + } + bool push_stats (const SmartPtr<VideoBuffer> &buffer); + +protected: + virtual bool started (); + virtual void stopped () { + _stats_queue.clear (); + } + virtual bool loop (); + +private: + XAnalyzer *_analyzer; + SafeList<VideoBuffer> _stats_queue; +}; + +class AnalyzerCallback { +public: + explicit AnalyzerCallback () {} + virtual ~AnalyzerCallback () {} + virtual void x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results); + virtual void x3a_calculation_failed (XAnalyzer *analyzer, int64_t timestamp, const char *msg); + +private: + XCAM_DEAD_COPY (AnalyzerCallback); +}; + +class AnalyzerThread; + +class XAnalyzer { + friend class AnalyzerThread; +public: + explicit XAnalyzer (const char *name = NULL); + virtual ~XAnalyzer (); + + bool set_results_callback (AnalyzerCallback *callback); + XCamReturn prepare_handlers (); + + // prepare_handlers must called before init + XCamReturn init (uint32_t width, uint32_t height, double framerate); + XCamReturn deinit (); + // set_sync_mode must be called before start + XCamReturn set_sync_mode (bool sync); + bool get_sync_mode () const { + return _sync; + }; + XCamReturn start (); + XCamReturn stop (); + XCamReturn push_buffer (const SmartPtr<VideoBuffer> &buffer); + + uint32_t get_width () const { + return _width; + } + uint32_t get_height () const { + return _height; + } + + double get_framerate () const { + return _framerate; + } + const char * get_name () const { + return _name; + } + +protected: + /* virtual function list */ + virtual XCamReturn create_handlers () = 0; + virtual XCamReturn release_handlers () = 0; + virtual XCamReturn internal_init (uint32_t width, uint32_t height, double framerate) = 0; + virtual XCamReturn internal_deinit () = 0; + + // in analyzer thread + virtual XCamReturn configure () = 0; + virtual XCamReturn analyze (const SmartPtr<VideoBuffer> &buffer) = 0; + +protected: + void notify_calculation_done (X3aResultList &results); + void notify_calculation_failed (AnalyzerHandler *handler, int64_t timestamp, const char *msg); + void set_results_timestamp (X3aResultList &results, int64_t timestamp); + +private: + + XCAM_DEAD_COPY (XAnalyzer); + +protected: + SmartPtr<AnalyzerThread> _analyzer_thread; + +private: + char *_name; + bool _sync; + bool _started; + uint32_t _width; + uint32_t _height; + double _framerate; + AnalyzerCallback *_callback; +}; + +} +#endif //XCAM_ANALYZER_H diff --git a/xcore/xcam_buffer.cpp b/xcore/xcam_buffer.cpp new file mode 100644 index 0000000..72c1629 --- /dev/null +++ b/xcore/xcam_buffer.cpp @@ -0,0 +1,297 @@ +/* + * xcam_buffer.cpp - video buffer standard version + * + * Copyright (c) 2016 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include <base/xcam_buffer.h> + +XCamReturn +xcam_video_buffer_info_reset ( + XCamVideoBufferInfo *info, + uint32_t format, + uint32_t width, uint32_t height, + uint32_t aligned_width, uint32_t aligned_height, uint32_t size) +{ + uint32_t image_size = 0; + uint32_t i = 0; + + XCAM_ASSERT (info && format); + XCAM_ASSERT (!aligned_width || aligned_width >= width); + XCAM_ASSERT (!aligned_height || aligned_height >= height); + + if (!aligned_width) + aligned_width = XCAM_ALIGN_UP (width, 4); + if (!aligned_height) + aligned_height = XCAM_ALIGN_UP (height, 2); + + info->format = format; + info->width = width; + info->height = height; + info->aligned_width = aligned_width; + info->aligned_height = aligned_height; + + switch (format) { + case V4L2_PIX_FMT_GREY: + info->color_bits = 8; + info->components = 1; + info->strides [0] = aligned_width; + info->offsets [0] = 0; + image_size = info->strides [0] * aligned_height; + break; + case V4L2_PIX_FMT_NV12: + info->color_bits = 8; + info->components = 2; + info->strides [0] = aligned_width; + info->strides [1] = info->strides [0]; + info->offsets [0] = 0; + info->offsets [1] = info->offsets [0] + info->strides [0] * aligned_height; + image_size = info->strides [0] * aligned_height + info->strides [1] * aligned_height / 2; + break; + case V4L2_PIX_FMT_YUYV: + info->color_bits = 8; + info->components = 1; + info->strides [0] = aligned_width * 2; + info->offsets [0] = 0; + image_size = info->strides [0] * aligned_height; + break; + case V4L2_PIX_FMT_RGB565: + info->color_bits = 16; + info->components = 1; + info->strides [0] = aligned_width * 2; + info->offsets [0] = 0; + image_size = info->strides [0] * aligned_height; + break; + case V4L2_PIX_FMT_RGB24: + info->color_bits = 8; + info->components = 1; + info->strides [0] = aligned_width * 3; + info->offsets [0] = 0; + image_size = info->strides [0] * aligned_height; + break; + // memory order RGBA 8-8-8-8 + case V4L2_PIX_FMT_RGBA32: + // memory order: BGRA 8-8-8-8 + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_BGR32: + // memory order: ARGB 8-8-8-8 + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_ARGB32: + case V4L2_PIX_FMT_XRGB32: + info->color_bits = 8; + info->components = 1; + info->strides [0] = aligned_width * 4; + info->offsets [0] = 0; + image_size = info->strides [0] * aligned_height; + break; + case XCAM_PIX_FMT_RGB48: + info->color_bits = 16; + info->components = 1; + info->strides [0] = aligned_width * 3 * 2; + info->offsets [0] = 0; + image_size = info->strides [0] * aligned_height; + break; + case XCAM_PIX_FMT_RGBA64: + info->color_bits = 16; + info->components = 1; + info->strides [0] = aligned_width * 4 * 2; + info->offsets [0] = 0; + image_size = info->strides [0] * aligned_height; + break; + + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + info->color_bits = 8; + info->components = 1; + info->strides [0] = aligned_width; + info->offsets [0] = 0; + image_size = info->strides [0] * aligned_height; + break; + + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + info->color_bits = 10; + info->components = 1; + info->strides [0] = aligned_width * 2; + info->offsets [0] = 0; + image_size = info->strides [0] * aligned_height; + break; + + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + info->color_bits = 12; + info->components = 1; + info->strides [0] = aligned_width * 2; + info->offsets [0] = 0; + image_size = info->strides [0] * aligned_height; + break; + + case V4L2_PIX_FMT_SBGGR16: + case XCAM_PIX_FMT_SGRBG16: + info->color_bits = 16; + info->components = 1; + info->strides [0] = aligned_width * 2; + info->offsets [0] = 0; + image_size = info->strides [0] * aligned_height; + break; + + case XCAM_PIX_FMT_LAB: + info->color_bits = 8; + info->components = 1; + info->strides [0] = aligned_width * 3; + info->offsets [0] = 0; + image_size = info->strides [0] * aligned_height; + break; + + case XCAM_PIX_FMT_RGB48_planar: + case XCAM_PIX_FMT_RGB24_planar: + if (XCAM_PIX_FMT_RGB48_planar == format) + info->color_bits = 16; + else + info->color_bits = 8; + info->components = 3; + info->strides [0] = info->strides [1] = info->strides [2] = aligned_width * (info->color_bits / 8); + info->offsets [0] = 0; + info->offsets [1] = info->offsets [0] + info->strides [0] * aligned_height; + info->offsets [2] = info->offsets [1] + info->strides [1] * aligned_height; + image_size = info->offsets [2] + info->strides [2] * aligned_height; + break; + + case XCAM_PIX_FMT_SGRBG16_planar: + case XCAM_PIX_FMT_SGRBG8_planar: + if (XCAM_PIX_FMT_SGRBG16_planar == format) + info->color_bits = 16; + else + info->color_bits = 8; + info->components = 4; + for (i = 0; i < info->components; ++i) { + info->strides [i] = aligned_width * (info->color_bits / 8); + } + info->offsets [0] = 0; + for (i = 1; i < info->components; ++i) { + info->offsets [i] = info->offsets [i - 1] + info->strides [i - 1] * aligned_height; + } + image_size = info->offsets [info->components - 1] + info->strides [info->components - 1] * aligned_height; + break; + + default: + XCAM_LOG_WARNING ("XCamVideoBufferInfo reset failed, unsupported format:%s", xcam_fourcc_to_string (format)); + return XCAM_RETURN_ERROR_PARAM; + } + + if (!size) + info->size = image_size; + else { + XCAM_ASSERT (size >= image_size); + info->size = size; + } + + return XCAM_RETURN_NO_ERROR; +} + +XCamReturn +xcam_video_buffer_get_planar_info ( + const XCamVideoBufferInfo *buf_info, XCamVideoBufferPlanarInfo *planar_info, const uint32_t index) +{ + XCAM_ASSERT (buf_info); + XCAM_ASSERT (planar_info); + + planar_info->width = buf_info->width; + planar_info->height = buf_info->height; + planar_info->pixel_bytes = XCAM_ALIGN_UP (buf_info->color_bits, 8) / 8; + + switch (buf_info->format) { + case V4L2_PIX_FMT_NV12: + XCAM_ASSERT (index <= 1); + if (index == 1) { + planar_info->height = buf_info->height / 2; + } + break; + + case V4L2_PIX_FMT_GREY: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + case V4L2_PIX_FMT_SBGGR16: + case XCAM_PIX_FMT_SGRBG16: + XCAM_ASSERT (index <= 0); + break; + + case V4L2_PIX_FMT_RGB24: + XCAM_ASSERT (index <= 0); + planar_info->pixel_bytes = 3; + break; + + case V4L2_PIX_FMT_RGBA32: + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_ARGB32: + case V4L2_PIX_FMT_XRGB32: + XCAM_ASSERT (index <= 0); + planar_info->pixel_bytes = 4; + break; + + case XCAM_PIX_FMT_RGB48: + XCAM_ASSERT (index <= 0); + planar_info->pixel_bytes = 3 * 2; + break; + + case XCAM_PIX_FMT_RGBA64: + planar_info->pixel_bytes = 4 * 2; + break; + + case XCAM_PIX_FMT_LAB: + planar_info->pixel_bytes = 3; + break; + + case XCAM_PIX_FMT_RGB48_planar: + case XCAM_PIX_FMT_RGB24_planar: + XCAM_ASSERT (index <= 2); + break; + + case XCAM_PIX_FMT_SGRBG16_planar: + case XCAM_PIX_FMT_SGRBG8_planar: + XCAM_ASSERT (index <= 3); + break; + + default: + XCAM_LOG_WARNING ("VideoBufferInfo get_planar_info failed, unsupported format:%s", xcam_fourcc_to_string (buf_info->format)); + return XCAM_RETURN_ERROR_PARAM; + } + + return XCAM_RETURN_NO_ERROR; +} diff --git a/xcore/xcam_common.cpp b/xcore/xcam_common.cpp new file mode 100644 index 0000000..f982060 --- /dev/null +++ b/xcore/xcam_common.cpp @@ -0,0 +1,120 @@ +/* + * xcam_common.cpp - xcam common + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <base/xcam_common.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <stdarg.h> + +static char log_file_name[XCAM_MAX_STR_SIZE] = {0}; + +uint32_t xcam_version () +{ + return XCAM_VERSION; +} + +void * xcam_malloc(size_t size) +{ + return malloc (size); +} + +void * xcam_malloc0(size_t size) +{ + void * ptr = malloc (size); + memset (ptr, 0, size); + return ptr; +} + +void xcam_free(void *ptr) +{ + if (ptr) + free (ptr); +} + +int xcam_device_ioctl (int fd, int cmd, void *arg) +{ + int ret = 0; + int tried_time = 0; + + if (fd < 0) + return -1; + + while (1) { + ret = ioctl (fd, cmd, arg); + if (ret >= 0) + break; + if (errno != EINTR && errno != EAGAIN) + break; + if (++tried_time > 5) + break; + } + + if (ret >= 0) { + XCAM_LOG_DEBUG ("ioctl return ok on fd(%d), cmd:%d", fd, cmd); + } else { + XCAM_LOG_DEBUG ("ioctl failed on fd(%d), cmd:%d, error:%s", + fd, cmd, strerror(errno)); + } + return ret; +} + +const char * +xcam_fourcc_to_string (uint32_t fourcc) +{ + static char str[5]; + + xcam_mem_clear (str); + memcpy (str, &fourcc, 4); + return str; +} + +void xcam_print_log (const char* format, ...) { + char buffer[XCAM_MAX_STR_SIZE] = {0}; + + va_list va_list; + va_start (va_list, format); + vsnprintf (buffer, XCAM_MAX_STR_SIZE, format, va_list); + va_end (va_list); + + if (strlen (log_file_name) > 0) { + FILE* p_file = fopen (log_file_name, "ab+"); + if (NULL != p_file) { + fwrite (buffer, sizeof (buffer[0]), strlen (buffer), p_file); + fclose (p_file); + } else { + printf ("%s", buffer); + } + } else { + printf ("%s", buffer); + } +} + +void xcam_set_log (const char* file_name) { + if (NULL != file_name) { + memset (log_file_name, 0, XCAM_MAX_STR_SIZE); + strncpy (log_file_name, file_name, XCAM_MAX_STR_SIZE); + } +} + diff --git a/xcore/xcam_mutex.h b/xcore/xcam_mutex.h new file mode 100644 index 0000000..b294570 --- /dev/null +++ b/xcore/xcam_mutex.h @@ -0,0 +1,120 @@ +/* + * xcam_mutex.h - Lock + * + * Copyright (c) 2014 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_MUTEX_H +#define XCAM_MUTEX_H + +#include <xcam_std.h> +#include <pthread.h> +#include <sys/time.h> + +namespace XCam { + +class Mutex { + friend class Cond; +private: + XCAM_DEAD_COPY (Mutex); + +public: + Mutex () { + int error_num = pthread_mutex_init (&_mutex, NULL); + if (error_num != 0) { + XCAM_LOG_WARNING ("Mutex init failed %d: %s", error_num, strerror(error_num)); + } + } + virtual ~Mutex () { + int error_num = pthread_mutex_destroy (&_mutex); + if (error_num != 0) { + XCAM_LOG_WARNING ("Mutex destroy failed %d: %s", error_num, strerror(error_num)); + } + } + + void lock() { + int error_num = pthread_mutex_lock (&_mutex); + if (error_num != 0) { + XCAM_LOG_WARNING ("Mutex lock failed %d: %s", error_num, strerror(error_num)); + } + } + void unlock() { + int error_num = pthread_mutex_unlock (&_mutex); + if (error_num != 0) { + XCAM_LOG_WARNING ("Mutex unlock failed %d: %s", error_num, strerror(error_num)); + } + } + +private: + pthread_mutex_t _mutex; +}; + +class Cond { +private: + XCAM_DEAD_COPY (Cond); + +public: + Cond () { + pthread_cond_init (&_cond, NULL); + } + ~Cond () { + pthread_cond_destroy (&_cond); + } + + int wait (Mutex &mutex) { + return pthread_cond_wait (&_cond, &mutex._mutex); + } + int timedwait (Mutex &mutex, uint32_t time_in_us) { + struct timeval now; + struct timespec abstime; + + gettimeofday (&now, NULL); + now.tv_usec += time_in_us; + xcam_mem_clear (abstime); + abstime.tv_sec += now.tv_sec + now.tv_usec / 1000000; + abstime.tv_nsec = (now.tv_usec % 1000000) * 1000; + + return pthread_cond_timedwait (&_cond, &mutex._mutex, &abstime); + } + + int signal() { + return pthread_cond_signal (&_cond); + } + int broadcast() { + return pthread_cond_broadcast (&_cond); + } +private: + pthread_cond_t _cond; +}; + +class SmartLock { +private: + XCAM_DEAD_COPY (SmartLock); + +public: + SmartLock (XCam::Mutex &mutex): _mutex(mutex) { + _mutex.lock(); + } + virtual ~SmartLock () { + _mutex.unlock(); + } +private: + XCam::Mutex &_mutex; +}; +}; +#endif //XCAM_MUTEX_H + diff --git a/xcore/xcam_obj_debug.h b/xcore/xcam_obj_debug.h new file mode 100644 index 0000000..57d0fc7 --- /dev/null +++ b/xcore/xcam_obj_debug.h @@ -0,0 +1,111 @@ +/* + * xcam_obj_debug.h - object profiling and debug + * + * Copyright (c) 2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_OBJ_DEBUG_H +#define XCAM_OBJ_DEBUG_H + +#include <stdio.h> + +// default duration of frame numbers +#define XCAM_OBJ_DUR_FRAME_NUM 30 + +#define XCAM_STATIC_FPS_CALCULATION(objname, count) \ + do{ \ + static uint32_t num_frame = 0; \ + static struct timeval last_sys_time; \ + static struct timeval first_sys_time; \ + static bool b_last_sys_time_init = false; \ + if (!b_last_sys_time_init) { \ + gettimeofday (&last_sys_time, NULL); \ + gettimeofday (&first_sys_time, NULL); \ + b_last_sys_time_init = true; \ + } else { \ + if ((num_frame%count)==0) { \ + double total, current; \ + struct timeval cur_sys_time; \ + gettimeofday (&cur_sys_time, NULL); \ + total = (cur_sys_time.tv_sec - first_sys_time.tv_sec)*1.0f + \ + (cur_sys_time.tv_usec - first_sys_time.tv_usec)/1000000.0f; \ + current = (cur_sys_time.tv_sec - last_sys_time.tv_sec)*1.0f + \ + (cur_sys_time.tv_usec - last_sys_time.tv_usec)/1000000.0f; \ + printf("%s Current fps: %.2f, Total avg fps: %.2f\n", \ + #objname, ((float)(count))/current, (float)num_frame/total); \ + last_sys_time = cur_sys_time; \ + } \ + } \ + ++num_frame; \ + }while(0) + +#define XCAM_STATIC_PROFILING_START(name) \ + static unsigned int name##_times = 0; \ + static struct timeval name##_start_time; \ + static struct timeval name##_end_time; \ + gettimeofday (& name##_start_time, NULL); \ + ++ name##_times; + +#define XCAM_STATIC_PROFILING_END(name, times_of_print) \ + static double name##_sum_time = 0; \ + gettimeofday (& name##_end_time, NULL); \ + name##_sum_time += (name##_end_time.tv_sec - name##_start_time.tv_sec)*1000.0f + \ + (name##_end_time.tv_usec - name##_start_time.tv_usec)/1000.0f; \ + if (name##_times >= times_of_print) { \ + printf ("profiling %s, fps:%.2f duration:%.2fms\n", #name, \ + (name##_times*1000.0f/name##_sum_time), name##_sum_time/name##_times); \ + name##_times = 0; \ + name##_sum_time = 0.0; \ + } + +#if ENABLE_PROFILING +#define XCAM_OBJ_PROFILING_DEFINES \ + struct timeval _profiling_start_time; \ + uint32_t _profiling_times; \ + double _profiling_sum_duration + +#define XCAM_OBJ_PROFILING_INIT \ + xcam_mem_clear (_profiling_start_time); \ + _profiling_times = 0; \ + _profiling_sum_duration = 0.0 + +#define XCAM_OBJ_PROFILING_START \ + gettimeofday (&_profiling_start_time, NULL) + +#define XCAM_OBJ_PROFILING_END(name, times) \ + struct timeval profiling_now; \ + gettimeofday (&profiling_now, NULL); \ + _profiling_sum_duration += \ + (profiling_now.tv_sec - _profiling_start_time.tv_sec) * 1000.0f + \ + (profiling_now.tv_usec - _profiling_start_time.tv_usec) / 1000.0f; \ + ++_profiling_times; \ + if (_profiling_times >= times) { \ + char buf[1024]; \ + snprintf (buf, 1024, "profiling %s,average duration:%.2fms\n", \ + (name), (_profiling_sum_duration/times)); \ + printf ("%s", buf); \ + _profiling_times = 0; \ + _profiling_sum_duration = 0.0; \ + } +#else +#define XCAM_OBJ_PROFILING_DEFINES +#define XCAM_OBJ_PROFILING_INIT +#define XCAM_OBJ_PROFILING_START +#define XCAM_OBJ_PROFILING_END(name, times) +#endif + +#endif //XCAM_OBJ_DEBUG_H diff --git a/xcore/xcam_std.h b/xcore/xcam_std.h new file mode 100644 index 0000000..ca98b11 --- /dev/null +++ b/xcore/xcam_std.h @@ -0,0 +1,49 @@ +/* + * xcam_std.h - xcam std + * + * Copyright (c) 2014-2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_STD_H +#define XCAM_STD_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <base/xcam_common.h> +#include <xcam_obj_debug.h> +extern "C" { +#include <linux/videodev2.h> +} +#include <cinttypes> +#include <vector> +#include <smartptr.h> + +namespace XCam { + +static const int64_t InvalidTimestamp = INT64_C(-1); + +enum NV12PlaneIdx { + NV12PlaneYIdx = 0, + NV12PlaneUVIdx, + NV12PlaneMax, +}; + +}; + +#endif //XCAM_STD_H
\ No newline at end of file diff --git a/xcore/xcam_thread.cpp b/xcore/xcam_thread.cpp new file mode 100644 index 0000000..c385f9e --- /dev/null +++ b/xcore/xcam_thread.cpp @@ -0,0 +1,142 @@ +/* + * xcam_thread.cpp - Thread + * + * Copyright (c) 2014 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#include "xcam_thread.h" +#include "xcam_mutex.h" +#include <errno.h> + +namespace XCam { + +Thread::Thread (const char *name) + : _name (NULL) + , _thread_id (0) + , _started (false) + , _stopped (true) +{ + if (name) + _name = strndup (name, XCAM_MAX_STR_SIZE); +} + +Thread::~Thread () +{ + if (_name) + xcam_free (_name); +} + +int +Thread::thread_func (void *user_data) +{ + Thread *thread = (Thread *)user_data; + bool ret = true; + + { + // Make sure running after start + SmartLock locker(thread->_mutex); + pthread_detach (pthread_self()); + } + ret = thread->started (); + + while (true) { + { + SmartLock locker(thread->_mutex); + if (!thread->_started || ret == false) { + thread->_started = false; + thread->_thread_id = 0; + ret = false; + break; + } + } + + ret = thread->loop (); + } + + thread->stopped (); + + SmartLock locker(thread->_mutex); + thread->_stopped = true; + thread->_exit_cond.broadcast (); + + return 0; +} + +bool +Thread::started () +{ + XCAM_LOG_DEBUG ("Thread(%s) started", XCAM_STR(_name)); + return true; +} + +void +Thread::stopped () +{ + XCAM_LOG_DEBUG ("Thread(%s) stopped", XCAM_STR(_name)); +} + +bool Thread::start () +{ + SmartLock locker(_mutex); + if (_started) + return true; + + if (pthread_create (&_thread_id, NULL, (void * (*)(void*))thread_func, this) != 0) + return false; + _started = true; + _stopped = false; + +#ifdef __USE_GNU + char thread_name[16]; + xcam_mem_clear (thread_name); + snprintf (thread_name, sizeof (thread_name), "xc:%s", XCAM_STR(_name)); + int ret = pthread_setname_np (_thread_id, thread_name); + if (ret != 0) { + XCAM_LOG_WARNING ("Thread(%s) set name to thread_id failed.(%d, %s)", XCAM_STR(_name), ret, strerror(ret)); + } +#endif + + return true; +} + +bool +Thread::emit_stop () +{ + SmartLock locker(_mutex); + _started = false; + return true; +} + +bool Thread::stop () +{ + SmartLock locker(_mutex); + if (_started) { + _started = false; + } + if (!_stopped) { + _exit_cond.wait(_mutex); + } + return true; +} + +bool Thread::is_running () +{ + SmartLock locker(_mutex); + return _started; +} + +}; diff --git a/xcore/xcam_thread.h b/xcore/xcam_thread.h new file mode 100644 index 0000000..dfb7b22 --- /dev/null +++ b/xcore/xcam_thread.h @@ -0,0 +1,66 @@ +/* + * xcam_thread.h - Thread + * + * Copyright (c) 2014 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_THREAD_H +#define XCAM_THREAD_H + +#include <xcam_std.h> +#include <xcam_mutex.h> + +namespace XCam { + +class Thread { +public: + Thread (const char *name = NULL); + virtual ~Thread (); + + bool start (); + virtual bool emit_stop (); + bool stop (); + bool is_running (); + const char *get_name () const { + return _name; + } + +protected: + // return true to start loop, else the thread stopped + virtual bool started (); + virtual void stopped (); + // return true to continue; false to stop + virtual bool loop () = 0; +private: + XCAM_DEAD_COPY (Thread); + + +private: + static int thread_func (void *user_data); + +private: + char *_name; + pthread_t _thread_id; + XCam::Mutex _mutex; + XCam::Cond _exit_cond; + bool _started; + bool _stopped; +}; + +}; + +#endif //XCAM_THREAD_H diff --git a/xcore/xcam_utils.cpp b/xcore/xcam_utils.cpp new file mode 100644 index 0000000..4393961 --- /dev/null +++ b/xcore/xcam_utils.cpp @@ -0,0 +1,321 @@ +/* + * xcam_utils.h - xcam utilities + * + * Copyright (c) 2014-2015 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + * Author: Zong Wei <wei.zong@intel.com> + * Author: Junkai Wu <junkai.wu@intel.com> + * Author: Yinhang Liu <yinhangx.liu@intel.com> + */ + +#include "xcam_utils.h" +#include "video_buffer.h" +#include "image_file_handle.h" + +namespace XCam { + +static float +transform_bowl_coord_to_image_x ( + const float bowl_x, const float bowl_y, + const uint32_t img_width) +{ + float offset_radian = (bowl_x < 0.0f) ? PI : ((bowl_y >= 0.0f) ? 2.0f * PI : 0.0f); + float arctan_radian = (bowl_x != 0.0f) ? atan (-bowl_y / bowl_x) : ((bowl_y >= 0.0f) ? -PI / 2.0f : PI / 2.0f); + + float img_x = arctan_radian + offset_radian; + img_x *= img_width / (2.0f * PI); + return XCAM_CLAMP (img_x, 0.0f, img_width - 1.0f); +} + +static float +transform_bowl_coord_to_image_y ( + const BowlDataConfig &config, + const float bowl_x, const float bowl_y, const float bowl_z, + const uint32_t img_height) +{ + float wall_image_height = config.wall_height / (config.wall_height + config.ground_length) * img_height; + float ground_image_height = img_height - wall_image_height; + float img_y = 0.0f; + + if (bowl_z > 0.0f) { + img_y = (config.wall_height - bowl_z) * wall_image_height / config.wall_height; + img_y = XCAM_CLAMP (img_y, 0.0f, wall_image_height - 1.0f); + } else { + float max_semimajor = config.b * + sqrt (1 - config.center_z * config.center_z / (config.c * config.c)); + float min_semimajor = max_semimajor - config.ground_length; + XCAM_ASSERT (min_semimajor >= 0); + XCAM_ASSERT (max_semimajor > min_semimajor); + float step = ground_image_height / (max_semimajor - min_semimajor); + + float axis_ratio = config.a / config.b; + float cur_semimajor = sqrt (bowl_x * bowl_x + bowl_y * bowl_y * axis_ratio * axis_ratio) / axis_ratio; + cur_semimajor = XCAM_CLAMP (cur_semimajor, min_semimajor, max_semimajor); + + img_y = (max_semimajor - cur_semimajor) * step + wall_image_height; + img_y = XCAM_CLAMP (img_y, wall_image_height, img_height - 1.0f); + } + return img_y; +} + +PointFloat2 bowl_view_coords_to_image ( + const BowlDataConfig &config, + const PointFloat3 &bowl_pos, + const uint32_t img_width, const uint32_t img_height) +{ + PointFloat2 img_pos; + img_pos.x = transform_bowl_coord_to_image_x (bowl_pos.x, bowl_pos.y, img_width); + img_pos.y = transform_bowl_coord_to_image_y (config, bowl_pos.x, bowl_pos.y, bowl_pos.z, img_height); + + return img_pos; +} + +PointFloat3 bowl_view_image_to_world ( + const BowlDataConfig &config, + const uint32_t img_width, const uint32_t img_height, + const PointFloat2 &img_pos) +{ + PointFloat3 world; + float angle; + + float a = config.a; + float b = config.b; + float c = config.c; + + float wall_image_height = config.wall_height / (float)(config.wall_height + config.ground_length) * (float)img_height; + float ground_image_height = (float)img_height - wall_image_height; + + float z_step = (float)config.wall_height / wall_image_height; + float angle_step = fabs(config.angle_end - config.angle_start) / img_width; + + if(img_pos.y < wall_image_height) { + world.z = config.wall_height - img_pos.y * z_step; // TODO world.z + angle = degree2radian (config.angle_start + img_pos.x * angle_step); + float r2 = 1 - (world.z - config.center_z) * (world.z - config.center_z) / (c * c); + + if(XCAM_DOUBLE_EQUAL_AROUND (angle, PI / 2)) { + world.x = 0.0f; + world.y = -sqrt(r2 * b * b); + } else if (XCAM_DOUBLE_EQUAL_AROUND (angle, PI * 3 / 2)) { + world.x = 0.0f; + world.y = sqrt(r2 * b * b); + } else if((angle < PI / 2) || (angle > PI * 3 / 2)) { + world.x = sqrt(r2 * a * a * b * b / (b * b + a * a * tan(angle) * tan(angle))); + world.y = -world.x * tan(angle); + } else { + world.x = -sqrt(r2 * a * a * b * b / (b * b + a * a * tan(angle) * tan(angle))); + world.y = -world.x * tan(angle); + } + } else { + a = a * sqrt(1 - config.center_z * config.center_z / (c * c)); + b = b * sqrt(1 - config.center_z * config.center_z / (c * c)); + + float ratio_ab = b / a; + + float step_b = config.ground_length / ground_image_height; + + b = b - (img_pos.y - wall_image_height) * step_b; + a = b / ratio_ab; + + angle = degree2radian (config.angle_start + img_pos.x * angle_step); + + if(XCAM_DOUBLE_EQUAL_AROUND (angle, PI / 2)) { + world.x = 0.0f; + world.y = -b; + } else if (XCAM_DOUBLE_EQUAL_AROUND (angle, PI * 3 / 2)) { + world.x = 0.0f; + world.y = b; + } else if((angle < PI / 2) || (angle > PI * 3 / 2)) { + world.x = a * b / sqrt(b * b + a * a * tan(angle) * tan(angle)); + world.y = -world.x * tan(angle); + } else { + world.x = -a * b / sqrt(b * b + a * a * tan(angle) * tan(angle)); + world.y = -world.x * tan(angle); + } + world.z = 0.0f; + } + + return world; +} + +void centralize_bowl_coord_from_cameras ( + ExtrinsicParameter &front_cam, ExtrinsicParameter &right_cam, + ExtrinsicParameter &rear_cam, ExtrinsicParameter &left_cam, + PointFloat3 &bowl_coord_offset) +{ + bowl_coord_offset.x = (front_cam.trans_x + rear_cam.trans_x) / 2.0f; + bowl_coord_offset.y = (right_cam.trans_y + left_cam.trans_y) / 2.0f; + bowl_coord_offset.z = 0.0f; + + front_cam.trans_x -= bowl_coord_offset.x; + front_cam.trans_y -= bowl_coord_offset.y; + + right_cam.trans_x -= bowl_coord_offset.x; + right_cam.trans_y -= bowl_coord_offset.y; + + rear_cam.trans_x -= bowl_coord_offset.x; + rear_cam.trans_y -= bowl_coord_offset.y; + + left_cam.trans_x -= bowl_coord_offset.x; + left_cam.trans_y -= bowl_coord_offset.y; +} + +double +linear_interpolate_p2 ( + double value_start, double value_end, + double ref_start, double ref_end, + double ref_curr) +{ + double weight_start = 0; + double weight_end = 0; + double dist_start = 0; + double dist_end = 0; + double dist_sum = 0; + double value = 0; + + dist_start = abs(ref_curr - ref_start); + dist_end = abs(ref_end - ref_curr); + dist_sum = dist_start + dist_end; + + if (dist_start == 0) { + weight_start = 10000000.0; + } else { + weight_start = ((double)dist_sum / dist_start); + } + + if (dist_end == 0) { + weight_end = 10000000.0; + } else { + weight_end = ((double)dist_sum / dist_end); + } + + value = (value_start * weight_start + value_end * weight_end) / (weight_start + weight_end); + return value; +} + +double +linear_interpolate_p4( + double value_lt, double value_rt, + double value_lb, double value_rb, + double ref_lt_x, double ref_rt_x, + double ref_lb_x, double ref_rb_x, + double ref_lt_y, double ref_rt_y, + double ref_lb_y, double ref_rb_y, + double ref_curr_x, double ref_curr_y) +{ + double weight_lt = 0; + double weight_rt = 0; + double weight_lb = 0; + double weight_rb = 0; + double dist_lt = 0; + double dist_rt = 0; + double dist_lb = 0; + double dist_rb = 0; + double dist_sum = 0; + double value = 0; + + dist_lt = (double)abs(ref_curr_x - ref_lt_x) + (double)abs(ref_curr_y - ref_lt_y); + dist_rt = (double)abs(ref_curr_x - ref_rt_x) + (double)abs(ref_curr_y - ref_rt_y); + dist_lb = (double)abs(ref_curr_x - ref_lb_x) + (double)abs(ref_curr_y - ref_lb_y); + dist_rb = (double)abs(ref_curr_x - ref_rb_x) + (double)abs(ref_curr_y - ref_rb_y); + dist_sum = dist_lt + dist_rt + dist_lb + dist_rb; + + if (dist_lt == 0) { + weight_lt = 10000000.0; + } else { + weight_lt = ((float)dist_sum / dist_lt); + } + if (dist_rt == 0) { + weight_rt = 10000000.0; + } else { + weight_rt = ((float)dist_sum / dist_rt); + } + if (dist_lb == 0) { + weight_lb = 10000000.0; + } else { + weight_lb = ((float)dist_sum / dist_lb); + } + if (dist_rb == 0) { + weight_rb = 10000000.0; + } else { + weight_rb = ((float)dist_sum / dist_rt); + } + + value = (double)floor ( (value_lt * weight_lt + value_rt * weight_rt + + value_lb * weight_lb + value_rb * weight_rb) / + (weight_lt + weight_rt + weight_lb + weight_rb) + 0.5 ); + return value; +} + +void +get_gauss_table (uint32_t radius, float sigma, std::vector<float> &table, bool normalize) +{ + uint32_t i; + uint32_t scale = radius * 2 + 1; + float dis = 0.0f, sum = 1.0f; + + //XCAM_ASSERT (scale < 512); + table.resize (scale); + table[radius] = 1.0f; + + for (i = 0; i < radius; i++) { + dis = ((float)i - radius) * ((float)i - radius); + table[i] = table[scale - i - 1] = exp(-dis / (2.0f * sigma * sigma)); + sum += table[i] * 2.0f; + } + + if (!normalize) + return; + + for(i = 0; i < scale; i++) + table[i] /= sum; +} + +void +dump_buf_perfix_path (const SmartPtr<VideoBuffer> buf, const char *prefix_name) +{ + char file_name[256]; + XCAM_ASSERT (prefix_name); + XCAM_ASSERT (buf.ptr ()); + + const VideoBufferInfo &info = buf->get_video_info (); + snprintf ( + file_name, 256, "%s-%dx%d.%s", + prefix_name, info.width, info.height, xcam_fourcc_to_string (info.format)); + + dump_video_buf (buf, file_name); +} + +bool +dump_video_buf (const SmartPtr<VideoBuffer> buf, const char *file_name) +{ + ImageFileHandle file; + XCAM_ASSERT (file_name); + + XCamReturn ret = file.open (file_name, "wb"); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), false, + "dump buffer failed when open file: %s", file_name); + + ret = file.write_buf (buf); + XCAM_FAIL_RETURN ( + ERROR, xcam_ret_is_ok (ret), false, + "dump buffer to file: %s failed", file_name); + + return true; +} + +} diff --git a/xcore/xcam_utils.h b/xcore/xcam_utils.h new file mode 100644 index 0000000..492744a --- /dev/null +++ b/xcore/xcam_utils.h @@ -0,0 +1,69 @@ +/* + * xcam_utils.h - xcam utilities + * + * Copyright (c) 2014-2017 Intel Corporation + * + * 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. + * + * Author: Wind Yuan <feng.yuan@intel.com> + */ + +#ifndef XCAM_UTILS_H +#define XCAM_UTILS_H + +#include <xcam_std.h> +#include <interface/data_types.h> + +namespace XCam { + +PointFloat2 bowl_view_coords_to_image ( + const BowlDataConfig &config, + const PointFloat3 &bowl_pos, + const uint32_t img_width, const uint32_t img_height); + +PointFloat3 bowl_view_image_to_world ( + const BowlDataConfig &config, + const uint32_t img_width, const uint32_t img_height, + const PointFloat2 &img_pos); + +void centralize_bowl_coord_from_cameras ( + ExtrinsicParameter &front_cam, ExtrinsicParameter &right_cam, + ExtrinsicParameter &rear_cam, ExtrinsicParameter &left_cam, + PointFloat3 &bowl_coord_offset); + +double +linear_interpolate_p2 ( + double value_start, double value_end, + double ref_start, double ref_end, + double ref_curr); + +double +linear_interpolate_p4( + double value_lt, double value_rt, + double value_lb, double value_rb, + double ref_lt_x, double ref_rt_x, + double ref_lb_x, double ref_rb_x, + double ref_lt_y, double ref_rt_y, + double ref_lb_y, double ref_rb_y, + double ref_curr_x, double ref_curr_y); + +void get_gauss_table ( + uint32_t radius, float sigma, std::vector<float> &table, bool normalize = true); + +class VideoBuffer; +void dump_buf_perfix_path (const SmartPtr<VideoBuffer> buf, const char *prefix_name); +bool dump_video_buf (const SmartPtr<VideoBuffer> buf, const char *file_name); + +}; + +#endif //XCAM_UTILS_H |