Android11.0(R) HAL 相机集成水印算法+多帧算法

221 阅读26分钟

一、写在前面

上网🏄经常看到一些好文章,除了收藏之外,顺手一会照着搞一搞。这次看到 qiuxintai 写的

MTK HAL算法集成之单帧算法

MTK HAL算法集成之多帧算法

有点东西,写的很详细,

适合来一遍,文章是基于MTK 9.0 的,大差不差。我就基于最新的 11 搞了。

f4gSmV.png f4cseK.png

二、准备工作

qiuxintai 文章中并没有提供 libwatermark.so watermark.rgba

libmultiframe.so 这几个关键的东西,所以我们要先把这几个东西集齐才能召唤神龙。

经过一顿翻看,好在 qiuxintai 还是留了点线索,去他 github 中提取这几个关键的东西。

github.com/qiuxintai/W…

github.com/qiuxintai/Y…

虽然你找到了这些原材料,好戏才刚刚开始,你需要将原材料提取成可放到 aosp 中编译的格式且不报错还是

有一点麻烦的。这期间停滞了好几天,也算是补充了不少 so 编译相关的知识。 那么开始干吧!

三、提取精华

新建 AS 工程,就叫 jnidemo 吧,从 YUV420Converter 中提取 cpp 文件夹下所有文件到 jnidemo 中

从 qiuxintai 多帧文章中提取 mf_processor_impl.cpp

从 Watermark 中提取 watermark.cpp 并进行改造

整合后的 jnidemo 链接

这里说一下 CMakeLists.txt 含义


cmake_minimum_required(VERSION 3.4.1)
#引入头文件依赖编译
include_directories(${CMAKE_SOURCE_DIR}/include)

find_library(log-lib log)
#编译 libNativeUtils.so
add_library(
        NativeUtils
        SHARED
        native.cpp
        native_utils.cpp
)
target_link_libraries(NativeUtils ${log-lib})

#引入第三方libopencv_java3.so 编译 opencv3
add_library(opencv3 SHARED IMPORTED)
set_target_properties(
        opencv3
        PROPERTIES
        IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libopencv_java3.so
)

#编译 libOpencvUtils.so 并链接刚刚 opencv3
add_library(
        OpencvUtils
        SHARED
        opencv.cpp
        opencv_utils.cpp
)
target_link_libraries(OpencvUtils opencv3 ${log-lib})

#引入第三方libyuv.so 编译 libyuv
add_library(libyuv SHARED IMPORTED)
set_target_properties(
        libyuv
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libyuv.so
)

#编译 libLibyuvUtils.so 并链接刚刚 libyuv
add_library(
        LibyuvUtils
        SHARED
        libyuv.cpp
        libyuv_utils.cpp
)
target_link_libraries(LibyuvUtils libyuv ${log-lib})

#编译 libmultiframe.so 并链接刚刚 libyuv
add_library(
        multiframe
        SHARED
        mf_processor_impl.cpp
)
target_link_libraries(multiframe libyuv ${log-lib})

#编译 libwatermark.so 
add_library(
        watermark
        SHARED
        watermark.cpp
)
target_link_libraries(watermark ${log-lib})

build.gradle 中配置使用 cmake 编译 so,并制定 so 对应平台


 defaultConfig {

....

 /*externalNativeBuild {
            ndkBuild {
                path "src/main/jni/Android.mk"
            }
        }*/

        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
        ndk {
            abiFilters  'arm64-v8a', 'armeabi-v7a'
        }
    }

    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }

使用CMake引入第三方so库及头文件

AS使用ndkbuild创建cpp工程记录

ubuntu16.04 安装交叉编译工具aarch64-linux-gnu-gcc/g++

项目 build 成功后, so 位于 \jnidemo\build\intermediates\cmake\release\obj\arm64-v8a

问题一

vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/tp_watermark/lib/arm64-v8a/libwatermark.so: error: DT_NEEDED "libstdc++.so" is not specified in shared_libs.
vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/tp_watermark/lib/arm64-v8a/libwatermark.so: note:
vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/tp_watermark/lib/arm64-v8a/libwatermark.so: note: Fix suggestions:
vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/tp_watermark/lib/arm64-v8a/libwatermark.so: note:   Android.bp: shared_libs: ["libc", "libdl", "libm", "libstdc++"],
vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/tp_watermark/lib/arm64-v8a/libwatermark.so: note:   Android.mk: LOCAL_SHARED_LIBRARIES := libc libdl libm libstdc++
vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/tp_watermark/lib/arm64-v8a/libwatermark.so: note:
vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/tp_watermark/lib/arm64-v8a/libwatermark.so: note: If the fix above doesn't work, bypass this check with:
vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/tp_watermark/lib/arm64-v8a/libwatermark.so: note:   Android.bp: check_elf_files: false,
vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/tp_watermark/lib/arm64-v8a/libwatermark.so: note:   Android.mk: LOCAL_CHECK_ELF_FILES := false
[  5% 661/11941] target Strip: vendor.mediatek.hardware.camera.bgservice@1.1-impl

libwatermark.so 有问题,最开始用的 ndk 编译 so 文件,扔到源码里就出现上面奇怪的错误,一开始并没有想到用

cmake 编译,而是去 Ubuntu 下使用 ndk 再次编译,结果还是一样的。

四、注入灵魂(水印算法+多帧算法)

接下来就是跟着 qiuxintai 步骤来

4.1 添加自定义feature

添加新feature,我们选择添加一个自定义feature:TP_FEATURE_WATERMARK

vendor/mediatek/proprietary/hardware/mtkcam3/include/mtkcam3/3rdparty/customer/customer_feature_type.h

@@ -61,6 +61,7 @@ enum eFeatureIndexCustomer {
     TP_FEATURE_RELIGHTING   = 1ULL << 45,
     TP_FEATURE_ASYNC_ASD    = 1ULL << 46,
     TP_FEATURE_ZOOM_FUSION  = 1ULL << 47,   // used by zoom scenario
+    TP_FEATURE_WATERMARK    = 1ULL << 48,   //cczheng
     // TODO: reserve for customer feature index (bit 32-63)
 };

vendor/mediatek/proprietary/hardware/mtkcam3/feature/core/featurePipe/capture/CaptureFeature_Common.cpp

@@ -592,6 +592,7 @@ const char* FeatID2Name(FeatureID_T fid)
     case FID_RELIGHTING_3RD_PARTY:  return "relighting_3rd_party";
     case FID_AINR_YHDR:             return "ainr_yhdr";
     case FID_AIHDR:                 return "aihdr";
+    case FID_WATERMARK_3RD_PARTY:   return "watermark_3rd_party";//cczheng
 
     default:                        return "unknown";
     };

vendor/mediatek/proprietary/hardware/mtkcam3/feature/core/featurePipe/capture/nodes/YUVNode.cpp

@@ -619,6 +619,9 @@ MBOOL YUVNode::onInit()
             featId = FID_RELIGHTING_3RD_PARTY;
         else if(rProperty.mFeatures & MTK_FEATURE_YHDR_FOR_AINR)
             featId = FID_AINR_YHDR;
