您的位置:首页 > 移动开发 > Android开发

android camera HAL

2012-11-21 18:20 225 查看

一 编译HAL

1 修改BoardConfig.mk

device/wolf/smdk6410/BoardConfig.mk

USE_CAMERA_STUB := false

hardware建立Camera HAL目录

hardware/wolf/libcamera

CannedJpeg.h

Ov965xCamera.cpp

Ov965xCamera.h

S3C6410CameraHardware.cpp

S3C6410CameraHareware.h

USBCamera.cpp

USBCamera.h

编写Android.mk文件

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \

USBCamera.cpp \

Ov965xCamera.cpp \

S3C6410CameraHardware.cpp

LOCAL_SHARED_LIBRARIES:= \

libui \

libutils \

libbinder \

liblog \

libcamera_client

LOCAL_MODULE:= libcamera

LOCAL_MODULE_TAGS := eng

LOCAL_C_INCLUDES += \

frameworks/base/libs

include $(BUILD_SHARED_LIBRARY)

2 android2.3.4_32bit$ source ./build/envsetup.sh

3 android2.3.4_32bit$ choosecombo

Build for the simulator or the device?

1. Device

2. Simulator

1

1

Which product would you like? [smdk6410]

回车

eng

4 make libcamera编译特定模块

开始编译摄像头模块,动态连接库文件*.so存放在

Install: out/target/product/smdk6410/system/lib/libcamera.so

用adb push把libcamera.so推到目标机/system/lib/中

cd D:\software\android-sdk-windows\tools

d:

adb push libcamera.so /system/lib/

5 目标机上

export ANDROID_LOG_TAGS="CameraHardware:D CameraHardware:E *:S"

logcat -d

6 问题

拍照

E/AudioService( 1902): Media server died.

解决:在init.c中添加

chmod 0777 /dev/video0

二 CAMERA 系统

Camera系统分成以下几个部分

1)摄像头驱动程序:通常基于linux的video for linux视频驱动框架

2)Camera硬件抽象层

接口的代码路径:frameworks/base/include/camera/

主要文件为CameraHardwareInterfacd.h,需要各个系统根据自己的情况实现

3)Camera服务部分

代码路径:frameworks/base/include/camera

Camera服务是Android系统中一个单独部分,通过调用Camera硬件抽象层来实现

4)Camera的本地框架代码

代码路径:frameworks/base/include/camera

5)Camera的JNI代码

代码路径:frameworks/base/core/jni/android_hardware_Camera.cpp

提供给Java类的本地支持,也包含了反向调用java传递信息和数据功能

6)Camera系统的Java类

代码路径:frameworks/base/core/java/android/hardware/Camera.java

Camera对Java层次的类为android.hardware.Camera,自Java应用程序提供接口

可用于在Java应用程序层构建照相机和扫描类的程序

-----------------------------------------------------------------------

移植的内容

在Android系统中,照相机系统的标准化部分是硬件抽象层的接口,因此

针对特定平台Camera系统的移植包括Camera驱动程序和Camera硬件抽象层

在Linux系统中,Camera的驱动程序都是用Linux标准的Video for Linux 2(V4L2)

驱动程序,从内核空间到用户空间,主要的数据流和控制类的均由V4L2驱动程序

的框架来定义,在Android系统的实现中,一般也都使用标准的V4L2驱动程序作为

照相机部分的驱动程序

Camera硬件抽象层主要实现取景器,视频录制,拍摄相片三个方面功能。V4L2驱动

程序一般只提供的Video数据的获得,而如何实现视频预览,如何向上层发送数据等

功用,这些都是Camera的硬件抽象层需要负责的方面了。

三 硬件抽象层

1. Camera硬件抽象层

frameworks/base/include/camera/

主要文件为CameraHardwareInterface.h,需要各个系统根据自己的情况实现

2. Camera服务部分

frameworks/base/services/camera/libcameraservice

Camera服务是Andriod系统中一个单独的部分,通过调用camera硬件抽象层

来实现。

3. Camera 的本地框架代码

frameworks/base/libs/camera/

4. Camera的硬件抽象层

是位于V4L2驱动程序和CameraService之间的部分,这是

一个C++的接口类,需要具体的实现者继承这个类,并实现其中的各个纯虚函数。

纯虚函数可以让类先具有一个操作名称,而没有操作内容,让派生类在继承时

再去具体地给出定义。

