Android Camera 实现一个基础的算法

我们就自己动手实现一个基础算法

为了看到效果,我们把数据流的一半变成灰色,另一半正常。

0-黑色

128-灰色

255-白色

hardware/qcom/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp

加入以下代码

void YUV2Gray(unsigned char* srcYuv,int w,int h) {
 int mid = wh/2;//找到图像中间位置
 unsigned char startP = srcYuv + mid;//指针移到中间
 //处理Y数据,uv数据是色彩信息 我们不管
 for(int i=0;i<mid;i++) {
 //把数据赋值128 即灰色
 *startP = 0x80;//128
 startP++;
 }
 }

YUV数据中,前面W * H是Y数据,后面W * H/2是UV数据。

那我们要定位到图像的中间位置,就是W * H/2.

举个例子:

宽:8 高:4的YUV 数据如下图

android获取相机参数进行压缩 安卓相机算法_数据

那么图像的中间就是Y17对的数据,即4x8/2=16(数组是从0开始计算的)。
算法很简单,麻雀虽小五脏俱全。

我们要对预览流进行处理,那么在相应的回调函数修改即可。

hardware/qcom/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp
 //自定义第三方算法
 void YUV2Gray(unsigned char* srcYuv,int w,int h) {
 int mid = wh/2;
 unsigned char startP = srcYuv + mid;
 for(int i=0;i<mid;i++) {
 *startP = 0x80;//128
 startP++;
 }
 }
 void QCamera2HardwareInterface::preview_stream_cb_routine(mm_camera_super_buf_t *super_frame,
 QCameraStream * stream,
 void *userdata)
 {
 ATRACE_CALL();
 CDBG("[KPI Perf] %s : BEGIN", func);
 int err = NO_ERROR;
 QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
 QCameraGrallocMemory *memory = (QCameraGrallocMemory *)super_frame->bufs[0]->mem_info;
if (pme == NULL) {
    ALOGE("%s: Invalid hardware object", __func__);
    free(super_frame);
    return;
}    
if (memory == NULL) {
    ALOGE("%s: Invalid memory object", __func__);
    free(super_frame);
    return;
}    

mm_camera_buf_def_t *frame = super_frame->bufs[0];
if (NULL == frame) {
    ALOGE("%s: preview frame is NLUL", __func__);
    free(super_frame);
    return;
}    
  //获取YUV数据地址
++ unsigned char* yuv = (unsigned char *)frame->buffer;
 ++ cam_dimension_t dim;
 //获取实际宽高
 ++ stream->getFrameDimension(dim);
 ++ cam_frame_len_offset_t offset;
 //获取对齐后宽高
 ++ stream->getFrameOffset(offset);
 ++ ALOGE("%s: zcf frame_len=%d dim.w=%d,diw.h=%d,对齐后w=%d,高=%d",
func,
 frame->frame_len,dim.width,dim.height,
 offset.mp[0].stride,offset.mp[0].scanline);
//获取调用第三方算法
++ YUV2Gray(yuv,offset.mp[0].offset.mp[0].scanline);
 ···
 }

我们把宽高打印出来看看:
【Camera专题】HAL层- 实现第三方算法并集成到Android系统_第3张图片
实际宽高:360x320
对齐宽高:384x320

实际上数据要做对齐:360/32=11.25 不能整除,系统会自动对齐,填充数据整除。
因此buf_len= 384x320x1.5=184320.
为啥log是188416呢,因为还有别的一些无效信息被填充,因此会大一些。

编译
你也可以编译整个系统:
make -j32 2>&1 | tee mlog
然后刷机验证。
或者
mmm hardware/qcom/camera/QCamera2/HAL/
编译完成后会在以下目录:
out/target/product/【项目名】/system/lib/hw
生成camera.msm8909.so库
adb push camera.msm8909.so system/lib/hw
然后重启生效

集成算法的步骤:

1.弄明白第三方算法的接口
2.熟悉整个数据流,知道在哪里改
那么集成算法有哪些技术含量呢?

1.熟悉数据流
2.懂得评估算法,从内存,耗时,效果三个方面
3.流程和策略上的优化
4.多帧处理,双摄甚至多摄的集成等

HAL层- 以SO库的方式集成第三方算法

1.把自己写的算法编译成so库
.创建文件
external/hello_algo/
hello_algo.c
这里是自己实现的算法:Yuv2Gray
Android.mk
这里面指定编译规则

hello_algo.c
 #include
 void YUV2Gray(unsigned char* srcYuv,int w,int h) {
 int mid = wh/2;
 unsigned char startP = srcYuv + mid;
 printf(“zcf YUV2Gray is call\n”);
 for(int i=0;i<mid;i++) {
 *startP = 0x80;//128
 startP++;
 }
 }


这个算法很简单,就不多逼逼了!

Android.mk
LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := optional
 //库的名称:lib_helloalgo
 LOCAL_MODULE := lib_helloalgo
 LOCAL_SRC_FILES := $(call all-subdir-c-files)
 #指定生成so库
 include $(BUILD_SHARED_LIBRARY)

b.编译生成so库

编译命令:

mmm external/hello_algo/

编译完成后,会在以下路径生成so库