+        else if (rProperty.mFeatures & TP_FEATURE_WATERMARK)
+            featId = FID_WATERMARK_3RD_PARTY;//cczheng
+ 
 
         if (featId != NULL_FEATURE) {
             MY_LOGD_IF(mLogLevel, "%s finds plugin:%s, priority:%d",

vendor/mediatek/proprietary/hardware/mtkcam3/include/mtkcam3/feature/featurePipe/ICaptureFeaturePipe.h

@@ -191,6 +191,7 @@ enum CaptureFeatureFeatureID {
     FID_RELIGHTING_3RD_PARTY,
     FID_AINR_YHDR,
     FID_AIHDR,
+    FID_WATERMARK_3RD_PARTY,
     NUM_OF_FEATURE,
     NULL_FEATURE = 0xFF,
 };
 

vendor/mediatek/proprietary/hardware/mtkcam3/pipeline/hwnode/p2/P2_CaptureProcessor.cpp

@@ -487,6 +487,8 @@ MBOOL CaptureProcessor::onEnque(const sp<P2FrameRequest> &pP2FrameRequest)
                     pCapRequest->addFeature(FID_HFG);
                 if (feature & MTK_FEATURE_DCE)
                     pCapRequest->addFeature(FID_DCE);
+                if (feature & TP_FEATURE_WATERMARK)
+                    pCapRequest->addFeature(FID_WATERMARK_3RD_PARTY);//cczheng
                 if (feature & MTK_FEATURE_AINR_YUV)
                     pCapRequest->addFeature(FID_AINR_YUV);
                 if (feature & MTK_FEATURE_AINR_YHDR)


4.2 将算法对应的feature添加到scenario配置表

在我们打开camera进行预览和拍照的时候,MTK HAL3会执行vendor/mediatek/proprietary/hardware/mtkcam3/pipeline/policy/FeatureSettingPolicy.cpp的代码,会分别调用 vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/scenario_mgr.cpp的 get_streaming_scenario函数和get_capture_scenario函数。它们会读取一个scenario的feature配置表,遍历所有的feature,决定哪些feature会被执行。这个配置表中有许多的scenario,一个scenario可能对应多个feature。因此添加自定义feature后,还需将自定义的feature添加到配置表中。MTK feature 对应的配置表是 gMtkScenarioFeaturesMaps,customer feature 对应的配置表是 gCustomerScenarioFeaturesMaps。

vendor/mediatek/proprietary/custom/mt6765/hal/camera/camera_custom_feature_table.cpp


#include "camera_custom_feature_table.h"

using namespace NSCam::NSPipelinePlugin;

// ======================================================================================================
// For Camera HAL Server
// ======================================================================================================
// TODO: Feature Combinations for MTK Camera HAL server
// #define  <feature combination>              (key feature         | post-processing features | ...)
//
// logical stream
// single cam capture feature combination
#define MTK_FEATURE_COMBINATION_SINGLE         (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| TP_FEATURE_WATERMARK)
#define MTK_FEATURE_COMBINATION_HDR            (TP_FEATURE_HDR      | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| TP_FEATURE_WATERMARK)
#define MTK_FEATURE_COMBINATION_AINR           (MTK_FEATURE_AINR    | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| TP_FEATURE_WATERMARK)
#define MTK_FEATURE_COMBINATION_AIHDR          (MTK_FEATURE_AIHDR   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
#define MTK_FEATURE_COMBINATION_REMOSAIC_MFNR  (MTK_FEATURE_REMOSAIC_MFNR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
#define MTK_FEATURE_COMBINATION_MFNR           (MTK_FEATURE_MFNR    | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| TP_FEATURE_WATERMARK)
#define MTK_FEATURE_COMBINATION_REMOSAIC       (MTK_FEATURE_REMOSAIC| MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| TP_FEATURE_WATERMARK)
#define MTK_FEATURE_COMBINATION_CSHOT          (NO_FEATURE_NORMAL   | MTK_FEATURE_CZ| MTK_FEATURE_HFG)
#define MTK_FEATURE_COMBINATION_MULTICAM       (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
#define MTK_FEATURE_COMBINATION_YUV_REPROCESS  (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_FB| TP_FEATURE_WATERMARK)
#define MTK_FEATURE_COMBINATION_RAW_REPROCESS  (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE| TP_FEATURE_FB| TP_FEATURE_WATERMARK)
#define MTK_FEATURE_COMBINATION_SUPER_NIGHT_RAW_REPROCESS (NO_FEATURE_NORMAL | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE| TP_FEATURE_FB| TP_FEATURE_WATERMARK)

// request source frame from camerahalserver.
// no feature pure image quality for processing, the full image processing will be process in isp hidl.
#define MTK_FEATURE_COMBINATION_ISP_HIDL_SOURCE_COMMON  (NO_FEATURE_NORMAL | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE)
#define MTK_FEATURE_COMBINATION_ISP_HIDL_SOURCE_MFNR    (MTK_FEATURE_MFNR  | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE)
#define MTK_FEATURE_COMBINATION_ISP_HIDL_SOURCE_AINR    (MTK_FEATURE_AINR  | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE)

// dual cam capture feature combination
// the VSDOF means the combination of Bokeh feature and Depth feature
#define MTK_FEATURE_COMBINATION_MTK_VSDOF          (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| MTK_FEATURE_VSDOF| TP_FEATURE_WATERMARK)
#define MTK_FEATURE_COMBINATION_MTK_VSDOF_HDR      (TP_FEATURE_HDR_DC   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| MTK_FEATURE_VSDOF| TP_FEATURE_WATERMARK)
#define MTK_FEATURE_COMBINATION_MTK_VSDOF_MFNR     (MTK_FEATURE_MFNR    | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| MTK_FEATURE_VSDOF| TP_FEATURE_WATERMARK)
#define MTK_FEATURE_COMBINATION_MTK_VSDOF_AINR     (MTK_FEATURE_AINR    | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| MTK_FEATURE_AINR_YUV| MTK_FEATURE_VSDOF)

// zoom fusion combination, need TP_FEATURE_ZOOM_FUSION when sensor nums >= 2 && has tp fusion plugin
#define MTK_FEATURE_COMBINATION_MTK_ZOOM          (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| TP_FEATURE_ZOOM_FUSION)
#define MTK_FEATURE_COMBINATION_MTK_ZOOM_HDR      (TP_FEATURE_HDR      | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| TP_FEATURE_ZOOM_FUSION)
#define MTK_FEATURE_COMBINATION_MTK_ZOOM_AINR     (MTK_FEATURE_AINR    | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| TP_FEATURE_ZOOM_FUSION)
#define MTK_FEATURE_COMBINATION_MTK_ZOOM_AIHDR    (MTK_FEATURE_AIHDR   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| TP_FEATURE_ZOOM_FUSION)
#define MTK_FEATURE_COMBINATION_MTK_ZOOM_MFNR     (MTK_FEATURE_MFNR    | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| TP_FEATURE_ZOOM_FUSION)
#define MTK_FEATURE_COMBINATION_MTK_ZOOM_REMOSAIC (MTK_FEATURE_REMOSAIC| MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| TP_FEATURE_ZOOM_FUSION)

// physical stream
// single cam capture feature combination
#define MTK_FEATURE_COMBINATION_MASTER          (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
#define MTK_FEATURE_COMBINATION_SLAVE           (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
#define MTK_FEATURE_COMBINATION_REMOSAIC_MASTER (MTK_FEATURE_REMOSAIC| MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
#define MTK_FEATURE_COMBINATION_REMOSAIC_SLAVE  (MTK_FEATURE_REMOSAIC| MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
#define MTK_FEATURE_COMBINATION_MULTICAM_MASTER (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
#define MTK_FEATURE_COMBINATION_MULTICAM_SLAVE  (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
//
#define MTK_FEATURE_COMBINATION_VSDOF_MASTER    (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
#define MTK_FEATURE_COMBINATION_VSDOF_SLAVE     (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
#define MTK_FEATURE_COMBINATION_ZOOM_MASTER   (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
#define MTK_FEATURE_COMBINATION_ZOOM_SLAVE    (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)

#define MTK_FEATURE_COMBINATION_TP_MFNR           (TP_FEATURE_MFNR     | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| MTK_FEATURE_MFNR)

// request source frame from camerahalserver.
// no feature pure image quality for processing, the full image processing will be process in isp hidl.
#define MTK_FEATURE_COMBINATION_YUV_REPROCESS_MASTER        (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_FB)
#define MTK_FEATURE_COMBINATION_RAW_REPROCESS_MASTER        (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE| TP_FEATURE_FB)
#define MTK_FEATURE_COMBINATION_YUV_REPROCESS_SLAVE         (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_FB)
#define MTK_FEATURE_COMBINATION_RAW_REPROCESS_SLAVE         (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE| TP_FEATURE_FB)

// streaming feature combination (TODO: it should be refined by streaming scenario feature)
#define MTK_FEATURE_COMBINATION_VIDEO_NORMAL     (MTK_FEATURE_FB|MTK_FEATURE_ASYNC_ASD|MTK_FEATURE_EIS|TP_FEATURE_FB|TP_FEATURE_ASYNC_ASD|TP_FEATURE_EIS|MTK_FEATURE_FOVA|TP_FEATURE_WATERMARK)
#define MTK_FEATURE_COMBINATION_VIDEO_NORMAL_VIDEO   (MTK_FEATURE_FB|MTK_FEATURE_ASYNC_ASD|MTK_FEATURE_EIS|TP_FEATURE_FB|TP_FEATURE_ASYNC_ASD|TP_FEATURE_EIS|MTK_FEATURE_FOVA)
#define MTK_FEATURE_COMBINATION_VIDEO_DUAL_YUV   (MTK_FEATURE_FB|MTK_FEATURE_ASYNC_ASD|MTK_FEATURE_EIS|MTK_FEATURE_DUAL_YUV|TP_FEATURE_FB|TP_FEATURE_ASYNC_ASD|TP_FEATURE_EIS|TP_FEATURE_DUAL_YUV|TP_FEATURE_WATERMARK)
#define MTK_FEATURE_COMBINATION_VIDEO_DUAL_HWDEPTH (MTK_FEATURE_FB|MTK_FEATURE_ASYNC_ASD|MTK_FEATURE_EIS|MTK_FEATURE_DUAL_HWDEPTH|TP_FEATURE_FB|TP_FEATURE_ASYNC_ASD|TP_FEATURE_EIS|TP_FEATURE_DUAL_HWDEPTH|TP_FEATURE_WATERMARK)
#define MTK_FEATURE_COMBINATION_VIDEO_DUAL_HWVSDOF (MTK_FEATURE_FB|TP_FEATURE_FB|TP_FEATURE_WATERMARK)
// ======================================================================================================
//
// add scenario/feature set for logical camera scenario
const std::vector<std::unordered_map<int32_t, ScenarioFeatures>>  gCustomerScenarioFeaturesMaps =
{
    {
        // capture
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_NORMAL)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_AIHDR,    MTK_FEATURE_COMBINATION_AIHDR)
        ADD_CAMERA_FEATURE_SET(TP_FEATURE_HDR,       MTK_FEATURE_COMBINATION_HDR)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_AINR,     MTK_FEATURE_COMBINATION_AINR)
        //ADD_CAMERA_FEATURE_SET(MTK_FEATURE_REMOSAIC_MFNR, MTK_FEATURE_COMBINATION_REMOSAIC_MFNR)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_MFNR,     MTK_FEATURE_COMBINATION_MFNR)
        ADD_CAMERA_FEATURE_SET(TP_FEATURE_MFNR,      MTK_FEATURE_COMBINATION_TP_MFNR)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_REMOSAIC, MTK_FEATURE_COMBINATION_REMOSAIC)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL,    MTK_FEATURE_COMBINATION_SINGLE)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_VSDOF)
        ADD_CAMERA_FEATURE_SET(TP_FEATURE_HDR_DC, MTK_FEATURE_COMBINATION_MTK_VSDOF_HDR)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_MFNR,  MTK_FEATURE_COMBINATION_MTK_VSDOF_MFNR)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_MTK_VSDOF)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_MULTICAM)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_AIHDR,    MTK_FEATURE_COMBINATION_AIHDR)
        ADD_CAMERA_FEATURE_SET(TP_FEATURE_HDR,       MTK_FEATURE_COMBINATION_HDR)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_AINR,     MTK_FEATURE_COMBINATION_AINR)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_MFNR,     MTK_FEATURE_COMBINATION_MFNR)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_REMOSAIC, MTK_FEATURE_COMBINATION_REMOSAIC)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL,    MTK_FEATURE_COMBINATION_MULTICAM)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_ZOOM)
        ADD_CAMERA_FEATURE_SET(TP_FEATURE_HDR,       MTK_FEATURE_COMBINATION_MTK_ZOOM_HDR)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_AINR,     MTK_FEATURE_COMBINATION_MTK_ZOOM_AINR)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_MFNR,     MTK_FEATURE_COMBINATION_MTK_ZOOM_MFNR)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_REMOSAIC, MTK_FEATURE_COMBINATION_MTK_ZOOM_REMOSAIC)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL,    MTK_FEATURE_COMBINATION_MTK_ZOOM)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_CSHOT)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_CSHOT)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_DNG_OPAQUE_RAW)
        /* not support multiframe features with dng capture yet */
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_SINGLE)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_YUV_REPROCESS)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_YUV_REPROCESS)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_RAW_REPROCESS)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_RAW_REPROCESS)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(CUSTOMER_CAMERA_SCENARIO_CAPTURE_SUPER_NIGHT)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_AINR,     MTK_FEATURE_COMBINATION_AINR)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_MFNR,     MTK_FEATURE_COMBINATION_MFNR)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL,    MTK_FEATURE_COMBINATION_SINGLE)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(CUSTOMER_CAMERA_SCENARIO_CAPTURE_SUPER_NIGHT_RAW_REPROCESS)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_SUPER_NIGHT_RAW_REPROCESS)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_REQUEST_FRAME_FOR_ISP_HIDL_YUV)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_ISP_HIDL_SOURCE_COMMON)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_REQUEST_FRAME_FOR_ISP_HIDL_RAW)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_AINR,  MTK_FEATURE_COMBINATION_ISP_HIDL_SOURCE_AINR)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_MFNR,  MTK_FEATURE_COMBINATION_ISP_HIDL_SOURCE_MFNR)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_ISP_HIDL_SOURCE_COMMON)
        CAMERA_SCENARIO_END
        //
        // streaming
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_NORMAL)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_NORMAL)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_NORMAL_VIDEO)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_NORMAL_VIDEO)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_DUAL_YUV)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_DUAL_YUV)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_DUAL_HWDEPTH)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_DUAL_HWDEPTH)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_DUAL_HWVSDOF)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_DUAL_HWVSDOF)
        CAMERA_SCENARIO_END
    },
};

// add scenario/feature set for master physical camera scenario
const std::vector<std::unordered_map<int32_t, ScenarioFeatures>>  gCustomerScenarioFeaturesMapsPhyMaster =
{
    {
        // capture physical master
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_NORMAL)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_REMOSAIC, MTK_FEATURE_COMBINATION_REMOSAIC_MASTER)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL,    MTK_FEATURE_COMBINATION_MASTER)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_VSDOF)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_REMOSAIC, MTK_FEATURE_COMBINATION_REMOSAIC_MASTER)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VSDOF_MASTER)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_MULTICAM)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_REMOSAIC, MTK_FEATURE_COMBINATION_REMOSAIC_MASTER)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_MULTICAM_MASTER)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_ZOOM)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_REMOSAIC, MTK_FEATURE_COMBINATION_REMOSAIC_MASTER)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_ZOOM_MASTER)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_YUV_REPROCESS)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_YUV_REPROCESS_MASTER)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_RAW_REPROCESS)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_RAW_REPROCESS_MASTER)
        CAMERA_SCENARIO_END
        //
        // streaming
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_NORMAL)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_NORMAL)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_NORMAL_VIDEO)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_NORMAL_VIDEO)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_DUAL_YUV)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_DUAL_YUV)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_DUAL_HWDEPTH)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_DUAL_HWDEPTH)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_DUAL_HWVSDOF)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_DUAL_HWVSDOF)
        CAMERA_SCENARIO_END
    },
};

// add scenario/feature set for slave physical camera scenario
const std::vector<std::unordered_map<int32_t, ScenarioFeatures>>  gCustomerScenarioFeaturesMapsPhySlave =
{
    {
        // capture physical slave
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_NORMAL)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_REMOSAIC, MTK_FEATURE_COMBINATION_REMOSAIC_SLAVE)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL,    MTK_FEATURE_COMBINATION_SLAVE)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_VSDOF)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_REMOSAIC, MTK_FEATURE_COMBINATION_REMOSAIC_SLAVE)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VSDOF_SLAVE)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_MULTICAM)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_REMOSAIC, MTK_FEATURE_COMBINATION_REMOSAIC_SLAVE)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_MULTICAM_SLAVE)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_ZOOM)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_REMOSAIC, MTK_FEATURE_COMBINATION_REMOSAIC_SLAVE)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_ZOOM_SLAVE)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_YUV_REPROCESS)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_YUV_REPROCESS_SLAVE)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_CAPTURE_RAW_REPROCESS)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_RAW_REPROCESS_SLAVE)
        CAMERA_SCENARIO_END
        //
        // streaming
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_NORMAL)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_NORMAL)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_NORMAL_VIDEO)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_NORMAL_VIDEO)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_DUAL_YUV)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_DUAL_YUV)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_DUAL_HWDEPTH)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_DUAL_HWDEPTH)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_CAMERA_SCENARIO_STREAMING_DUAL_HWVSDOF)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL, MTK_FEATURE_COMBINATION_VIDEO_DUAL_HWVSDOF)
        CAMERA_SCENARIO_END
    },
};


// ======================================================================================================
// For ISP HIDL only
// ======================================================================================================
// TODO: Feature Combinations for MTK ISP Device HIDL
// #define  <feature combination>              (key feature         | post-processing features | ...)
//
// isp hidl feature combination
#define MTK_FEATURE_COMBINATION_SINGLE_FULL         (NO_FEATURE_NORMAL | MTK_FEATURE_DCE| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_NR| MTK_FEATURE_CZ)
#define MTK_FEATURE_COMBINATION_AINR_FULL           (MTK_FEATURE_AINR  | MTK_FEATURE_DCE| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_NR| MTK_FEATURE_CZ)
#define MTK_FEATURE_COMBINATION_MFNR_FULL           (MTK_FEATURE_MFNR  | MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_NR| MTK_FEATURE_CZ)

