Snap for 4545621 from 6bd266236b4d1fb459cd90faeb32810e50b1a9d5 to pi-release

Change-Id: If4b034303371be3212369843236041d628ee6619
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
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e2fd75b
--- /dev/null
+++ b/AUTHORS
@@ -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)
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..744d243
--- /dev/null
+++ b/COPYING
@@ -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
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..744d243
--- /dev/null
+++ b/LICENSE
@@ -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
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..119b819
--- /dev/null
+++ b/NOTICE
@@ -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 &param_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 &param_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 &param_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
new file mode 100644
index 0000000..2763d2d
--- /dev/null
+++ b/doc/xcam_cl_pipeline_20170407.png
Binary files differ
diff --git a/doc/xcam_dataflow_20160930.png b/doc/xcam_dataflow_20160930.png
new file mode 100644
index 0000000..cfde1f8
--- /dev/null
+++ b/doc/xcam_dataflow_20160930.png
Binary files differ
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&#160;<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
new file mode 100644
index 0000000..ea7b7ee
--- /dev/null
+++ b/doc/xcam_framework_20170407.png
Binary files differ
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
index 0000000..79cf910
--- /dev/null
+++ b/ext/atomisp
@@ -0,0 +1 @@
+Subproject commit 79cf910fb8d8f547c80c3ceb3188b319c55c98d2
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 &param)
+{
+    if (!_analyzer_aiq->update_ae_parameters (param))
+        return XCAM_RETURN_ERROR_AIQ;
+
+    return DynamicAnalyzer::analyze_ae (param);
+}
+
+XCamReturn
+HybridAnalyzer::analyze_awb (XCamAwbParam &param)
+{
+    if (!_analyzer_aiq->update_awb_parameters (param))
+        return XCAM_RETURN_ERROR_AIQ;
+
+    return DynamicAnalyzer::analyze_awb (param);
+}
+
+XCamReturn
+HybridAnalyzer::analyze_af (XCamAfParam &param)
+{
+    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 &param);
+    virtual XCamReturn analyze_awb (XCamAwbParam &param);
+    virtual XCamReturn analyze_af (XCamAfParam &param);
+
+    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 &param)
+{
+    XCamReturn ret = XCAM_RETURN_NO_ERROR;
+
+    XCAM_ASSERT (_analyzer.ptr ());
+    _analyzer->update_ae_parameters (param);
+    return ret;
+}
+
+XCamReturn
+X3aAnalyzeTuner::analyze_awb (XCamAwbParam &param)
+{
+    XCamReturn ret = XCAM_RETURN_NO_ERROR;
+
+    XCAM_ASSERT (_analyzer.ptr ());
+    _analyzer->update_awb_parameters (param);
+    return ret;
+}
+
+XCamReturn
+X3aAnalyzeTuner::analyze_af (XCamAfParam &param)
+{
+    XCamReturn ret = XCAM_RETURN_NO_ERROR;
+
+    XCAM_ASSERT (_analyzer.ptr ());
+    _analyzer->update_af_parameters (param);
+    return ret;
+}
+
+XCamReturn
+X3aAnalyzeTuner::analyze_common (XCamCommonParam &param)
+{
+    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 &param);
+    XCamReturn analyze_awb (XCamAwbParam &param);
+    XCamReturn analyze_af (XCamAfParam &param);
+    XCamReturn analyze_common (XCamCommonParam &param);
+
+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 &parameters)
+{
+    if ( _device->io_control (ATOMISP_IOC_G_ISP_PARM, &parameters) < 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 &parameters);
+
+    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 = &ee;
+    }
+    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, &region, &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 &params)
+{
+    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 &params);
+    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> &current = *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> &param,
+        const SmartPtr<VideoBuffer> &in_buf,
+        const uint32_t level, const SoftBlender::BufIdx idx);
+
+    XCamReturn start_lap_task (
+        const SmartPtr<ImageHandler::Parameters> &param,
+        const uint32_t level, const SoftBlender::BufIdx idx,
+        const SmartPtr<GaussDownScale::Args> &scale_args);
+    XCamReturn start_blend_task (
+        const SmartPtr<ImageHandler::Parameters> &param,
+        const SmartPtr<VideoBuffer> &buf,
+        const SoftBlender::BufIdx idx);
+
+    XCamReturn start_reconstruct_task_by_lap (
+        const SmartPtr<ImageHandler::Parameters> &param,
+        const SmartPtr<VideoBuffer> &lap,
+        const uint32_t level, const SoftBlender::BufIdx idx);
+    XCamReturn start_reconstruct_task_by_gauss (
+        const SmartPtr<ImageHandler::Parameters> &param,
+        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> &param,
+    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> &param,
+    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> &param,
+    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> &param,
+    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> &param,
+    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> &param)
+{
+    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> &param);
+    XCamReturn start_work (const SmartPtr<Parameters> &param);
+
+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> &param,
+            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> &param,
+            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> &param,
+            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> &param,
+            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> &param)
+            : 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> &param)
+{
+    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> &param)
+{
+    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> &param)
+{
+    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> &param);
+    XCamReturn start_work (const SmartPtr<Parameters> &param);
+
+private:
+    XCamReturn start_remap_task (const SmartPtr<ImageHandler::Parameters> &param);
+
+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> &param)
+            : 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> &param, 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> &param, 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> &param, 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> &param, 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> &param)
+{
+    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> &param = NULL) : _param (param) {}
+    inline const SmartPtr<ImageHandler::Parameters> &get_param () const {
+        return _param;
+    }
+    inline void set_param (const SmartPtr<ImageHandler::Parameters> &param) {
+        _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> &param, bool sync);
+    virtual XCamReturn finish ();
+    virtual XCamReturn terminate ();
+
+protected:
+    virtual XCamReturn configure_resource (const SmartPtr<Parameters> &param) = 0;
+    virtual XCamReturn start_work (const SmartPtr<Parameters> &param) = 0;
+    //virtual SmartPtr<Worker::Arguments> get_first_worker_args (const SmartPtr<SoftWorker> &worker, SmartPtr<Parameters> &params) = 0;
+    virtual void work_well_done (const SmartPtr<ImageHandler::Parameters> &param, XCamReturn err);
+    virtual void work_broken (const SmartPtr<ImageHandler::Parameters> &param, XCamReturn err);
+
+    //directly usage
+    bool check_work_continue (const SmartPtr<ImageHandler::Parameters> &param, XCamReturn err);
+
+private:
+    XCamReturn confirm_configured ();
+    void param_ended (SmartPtr<ImageHandler::Parameters> param, XCamReturn err);
+    static bool is_param_error (const SmartPtr<ImageHandler::Parameters> &param);
+
+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> &param)
+        : 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> &param,
+        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> &param);
+    int32_t dec_task_count (const SmartPtr<SoftStitcher::StitcherParam> &param);
+
+    XCamReturn start_dewarp_works (const SmartPtr<SoftStitcher::StitcherParam> &param);
+    XCamReturn start_task_count (const SmartPtr<SoftStitcher::StitcherParam> &param);
+    XCamReturn start_overlap_tasks (
+        const SmartPtr<SoftStitcher::StitcherParam> &param,
+        const uint32_t idx, const SmartPtr<VideoBuffer> &buf);
+    XCamReturn start_copy_tasks (
+        const SmartPtr<SoftStitcher::StitcherParam> &param,
+        const uint32_t idx, const SmartPtr<VideoBuffer> &buf);
+
+    XCamReturn start_single_blender (const uint32_t idx, const SmartPtr<BlenderParam> &param);
+    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> &param)
+{
+    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> &param)
+{
+    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> &param)
+{
+    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> &param)
+{
+    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> &param,
+    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> &param,
+    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> &param,
+    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 &copy = *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> &param)
+{
+    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> &param)
+{
+    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> &param);
+    XCamReturn start_work (const SmartPtr<Parameters> &param);
+
+private:
+    // handler done, call back functions
+    XCamReturn start_task_count (
+        const SmartPtr<SoftStitcher::StitcherParam> &param);
+    void dewarp_done (
+        const SmartPtr<ImageHandler> &handler,
+        const SmartPtr<ImageHandler::Parameters> &param, const XCamReturn error);
+    void blender_done (
+        const SmartPtr<ImageHandler> &handler,
+        const SmartPtr<ImageHandler::Parameters> &param, 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 &param)
+{
+    XCAM_ASSERT (_context);
+    return _desc->analyze_ae (_context, &param);
+}
+
+XCamReturn
+DynamicAnalyzer::analyze_awb (XCamAwbParam &param)
+{
+    XCAM_ASSERT (_context);
+    return _desc->analyze_awb (_context, &param);
+}
+
+XCamReturn
+DynamicAnalyzer::analyze_af (XCamAfParam &param)
+{
+    XCAM_ASSERT (_context);
+    return _desc->analyze_af (_context, &param);
+}
+
+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 &param);
+    virtual XCamReturn analyze_awb (XCamAwbParam &param);
+    virtual XCamReturn analyze_af (XCamAfParam &param);
+
+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 &params)
+{
+    {
+        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 &params)
+{
+    {
+        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 &params)
+{
+    {
+        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 &params)
+{
+    {
+        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 &params);
+
+    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 &params);
+
+    //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 &params);
+
+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 &params);
+
+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> &params, 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> &params,  \
+            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> &params, 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> &params, bool sync) = 0;
+    virtual XCamReturn finish ();
+    virtual XCamReturn terminate ();
+
+protected:
+    virtual void execute_status_check (const SmartPtr<Parameters> &params, 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 &params)
+    : _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 &params)
+{
+    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 &params);
+    explicit ImageProjector (
+        double focal_x,
+        double focal_y,
+        double offset_x,
+        double offset_y,
+        double skew);
+
+    virtual ~ImageProjector () {};
+
+    XCamReturn set_sensor_calibration (CalibrationParams &params);
+    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 &current,
+    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 &current = 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 &params)
+{
+    XCamReturn ret = XCAM_RETURN_NO_ERROR;
+
+    XCAM_ASSERT (_context);
+    ret = _desc->update_params (_context, &params);
+    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 &params);
+    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 &params)
+{
+    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 &params);
+    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, &param) < 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, &param) < 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, &param) < 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 &params)
+{
+    XCAM_ASSERT (_awb_handler.ptr());
+    return _awb_handler->update_parameters (params);
+}
+
+bool
+X3aAnalyzer::update_common_parameters (const XCamCommonParam &params)
+{
+    XCAM_ASSERT (_common_handler.ptr());
+    return _common_handler->update_parameters (params);
+}
+
+bool
+X3aAnalyzer::update_ae_parameters (const XCamAeParam &params)
+{
+    XCAM_ASSERT (_ae_handler.ptr());
+    return _ae_handler->update_parameters (params);
+}
+
+bool
+X3aAnalyzer::update_af_parameters (const XCamAfParam &params)
+{
+    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 &params);
+    bool update_ae_parameters (const XCamAeParam &params);
+    bool update_af_parameters (const XCamAfParam &params);
+    bool update_common_parameters (const XCamCommonParam &params);
+
+    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