【Camera专题】HAL层- 以SO库的方式集成第三方算法

android获取相机参数进行压缩 安卓相机算法_Android_02


库的名称就是我们在Android.mk里面指定的名称:

LOCAL_MODULE := lib_helloalgo

到此,我们自己写的算法就变成so库了。

2.以so库的方式集成第三方算法
算法库名称:lib_helloalgo.so
头文件:hello_algo.h
可调用方法:YUV2Gray

a.在Android源码中预编译算法库

创建目录hello_algo及子文件

h a r d w a r e / q c o m / c a m e r a / Q C a m e r a 2 / H A L / h e l l o _ a l g o \color{red}{hardware/qcom/camera/QCamera2/HAL/hello_algo} hardware/qcom/camera/QCamera2/HAL/hello_algo
│─Android.mk
 │
 ├─include/
 │── hello_algo.h
 │
 ├─lib/
 │── lib_helloalgo.so
 Android.mk内容LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 #默认不会加上lib前缀
 LOCAL_MODULE := lib_helloalgo
 #不管是release还是debug版本, 都编译这个模块
 LOCAL_MODULE_TAGS := optional
 #so文件路径以及名字
 LOCAL_SRC_FILES := lib/lib_helloalgo.so
 LOCAL_MODULE_STEM := $(LOCAL_MODULE)
 #需要指定文件后缀
 LOCAL_MODULE_SUFFIX := $(suffix $(LOCAL_SRC_FILES))
 #编译32位算法库
 LOCAL_MULTILIB := 32
 #表明预编译的是动态库
 LOCAL_MODULE_CLASS := SHARED_LIBRARIES
 include $(BUILD_PREBUILT)
 hello_algo.h内容extern “C” void YUV2Gray(unsigned char* srcYuv,int w,int h);
 注意前面一点要加入extern “C”,不然编译的时候,会报错:undefined reference to xxxb.在调用的模块Android.mk中加入依赖库
 h a r d w a r e / q c o m / c a m e r a / Q C a m e r a 2 / H A L / A n d r o i d . m k \color{red}{hardware/qcom/camera/QCamera2/HAL/Android.mk} hardware/qcom/camera/QCamera2/HAL/Android.mk

表明引入的头文件

++LOCAL_C_INCLUDES += $(LOCAL_PATH)/hello_algo/include

表明当前HAL模块依赖我们要调用的算法库

++LOCAL_SHARED_LIBRARIES += lib_helloalgo
 #在最末尾出引入我们预编译的Android.mk, 不然默认系统不会执行我们写的预编译用的Android.mk
 ++include $(LOCAL_PATH)/hello_algo/Android.mk
 c.调用算法库
 h a r d w a r e / q c o m / c a m e r a / Q C a m e r a 2 / H A L / Q C a m e r a 2 H W I C a l l b a c k s . c p p \color{red}{hardware/qcom/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp} hardware/qcom/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp#include
 #include
 #include “QCamera2HWI.h”
 //引入头文件
 ++#include “hello_algo.h”void QCamera2HardwareInterface::preview_stream_cb_routine(mm_camera_super_buf_t *super_frame,
 QCameraStream * stream,
 void *userdata)
 {
 ATRACE_CALL();
 CDBG("[KPI Perf] %s : BEGIN", func);
 int err = NO_ERROR;
 QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
 QCameraGrallocMemory *memory = (QCameraGrallocMemory *)super_frame->bufs[0]->mem_info;
if (pme == NULL) {
    ALOGE("%s: Invalid hardware object", __func__);
    free(super_frame);
    return;
}    
if (memory == NULL) {
    ALOGE("%s: Invalid memory object", __func__);
    free(super_frame);
    return;
}    

mm_camera_buf_def_t *frame = super_frame->bufs[0];
if (NULL == frame) {
    ALOGE("%s: preview frame is NLUL", __func__);
    free(super_frame);
    return;
}    
  //获取YUV数据地址
++ unsigned char* yuv = (unsigned char *)frame->buffer;
 ++ cam_dimension_t dim;
 //获取实际宽高
 ++ stream->getFrameDimension(dim);
 ++ cam_frame_len_offset_t offset;
 //获取对齐后宽高
 ++ stream->getFrameOffset(offset);
 ++ ALOGE("%s: zcf frame_len=%d dim.w=%d,diw.h=%d,对齐后w=%d,高=%d",
func,
 frame->frame_len,dim.width,dim.height,
 offset.mp[0].stride,offset.mp[0].scanline);
//获取调用第三方算法
++ YUV2Gray(yuv,offset.mp[0].offset.mp[0].scanline);
 ···
 }


我们在代码里并没有YUV2Gray函数的实现,而是引入了头文件hello_algo.h,
最终会调用到lib_helloalgo.so里面的实现!

编译
你也可以编译整个系统:
make -j32 2>&1 | tee mlog
然后刷机验证。
或者
mmm hardware/qcom/camera/QCamera2/HAL/
编译完成后会在以下目录:
out/target/product/【项目名】/system/lib/hw
生成camera.msm8909.so库

adb push camera.msm8909.so system/lib/hw
adb push lib_helloalgo.so system/lib
然后重启生效