// single frame in
#define MTK_FEATURE_COMBINATION_SINGLE_RAW_TO_YUV   (NO_FEATURE_NORMAL | MTK_FEATURE_DCE| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_NR| MTK_FEATURE_CZ)
#define MTK_FEATURE_COMBINATION_SINGLE_RAW_TO_JPEG  (NO_FEATURE_NORMAL | MTK_FEATURE_DCE| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_NR| MTK_FEATURE_CZ)
#define MTK_FEATURE_COMBINATION_SINGLE_YUV_TO_YUV   (NO_FEATURE_NORMAL) // image transform and crop/resize only
#define MTK_FEATURE_COMBINATION_SINGLE_YUV_TO_JPEG  (NO_FEATURE_NORMAL) // encode yuv to jpeg only.
// multiple frame in
#define MTK_FEATURE_COMBINATION_AINR_RAW_TO_RAW     (MTK_FEATURE_AINR)  // output AINR RAW only
#define MTK_FEATURE_COMBINATION_AINR_RAW_TO_YUV     (MTK_FEATURE_AINR  | MTK_FEATURE_DCE| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_NR| MTK_FEATURE_CZ)
#define MTK_FEATURE_COMBINATION_AINR_RAW_TO_JPEG    (MTK_FEATURE_AINR  | MTK_FEATURE_DCE| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_NR| MTK_FEATURE_CZ)
#define MTK_FEATURE_COMBINATION_MFNR_RAW_TO_YUV     (MTK_FEATURE_MFNR  | MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_NR| MTK_FEATURE_CZ)
#define MTK_FEATURE_COMBINATION_MFNR_RAW_TO_JPEG    (MTK_FEATURE_MFNR  | MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_NR| MTK_FEATURE_CZ)
// ======================================================================================================
//
const std::vector<std::unordered_map<int32_t, ScenarioFeatures>>  gCustomerIspHidlScenarioFeaturesMaps =
{
    {
        // capture
        CAMERA_SCENARIO_START(MTK_ISP_HIDL_SCENARIO_CAPTURE_ALL)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_AINR,     MTK_FEATURE_COMBINATION_AINR_FULL)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_MFNR,     MTK_FEATURE_COMBINATION_MFNR_FULL)
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL,    MTK_FEATURE_COMBINATION_SINGLE_FULL)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_ISP_HIDL_SCENARIO_CAPTURE_SINGLE_RAW_TO_YUV) // encode single raw to yuv
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL,    MTK_FEATURE_COMBINATION_SINGLE_RAW_TO_YUV)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_ISP_HIDL_SCENARIO_CAPTURE_SINGLE_RAW_TO_JPEG) // encode single raw to yuv and encode to jepg
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL,    MTK_FEATURE_COMBINATION_SINGLE_RAW_TO_JPEG)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_ISP_HIDL_SCENARIO_CAPTURE_SINGLE_YUV_TO_YUV) // single yuv reprocessing
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL,    MTK_FEATURE_COMBINATION_SINGLE_YUV_TO_YUV)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_ISP_HIDL_SCENARIO_CAPTURE_SINGLE_YUV_TO_JPEG) // encode single yuv to jpeg
        ADD_CAMERA_FEATURE_SET(NO_FEATURE_NORMAL,    MTK_FEATURE_COMBINATION_SINGLE_YUV_TO_JPEG)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_ISP_HIDL_SCENARIO_CAPTURE_MULTIPLE_RAW_TO_RAW) // multiframe raw to single raw
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_AINR,     MTK_FEATURE_COMBINATION_AINR_RAW_TO_RAW)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_ISP_HIDL_SCENARIO_CAPTURE_MULTIPLE_RAW_TO_YUV) // multiframe raw to single yuv
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_AINR,     MTK_FEATURE_COMBINATION_AINR_RAW_TO_YUV)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_MFNR,     MTK_FEATURE_COMBINATION_MFNR_RAW_TO_YUV)
        CAMERA_SCENARIO_END
        //
        CAMERA_SCENARIO_START(MTK_ISP_HIDL_SCENARIO_CAPTURE_MULTIPLE_RAW_TO_JPEG) // multiframe raw to jpeg
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_AINR,     MTK_FEATURE_COMBINATION_AINR_RAW_TO_JPEG)
        ADD_CAMERA_FEATURE_SET(MTK_FEATURE_MFNR,     MTK_FEATURE_COMBINATION_MFNR_RAW_TO_JPEG)
        CAMERA_SCENARIO_END
    },
};

vendor/mediatek/proprietary/packages/apps/Camera2/camerapostalgo/main/3rdparty/mtk/mtk_scenario_mgr.cpp

@@ -80,31 +80,31 @@ using namespace NSCam::v3::pipeline::policy::scenariomgr;
 // #define  <feature combination>              (key feature         | post-processing features | ...)
 //
 // single cam capture feature combination
-#define MTK_FEATURE_COMBINATION_SINGLE         (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
-#define MTK_FEATURE_COMBINATION_HDR            (TP_FEATURE_HDR      | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
-#define MTK_FEATURE_COMBINATION_AINR           (MTK_FEATURE_AINR    | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
+#define MTK_FEATURE_COMBINATION_SINGLE         (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| TP_FEATURE_WATERMARK)
+#define MTK_FEATURE_COMBINATION_HDR            (TP_FEATURE_HDR      | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| TP_FEATURE_WATERMARK)
+#define MTK_FEATURE_COMBINATION_AINR           (MTK_FEATURE_AINR    | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| T
P_FEATURE_WATERMARK)
 #define MTK_FEATURE_COMBINATION_AINR_HDR       (MTK_FEATURE_AINR_YHDR| MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
-#define MTK_FEATURE_COMBINATION_MFNR           (MTK_FEATURE_MFNR    | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
-#define MTK_FEATURE_COMBINATION_REMOSAIC       (MTK_FEATURE_REMOSAIC| MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB)
+#define MTK_FEATURE_COMBINATION_MFNR           (MTK_FEATURE_MFNR    | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| T
P_FEATURE_WATERMARK)
+#define MTK_FEATURE_COMBINATION_REMOSAIC       (MTK_FEATURE_REMOSAIC| MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_FB| T
P_FEATURE_WATERMARK)
 #define MTK_FEATURE_COMBINATION_CSHOT          (NO_FEATURE_NORMAL   | MTK_FEATURE_CZ| MTK_FEATURE_HFG)
 #define MTK_FEATURE_COMBINATION_MULTICAM       (NO_FEATURE_NORMAL)
-#define MTK_FEATURE_COMBINATION_YUV_REPROCESS  (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_FB)
-#define MTK_FEATURE_COMBINATION_RAW_REPROCESS  (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE| TP_FEATURE_FB)
-#define MTK_FEATURE_COMBINATION_SUPER_NIGHT_RAW_REPROCESS (NO_FEATURE_NORMAL | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE| TP_FEATURE_FB)
+#define MTK_FEATURE_COMBINATION_YUV_REPROCESS  (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_FB| TP_FEATURE_WATERMARK)
+#define MTK_FEATURE_COMBINATION_RAW_REPROCESS  (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE| TP_FEATURE_FB| TP_FEATURE_WATERMARK
)
+#define MTK_FEATURE_COMBINATION_SUPER_NIGHT_RAW_REPROCESS (NO_FEATURE_NORMAL | MTK_FEATURE_NR| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE| TP_FEATURE_FB| TP_FEATURE_
WATERMARK)
 
 // dual cam capture feature combination
 // the VSDOF means the combination of Bokeh feature and Depth feature
-#define MTK_FEATURE_COMBINATION_MTK_VSDOF          (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_F
B| MTK_FEATURE_VSDOF)
-#define MTK_FEATURE_COMBINATION_MTK_VSDOF_HDR      (TP_FEATURE_HDR_DC   | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_F
B| MTK_FEATURE_VSDOF)
-#define MTK_FEATURE_COMBINATION_MTK_VSDOF_MFNR     (MTK_FEATURE_MFNR    | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_F
B| MTK_FEATURE_VSDOF)
+#define MTK_FEATURE_COMBINATION_MTK_VSDOF          (NO_FEATURE_NORMAL   | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_F
B| MTK_FEATURE_VSDOF| TP_FEATURE_WATERMARK)
+#define MTK_FEATURE_COMBINATION_MTK_VSDOF_HDR      (TP_FEATURE_HDR_DC   | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_F
B| MTK_FEATURE_VSDOF| TP_FEATURE_WATERMARK)
+#define MTK_FEATURE_COMBINATION_MTK_VSDOF_MFNR     (MTK_FEATURE_MFNR    | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_F
B| MTK_FEATURE_VSDOF| TP_FEATURE_WATERMARK)
 #define MTK_FEATURE_COMBINATION_MTK_VSDOF_AINR     (MTK_FEATURE_AINR    | MTK_FEATURE_NR| MTK_FEATURE_ABF| MTK_FEATURE_CZ| MTK_FEATURE_DRE| MTK_FEATURE_HFG| MTK_FEATURE_DCE | MTK_FEATURE_F
B| MTK_FEATURE_AINR_YUV| MTK_FEATURE_VSDOF)
 
 // streaming feature combination (TODO: it should be refined by streaming scenario feature)
-#define MTK_FEATURE_COMBINATION_VIDEO_NORMAL     (MTK_FEATURE_FB|MTK_FEATURE_ASYNC_ASD|MTK_FEATURE_EIS|TP_FEATURE_FB|TP_FEATURE_ASYNC_ASD|TP_FEATURE_EIS|MTK_FEATURE_FOVA)
+#define MTK_FEATURE_COMBINATION_VIDEO_NORMAL     (MTK_FEATURE_FB|MTK_FEATURE_ASYNC_ASD|MTK_FEATURE_EIS|TP_FEATURE_FB|TP_FEATURE_ASYNC_ASD|TP_FEATURE_EIS|MTK_FEATURE_FOVA|TP_FEATURE_WATERMA
RK)
 #define MTK_FEATURE_COMBINATION_VIDEO_NORMAL_VIDEO   (MTK_FEATURE_FB|MTK_FEATURE_ASYNC_ASD|MTK_FEATURE_EIS|TP_FEATURE_FB|TP_FEATURE_ASYNC_ASD|TP_FEATURE_EIS|MTK_FEATURE_FOVA)
-#define MTK_FEATURE_COMBINATION_VIDEO_DUAL_YUV   (MTK_FEATURE_FB|MTK_FEATURE_ASYNC_ASD|MTK_FEATURE_EIS|MTK_FEATURE_DUAL_YUV|TP_FEATURE_FB|TP_FEATURE_ASYNC_ASD|TP_FEATURE_EIS|TP_FEATURE_DUA
L_YUV)
-#define MTK_FEATURE_COMBINATION_VIDEO_DUAL_HWDEPTH (MTK_FEATURE_FB|MTK_FEATURE_ASYNC_ASD|MTK_FEATURE_EIS|MTK_FEATURE_DUAL_HWDEPTH|TP_FEATURE_FB|TP_FEATURE_ASYNC_ASD|TP_FEATURE_EIS|TP_FEATU
RE_DUAL_HWDEPTH)
-#define MTK_FEATURE_COMBINATION_VIDEO_DUAL_HWVSDOF (MTK_FEATURE_FB|TP_FEATURE_FB)
+#define MTK_FEATURE_COMBINATION_VIDEO_DUAL_YUV   (MTK_FEATURE_FB|MTK_FEATURE_ASYNC_ASD|MTK_FEATURE_EIS|MTK_FEATURE_DUAL_YUV|TP_FEATURE_FB|TP_FEATURE_ASYNC_ASD|TP_FEATURE_EIS|TP_FEATURE_DUA
L_YUV|TP_FEATURE_WATERMARK)
+#define MTK_FEATURE_COMBINATION_VIDEO_DUAL_HWDEPTH (MTK_FEATURE_FB|MTK_FEATURE_ASYNC_ASD|MTK_FEATURE_EIS|MTK_FEATURE_DUAL_HWDEPTH|TP_FEATURE_FB|TP_FEATURE_ASYNC_ASD|TP_FEATURE_EIS|TP_FEATU
RE_DUAL_HWDEPTH|TP_FEATURE_WATERMARK)
+#define MTK_FEATURE_COMBINATION_VIDEO_DUAL_HWVSDOF (MTK_FEATURE_FB|TP_FEATURE_FB|TP_FEATURE_WATERMARK)

4.3 为算法选择plugin

MTK HAL3在vendor/mediatek/proprietary/hardware/mtkcam3/include/mtkcam3/3rdparty/plugin/PipelinePluginType.h 中将三方算法的挂载点大致分为以下几类:

BokehPlugin: Bokeh算法挂载点,双摄景深算法的虚化部分。

DepthPlugin: Depth算法挂载点,双摄景深算法的计算深度部分。

FusionPlugin: Depth和Bokeh放在1个算法中,即合并的双摄景深算法挂载点。

JoinPlugin: Streaming相关算法挂载点,预览算法都挂载在这里。

MultiFramePlugin: 多帧算法挂载点,包括YUV与RAW,例如MFNR/HDR

RawPlugin: RAW算法挂载点,例如remosaic

YuvPlugin: Yuv单帧算法挂载点,例如美颜、广角镜头畸变校正等

对号入座,将要集成的算法选择相应的plugin。

单帧水印算法,所以预览我们选择JoinPlugin,拍照选择YuvPlugin。

多帧算法,只能选择MultiFramePlugin。并且,一般情况下多帧算法只用于拍照,不用于预览。

4.4 编写算法集成文件

水印算法目录结构

参照 FBImpl.cpp 和 sample_streaming_fb.cpp 中分别实现拍照和预览。目录结构如下: vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/tp_watermark/ ├── Android.mk ├── include │ └── watermark.h ├── lib │ ├── arm64-v8a │ │ └── libwatermark.so │ └── armeabi-v7a │ └── libwatermark.so ├── res │ └── watermark.rgba ├── WatermarkCapture.cpp └── WatermarkPreview.cpp

文件说明:

Android.mk中配置算法库、头文件、集成的源代码CPP文件编译成库libmtkcam.plugin.tp_watermark,供libmtkcam_3rdparty.customer依赖调用。 集成的源代码CPP文件,WatermarkCapture.cpp用于拍照,WatermarkPreview.cpp用于预览。 libwatermark.so实现了添加水印的功能,libwatermark.so用来模拟需要接入的第三方算法库。watermark.h是头文件。 watermark.rgba是对应的水印文件。

多帧算法目录结构

参照mfnr/MFNRImpl.cpp中实现MFNR拍照。目录结构如下: vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/cp_tp_mfnr/ ├── Android.mk ├── include │ └── mf_processor.h ├── lib │ ├── arm64-v8a │ │ └── libmultiframe.so │ └── armeabi-v7a │ └── libmultiframe.so └── MFNRImpl.cpp

文件说明:

Android.mk中配置算法库、头文件、集成的源代码MFNRImpl.cpp文件,将它们编译成库libmtkcam.plugin.tp_mfnr,供libmtkcam_3rdparty.customer依赖调用。

libmultiframe.so实现了将连续4帧图像缩小,并拼接成一张图的功能,libmultiframe.so用来模拟需要接入的第三方多帧算法库。mf_processor.h是头文件。

MFNRImpl.cpp是集成的源代码CPP文件。

4.5 开撸代码

添加全局宏控,是否编译三方算法

device/mediateksample/[platform]/ProjectConfig.mk

@@ -5,6 +5,8 @@ AUTO_ADD_GLOBAL_DEFINE_BY_VALUE = BOOT_LOGO MTK_PLATFORM CUSTOM_KERNEL_MAIN_IMGS
 BUILD_KERNEL = yes