硬件抽象层的主要的头文件为CameraHardwareInterface.h,定义了C++的接口类

需要根据系统的情况继承实现。

camera.h 这是Camera系统本地对上层的接口

CameraParameters.h定义Camera系统的参数,在本地代码的各个层次中使用。

Camera硬件抽象层的实现通常需要生成动态库libcamera.so

5. CameraHardwareInterface中定义了几种回调函数

typedef void (*notify_callback)(int32_t msgType, //通知回调

int32_t ext1,

int32_t ext2,

void* user);

typedef void (*data_callback)(int32_t msgType, //数据回调

const sp<IMemory>& dataPtr,

void* user);

typedef void (*data_callback_timestamp)(nsecs_t timestamp,//带有时间的数据回调

int32_t msgType,

const sp<IMemory>& dataPtr,

void* user);

消息类型mstType 数据IMemory

回调函数由setCallbacks(),enableMsgType()函数统一处理。

setCallbacks()可以设置三个类型的回调函数指针

/** Set the notification and data callbacks */

virtual void setCallbacks(notify_callback notify_cb,

data_callback data_cb,

data_callback_timestamp data_cb_timestamp,

void* user) = 0;

6. Camera硬件抽象层的三种业务

A 取景器preview(使用YUV原始数据格式,发送到视频输出设备)

S3C6410CameraHardware.cpp中

[csharp]
view plaincopy

1)在初始化过程中,建立preview的内存队列
void CameraHardware::initHeapLocked()
{
// Create raw heap.
int picture_width, picture_height;
mParameters.getPictureSize(&picture_width, &picture_height);
mRawHeap = new MemoryHeapBase(picture_width * picture_height * 2);

int preview_width, preview_height;
mParameters.getPreviewSize(&preview_width, &preview_height);

int how_big = preview_width * preview_height*2;
}

void CameraHardware::initDefaultParameters()
{
CameraParameters p;

p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, "320x240");
p.setPreviewSize(320, 240);//大小为320*240
p.setPreviewFrameRate(15);//帧率为15bps

p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_RGB565);//preview 的格式为RGB565
p.set(CameraParameters::KEY_ROTATION, 0);//90

p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, "320x240");
p.setPictureSize(320, 240);
p.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);// SET OUTPUT PIC TO BMP FORMAT

if (setParameters(p) != NO_ERROR) {
LOGE("Failed to set default parameters?!");
}

}
2) 在startPreview()的实现中,建立preview线程
status_t CameraHardware::startPreview()
{
Mutex::Autolock lock(mLock);
if (mPreviewThread != 0) {
return INVALID_OPERATION;
}
mPreviewThread = new PreviewThread(this);
return NO_ERROR;
}
3)在preview线程的循环中,等待视频数据的到达
int CameraHardware::previewThread()
{
if(mCamType == CAMTYPE_CMOS)
Ov965xCamera->getNextFrameAsRgb565((uint16_t *)frame);
4)视频帧到达后使用preview回调的机制CAMERA_MSG_PREVIEW_FRAME,将视频
帧向上层传送
// Notify the client of a new frame.
if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie);
B拍摄照片(可以使用原始数据或者压缩图像数据)
1) takePicture()函数表示开始拍摄,可以建立单独的线程来处理
status_t CameraHardware::takePicture()
{
stopPreview();
if (createThread(beginPictureThread, this) == false)
return UNKNOWN_ERROR;
return NO_ERROR;
}

int CameraHardware::beginPictureThread(void *cookie)
{
CameraHardware *c = (CameraHardware *)cookie;
return c->pictureThread();
}

int CameraHardware::pictureThread()
{
if (mMsgEnabled & CAMERA_MSG_SHUTTER)
mNotifyCb(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie);

if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE) {
//FIXME: use a canned YUV image!
// In the meantime just make another fake camera picture.
int w, h;
mParameters.getPictureSize(&w, &h);
sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * h * 2);

Ov965xCamera cam(w, h);
//cam.getNextFrameAsYuv420((uint8_t *)mRawHeap->base());

if(mCamType == CAMTYPE_CMOS)
{
cam.getNextFrameAsRgb565((uint16_t *)mRawHeap->base());
}
else if (mCamType == CAMTYPE_USB)
{
//USBCamera cam1(w, h);
LOGE("%s, Taking picure using USB CAM", LOG_TAG);
//cam.getNextFrameAsRgb565((uint16_t *)mRawHeap->base());
//cam1.getNextFrameAsYuv420((uint16_t *)mRawHeap->base());
}
mDataCb(CAMERA_MSG_RAW_IMAGE, mem, mCallbackCookie);
}

