android camera HAL

reference http://www.cnblogs.com/FlexChen/archive/2011/09/10/2169380.html

一 编译HAL

修改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 pushlibcamera.so推到目标机/system/lib/

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

d:

adb push libcamera.so /system/lib/

目标机上

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

logcat -d

问题

拍照

E/AudioService( 1902): Media server died.

解决:在init.c中添加

chmod 0777 /dev/video0

二 CAMERA 系统

Camera系统分成以下几个部分

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

2Camera硬件抽象层

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

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

3)Camera服务部分

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

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

4Camera的本地框架代码

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

5CameraJNI代码

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

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

6Camera系统的Java

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

CameraJava层次的类为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硬件抽象层的三种业务

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

S3C6410CameraHardware.cpp

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将数据传送

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

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

preview线程

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

发送

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

可以进行下一次的处理。

四 、 android camera HAL的改写

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格式的



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值