+QXT_MFNR_SUPPORT = yes
+QXT_WATERMARK_SUPPORT = yes
 BUILD_LK = yes

新增 vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/tp_watermark/ 文件夹

vendor\mediatek\proprietary\hardware\mtkcam3\3rdparty\customer\tp_watermark\Android.mk

ifeq ($(QXT_WATERMARK_SUPPORT),yes)
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := libwatermark
LOCAL_SRC_FILES_32 := lib/armeabi-v7a/libwatermark.so
LOCAL_SRC_FILES_64 := lib/arm64-v8a/libwatermark.so
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_SUFFIX := .so
LOCAL_PROPRIETARY_MODULE := true
LOCAL_CHECK_ELF_FILES := false
LOCAL_MULTILIB := both
include $(BUILD_PREBUILT)
################################################################################

################################################################################
include $(CLEAR_VARS)

#-----------------------------------------------------------
include $(TOP)/$(MTK_PATH_SOURCE)/hardware/mtkcam/mtkcam.mk

#-----------------------------------------------------------
LOCAL_SRC_FILES += WatermarkCapture.cpp
LOCAL_SRC_FILES += WatermarkPreview.cpp

#-----------------------------------------------------------
LOCAL_C_INCLUDES += $(MTKCAM_C_INCLUDES)
LOCAL_C_INCLUDES += $(TOP)/$(MTK_PATH_SOURCE)/hardware/mtkcam3/include
LOCAL_C_INCLUDES += $(TOP)/$(MTK_PATH_SOURCE)/hardware/mtkcam/include
#
LOCAL_C_INCLUDES += system/media/camera/include
LOCAL_C_INCLUDES += $(TOP)/external/libyuv/files/include/
LOCAL_C_INCLUDES += $(TOP)/$(MTK_PATH_SOURCE)/hardware/mtkcam3/3rdparty/customer/tp_watermark/include

#-----------------------------------------------------------
LOCAL_CFLAGS += $(MTKCAM_CFLAGS)
#

#-----------------------------------------------------------
LOCAL_STATIC_LIBRARIES +=
#
LOCAL_WHOLE_STATIC_LIBRARIES +=

#-----------------------------------------------------------
LOCAL_SHARED_LIBRARIES += liblog
LOCAL_SHARED_LIBRARIES += libutils
LOCAL_SHARED_LIBRARIES += libcutils
LOCAL_SHARED_LIBRARIES += libmtkcam_modulehelper
LOCAL_SHARED_LIBRARIES += libmtkcam_stdutils
LOCAL_SHARED_LIBRARIES += libmtkcam_pipeline
LOCAL_SHARED_LIBRARIES += libmtkcam_metadata
LOCAL_SHARED_LIBRARIES += libmtkcam_metastore
LOCAL_SHARED_LIBRARIES += libmtkcam_streamutils
LOCAL_SHARED_LIBRARIES += libmtkcam_imgbuf
LOCAL_SHARED_LIBRARIES += libyuv.vendor
#-----------------------------------------------------------
LOCAL_HEADER_LIBRARIES := libutils_headers liblog_headers libhardware_headers

#-----------------------------------------------------------
LOCAL_MODULE := libmtkcam.plugin.tp_watermark
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_OWNER := mtk
LOCAL_MODULE_TAGS := optional
include $(MTK_STATIC_LIBRARY)
################################################################################

include $(call all-makefiles-under,$(LOCAL_PATH))
endif

新增 vendor\mediatek\proprietary\hardware\mtkcam3\3rdparty\customer\tp_watermark\include\watermark.h

#include <stdio.h>
#include <string.h>
// #include <android/log.h>

namespace Watermark
{
    void add(unsigned char* src, int srcWidth, int srcHeight, unsigned char* watermark,
              int watermarkWidth, int watermarkHeight, int x, int y);
}


新增 vendor\mediatek\proprietary\hardware\mtkcam3\3rdparty\customer\tp_watermark\WatermarkCapture.cpp

主要函数介绍:

在property函数中feature类型设置我们在第三步中添加的TP_FEATURE_WATERMARK,并设置名称、优先级等等属性。

在negotiate函数中配置算法需要的输入、输出图像的格式、尺寸。

在negotiate函数或者process函数中获取上层传下来的metadata参数,根据参数决定算法是否运行,或者将参数传给算法。

在process函数中接入算法。

#define LOG_TAG "WatermarkCapture"
//
#include <mtkcam/utils/std/Log.h>
//
#include <stdlib.h>
#include <utils/Errors.h>
#include <utils/List.h>
#include <utils/RefBase.h>
#include <sstream>
//
#include <mtkcam/utils/metadata/client/mtk_metadata_tag.h>
#include <mtkcam/utils/metadata/hal/mtk_platform_metadata_tag.h>
//
//
#include <mtkcam/utils/imgbuf/IIonImageBufferHeap.h>
//
#include <mtkcam/drv/IHalSensor.h>
#include <mtkcam/utils/std/Format.h>
//
#include <mtkcam3/pipeline/hwnode/NodeId.h>

#include <mtkcam/utils/metastore/ITemplateRequest.h>
#include <mtkcam/utils/metastore/IMetadataProvider.h>
#include <mtkcam3/3rdparty/plugin/PipelinePlugin.h>
#include <mtkcam3/3rdparty/plugin/PipelinePluginType.h>

#include <stdlib.h>
#include <watermark.h>
#include <mtkcam/utils/std/Time.h>
#include <time.h>
#include <libyuv.h>
//
using namespace NSCam;
using namespace android;
using namespace std;
using namespace NSCam::NSPipelinePlugin;
/******************************************************************************
 *
 ******************************************************************************/
#define MY_LOGV(fmt, arg...)        CAM_LOGV("(%d)[%s] " fmt, ::gettid(), __FUNCTION__, ##arg)
#define MY_LOGD(fmt, arg...)        CAM_LOGD("(%d)[%s] " fmt, ::gettid(), __FUNCTION__, ##arg)
#define MY_LOGI(fmt, arg...)        CAM_LOGI("(%d)[%s] " fmt, ::gettid(), __FUNCTION__, ##arg)
#define MY_LOGW(fmt, arg...)        CAM_LOGW("(%d)[%s] " fmt, ::gettid(), __FUNCTION__, ##arg)
#define MY_LOGE(fmt, arg...)        CAM_LOGE("(%d)[%s] " fmt, ::gettid(), __FUNCTION__, ##arg)
//
#define FUNCTION_IN                 MY_LOGD("%s +", __FUNCTION__)
#define FUNCTION_OUT                MY_LOGD("%s -", __FUNCTION__)
//systrace
#if 1
#ifndef ATRACE_TAG
#define ATRACE_TAG                           ATRACE_TAG_CAMERA
#endif
#include <utils/Trace.h>

#define WATERMARK_TRACE_CALL()                      ATRACE_CALL()
#define WATERMARK_TRACE_NAME(name)                  ATRACE_NAME(name)
#define WATERMARK_TRACE_BEGIN(name)                 ATRACE_BEGIN(name)
#define WATERMARK_TRACE_END()                       ATRACE_END()
#else
#define WATERMARK_TRACE_CALL()
#define WATERMARK_TRACE_NAME(name)
#define WATERMARK_TRACE_BEGIN(name)
#define WATERMARK_TRACE_END()
#endif

template <class T>
inline bool
tryGetMetadata(IMetadata const *pMetadata, MUINT32 tag, T& rVal)
{
    if(pMetadata == nullptr) return MFALSE;

    IMetadata::IEntry entry = pMetadata->entryFor(tag);
    if(!entry.isEmpty())
    {
        rVal = entry.itemAt(0,Type2Type<T>());
        return true;
    }
    else
    {
#define var(v) #v
#define type(t) #t
        MY_LOGW("no metadata %s in %s", var(tag), type(pMetadata));
#undef type
#undef var
    }
    return false;
}

/******************************************************************************
*
******************************************************************************/
class WatermarkCapture : public YuvPlugin::IProvider {

public:
    typedef YuvPlugin::Property Property;
    typedef YuvPlugin::Selection Selection;
    typedef YuvPlugin::Request::Ptr RequestPtr;
    typedef YuvPlugin::RequestCallback::Ptr RequestCallbackPtr;

private:
    int mOpenid;

    MBOOL mEnable = 1;
    MBOOL mDump = 0;
    unsigned char *mSrcRGBA = nullptr;
    unsigned char *mWatermarkRGBA = nullptr;
    int mWatermarkWidth = 0;
    int mWatermarkHeight = 0;

public:
    WatermarkCapture();

    ~WatermarkCapture();

    void init();

    void uninit();

    void abort(vector <RequestPtr> &pRequests);

    void set(MINT32 iOpenId, MINT32 iOpenId2);

    const Property &property();

    MERROR negotiate(Selection &sel);

    MERROR process(RequestPtr pRequest, RequestCallbackPtr pCallback);

};

WatermarkCapture::WatermarkCapture() : mOpenid(-1) {
    FUNCTION_IN;
    mEnable = property_get_bool("vendor.debug.camera.watermark.capture.enable", 1);
    mDump = property_get_bool("vendor.debug.camera.watermark.capture.dump", 0);
    FUNCTION_OUT;
}

WatermarkCapture::~WatermarkCapture() {
    FUNCTION_IN;
    FUNCTION_OUT;
}

void WatermarkCapture::init() {
    FUNCTION_IN;
    mWatermarkWidth = 180;
    mWatermarkHeight = 640;
    int watermarkSize = mWatermarkWidth * mWatermarkHeight * 4;
    mWatermarkRGBA = (unsigned char *) malloc(watermarkSize);

    FILE *fp;
    char path[256];
    snprintf(path, sizeof(path), "/vendor/res/images/watermark.rgba");
    if ((fp = fopen(path, "r")) == NULL) {
        MY_LOGE("Failed to open /vendor/res/images/watermark.rgba");
    }
    fread(mWatermarkRGBA, 1, watermarkSize, fp);
    fclose(fp);
    FUNCTION_OUT;
}

void WatermarkCapture::uninit() {
    FUNCTION_IN;
    free(mWatermarkRGBA);
    FUNCTION_OUT;
}

void WatermarkCapture::abort(vector <RequestPtr> &pRequests) {
    FUNCTION_IN;
    (void)pRequests;
    FUNCTION_OUT;
}

void WatermarkCapture::set(MINT32 iOpenId, MINT32 iOpenId2) {
    FUNCTION_IN;
    MY_LOGD("set openId:%d openId2:%d", iOpenId, iOpenId2);
    mOpenid = iOpenId;
    FUNCTION_OUT;
}

const WatermarkCapture::Property &WatermarkCapture::property() {
    FUNCTION_IN;
    static Property prop;
    static bool inited;

    if (!inited) {
        prop.mName = "TP_WATERMARK";
        prop.mFeatures = TP_FEATURE_WATERMARK;
        prop.mInPlace = MTRUE;
        prop.mFaceData = eFD_Current;
        prop.mPosition = 0;
        inited = true;
    }
    FUNCTION_OUT;
    return prop;
}

MERROR WatermarkCapture::negotiate(Selection &sel) {
    FUNCTION_IN;
    if (!mEnable) {
        MY_LOGD("Force off TP_WATERMARK");
        FUNCTION_OUT;
        return -EINVAL;
    }

    sel.mIBufferFull
            .setRequired(MTRUE)
            .addAcceptedFormat(eImgFmt_I420)
            .addAcceptedSize(eImgSize_Full);

    sel.mIMetadataDynamic.setRequired(MTRUE);
    sel.mIMetadataApp.setRequired(MTRUE);
    sel.mIMetadataHal.setRequired(MTRUE);
    sel.mOMetadataApp.setRequired(MTRUE);
    sel.mOMetadataHal.setRequired(MTRUE);

    FUNCTION_OUT;
    return OK;
}