// ToDo: Release MemoryHeapBase
// ToDo: Convert BMP to JPEG
// Todo: Higher Resultion Support
if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {
LOGE("%s, COMPRESSED IMAGE", LOG_TAG);
int w, h;
unsigned int DATA_OFFSET = 54;
uint16_t WIDTH = w;
uint16_t HEIGHT = h;

mParameters.getPictureSize(&w, &h);
Ov965xCamera* Ov965xCamera = mOv965xCamera;
sp<MemoryHeapBase> heap = new MemoryHeapBase(DATA_OFFSET+w * h* 2);
sp<MemoryBase> mem = new MemoryBase(heap, 0, DATA_OFFSET+w * h* 2); //16 bits for one pixel

uint8_t header[54] = { 0x42, // identity : B
0x4d, // identity : M
0, 0, 0, 0, // file size
0, 0, // reserved1
0, 0, // reserved2
54, 0, 0, 0, // RGB data offset
40, 0, 0, 0, // struct BITMAPINFOHEADER size
0, 0, 0, 0, // bmp height
0, 0, 0, 0, // bmp width
1, 0, // planes
16, 0, // bit per pixel
0, 0, 0, 0, // compression
0, 0, 0, 0, // data size
0, 0, 0, 0, // h resolution
0, 0, 0, 0, // v resolution
0, 0, 0, 0, // used colors
0, 0, 0, 0 // important colors
};

// file size offset 54
uint16_t file_size = WIDTH * HEIGHT * 2 + DATA_OFFSET;
header[2] = (uint8_t)(file_size & 0x000000ff);
header[3] = (file_size >> 8) & 0x000000ff;
header[4] = (file_size >> 16) & 0x000000ff;
header[5] = (file_size >> 24) & 0x000000ff;

// height
header[18] = HEIGHT & 0x000000ff;
header[19] = (HEIGHT >> 8) & 0x000000ff;
header[20] = (HEIGHT >> 16) & 0x000000ff;
header[21] = (HEIGHT >> 24) & 0x000000ff;

// width
header[22] = WIDTH & 0x000000ff;
header[23] = (WIDTH >> 8) & 0x000000ff;
header[24] = (WIDTH >> 16) & 0x000000ff;
header[25] = (WIDTH >> 24) & 0x000000ff;

LOGE("%s, Header Ready", LOG_TAG);

unsigned int i;
for(i=0;i<DATA_OFFSET;i++){
*((uint8_t*)heap->base()+i)=header[i];
}

Ov965xCamera->getNextFrameAsRgb565((uint16_t*)heap->base()+DATA_OFFSET/2);

uint16_t *heap_base = (uint16_t*)heap->base();
uint16_t pixel_data;
uint8_t tail_data;
for(i=DATA_OFFSET/2;i<DATA_OFFSET/2+WIDTH*HEIGHT;i++){
pixel_data = *(heap_base+i);
tail_data = (uint8_t)(pixel_data & 0x001f);
pixel_data = (pixel_data & 0xffc0)>>1 | tail_data;
*(heap_base+i)=pixel_data;
}

mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mem, mCallbackCookie);
heap=NULL;
LOGE("%s, IMAGE SAVED!", LOG_TAG);
}
return NO_ERROR;
}

2)使用回调机制传送数据:如果得原始格式(通常是YUV的格式,如yuv422sp,这里是RGB565)

的数据,使用CAMERA_MSG_RAW_IMAGE将数据传送;如果得到压缩图像(通常JPEG格式,这里是BMP)

使用CAMERA_MSG_COMPRESSED_IMAGE将数据传送

C 视频录制(将数据传送给视频编码器程序)

1)在startRecording()的实现中,开始录制的准备,录制视频可以使用自己的线程,也可以使用

preview线程

2)当一个视频帧到来的时候,通过录制回调机制(使用CAMERA_MSG_VIDEO_FRAME)将视频帧向上

发送

3)releaseRecordingFrame()被调用后,表示上层通知Camera硬件抽象层,这一帧的内存已经用完

可以进行下一次的处理。

四 、 android camera HAL的改写

[csharp]
view plaincopy

