Android Camera Subsystem 架构(Binder机制)及显示分析(4)

首先调用V4L2Camera的GrabRawFrame函数,通过V4L2驱动取得Camera采集的一帧数据,将该帧数据放到指定缓冲区中;

其次将取得的原始数据通过数据格式转化函数convert,将采集到得原始数据转化成与Preview Buffer注册类型相一致的数据类型,也就是RGB565。在我们的系统中,Camera hardware采集的原始数据时YUYV(YUV4:2:2)格式的。所以我们必须将YUYV格式的原始数据转化为RGB565格式的数据,然后放到PreviewBuffer中。

最后,通过回调函数,向CameraService发送Preview消息CAMERA_MSG_PREVIEW_FRAME,CameraService收到该消息之后调用Preview处理函数handlePreviewData,通过调用postBuffer函数,最终由SurfaceFlinger完成对PreviewBuffer的Draw工作。

void CameraService::Client::handlePreviewData(const sp<IMemory>& mem) {

ssize_t offset,size;

sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);

if (!mUseOverlay)

{

Mutex::Autolock surfaceLock(mSurfaceLock);

if (mSurface != NULL) {

mSurface->postBuffer(offset);

}

}

int flags = mPreviewCallbackFlag;

if (!(flags & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {

LOGV("frame callback is diabled");

return;

}

……..

}

 
     

如上所示,HAL层将数据投递到framebuffer中,然后通知CameraService调用postBuffer对数据进行显示。Preview模式下,底层并不需要向上层AP通知自己的状态,所以postBuffer之后直接返回不再向上通知CAMERA_MSG_PREVIEW_FRAME消息。

(2)Camera TakePicture Image Display

Android Camera Subsystem 架构(Binder机制)及显示分析

在Preview模式下,通过ClickShutterButton,Camera由Previw模式进入TakePicture模式。在进入TakePicture模式之前,需要关闭Camera的预览功能,即停止Camera Preview Display。在TakePicture模式下,AP层首先会发送一个Focus请求,Focus请求会直接到达CameraHardware层,CameraHardware调用底层硬件提供的接口完成Focus功能。并通过回调函数notify,发送CAMERA_MSG_FOCUS消息,完成Focus,在完成Focus之前,系统并不会停止Preview Display,只有上层接到底层返回的FOCUS成功消息之后,才真正的进入TakePicture模式。在进入TakePicture之后,Camera主要完成三个功能。

int CameraHardware::pictureThread() {

int width, height;

if (mMsgEnabled & CAMERA_MSG_SHUTTER) {

①mNotifyFn(CAMERA_MSG_SHUTTER, 0, 0, mUser);

}

mParameters.getPictureSize(&width, &height);

②mCamera.GrabRawFrame(mHeap->getBase());

if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE) {

②mCamera.convert((unsigned char *)mHeap->getBase(),

(uint8_t *)mRawHeap->getBase(), width, height);

②mDataFn(CAMERA_MSG_RAW_IMAGE, mRawBuffer,mUser);

}

if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {

③mDataFn(CAMERA_MSG_COMPRESSED_IMAGE,

camera.GrabJpegFrame(mHeap->getBase()),mUser);

}

return NO_ERROR;

}

 
 

Step1:上层通过调用takepicture函数,最终通过Camera HAL层的CameraHardware启动captureThread线程,启动Capture线程之后,CameraHardware在第一时间会通过回调函数notify,向上发送CAMERA_MSG_SHUTTER消息给CameraService,同时CameraService将该消息返回给上层AP。

void CameraService::Client::handleShutter(image_rect_type *size) {

// Play shutter sound.

……

// Screen goes black after the buffer is unregistered.

if (mSurface != 0 && !mUseOverlay) {

mSurface->unregisterBuffers();

}

sp<ICameraClient> c = mCameraClient;

if (c != NULL) {

c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);

}

mHardware->disableMsgType(CAMERA_MSG_SHUTTER);

if (mSurface != 0 && !mUseOverlay) {

int width, height;

CameraParameters params(mHardware->getParameters());

width = size->width;

height = size->height;

ISurface::BufferHeap buffers(width, height, width, height,

PIXEL_FORMAT_RGB_565,

mOrientation, 0, mHardware->getRawHeap());

mSurface->registerBuffers(buffers);

IPCThreadState::self()->flushCommands();

}

}

 
 

如上图所示,CameraService收到CAMERA_MSG_SHUTTER消息之后,首先通过回调函数,将该消息再转发给上层AP,然后根据Picture大小调用ISurface注册用于Capture Image Display的Capture Image Display Buffer。

Step2:CameraHardware开始真正的Capture Frame,首先调用底层GrabRawFrame函数获取Capture Image Frame,接下来要完成两件事:

一是将获取的原始Capture Frame数据转化为与显示缓冲区一直的数据格式,然后将转化后的数据投递到之前注册的Capture Image Display缓冲区中。

二是通过回调函数,向CameraService发送Capture Image Display消息CAMERA_MSG_RAW_IMAGE,CameraService收到该消息之后调用RawPicture处理函数handleRawPicture,通过调用postBuffer函数,最终由SurfaceFlinger完成对RawBuffer的Draw工作。

void CameraService::Client::handleRawPicture(const sp<IMemory>& mem)

{

ssize_t offset;

size_t size;

sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);

// Put the YUV version of the snapshot in the preview display.

if (mSurface != 0 && !mUseOverlay) {

mSurface->postBuffer(offset);

}

sp<ICameraClient> c = mCameraClient;

if (c != NULL) {

c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem);

}

mHardware->disableMsgType(CAMERA_MSG_RAW_IMAGE);

}

 

private final class RawPictureCallback implements PictureCallback {

public void onPictureTaken(

byte [] rawData, Android.hardware.Camera camera) {

mRawPictureCallbackTime = System.currentTimeMillis();

}

}

 

与Preview消息不同的是,CameraService会将该消息继续发给上层AP,上层针对该消息会做一些简单的处理,主要是记录消息到达的系统时间。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwgysw.html