MERROR WatermarkCapture::process(RequestPtr pRequest,
                               RequestCallbackPtr pCallback = nullptr) {
    FUNCTION_IN;
    WATERMARK_TRACE_CALL();

    MBOOL needRun = MFALSE;
    if (pRequest->mIBufferFull != nullptr && pRequest->mOBufferFull != nullptr) {
        IImageBuffer *pIBufferFull = pRequest->mIBufferFull->acquire();
        IImageBuffer *pOBufferFull = pRequest->mOBufferFull->acquire();

        if (pRequest->mIMetadataDynamic != nullptr) {
            IMetadata *meta = pRequest->mIMetadataDynamic->acquire();
            if (meta != NULL)
                MY_LOGD("[IN] Dynamic metadata count: %d", meta->count());
            else
                MY_LOGD("[IN] Dynamic metadata empty");
        }

        int frameNo = 0, requestNo = 0;
        if (pRequest->mIMetadataHal != nullptr) {
            IMetadata *pIMetataHAL = pRequest->mIMetadataHal->acquire();
            if (pIMetataHAL != NULL) {
                MY_LOGD("[IN] HAL metadata count: %d", pIMetataHAL->count());
                if (!tryGetMetadata<int>(pIMetataHAL, MTK_PIPELINE_FRAME_NUMBER, frameNo)) {
                    frameNo = 0;
                }
                if (!tryGetMetadata<int>(pIMetataHAL, MTK_PIPELINE_REQUEST_NUMBER, requestNo)) {
                    requestNo = 0;
                }
                MY_LOGD("frameNo: %d, requestNo: %d", frameNo, requestNo);
            } else {
                MY_LOGD("[IN] HAL metadata empty");
            }
        }

        if (pRequest->mIMetadataApp != nullptr) {
            IMetadata *pIMetadataApp = pRequest->mIMetadataApp->acquire();
            MINT32 mode = 0;
            if (!tryGetMetadata<MINT32>(pIMetadataApp, QXT_FEATURE_WATERMARK, mode)) {
                mode = 0;
            }
            needRun = mode == 1 ? 1 : 0;
        }
        MY_LOGD("needRun: %d", needRun);

        int width = pIBufferFull->getImgSize().w;
        int height = pIBufferFull->getImgSize().h;
        MINT inFormat = pIBufferFull->getImgFormat();

        if (needRun && inFormat == NSCam::eImgFmt_I420) {
            uint32_t currentTime = (NSCam::Utils::TimeTool::getReadableTime()) % 1000;
            time_t timep;
            time (&timep);
            char currentDate[20];
            strftime(currentDate, sizeof(currentDate), "%Y%m%d_%H%M%S", localtime(&timep));

            //dump input I420
            if (mDump) {
                char path[256];
                snprintf(path, sizeof(path), "/data/vendor/camera_dump/capture_in_frame%d_%dx%d_%s_%d.i420",
                    frameNo, width, height, currentDate, currentTime);
                pIBufferFull->saveToFile(path);
            }

            nsecs_t t1 = systemTime(CLOCK_MONOTONIC);
            if (mSrcRGBA == NULL) {
                mSrcRGBA = (unsigned char *) malloc(width * height * 4);
            }
            //convert I420 to RGBA
            libyuv::I420ToABGR((unsigned char *) (pIBufferFull->getBufVA(0)), width,
                               (unsigned char *) (pIBufferFull->getBufVA(1)), width >> 1,
                               (unsigned char *) (pIBufferFull->getBufVA(2)), width >> 1,
                               mSrcRGBA, width * 4,
                               width, height);
            nsecs_t t2 = systemTime(CLOCK_MONOTONIC);
            MY_LOGD("Prepare src cost %02ld ms", ns2ms(t2 - t1));

            Watermark::add(mSrcRGBA, width, height, mWatermarkRGBA, mWatermarkWidth, mWatermarkHeight, (width - mWatermarkWidth) / 2, (height - mWatermarkHeight) / 2);
            nsecs_t t3 = systemTime(CLOCK_MONOTONIC);
            MY_LOGD("Add watermark cost %02ld ms", ns2ms(t3 - t2));

            //convert RGBA to I420
            libyuv::ABGRToI420(mSrcRGBA, width * 4,
                               (unsigned char *) (pOBufferFull->getBufVA(0)), width,
                               (unsigned char *) (pOBufferFull->getBufVA(1)), width >> 1,
                               (unsigned char *) (pOBufferFull->getBufVA(2)), width >> 1,
                               width, height);
            nsecs_t t4 = systemTime(CLOCK_MONOTONIC);
            MY_LOGD("Copy in to out cost %02ld ms", ns2ms(t4 - t3));

            //dump output I420
            if (mDump) {
                char path[256];
                snprintf(path, sizeof(path), "/data/vendor/camera_dump/capture_out_frame%d_%dx%d_%s_%d.i420",
                    frameNo, width, height, currentDate, currentTime);
                pOBufferFull->saveToFile(path);
            }
            free(mSrcRGBA);
        } else {
            if (!needRun) {
                MY_LOGE("No need run, skip add watermark for capture.");
            } else if (inFormat != NSCam::eImgFmt_YV12) {
                MY_LOGE("Unsupported format, skip add watermark for capture.");
            } else {
                MY_LOGE("Unknown exception, skip add watermark for capture.");
            }

            memcpy((unsigned char *) (pOBufferFull->getBufVA(0)),
                   (unsigned char *) (pIBufferFull->getBufVA(0)),
                   pIBufferFull->getBufSizeInBytes(0));
            memcpy((unsigned char *) (pOBufferFull->getBufVA(1)),
                   (unsigned char *) (pIBufferFull->getBufVA(1)),
                   pIBufferFull->getBufSizeInBytes(1));
            memcpy((unsigned char *) (pOBufferFull->getBufVA(2)),
                   (unsigned char *) (pIBufferFull->getBufVA(2)),
                   pIBufferFull->getBufSizeInBytes(2));
        }

        pRequest->mIBufferFull->release();
        pRequest->mOBufferFull->release();

        if (pRequest->mIMetadataDynamic != nullptr) {
            pRequest->mIMetadataDynamic->release();
        }

        if (pRequest->mIMetadataHal != nullptr) {
            pRequest->mIMetadataHal->release();
        }

        if (pRequest->mIMetadataApp != nullptr) {
            pRequest->mIMetadataApp->release();
        }
    }

    if (pCallback != nullptr) {
        MY_LOGD("callback request");
        pCallback->onCompleted(pRequest, 0);
    }
    FUNCTION_OUT;
    return OK;
}

REGISTER_PLUGIN_PROVIDER(Yuv, WatermarkCapture);

新增

vendor\mediatek\proprietary\hardware\mtkcam3\3rdparty\customer\tp_watermark\WatermarkPreview.cpp

#include <mtkcam3/3rdparty/plugin/PipelinePluginType.h>
#include <mtkcam/utils/metadata/hal/mtk_platform_metadata_tag.h>
#include <mtkcam/utils/metadata/client/mtk_metadata_tag.h>

#include <cutils/properties.h>

#include <watermark.h>
#include <mtkcam/utils/std/Time.h>
#include <time.h>
#include <libyuv.h>
#include <dlfcn.h>

using NSCam::NSPipelinePlugin::Interceptor;
using NSCam::NSPipelinePlugin::PipelinePlugin;
using NSCam::NSPipelinePlugin::PluginRegister;
using NSCam::NSPipelinePlugin::Join;
using NSCam::NSPipelinePlugin::JoinPlugin;

using namespace NSCam::NSPipelinePlugin;
using NSCam::MSize;

using NSCam::MERROR;
using NSCam::IImageBuffer;
using NSCam::IMetadata;
using NSCam::Type2Type;

#ifdef LOG_TAG
#undef LOG_TAG
#endif // LOG_TAG
#define LOG_TAG "WatermarkPreview"

#include <log/log.h>
#include <android/log.h>

#define MY_LOGI(fmt, arg...)  ALOGI("[%s] " fmt, __FUNCTION__, ##arg)
#define MY_LOGD(fmt, arg...)  ALOGD("[%s] " fmt, __FUNCTION__, ##arg)
#define MY_LOGW(fmt, arg...)  ALOGW("[%s] " fmt, __FUNCTION__, ##arg)
#define MY_LOGE(fmt, arg...)  ALOGE("[%s] " fmt, __FUNCTION__, ##arg)
#define FUNCTION_IN   MY_LOGD("%s +", __FUNCTION__)
#define FUNCTION_OUT  MY_LOGD("%s -", __FUNCTION__)

template <class T>
inline bool
tryGetMetadata(IMetadata const *pMetadata, MUINT32 tag, T& rVal)
{
    if(pMetadata == nullptr) return MFALSE;

    IMetadata::IEntry entry = pMetadata->entryFor(tag);
    if(!entry.isEmpty())
    {
        rVal = entry.itemAt(0,Type2Type<T>());
        return true;
    }
    else
    {
#define var(v) #v
#define type(t) #t
        MY_LOGW("no metadata %s in %s", var(tag), type(pMetadata));
#undef type
#undef var
    }
    return false;
}

class WatermarkPreview : public JoinPlugin::IProvider {
public:
    typedef JoinPlugin::Property Property;
    typedef JoinPlugin::Selection Selection;
    typedef JoinPlugin::Request::Ptr RequestPtr;
    typedef JoinPlugin::RequestCallback::Ptr RequestCallbackPtr;

private:
    bool mDisponly = false;
    bool mInplace = false;
    int mOpenID1 = 0;
    int mOpenID2 = 0;

    MBOOL mEnable = 1;
    MBOOL mDump = 0;
    unsigned char *mSrcRGBA = nullptr;
    unsigned char *mWatermarkRGBA = nullptr;
    int mWatermarkWidth = 0;
    int mWatermarkHeight = 0;

public:
    WatermarkPreview();

    ~WatermarkPreview();

    void init();

    void uninit();

    void abort(std::vector <RequestPtr> &pRequests);

    void set(MINT32 openID1, MINT32 openID2);

    const Property &property();

    MERROR negotiate(Selection &sel);

    MERROR process(RequestPtr pRequest, RequestCallbackPtr pCallback);

private:
    MERROR getConfigSetting(Selection &sel);

    MERROR getP1Setting(Selection &sel);

    MERROR getP2Setting(Selection &sel);
};

WatermarkPreview::WatermarkPreview() {
    FUNCTION_IN;
    mEnable = property_get_bool("vendor.debug.camera.watermark.preview.enable", 1);
    mDump = property_get_bool("vendor.debug.camera.watermark.preview.dump", 0);
    FUNCTION_OUT;
}

WatermarkPreview::~WatermarkPreview() {
    FUNCTION_IN;
    FUNCTION_OUT;
}

void WatermarkPreview::init() {
    FUNCTION_IN;
    mWatermarkWidth = 180;
    mWatermarkHeight = 640;
    int watermarkSize = mWatermarkWidth * mWatermarkHeight * 4;
    mWatermarkRGBA = (unsigned char *) malloc(watermarkSize);

    FILE *fp;
    char path[256];
    snprintf(path, sizeof(path), "/vendor/res/images/watermark.rgba");
    if ((fp = fopen(path, "r")) == NULL) {
        MY_LOGE("Failed to open /vendor/res/images/watermark.rgba");
    }
    fread(mWatermarkRGBA, 1, watermarkSize, fp);
    fclose(fp);
    FUNCTION_OUT;
}

void WatermarkPreview::uninit() {
    FUNCTION_IN;
    free(mSrcRGBA);
    free(mWatermarkRGBA);
    FUNCTION_OUT;
}

void WatermarkPreview::abort(std::vector <RequestPtr> &pRequests) {
    FUNCTION_IN;
    (void)pRequests;
    FUNCTION_OUT;
}

void WatermarkPreview::set(MINT32 openID1, MINT32 openID2) {
    FUNCTION_IN;
    MY_LOGD("set openID1:%d openID2:%d", openID1, openID2);
    mOpenID1 = openID1;
    mOpenID2 = openID2;
    FUNCTION_OUT;
}

const WatermarkPreview::Property &WatermarkPreview::property() {
    FUNCTION_IN;
    static Property prop;
    static bool inited;

    if (!inited) {
        prop.mName = "TP_WATERMARK";
        prop.mFeatures = TP_FEATURE_WATERMARK;
        //prop.mInPlace = MTRUE;
        //prop.mFaceData = eFD_Current;
        //prop.mPosition = 0;
        inited = true;
    }
    FUNCTION_OUT;
    return prop;
}

MERROR WatermarkPreview::negotiate(Selection &sel) {
    FUNCTION_IN;
    MERROR ret = OK;

    if (sel.mSelStage == eSelStage_CFG) {
        ret = getConfigSetting(sel);
    } else if (sel.mSelStage == eSelStage_P1) {
        ret = getP1Setting(sel);
    } else if (sel.mSelStage == eSelStage_P2) {
        ret = getP2Setting(sel);
    }
    FUNCTION_OUT;
    return ret;
}