1. 修改BoardConfig.mk
USE_CAMERA_STUB := false
2. hardware下建立Camera HAL目录
/hardware/ego/libcamera
复制几个文件
cp ../../../frameworks/base/services/camera/libcameraservice/CameraHardwareStub.cpp
S3C6410CameraHardware.cpp
cp ../../../frameworks/base/services/camera/rks/base/services/camera/libcameraservice/CameraHardwareStub.h
S3C6410CameraHardware.h
cp ../../../frameworks/base/services/camera/libcameraservice/FakeCamera.cpp Ov965xCamera.cpp
cp ../../../frameworks/base/services/camera/libcameraservice/FakeCamera.h Ov965xCamera.h
3. 编译Android.mk文件
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
S3C6410CameraHardware.cpp \
Ov965xCamera.cpp

LOCAL_SHARED_LIBRARIES:= \
libui \
libutils \
libbinder \
liblog \
libcamera_client

LOCAL_MODULE:= libcamera
LOCAL_MODULE_TAGS:= eng

LOCAL_C_INCLUDES += \
frameworks/base/libs

include $(BUILD_SHARED_LIBRARY)

根据这个脚本可编译出libcamera.so
4. 修改Ov965xCamera.cpp,该文件可以按照V4L2流程来写
1)构造函数中进行初始化

Ov965xCamera::Ov965xCamera(int width, int height)
: mTmpRgb16Buffer(0)
{
struct v4l2_format fmt;
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

v4l2_fd = open("/dev/video0", O_RDWR | O_SYNC);
LOGE("open /dev/video0 fd is %d", v4l2_fd);

fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = width;
fmt.fmt.pix.height = height;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;

ioctl(v4l2_fd, VIDIOC_S_FMT, &fmt);
ioctl(v4l2_fd, VIDIOC_STREAMON, &type);
setSize(width, height);
}
-------->调用setSize()

5. 修改S3C6410CameraHardware.cpp
//参数设置
void CameraHardware::initDefaultParameters()
{

CameraParameters p;
//设置preview大小
p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, "320x240");
p.setPreviewSize(320, 240);
//设置帧率
p.setPreviewFrameRate(15);
p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_RGB565);
p.set(CameraParameters::KEY_ROTATION, 0);

p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, "320x240");
p.setPictureSize(320, 240);
p.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);

if (setParameters(p) != NO_ERROR) {
LOGE("Failed to set default parameters!");
}
}

调用----->setParameters(p)
status_t CameraHardware::setParameters(const CameraParameters& params)
{
Mutex::Autolock lock(mLock);

if (strcmp(params.getPreviewFormat(),
CameraParameters::PIXEL_FORMAT_RGB565) != 0) {
LOGE("Only rgb565 preview is supported");
return -1;
}

if (strcmp(params.getPictureFormat(),
CameraParameters::PIXEL_FORMAT_JPEG) != 0) {
LOGE("Only jpeg still pictures are supported");
return -1;
}

int w, h;
params.getPictureSize(&w, &h);

mParameters = params;
initHeapLocked();

return NO_ERROR;
}

调用----->initHeapLocked();
void CameraHardware::initHeapLocked()
{
int picture_width, picture_height;
mParameters.getPictureSize(&picture_width, &picture_height);
//建立内存堆
mRawHeap = new MemoryHeapBase(picture_width * picture_height * 2);

//从参数中获取信息
int preview_width, preview_height;
mParameters.getPreviewSize(&preview_width, &preview_height);
LOGD("initHeapLocked: preview size=%dx%d", preview_width, preview_height);

int how_big = preview_width * preview_height * 2;
mPreviewFrameSize = how_big;
//制作新mmap'ed的堆,可以跨进程共享。
mPreviewHeap = new MemoryHeapBase(mPreviewFrameSize * kBufferCount);
//建立内存队列kBufferCount 4个
for (int i = 0; i < kBufferCount; i++) {
mBuffers[i] = new MemoryBase(mPreviewHeap, i * mPreviewFrameSize, mPreviewFrameSize);

}

if (mOv965xCamera != 0)
{
LOGD("delete mOv965xCamera");
delete mOv965xCamera;
mOv965xCamera = 0;
}
else if(mCamType == CAMTYPE_CMOS)
{
LOGD("new mOv965xCamera");
mOv965xCamera = new Ov965xCamera(preview_width, preview_height);
}
}
在这个过程中,建立了两块内存(MemoryHeapBase): mRawHeap 表示一个拍照照片的内存
mPreviewHeap表示取景preview的内存,由于取景器preview的内容是一个队列,因此在
mPreviewHeap中建立kBufferCount(为4个)MemoryBase
new Ov965xCamera作为摄像头输入数据的来源

