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 数据如下图
那么图像的中间就是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.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
然后重启生效