MERROR WatermarkPreview::process(RequestPtr pRequest, RequestCallbackPtr pCallback) {
    FUNCTION_IN;
    (void) pCallback;
    MERROR ret = -EINVAL;
    MBOOL needRun = MFALSE;
    IImageBuffer *in = NULL, *out = NULL;

    if (pRequest->mIBufferMain1 != NULL && pRequest->mOBufferMain1 != NULL) {
        in = pRequest->mIBufferMain1->acquire();
        out = pRequest->mOBufferMain1->acquire();

        int frameNo = 0, requestNo = 0;
        if (pRequest->mIMetadataHal1 != nullptr) {
            IMetadata *pIMetataHAL1 = pRequest->mIMetadataHal1->acquire();
            if (pIMetataHAL1 != NULL) {
                if (!tryGetMetadata<int>(pIMetataHAL1, MTK_PIPELINE_FRAME_NUMBER, frameNo)) {
                    frameNo = 0;
                }
                if (!tryGetMetadata<int>(pIMetataHAL1, MTK_PIPELINE_REQUEST_NUMBER, requestNo)) {
                    requestNo = 0;
                }
                pRequest->mIMetadataHal1->release();
                MY_LOGD("frameNo: %d, requestNo: %d", frameNo, requestNo);
            } else {
                MY_LOGD("HAL metadata empty");
            }
        }

        MY_LOGD("in[%d](%dx%d)=%p out[%d](%dx%d)=%p",
                in->getPlaneCount(), in->getImgSize().w, in->getImgSize().h, in,
                out->getPlaneCount(), out->getImgSize().w, out->getImgSize().h, out);

        if (pRequest->mIMetadataApp != nullptr) {
            IMetadata *pIMetadataApp = pRequest->mIMetadataApp->acquire();
            MINT32 mode = 0;
            if (!tryGetMetadata<MINT32>(pIMetadataApp, QXT_FEATURE_WATERMARK, mode)) {
                mode = 0;
            }
            needRun = mode == 1 ? 1 : 0;
            pRequest->mIMetadataApp->release();
        }
        MY_LOGD("needRun: %d", needRun);

        int width = in->getImgSize().w;
        int height = in->getImgSize().h;
        MINT inFormat = in->getImgFormat();

        if (needRun && inFormat == NSCam::eImgFmt_YV12) {
            uint32_t currentTime = (NSCam::Utils::TimeTool::getReadableTime()) % 1000;
            time_t timep;
            time (&timep);
            char currentDate[20];
            strftime(currentDate, sizeof(currentDate), "%Y%m%d_%H%M%S", localtime(&timep));

            //dump input YV12
            if (mDump) {
                char path[256];
                snprintf(path, sizeof(path), "/data/vendor/camera_dump/preview_in_frame%d_%dx%d_%s_%d.yv12",
                    frameNo, width, height, currentDate, currentTime);
                in->saveToFile(path);
            }

            nsecs_t t1 = systemTime(CLOCK_MONOTONIC);
            if (mSrcRGBA == NULL) {
                mSrcRGBA = (unsigned char *) malloc(width * height * 4);
            }
            //convert YV12 to RGBA
            libyuv::I420ToABGR((unsigned char *)(in->getBufVA(0)), width,
                               (unsigned char *)(in->getBufVA(2)), width >> 1,
                               (unsigned char *)(in->getBufVA(1)), width >> 1,
                               mSrcRGBA, width * 4,
                               width, height);
            nsecs_t t2 = systemTime(CLOCK_MONOTONIC);
            MY_LOGD("Prepare src cost %02ld ms", ns2ms(t2 - t1));

            Watermark::add(mSrcRGBA, width, height, mWatermarkRGBA, mWatermarkWidth, mWatermarkHeight, (width - mWatermarkWidth) / 2, (height - mWatermarkHeight) / 2);
            nsecs_t t3 = systemTime(CLOCK_MONOTONIC);
            MY_LOGD("Add watermark cost %02ld ms", ns2ms(t3 - t2));

            //convert RGBA to YV12
            libyuv::ABGRToI420(mSrcRGBA, width * 4,
                               (unsigned char *)(out->getBufVA(0)), width,
                               (unsigned char *)(out->getBufVA(2)), width >> 1,
                               (unsigned char *)(out->getBufVA(1)), width >> 1,
                               width, height);
            nsecs_t t4 = systemTime(CLOCK_MONOTONIC);
            MY_LOGD("Copy in to out cost %02ld ms", ns2ms(t4 - t3));

            //dump output YV12
            if (mDump) {
                char path[256];
                snprintf(path, sizeof(path), "/data/vendor/camera_dump/preview_out_frame%d_%dx%d_%s_%d.yv12",
                    frameNo, width, height, currentDate, currentTime);
                out->saveToFile(path);
            }

        } else {
            if (!needRun) {
                MY_LOGE("No need run, skip add watermark for preview.");
            } else if (inFormat != NSCam::eImgFmt_YV12) {
                MY_LOGE("Unsupported format, skip add watermark for preview.");
            } else {
                MY_LOGE("Unknown exception, skip add watermark for preview.");
            }
            memcpy((unsigned char *) (out->getBufVA(0)),
                   (unsigned char *)(in->getBufVA(0)),
                   in->getBufSizeInBytes(0));
            memcpy((unsigned char *) (out->getBufVA(1)),
                   (unsigned char *)(in->getBufVA(1)),
                   in->getBufSizeInBytes(1));
            memcpy((unsigned char *) (out->getBufVA(2)),
                   (unsigned char *)(in->getBufVA(2)),
                   in->getBufSizeInBytes(2));
        }

        pRequest->mIBufferMain1->release();
        pRequest->mOBufferMain1->release();
        ret = OK;
    }

    FUNCTION_OUT;
    return ret;
}

MERROR WatermarkPreview::getConfigSetting(Selection &sel) {
    MY_LOGI("max out size(%dx%d)",
            sel.mCfgInfo.mMaxOutSize.w, sel.mCfgInfo.mMaxOutSize.h);

    mDisponly = property_get_bool("vendor.debug.tpi.s.fb.disponly", 0);
    mInplace = mDisponly || property_get_bool("vendor.debug.tpi.s.fb.inplace", 0);

    sel.mCfgOrder = 3;
    sel.mCfgJoinEntry = eJoinEntry_S_YUV;
    sel.mCfgInplace = mInplace;
    sel.mCfgEnableFD = MTRUE;
    sel.mCfgRun = mEnable;
    sel.mIBufferMain1.setRequired(MTRUE);
    if (!mDisponly && property_get_bool("vendor.debug.tpi.s.fb.nv21", 0)) {
        sel.mIBufferMain1.addAcceptedFormat(NSCam::eImgFmt_NV21);
    }
    if (!mDisponly && property_get_bool("vendor.debug.tpi.s.fb.size", 0)) {
        sel.mIBufferMain1.setSpecifiedSize(sel.mCfgInfo.mMaxOutSize);
    }
    sel.mOBufferMain1.setRequired(MTRUE);
    sel.mIBufferMain1.addAcceptedFormat(NSCam::eImgFmt_YV12);
    sel.mIBufferMain1.addAcceptedSize(eImgSize_Full);

    IMetadata *meta = sel.mIMetadataApp.getControl().get();
    MY_LOGD("sessionMeta=%p", meta);

    return OK;
}

MERROR WatermarkPreview::getP1Setting(Selection &sel) {
    (void) sel;
    return OK;
}

MERROR WatermarkPreview::getP2Setting(Selection &sel) {
    MBOOL run = MTRUE;
    sel.mP2Run = run;
    return OK;
}

REGISTER_PLUGIN_PROVIDER(Join, WatermarkPreview);

将上面编译得到的 libwatermark.so 拷贝到对应文件夹

至此水印算法相关代码增加完成,接下来是多帧算法相关源码

新增 vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/cp_tp_mfnr/ 文件夹

新增

vendor\mediatek\proprietary\hardware\mtkcam3\3rdparty\customer\cp_tp_mfnr\Android.mk

ifeq ($(QXT_MFNR_SUPPORT),yes)
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := libmultiframe
LOCAL_SRC_FILES_32 := lib/armeabi-v7a/libmultiframe.so
LOCAL_SRC_FILES_64 := lib/arm64-v8a/libmultiframe.so
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_SUFFIX := .so
LOCAL_PROPRIETARY_MODULE := true
LOCAL_CHECK_ELF_FILES := false
LOCAL_MULTILIB := both
include $(BUILD_PREBUILT)
################################################################################

################################################################################
include $(CLEAR_VARS)

#-----------------------------------------------------------
include $(TOP)/$(MTK_PATH_SOURCE)/hardware/mtkcam/mtkcam.mk

#-----------------------------------------------------------
LOCAL_SRC_FILES += MFNRImpl.cpp

#-----------------------------------------------------------
LOCAL_C_INCLUDES += $(MTKCAM_C_INCLUDES)
LOCAL_C_INCLUDES += $(TOP)/$(MTK_PATH_SOURCE)/hardware/mtkcam3/include $(MTK_PATH_SOURCE)/hardware/mtkcam/include
LOCAL_C_INCLUDES += $(TOP)/$(MTK_PATH_COMMON)/hal/inc
LOCAL_C_INCLUDES += $(TOP)/$(MTK_PATH_CUSTOM_PLATFORM)/hal/inc
LOCAL_C_INCLUDES += $(TOP)/external/libyuv/files/include/
LOCAL_C_INCLUDES += $(TOP)/$(MTK_PATH_SOURCE)/hardware/mtkcam3/3rdparty/customer/cp_tp_mfnr/include
#
LOCAL_C_INCLUDES += system/media/camera/include

#-----------------------------------------------------------
LOCAL_CFLAGS += $(MTKCAM_CFLAGS)
#

#-----------------------------------------------------------
LOCAL_STATIC_LIBRARIES +=
#
LOCAL_WHOLE_STATIC_LIBRARIES +=

#-----------------------------------------------------------
LOCAL_SHARED_LIBRARIES += liblog
LOCAL_SHARED_LIBRARIES += libutils
LOCAL_SHARED_LIBRARIES += libcutils
LOCAL_SHARED_LIBRARIES += libmtkcam_modulehelper
LOCAL_SHARED_LIBRARIES += libmtkcam_stdutils
LOCAL_SHARED_LIBRARIES += libmtkcam_pipeline
LOCAL_SHARED_LIBRARIES += libmtkcam_metadata
LOCAL_SHARED_LIBRARIES += libmtkcam_metastore
LOCAL_SHARED_LIBRARIES += libmtkcam_streamutils
LOCAL_SHARED_LIBRARIES += libmtkcam_imgbuf
LOCAL_SHARED_LIBRARIES += libmtkcam_exif
#LOCAL_SHARED_LIBRARIES += libmtkcam_3rdparty

#-----------------------------------------------------------
LOCAL_HEADER_LIBRARIES := libutils_headers liblog_headers libhardware_headers

#-----------------------------------------------------------
LOCAL_MODULE := libmtkcam.plugin.tp_mfnr
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_OWNER := mtk
LOCAL_MODULE_TAGS := optional
include $(MTK_STATIC_LIBRARY)

################################################################################
#
################################################################################
include $(call all-makefiles-under,$(LOCAL_PATH))
endif

新增

vendor\mediatek\proprietary\hardware\mtkcam3\3rdparty\customer\cp_tp_mfnr\include\mf_processor.h

头文件中的接口函数介绍:

setFrameCount: 没有实际作用,用于模拟设置第三方多帧算法的帧数。因为部分第三方多帧算法在不同场景下需要的帧数可能是不同的。

setParams: 也没有实际作用,用于模拟设置第三方多帧算法所需的参数。

addFrame: 用于添加一帧图像数据,用于模拟第三方多帧算法添加图像数据。

process: 将前面添加的4帧图像数据,缩小并拼接成一张原大小的图。

createInstance: 创建接口类对象。

#ifndef QXT_MULTI_FRAME_H
#define QXT_MULTI_FRAME_H

class MFProcessor {

public:
    virtual ~MFProcessor() {}

    virtual void setFrameCount(int num) = 0;

    virtual void setParams() = 0;

    virtual void addFrame(unsigned char *src, int srcWidth, int srcHeight) = 0;

    virtual void addFrame(unsigned char *srcY, unsigned char *srcU, unsigned char *srcV,
            int srcWidth, int srcHeight) = 0;

    virtual void scale(unsigned char *src, int srcWidth, int srcHeight,
                       unsigned char *dst, int dstWidth, int dstHeight) = 0;

    virtual void process(unsigned char *output, int outputWidth, int outputHeight) = 0;

    virtual void process(unsigned char *outputY, unsigned char *outputU, unsigned char *outputV,
            int outputWidth, int outputHeight) = 0;

    static MFProcessor* createInstance(int width, int height);
};

#endif //QXT_MULTI_FRAME_H

新增

vendor\mediatek\proprietary\hardware\mtkcam3\3rdparty\customer\cp_tp_mfnr\MFNRImpl.cpp

主要函数介绍:

在property函数中feature类型设置成TP_FEATURE_MFNR,并设置名称、优先级、最大帧数等等属性。尤其注意mNeedRrzoBuffer属性,一般情况下,多帧算法必须要设置为MTRUE。

在negotiate函数中配置算法需要的输入、输出图像的格式、尺寸。注意,多帧算法有多帧输入,但是只需要一帧输出。因此这里设置了mRequestIndex == 0时才需要mOBufferFull。也就是只有第一帧才有输入和输出,其它帧只有输入。 另外,还在negotiate函数中获取上层传下来的metadata参数,根据参数决定算法是否运行。

在process函数中接入算法。第一帧时创建算法接口类对象,然后每一帧都调用算法接口函数addFrame加入,最后一帧再调用算法接口函数process进行处理并获取输出

#ifdef LOG_TAG
#undef LOG_TAG
#endif // LOG_TAG
#define LOG_TAG "MFNRProvider"
static const char *__CALLERNAME__ = LOG_TAG;

//
#include <mtkcam/utils/std/Log.h>
//
#include <stdlib.h>
#include <utils/Errors.h>
#include <utils/List.h>
#include <utils/RefBase.h>
#include <sstream>
#include <unordered_map> // std::unordered_map
//
#include <mtkcam/utils/metadata/client/mtk_metadata_tag.h>
#include <mtkcam/utils/metadata/hal/mtk_platform_metadata_tag.h>
//zHDR
#include <mtkcam/utils/hw/HwInfoHelper.h> // NSCamHw::HwInfoHelper
#include <mtkcam3/feature/utils/FeatureProfileHelper.h> //ProfileParam
#include <mtkcam/drv/IHalSensor.h>
//
#include <mtkcam/utils/imgbuf/IIonImageBufferHeap.h>
//
#include <mtkcam/utils/std/Format.h>
#include <mtkcam/utils/std/Time.h>
//
#include <mtkcam3/pipeline/hwnode/NodeId.h>
//
#include <mtkcam/utils/metastore/IMetadataProvider.h>
#include <mtkcam/utils/metastore/ITemplateRequest.h>
#include <mtkcam/utils/metastore/IMetadataProvider.h>
#include <mtkcam3/3rdparty/plugin/PipelinePlugin.h>
#include <mtkcam3/3rdparty/plugin/PipelinePluginType.h>
//
#include <isp_tuning/isp_tuning.h>  //EIspProfile_T, EOperMode_*

//
#include <custom_metadata/custom_metadata_tag.h>

//
#include <libyuv.h>
#include <mf_processor.h>

using namespace NSCam;
using namespace android;
using namespace std;
using namespace NSCam::NSPipelinePlugin;
using namespace NSIspTuning;
/******************************************************************************
 *
 ******************************************************************************/