CameraService.cpp调用----------->startPreview()
status_t CameraHardware::startPreview()
{
Mutex::Autolock lock(mLock);
if (mPreviewThread != 0) {
return INVALID_OPERATION;
}

//建立视频preview的线程
mPreviewThread = new PreviewThread(this);

return NO_ERROR;
}

调用----------->PreviewThread()
在PreviewThread线程中通过调用preview的回调机制,实现preview
数据的数据传递给上层就是CameraService
int CameraHardware::previewThread()
{
mLock.lock();

int previewFrameRate = mParameters.getPreviewFrameRate();
//获取内存偏移
ssize_t offset = mCurrentPreviewFrame * mPreviewFrameSize;
sp<MemoryHeapBase> heap = mPreviewHeap;

//获得Ov965xCamera类
Ov965xCamera* Ov965xCamera = mOv965xCamera;

sp<MemoryBase> buffer = mBuffers[mCurrentPreviewFrame];

mLock.unlock();

if (buffer != 0) {
//计算帧之间等待多久
int delay = (int)(1000000.0f / float(previewFrameRate));
//获得内存地址
void *base = heap->base();
//获得视频帧
uint8_t *frame = ((uint8_t *)base) + offset;

//获取一个帧的数据,放入frame
Ov965xCamera->getNextFrameAsRgb565((uint16_t *)frame);
//通知客户端的一个新的一帧,调用Callback向上层发送数据
if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie);
//推进缓冲区指针
mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount;

usleep(delay);
}
return NO_ERROR;
}
硬件抽象层实现的取景器数据来自 Ov965xCamera,可以得到数据,并使用
回调函数CAMERA_MSG_PREVIEW_FRAME宏为参数将数据送向上层,这里使用
mDataCb是上层CameraService,通过setCallbacks()函数设置。
其中mPreviewHeap存储着n个帧的缓冲,这块区域被分割为n个mBuffers。
buffer为当前帧的引用,通过mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie)
就可以将buffer输出到屏幕。那每一个帧是怎么存到mPreviewHeap上的呢?
关键的一句就是Ov965xCamera->getNextFrameAsRgb565((uint16_t *)frame) ,
通过看它的实现可以知道(在Ov96xCamera.app中),一个帧的数据以16位的格式写入frame中,
这里的frame即是对mPreviewHeap上某个mBuffer的引用
调用--------->getNextFrameAsRgb565((uint16_t *)frame)
void Ov965xCamera::getNextFrameAsRgb565(uint16_t *buffer)
{
int ret;
unsigned long len;
if (v4l2_fd != -1)
{
len = mWidth * mHeight*2;
ret = read(v4l2_fd, buffer, len);
}
}
--------------------------------------------------------
setCallbacks()函数的实现
void CameraHardware::setCallbacks(notify_callback notify_cb,
data_callback data_cb,
data_callback_timestamp data_cb_timestamp,
void* user)
{
Mutex::Autolock lock(mLock);
mNotifyCb = notify_cb;//通知回调
mDataCb = data_cb;//数据回调
mDataCbTimestamp = data_cb_timestamp;
mCallbackCookie = user;
}

--------------->takePicture()函数在拍摄照片时被调用,它也保存了回调函数的指针,并建立了拍摄照片
的线程
status_t CameraHardware::takePicture()
{
stopPreview();
if (createThread(beginPictureThread, this) == false)
return UNKNOWN_ERROR;

return NO_ERROR;
}
调用----------------->beginPictureThread()
int CameraHardware::beginPictureThread(void *cookie)
{
CameraHardware *c = (CameraHardware *)cookie;
return c->pictureThread();
}
调用----------------->pictureThread()
int CameraHardware::pictureThread()
{

//快门回调机制
if (mMsgEnabled & CAMERA_MSG_SHUTTER)
mNotifyCb(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie);

//传送原始数据的处理
if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE) {
int w, h;
mParameters.getPictureSize(&w, &h);
sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * h * 2);