#define MY_LOGV(fmt, arg...)        CAM_LOGV("(%d)[%s] " fmt, ::gettid(), __FUNCTION__, ##arg)
#define MY_LOGD(fmt, arg...)        CAM_LOGD("(%d)[%s] " fmt, ::gettid(), __FUNCTION__, ##arg)
#define MY_LOGI(fmt, arg...)        CAM_LOGI("(%d)[%s] " fmt, ::gettid(), __FUNCTION__, ##arg)
#define MY_LOGW(fmt, arg...)        CAM_LOGW("(%d)[%s] " fmt, ::gettid(), __FUNCTION__, ##arg)
#define MY_LOGE(fmt, arg...)        CAM_LOGE("(%d)[%s] " fmt, ::gettid(), __FUNCTION__, ##arg)
//
#define MY_LOGV_IF(cond, ...)       do { if ( (cond) ) { MY_LOGV(__VA_ARGS__); } }while(0)
#define MY_LOGD_IF(cond, ...)       do { if ( (cond) ) { MY_LOGD(__VA_ARGS__); } }while(0)
#define MY_LOGI_IF(cond, ...)       do { if ( (cond) ) { MY_LOGI(__VA_ARGS__); } }while(0)
#define MY_LOGW_IF(cond, ...)       do { if ( (cond) ) { MY_LOGW(__VA_ARGS__); } }while(0)
#define MY_LOGE_IF(cond, ...)       do { if ( (cond) ) { MY_LOGE(__VA_ARGS__); } }while(0)
//
#define ASSERT(cond, msg)           do { if (!(cond)) { printf("Failed: %s\n", msg); return; } }while(0)


#define __DEBUG // enable debug

#ifdef __DEBUG
#include <memory>
#define FUNCTION_SCOPE \
auto __scope_logger__ = [](char const* f)->std::shared_ptr<const char>{ \
    CAM_LOGD("(%d)[%s] + ", ::gettid(), f); \
    return std::shared_ptr<const char>(f, [](char const* p){CAM_LOGD("(%d)[%s] -", ::gettid(), p);}); \
}(__FUNCTION__)
#else
#define FUNCTION_SCOPE
#endif

template <typename T>
inline MBOOL
tryGetMetadata(
    IMetadata* pMetadata,
    MUINT32 const tag,
    T & rVal
)
{
    if (pMetadata == NULL) {
        MY_LOGW("pMetadata == NULL");
        return MFALSE;
    }

    IMetadata::IEntry entry = pMetadata->entryFor(tag);
    if (!entry.isEmpty()) {
        rVal = entry.itemAt(0, Type2Type<T>());
        return MTRUE;
    }
    return MFALSE;
}

#define MFNR_FRAME_COUNT 4
/******************************************************************************
*
******************************************************************************/
class MFNRProviderImpl : public MultiFramePlugin::IProvider {
    typedef MultiFramePlugin::Property Property;
    typedef MultiFramePlugin::Selection Selection;
    typedef MultiFramePlugin::Request::Ptr RequestPtr;
    typedef MultiFramePlugin::RequestCallback::Ptr RequestCallbackPtr;

public:

    virtual void set(MINT32 iOpenId, MINT32 iOpenId2) {
        MY_LOGD("set openId:%d openId2:%d", iOpenId, iOpenId2);
        mOpenId = iOpenId;
    }

    virtual const Property& property() {
        FUNCTION_SCOPE;
        static Property prop;
        static bool inited;

        if (!inited) {
            prop.mName              = "TP_MFNR";
            prop.mFeatures          = TP_FEATURE_MFNR;
            prop.mThumbnailTiming   = eTiming_P2;
            prop.mPriority          = ePriority_Highest;
            prop.mZsdBufferMaxNum   = 8; // maximum frames requirement
            prop.mNeedRrzoBuffer    = MTRUE; // rrzo requirement for BSS
            inited                  = MTRUE;
        }
        return prop;
    };

    virtual MERROR negotiate(Selection& sel) {
        FUNCTION_SCOPE;

        IMetadata* appInMeta = sel.mIMetadataApp.getControl().get();
        tryGetMetadata<MINT32>(appInMeta, QXT_FEATURE_MFNR, mEnable);
        MY_LOGD("mEnable: %d", mEnable);
        if (!mEnable) {
            MY_LOGD("Force off TP_MFNR shot");
            return BAD_VALUE;
        }

        sel.mRequestCount = MFNR_FRAME_COUNT;

        MY_LOGD("mRequestCount=%d", sel.mRequestCount);
        sel.mIBufferFull
                .setRequired(MTRUE)
                .addAcceptedFormat(eImgFmt_I420) // I420 first
                .addAcceptedFormat(eImgFmt_YV12)
                .addAcceptedFormat(eImgFmt_NV21)
                .addAcceptedFormat(eImgFmt_NV12)
                .addAcceptedSize(eImgSize_Full);
        //sel.mIBufferSpecified.setRequired(MTRUE).setAlignment(16, 16);
        sel.mIMetadataDynamic.setRequired(MTRUE);
        sel.mIMetadataApp.setRequired(MTRUE);
        sel.mIMetadataHal.setRequired(MTRUE);
        if (sel.mRequestIndex == 0) {
            sel.mOBufferFull
                .setRequired(MTRUE)
                .addAcceptedFormat(eImgFmt_I420) // I420 first
                .addAcceptedFormat(eImgFmt_YV12)
                .addAcceptedFormat(eImgFmt_NV21)
                .addAcceptedFormat(eImgFmt_NV12)
                .addAcceptedSize(eImgSize_Full);
            sel.mOMetadataApp.setRequired(MTRUE);
            sel.mOMetadataHal.setRequired(MTRUE);
        } else {
            sel.mOBufferFull.setRequired(MFALSE);
            sel.mOMetadataApp.setRequired(MFALSE);
            sel.mOMetadataHal.setRequired(MFALSE);
        }

        return OK;
    };

    virtual void init() {
        FUNCTION_SCOPE;
        mDump = property_get_bool("vendor.debug.camera.mfnr.dump", 0);
        //nothing to do for MFNR
    };

    virtual MERROR process(RequestPtr pRequest, RequestCallbackPtr pCallback) {
        FUNCTION_SCOPE;
        MERROR ret = 0;
        // restore callback function for abort API
        if (pCallback != nullptr) {
            m_callbackprt = pCallback;
        }
        //maybe need to keep a copy in member<sp>
        IMetadata* pAppMeta = pRequest->mIMetadataApp->acquire();
        IMetadata* pHalMeta = pRequest->mIMetadataHal->acquire();
        IMetadata* pHalMetaDynamic = pRequest->mIMetadataDynamic->acquire();
        MINT32 processUniqueKey = 0;
        IImageBuffer* pInImgBuffer = NULL;
        uint32_t width = 0;
        uint32_t height = 0;
        if (!IMetadata::getEntry<MINT32>(pHalMeta, MTK_PIPELINE_UNIQUE_KEY, processUniqueKey)) {
            MY_LOGE("cannot get unique about MFNR capture");
            return BAD_VALUE;
        }

        if (pRequest->mIBufferFull != nullptr) {
            pInImgBuffer = pRequest->mIBufferFull->acquire();
            width = pInImgBuffer->getImgSize().w;
            height = pInImgBuffer->getImgSize().h;
            MY_LOGD("[IN] Full image VA: 0x%p, Size(%dx%d), Format: %s",
                pInImgBuffer->getBufVA(0), width, height, format2String(pInImgBuffer->getImgFormat()));
            if (mDump) {
                char path[256];
                snprintf(path, sizeof(path), "/data/vendor/camera_dump/mfnr_capture_in_%d_%dx%d.%s",
                        pRequest->mRequestIndex, width, height, format2String(pInImgBuffer->getImgFormat()));
                pInImgBuffer->saveToFile(path);
            }
        }
        if (pRequest->mIBufferSpecified != nullptr) {
            IImageBuffer* pImgBuffer = pRequest->mIBufferSpecified->acquire();
            MY_LOGD("[IN] Specified image VA: 0x%p, Size(%dx%d)", pImgBuffer->getBufVA(0), pImgBuffer->getImgSize().w, pImgBuffer->getImgSize().h);
        }
        if (pRequest->mOBufferFull != nullptr) {
            mOutImgBuffer = pRequest->mOBufferFull->acquire();
            MY_LOGD("[OUT] Full image VA: 0x%p, Size(%dx%d)", mOutImgBuffer->getBufVA(0), mOutImgBuffer->getImgSize().w, mOutImgBuffer->getImgSize().h);
        }
        if (pRequest->mIMetadataDynamic != nullptr) {
            IMetadata *meta = pRequest->mIMetadataDynamic->acquire();
            if (meta != NULL)
                MY_LOGD("[IN] Dynamic metadata count: ", meta->count());
            else
                MY_LOGD("[IN] Dynamic metadata Empty");
        }

        MY_LOGD("frame:%d/%d, width:%d, height:%d", pRequest->mRequestIndex, pRequest->mRequestCount, width, height);

        if (pInImgBuffer != NULL && mOutImgBuffer != NULL) {
            uint32_t yLength = pInImgBuffer->getBufSizeInBytes(0);
            uint32_t uLength = pInImgBuffer->getBufSizeInBytes(1);
            uint32_t vLength = pInImgBuffer->getBufSizeInBytes(2);
            uint32_t yuvLength = yLength + uLength + vLength;

            if (pRequest->mRequestIndex == 0) {//First frame
                //When width or height changed, recreate multiFrame
                if (mLatestWidth != width || mLatestHeight != height) {
                    if (mMFProcessor != NULL) {
                        delete mMFProcessor;
                        mMFProcessor = NULL;
                    }
                    mLatestWidth = width;
                    mLatestHeight = height;
                }
                if (mMFProcessor == NULL) {
                    MY_LOGD("create mMFProcessor %dx%d", mLatestWidth, mLatestHeight);
                    mMFProcessor = MFProcessor::createInstance(mLatestWidth, mLatestHeight);
                    mMFProcessor->setFrameCount(pRequest->mRequestCount);
                }
            }

            mMFProcessor->addFrame((uint8_t *)pInImgBuffer->getBufVA(0),
                                  (uint8_t *)pInImgBuffer->getBufVA(1),
                                  (uint8_t *)pInImgBuffer->getBufVA(2),
                                  mLatestWidth, mLatestHeight);

            if (pRequest->mRequestIndex == pRequest->mRequestCount - 1) {//Last frame
                if (mMFProcessor != NULL) {
                    mMFProcessor->process((uint8_t *)mOutImgBuffer->getBufVA(0),
                                         (uint8_t *)mOutImgBuffer->getBufVA(1),
                                         (uint8_t *)mOutImgBuffer->getBufVA(2),
                                         mLatestWidth, mLatestHeight);
                    if (mDump) {
                        char path[256];
                        snprintf(path, sizeof(path), "/data/vendor/camera_dump/mfnr_capture_out_%d_%dx%d.%s",
                            pRequest->mRequestIndex, mOutImgBuffer->getImgSize().w, mOutImgBuffer->getImgSize().h,
                            format2String(mOutImgBuffer->getImgFormat()));
                        mOutImgBuffer->saveToFile(path);
                    }
                } else {
                    memcpy((uint8_t *)mOutImgBuffer->getBufVA(0),
                           (uint8_t *)pInImgBuffer->getBufVA(0),
                           pInImgBuffer->getBufSizeInBytes(0));
                    memcpy((uint8_t *)mOutImgBuffer->getBufVA(1),
                           (uint8_t *)pInImgBuffer->getBufVA(1),
                           pInImgBuffer->getBufSizeInBytes(1));
                    memcpy((uint8_t *)mOutImgBuffer->getBufVA(2),
                           (uint8_t *)pInImgBuffer->getBufVA(2),
                           pInImgBuffer->getBufSizeInBytes(2));
                }
                mOutImgBuffer = NULL;
            }
        }

        if (pRequest->mIBufferFull != nullptr) {
            pRequest->mIBufferFull->release();
        }
        if (pRequest->mIBufferSpecified != nullptr) {
            pRequest->mIBufferSpecified->release();
        }
        if (pRequest->mOBufferFull != nullptr) {
            pRequest->mOBufferFull->release();
        }
        if (pRequest->mIMetadataDynamic != nullptr) {
            pRequest->mIMetadataDynamic->release();
        }

        mvRequests.push_back(pRequest);
        MY_LOGD("collected request(%d/%d)", pRequest->mRequestIndex, pRequest->mRequestCount);
        if (pRequest->mRequestIndex == pRequest->mRequestCount - 1) {
            for (auto req : mvRequests) {
                MY_LOGD("callback request(%d/%d) %p", req->mRequestIndex, req->mRequestCount, pCallback.get());
                if (pCallback != nullptr) {
                    pCallback->onCompleted(req, 0);
                }
            }
            mvRequests.clear();
        }
        return ret;
    };

    virtual void abort(vector<RequestPtr>& pRequests) {
        FUNCTION_SCOPE;

        bool bAbort = false;
        IMetadata *pHalMeta;
        MINT32 processUniqueKey = 0;

        for (auto req:pRequests) {
            bAbort = false;
            pHalMeta = req->mIMetadataHal->acquire();
            if (!IMetadata::getEntry<MINT32>(pHalMeta, MTK_PIPELINE_UNIQUE_KEY, processUniqueKey)) {
                MY_LOGW("cannot get unique about MFNR capture");
            }

            if (m_callbackprt != nullptr) {
                MY_LOGD("m_callbackprt is %p", m_callbackprt.get());
               /*MFNR plugin callback request to MultiFrameNode */
               for (Vector<RequestPtr>::iterator it = mvRequests.begin() ; it != mvRequests.end(); it++) {
                    if ((*it) == req) {
                        mvRequests.erase(it);
                        m_callbackprt->onAborted(req);
                        bAbort = true;
                        break;
                    }
               }
            } else {
               MY_LOGW("callbackptr is null");
            }

            if (!bAbort) {
               MY_LOGW("Desire abort request[%d] is not found", req->mRequestIndex);
            }

        }
    };

    virtual void uninit() {
        FUNCTION_SCOPE;
        if (mMFProcessor != NULL) {
            delete mMFProcessor;
            mMFProcessor = NULL;
        }
        mLatestWidth = 0;
        mLatestHeight = 0;
    };

    virtual ~MFNRProviderImpl() {
        FUNCTION_SCOPE;
    };

    const char * format2String(MINT format) {
        switch(format) {
           case NSCam::eImgFmt_RGBA8888:          return "rgba";
           case NSCam::eImgFmt_RGB888:            return "rgb";
           case NSCam::eImgFmt_RGB565:            return "rgb565";
           case NSCam::eImgFmt_STA_BYTE:          return "byte";
           case NSCam::eImgFmt_YVYU:              return "yvyu";
           case NSCam::eImgFmt_UYVY:              return "uyvy";
           case NSCam::eImgFmt_VYUY:              return "vyuy";
           case NSCam::eImgFmt_YUY2:              return "yuy2";
           case NSCam::eImgFmt_YV12:              return "yv12";
           case NSCam::eImgFmt_YV16:              return "yv16";
           case NSCam::eImgFmt_NV16:              return "nv16";
           case NSCam::eImgFmt_NV61:              return "nv61";
           case NSCam::eImgFmt_NV12:              return "nv12";
           case NSCam::eImgFmt_NV21:              return "nv21";
           case NSCam::eImgFmt_I420:              return "i420";
           case NSCam::eImgFmt_I422:              return "i422";
           case NSCam::eImgFmt_Y800:              return "y800";
           case NSCam::eImgFmt_BAYER8:            return "bayer8";
           case NSCam::eImgFmt_BAYER10:           return "bayer10";
           case NSCam::eImgFmt_BAYER12:           return "bayer12";
           case NSCam::eImgFmt_BAYER14:           return "bayer14";
           case NSCam::eImgFmt_FG_BAYER8:         return "fg_bayer8";
           case NSCam::eImgFmt_FG_BAYER10:        return "fg_bayer10";
           case NSCam::eImgFmt_FG_BAYER12:        return "fg_bayer12";
           case NSCam::eImgFmt_FG_BAYER14:        return "fg_bayer14";
           default:                               return "unknown";
        };
    };

private:

    MINT32                          mUniqueKey;
    MINT32                          mOpenId;
    MINT32                          mRealIso;
    MINT32                          mShutterTime;
    MBOOL                           mZSDMode;
    MBOOL                           mFlashOn;

    Vector<RequestPtr>              mvRequests;

    RequestCallbackPtr              m_callbackprt;
    MFProcessor* mMFProcessor = NULL;
    IImageBuffer* mOutImgBuffer = NULL;
    uint32_t mLatestWidth = 0;
    uint32_t mLatestHeight = 0;
    MINT32 mEnable = 0;
    MINT32 mDump = 0;
    // add end
};

REGISTER_PLUGIN_PROVIDER(MultiFrame, MFNRProviderImpl);

将上面编译得到的 libmultiframe.so 拷贝到对应文件夹

至此多帧算法相关代码增加完成

注意:

MTK原文: negotiate函数设置格式时,一个挂载点如果挂载多个同类型的plugin,则只有第一个 plugin 中的 negotiate 中的 input buffer 设定有效。 在YUVNode 下挂载单帧 YUV plugin时,一定要确保 MTK 平台的SWNR plugin 的 negotiate 直接返回不OK,不做任何 accepted format 等的设定。否则,可能会出现因 SWNR plugin和三方plugin negotiate时设定的 accepted format 不一致而导致的三方 plugin 拿不到它想要的 format 的buffer。

vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/mtk/swnr/SWNRImpl.cpp

@@ -391,7 +391,8 @@ negotiate(Selection& sel)
     sel.mOMetadataApp.setRequired(false);
     sel.mOMetadataHal.setRequired(true);
 
-    return OK;
+    //return OK;^M
+    return -EINVAL;//cczheng^M
 }
 

最终vendor.img需要的目标共享库是libmtkcam_3rdparty.customer.so。因此,我们还需要修改Android.mk,

使模块 libmtkcam_3rdparty.customer 依赖 libmtkcam.plugin.tp_watermark

模块 libmtkcam_3rdparty.customer 依赖 libmtkcam.plugin.tp_mfnr

vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/Android.mk

@@ -76,6 +76,19 @@ LOCAL_WHOLE_STATIC_LIBRARIES += libmtkcam.plugin.tp_zoomfusion
 #
 LOCAL_SHARED_LIBRARIES += libcam.iopipe
 endif
+
+ifeq ($(QXT_WATERMARK_SUPPORT), yes)
+LOCAL_SHARED_LIBRARIES += libwatermark
+LOCAL_SHARED_LIBRARIES += libyuv.vendor
+LOCAL_WHOLE_STATIC_LIBRARIES += libmtkcam.plugin.tp_watermark
+endif
+
+ifeq ($(QXT_MFNR_SUPPORT), yes)
+LOCAL_SHARED_LIBRARIES += libmultiframe
+LOCAL_SHARED_LIBRARIES += libyuv.vendor
+LOCAL_WHOLE_STATIC_LIBRARIES += libmtkcam.plugin.tp_mfnr
+endif
+
 #
 LOCAL_SHARED_LIBRARIES += libfeature.stereo.provider
 #

预置水印文件

device/mediateksample/k62v1_64_bsp/device.mk

+++ b/alps/device/mediateksample/k62v1_64_bsp/device.mk
@@ -43,6 +43,9 @@ endif
 PRODUCT_COPY_FILES += frameworks/native/data/etc/android.hardware.usb.host.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.usb.host.xml
 
 
+ifeq ($(QXT_WATERMARK_SUPPORT),yes)
+PRODUCT_COPY_FILES += vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/customer/tp_watermark/res/watermark.rgba::$(TARGET_COPY_OUT_VENDOR)/res/images/watermark.rgba
+endif

camera hal进程为mtk_camera_hal,它要读取/vendor/res/images/watermark.rgba,读取需要vendor_file SELinux权限。这里为mtk_camera_hal配置SELinux权限:

device/mediatek/sepolicy/bsp/non_plat/mtk_hal_camera.te

@@ -93,7 +93,7 @@ set_prop(mtk_hal_camera, vendor_mtk_camera_prop)
 allow mtk_hal_camera teei_client_device:chr_file rw_file_perms;
 
 allow mtk_hal_camera mdla_device:chr_file rw_file_perms;
-
+allow mtk_hal_camera vendor_file:file { read getattr open };
 #Date: 2019/11/11

移除MTK示例的MFNR算法

一般情况下,MFNR 算法同一时间只允许运行一个。因此,需要移除 MTK 示例的 MFNR 算法。我们可以使用宏控来移除,这里就简单粗暴,直接注释掉了。

vendor/mediatek/proprietary/hardware/mtkcam3/3rdparty/mtk/Android.mk

@@ -146,7 +146,7 @@ LOCAL_SHARED_LIBRARIES += libfeature.stereo.provider
 LOCAL_SHARED_LIBRARIES += liblpcnr
 #-----------------------------------------------------------
 ifneq ($(strip $(MTKCAM_HAVE_MFB_SUPPORT)),0)
-LOCAL_WHOLE_STATIC_LIBRARIES += libmtkcam.plugin.mfnr
+# LOCAL_WHOLE_STATIC_LIBRARIES += libmtkcam.plugin.mfnr
 endif
 #4 Cell
 LOCAL_WHOLE_STATIC_LIBRARIES += libmtkcam.plugin.remosaic

自定义metadata

添加metadata是为了让APP层能够通过metadata传递相应的参数给HAL层。APP层是通过CaptureRequest.Builder.set(@NonNull Key key, T value)来设置参数的。 由于我们是自定义的feature,无法复用MTK提供的metadata,因此,我们需要自定义metadata。

vendor/mediatek/proprietary/hardware/mtkcam/include/mtkcam/utils/metadata/client/mtk_metadata_tag.h

@@ -94,6 +94,7 @@ typedef enum mtk_camera_metadata_section {
     MTK_SMVR_FEATURE                = 15,
     MTK_SINGLEHW_SETTING            = 16,
     MTK_ABF_FEATURE                 = 17,
+    QXT_FEATURE                     = 18,//cczheng
     MTK_VENDOR_SECTION_COUNT,
 } mtk_camera_metadata_section_t;
 
@@ -155,6 +156,7 @@ typedef enum mtk_camera_metadata_section_start {
     MTK_SMVR_FEATURE_START                      = (MTK_SMVR_FEATURE + MTK_VENDOR_TAG_SECTION) << 16,
     MTK_SINGLEHW_SETTING_START                  = (MTK_SINGLEHW_SETTING + MTK_VENDOR_TAG_SECTION) << 16,
     MTK_ABF_FEATURE_START                       = (MTK_ABF_FEATURE + MTK_VENDOR_TAG_SECTION)   << 16,
+    QXT_FEATURE_START                           = (QXT_FEATURE + MTK_VENDOR_TAG_SECTION) << 16,//cczheng
 } mtk_camera_metadata_section_start_t;
 
 
@@ -754,6 +756,10 @@ typedef enum mtk_camera_metadata_tag {
     MTK_ABF_FEATURE_ABF_RESULT,
     MTK_ABF_FEATURE_AVAILABLE_ABF_MODES,
     MTK_ABF_FEATURE_END,
+
+    QXT_FEATURE_WATERMARK = QXT_FEATURE_START,
+    QXT_FEATURE_MFNR,//cczheng
+    QXT_FEATURE_END,//cczheng
 } mtk_camera_metadata_tag_t;
 
 /**

vendor/mediatek/proprietary/hardware/mtkcam/include/mtkcam/utils/metadata/client/mtk_metadata_tag_info.inl

@@ -92,6 +92,8 @@ _IMP_SECTION_INFO_(MTK_HEIC,                        "mtk.heic")
 _IMP_SECTION_INFO_(MTK_HEIC_INFO,                   "mtk.heic.ifno")
 _IMP_SECTION_INFO_(MTK_IOPIPE_INFO,                 "mtk.iopipe.info")
 _IMP_SECTION_INFO_(MTK_HAL_INFO,                    "mtk.hal.info")
+_IMP_SECTION_INFO_(QXT_FEATURE,                     "com.qxt.camera")
+//cczheng
 
 /******************************************************************************
  *
@@ -106,6 +108,12 @@ _IMP_TAG_INFO_( MTK_COLOR_CORRECTION_ABERRATION_MODE,
                 MUINT8,     "aberrationMode")
 _IMP_TAG_INFO_( MTK_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
                 MUINT8,     "availableAberrationModes")
+
+_IMP_TAG_INFO_( QXT_FEATURE_WATERMARK,
+                MINT32,     "watermark")
+_IMP_TAG_INFO_( QXT_FEATURE_MFNR,
+                MINT32,     "mfnr")
+
 //
 _IMP_TAG_INFO_( MTK_CONTROL_AE_ANTIBANDING_MODE,
                 MUINT8,     "aeAntibandingMode")

vendor/mediatek/proprietary/hardware/mtkcam/utils/metadata/vendortag/VendorTagTable.h

@@ -547,6 +547,19 @@ static auto& _FlashFeature_()
      //
      return sInst;
 }
+//cczheng
+static auto& _QxtFeature_()
+{
+    static const std::map<uint32_t, VendorTag_t>
+    sInst = {
+        _TAG_(QXT_FEATURE_WATERMARK,
+            "watermark",   TYPE_INT32),
+        _TAG_(QXT_FEATURE_MFNR,
+            "mfnr",   TYPE_INT32),
+     };
+     //
+     return sInst;
+}
 
 static auto& _SingleHWSetting_()
 {
@@ -668,6 +681,10 @@ static auto& getGlobalSections()
                     MTK_ABF_FEATURE_START,
                     MTK_ABF_FEATURE_END,
                     _ABFFeature_() ),
+        _SECTION_( "com.qxt.camera",
+                    QXT_FEATURE_START,
+                    QXT_FEATURE_END,
+                    _QxtFeature_() ),
     };
 
     // append custom vendor tags sections to mtk sections

vendor/mediatek/proprietary/hardware/mtkcam/utils/metastore/metadataprovider/constructStaticMetadata.cpp

@@ -1325,6 +1325,20 @@ updateData(IMetadata &rMetadata)
         rMetadata.update(availReqEntry.tag(), availReqEntry);
     }
+//cczheng 
+#if 1
+    {
+        IMetadata::IEntry qxtAvailRequestEntry = rMetadata.entryFor(MTK_REQUEST_AVAILABLE_REQUEST_KEYS);
+        qxtAvailRequestEntry.push_back(QXT_FEATURE_WATERMARK , Type2Type< MINT32 >());
+        qxtAvailRequestEntry.push_back(QXT_FEATURE_MFNR , Type2Type< MINT32 >());
+        rMetadata.update(qxtAvailRequestEntry.tag(), qxtAvailRequestEntry);
+
+        IMetadata::IEntry qxtAvailSessionEntry = rMetadata.entryFor(MTK_REQUEST_AVAILABLE_SESSION_KEYS);
+        qxtAvailSessionEntry.push_back(QXT_FEATURE_WATERMARK , Type2Type< MINT32 >());
+        qxtAvailSessionEntry.push_back(QXT_FEATURE_MFNR , Type2Type< MINT32 >());
+        rMetadata.update(qxtAvailSessionEntry.tag(), qxtAvailSessionEntry);
+    }
+#endif
+
     // update multi-cam feature mode to static metadata
     // vendor tag
     {

好了,搞到这一步。大功告成了,先 make 一把,刷机看效果

最后

由于 watermark.rgba 没找到源文件,我从其它地方搞了个所以水印显示时宽高不太对,就没正确显示,具体效果我没仔细调整。

另外既然系统已经预制了这两个算法,所有 app 均可调用,那么可以在系统相机中也增加两按钮,加载这两算法,也算是丰富了

原始相机单一风格,有兴趣的朋友可以自己去加下,毕竟普通 app 的代码已经提供了。