Ov965xCamera cam(w, h);
if (mCamType == CAMTYPE_CMOS)
{
//获得指针
cam.getNextFrameAsRgb565((uint16_t *)mRawHeap->base());
LOGD("----------Taking picture using OV9650 CAM------");
}
//传送数据
mDataCb(CAMERA_MSG_RAW_IMAGE, mem, mCallbackCookie);
}

//传送JPEG数据的处理
if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {
LOGE("%s, --------COMPRESSD IMAGE------", LOG_TAG);
//step1 首先申请BMP暂存区:
int w, h;
unsigned int DATA_OFFSET = 54;
uint16_t WIDTH = w;
uint16_t HEIGHT = h;

mParameters.getPictureSize(&w, &h);
Ov965xCamera* Ov965xCamera = mOv965xCamera;
sp<MemoryHeapBase> heap = new MemoryHeapBase(DATA_OFFSET + w * h * 2);
//一个像素6位
sp<MemoryBase> mem = new MemoryBase(heap, 0, DATA_OFFSET + w * h * 2);

//写BMP文件头
uint8_t header[54] = {
0x42, 0x4d,//BM
0, 0, 0, 0, //file size
0, 0, //reserved1
0, 0, //reserved2
54, 0, 0, 0, //RGB data offset
40, 0, 0, 0, //struct BITMAPINFOHEADER size
0, 0, 0, 0,//bmp height
0, 0, 0, 0, //bmp width
1, 0, //planes
16, 0, //一个像素16位
0, 0, 0, 0,//压缩
0, 0, 0, 0,//data size
0, 0, 0, 0,//h resolution
0, 0, 0, 0,//v resolution
0, 0, 0, 0,//used colors
0, 0, 0, 0//important colors
};

//file size offset 54
uint16_t file_size = WIDTH * HEIGHT * 2 + DATA_OFFSET;
header[2] = (uint8_t)(file_size & 0x000000ff);
header[3] = (file_size >> 8) & 0x000000ff;
header[4] = (file_size >> 16) & 0x000000ff;
header[5] = (file_size >> 24) & 0x000000ff;

//height
header[18] = HEIGHT & 0x000000ff;
header[19] = (HEIGHT >> 8) & 0x000000ff;
header[20] = (HEIGHT >> 16) & 0x000000ff;
header[21] = (HEIGHT >> 24) & 0x000000ff;

//width
header[22] = WIDTH & 0x000000ff;
header[23] = (WIDTH >> 8 ) & 0x000000ff;
header[24] = (WIDTH >> 16) & 0x000000ff;
header[25] = (WIDTH >> 24) & 0x000000ff;

//step2 获取当前帧,进行RGB565到RGB555的转换,将转换后的
//数据放入MemoryHeap中
unsigned int i;
for (i=0; i< DATA_OFFSET; i++){
*((uint8_t *)heap->base() + i) = header[i];
}

Ov965xCamera->getNextFrameAsRgb565((uint16_t *)heap->base() + DATA_OFFSET/2);

uint16_t *heap_base = (uint16_t *)heap->base();
uint16_t pixel_data;
uint8_t tail_data;
for(i=DATA_OFFSET/2; i<DATA_OFFSET/2+WIDTH*HEIGHT; i++) {
pixel_data = *(heap_base + i);
tail_data = (uint8_t)(pixel_data & 0x001f);
pixel_data = (pixel_data & 0xffc0)>>1 | tail_data;
*(heap_base + i) = pixel_data;
}
//step3 调用callback,将数据存储到设备,并释放MemoryHeap

mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mem, mCallbackCookie);
heap = NULL;
LOGE("%s, -----IMAGE SAVED-----", LOG_TAG);
}

return NO_ERROR;
}
-----------------------------------------------------------
---------------->autoFocus()
status_t CameraHardware::autoFocus()
{
Mutex::Autolock lock(mLock);
if (createThread(beginAutoFocusThread, this) == false)
return UNKNOWN_ERROR;
return NO_ERROR;
}
调用-------------->beginAutoFocusThread()
int CameraHardware::beginAutoFocusThread(void *cookie)
{
CameraHardware *c = (CameraHardware *)cookie;
return c->autoFocusThread();
}
调用-------------->autoFocusThread()
int CameraHardware::autoFocusThread()
{
if (mMsgEnabled & CAMERA_MSG_FOCUS)
mNotifyCb(CAMERA_MSG_FOCUS, true, 0, mCallbackCookie);
return NO_ERROR;
}
----------------------------------------------------------------
上面是实现的RGB565写成BMP格式的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: