贴吧附近的人没了:Android Camera Subsystem 架构(Binder机制)及显示分析

来源:百度文库 编辑:偶看新闻 时间:2024/03/29 03:32:00

1 Camera Architecture (Binder机制应用)

该部分主要借助Camera Subsystem分享自己对binder的理解。对该部分的阅读不需要太多对Camera子系统的了解,结合大体类图,顺着我的思路也可以学习binder设计思想。通过我个人的一个思考路线,来阐述如何将binder通信机制嵌入到一个Subsystem中。通过这部分的启发,可以帮助大家应用binder通信机制,可以为Android Framwork开发更多的服务。也希望大家在阅读的时候,给我一些指导,同时帮助我更深的理解Android。大家看到的结构图和类图,我会尽快更新,因为这两个图是我大概在三个月之前刚接触项目,大概浏览下源码简单了解结构之后画的,大体方向没有错误,但是缺少一些细节,最近工作比较忙,没来的及更新。项目release之后我会添加详细结构图及类图。

2 Camera Display

该部分主要是结合自己对Camera Subsystem中涉及的Display的一个分析,帮助大家尽快理解Camera Subsystem。对这块的理解需要一些Android基础知识和Camera Subsystem源码基础。代码可能和你看到的源码不是很一样,因为已经是修改过的,包括Capture和Recording都可以很健壮的运行,而且已经过严格测试。

1、Camera Architecture

(1)Camera Architecture

 

(2)Camera File

 

          

 

 (3)Camera Framework
 

 

 

上面的类图只是一个简单的继承关系,并没有体现出很多细节,只供大家参考。ICamera、ICameraClient、ICameraServices三个类是按照Binder IPC要求的框架实现的。类Camera与CameraService端通过Binder IPC机制来实现具体的功能。 Camera类通过getCameraService()向ServiceManager发出请求,得到了一个名字为“media.camera”的CameraService实例。 通过调用CameraService提供的接口connect()在CameraService端new一个CameraService::Client类的对象mClient,通过connect将该对对象返回给Camera Client端 。随后Camera通过这个sp mCamera对象调用函数就如同直接调用CameraService::Client类的函数。 CameraService::Client 在CameraService内部真正处理由Camera Client发往Camera Service的请求和由 Camera  HAL返回的数据及notify信息。其中之前的callback函数和Camera HAL都以成员变量的形式存在于 class Client。


但是要问,这样一种组织如何将binder引入其中呢,这么多接口又是如何组织的?

首先,如果是我们自己一旦确定使用C/S架构。那么我们肯定会至少定义两个类,一个是Client类,一个是Server类。哪如何实现Client与Server之间的交互呢,或者通信呢?不用问肯定想到了网络通信Socket。因为很多时候大家只要提到Client和Server,第一本能好像就会联想到网络通信Socket,其实这个本能害人不小,让你失去了很多了解真相的机会。我们学过最基本的IPC能叫得上名字的至少有6种,其中socket只是其中的一种,也可以说socket是网络环境下最常用的一种通信方式。如果你了解linux内核,你就会知道socket的用处绝不仅限于此。说到底双方只要达到对消息结构的一致解释,就可以实现通信,完成相应的功能需求。那如果我告诉你,Client端和Server端运行在同一台机器上,使用同一根内存条。我们是不是又本能的想到了共享内存呢,这会你怎么没想到socket呢?我们能不能使用本地socket呢?其实Android中很多系统服务就是利用的本地socket来实现进程通信,通过在init的时候创建,然后在模块启动之后直接引用,因为socket无非就对应着本地文件么,创建了之后就放在那里。例如vold中就充分利用了socket。当然本地Socket、共享内存只是我们众多备选方案中最常用的两种。每次谈到IPC,很多人都觉得很难懂。其实很多时候是我们自己理解复杂了,将能用鼠标点到和眼睛看到的东西掉入了内存,就觉得摸不到了,结果给自己设置了一些障碍。举个例子,不考虑时间,最通俗的方法,你在随手建的文件夹test中写一个带main函数的程序,通过该程序在当前目录下创建并写了一个文件;随后你又在同一个目录下又创建了另一个带main函数的程序,执行该程序去访问先前程序创建的文件,你对文件又做了修改。这样两个进程实际上就实现了通信,你觉得这很容易理解,因为你将自己的思维定格在了这个test文件夹中,你能不能更深更远的拓展一下这种思维呢。而为让这种通信得到有效的保证,随后我们又提出同步,锁机制等等。

言归正传,一个进程和另一个进程要交换数据,或者要协同工作,抽象到程序上来说就是类与类之间的引用关系,函数之间的调用关系。我自己将其分为两类,一种是采用依赖调用的方式,另一种是消息机制。我在这里要说的意思是,通信双方要不要为对方提供完整的调用接口。如果我是采用依赖调用,我得知道我能调用你那些方法,这样就必须为调用者提供完整的调用接口;如果采用消息解析,我得知道我能发送那些消息或者命令,至于你能对这些命令做出符合协议规定的动作那是你的事,我只需要结果,那至少要维护一个命令接收和命令处理的状态机。两者的实质是一样,其实依赖调用按照面向对象来说也是一种消息机制。如果是依赖调用,那我们就必须提供一定的权限和完整的结构供对方调用。最基本的:如果是C函数,那你就不能把供别人调用的方法在实现文件中定义为static;如果是C++,那你就不能把它定义为private,protected(protected其实还说的过去,至少自己人可以访问)。如果是消息,我们得看看你响应的命令集或消息结构。

我第一次拿到Camera Subsystem的时候,就被从网上看到的这句话给蒙住了“ICamera/ICameraClient/ICameraServices三个类是按照Binder IPC要求的框架实现的”。我要问,到底是按什么框架要求实现的?我知道它的Client端和Service端用了Binder通信机制,但我一直捉摸不透,这个框架它为什么要求定义那么多接口,还有那么多所谓的Proxy Class和Native Class,还相互继承来继承去的。后来我总算明白了一点,他们是用了一些设计模式才会弄得这么复杂,给自己看不懂找点借口。后来我对自己产生怀疑,我问自己仅仅是设计模式的原因吗,你真的懂细节吗?我发现我还一时回答不了这个问题,我觉得还是我没搞清楚这些结构定义的目的和他们之间的调用关系。

回到Android的Binder。至少在Camera Subsystem中来看Binder通信。用我自己的理解,Binder通信机制正好是结合了依赖调用和消息机制。ICamera、ICameraClient、ICameraService为Camera Client端和Camera Service端之间的交互提供了完备的接口,这样实现了他们之间的相互调用,而隐含在这些接口下面的却是一块共享内存,这块共享内从由上层的ProcessState和IPCThreadState和内核的Binder Driver来管理。而Binder中的transact和OnTransact方法就分别对应着命令接收器和命令处理器。

再看Camera Subsystem。首先,如果不考虑Camera HAL层,在Camera Subsystem Native层存在三个主要对象:一个是充当Camera Client的Camera类;一个是充当Camera Server的CameraService类;还有另一个无名英雄类CameraService::Client类,说它是无名英雄,一点都不过分,它几乎干了CameraService的所有事情,也可以认为CameraService是个高明的管理者,它善于放权,把一切都交给CameraService::Client类来处理。如果是我,我肯定不会设计出CameraService::Client这个类来,我肯定是CameraService包揽一起,因为我还不懂得功能细化,最主要的原因是我还没有足够的经验和能力设计出它。首先站在Client的角度,要完成两件事,

一是与Server端建立连接,我自己都克制不住socket的思想又冒出来了,其实很简单,我们只要new 一个Client对象,把这个对象赋值给Server端内部维护的Client指针,同时在new一个Server对象,赋值给Client端内部的Server指针,只要双方能够彼此引用,那么连接就已经建立起来了;

二是通过各自内部保存的对方的句柄,调用相应的功能,完成请求和响应。而从Server端角度来说,一是我要响应Client端的请求,包括连接请求和功能请求,二是我必须维护对Client的管理,因为我这里可能并不是只针对一个Client。

考虑到Server端还要与HAL打交道,对Client端的请求做出响应。问题越来越清晰,Server端的功能可以明确的划分为两部分,一部分是专门实施对Client的管理,而另一部分则是完成Client的请求并作出响应。但是这种划分对Client来说是透明的,它看到的只有CameraService,在Client看来,他的所有请求都由CameraService完成。当然CameraService在公关场合,也体现出了这种能力,而在内部做了合理布局,这样CameraService就很自然的设计出了CameraService::Client类,帮助CameraService更好的为Client服务,同时CameraService::Client类的对象也正好与每一个Client相对应,CameraService只要维护本地CameraService::Client的对象,就能实现对Client的管理。

在这样一个基本框架形成之后,我们需要考虑细节,现在系统中存在Camera(CameraClient)、CameraService、CameraService::Client三个实体。而对于这三个实体,我们有了调用接口之后,我们还需要命令处理来完善他们之间的通信。我们首先想到的是:我们需要一个命令接收器、一个命令缓冲器(命令队列)和一个命令处理器。再看Binder,binder本质是共享内存,它告诉我们只需要一个命令接收器和命令处理器,而命令队列由Binder的驱动来完成。既然确定了必须要有一个命令接收器,和一个命令处理器,那从功能划分的思想来看,命令接收器肯定是要提供给调用者,这样调用者才能将命令投递到我们的接收器中,所以命令接收器必须是一个为对端开放的接口,而对端并不需要知道我们去如何处理这些命令,那么我们的命令处理器对对端来说应该是隐藏的。

通过分析,在我得到了上面这些信息之后,首先我会立马想到一个solution,我首先会定义一个抽象类叫BinderInterface, 然后里面至少有两个方法,就是transact和onTransact;然后定义transact为一个public的纯虚函数,定义onTransact为一个protected的纯虚函数。然后我们在BinderInterface的派生类中去分别实现这两个方法。其实按我自己的想法,觉得这样没有错。

到这里,还是回去看看binder的源码,看看实际系统是如何实现的,binder本地层源码给出了三个类:IBinder、BpBinder、BBinder(叫BnBinder更好)。其中IBinder相当于是我上面提到的BinderInterface类,但是按照我上面的想法,IBinder类中应该有transact和onTransact方法啊,可是找了半天,却只发现一个transact方法,但是transact方法确实是public权限,我有点疑惑,算了我还是看看BpBinder和BBinder类的定义吧。

class BpBinder : public IBinder

class BBinder : public IBinder
 


原来BpBinder和BBinder都继承与IBinder,我继续往下看了看BpBinder和BBinder的函数结构,发现BpBinder和BBinder对IBinder中的纯虚方法都进行了申明,而且也是virtual函数,如果你思维够敏锐,对面向对象理解深刻,那基本可以猜到BpBinder和BBinder的作用了,那就是如果不出差错,利用他们基本可以构造出Binder的架构。即便如此,我没有断然做出定论,而是继续观察这两个类,因为我还有一桩心事未了,那就是还没看到onTransact方法,如果看不到onTransact,那我之前的推理至少是不合理的。突然眼前豁然开朗,在BBinder类中找到了onTransact,这时候就要问自己了,为什么Binder模块会将onTransact方法放在BBinder中,而没有将其一开始就放在IBinder中呢,我思考了一下,尽量使自己能理解这种设计的初衷。我想了想,难道?不错,就是设计模式,结合类的命名和我浅显的设计模式知识,这就是代理模式。IBinder既然作为一种接口,而接口的目的是供调用者使用的,那么onTransact作为一个内部方法,就不应该展现给调用者,所以在最高层的抽象中,并不会出现onTransact方法,而是在抽象层的下层利用设计模式,将这种职权进行划分,设计出一个Proxy类和Native类,将Proxy类呈献给调用者,而对调用者隐藏Native类,所以我们会在Proxy类中真正实现ontrasact方法,而在Native类中实现onTransact方法。这样我们上面设计的不合理性就会暴露出来。

在回到CameraSubsystem中,如果我们要实现Camera(CameraClient)、CameraService、CameraService::Client三个实体之间的Binder通信,那在每一个端,我们都必须去继承于BpBinder和BBinder类,来构造这种所谓的Proxy端和Native端。所以每个模块至少要有对应的两个类一个BpCamera***类,和一个BnCamera***类,在BpCamera***类中实现transact方法,在BnCamera***类中实现onTransact方法,最终达到各实体之间的数据交换。


2、Camera Display

对于AP层用户,通过Camera界面, 以最直观的方式能够从Camera显示窗口中看到的Camera Display主要包括三部分。各部分的具体细节如下所示。

(1)Camera Preview Display

 


对于Camera Preview Display, 从Camera应用程序的角度来看,AP层需要实现Android.hardware.Camera(Framework层)类提供给上层应用的preview相关接口,完成相应的逻辑处理。但Preview作为大数据量交换的处理过程,系统不可能通过回调方式,最终将底层Camera硬件设备采集的数据交给AP层来处理。所以,上层应用只需要做一些简单的状态和UI显示处理,AP不需要接收处理真正的Preview数据,而是将数据接收和处理的过程交由ISurface接口来完成,确切的说是由ISurface的实现类SurfaceFlinger来完成。

AP层通过调用Android.hardware.Camera类提供的startPreview函数,最终通过libcamera_client.so的Camera类,利用Binder IPC,通知CameraService, CameraService通过调用其内部类Clien,内部类再通过调用HAL层提供的Camera功能完成相应的操作。

CameraService层针对Camera Client端得请求,都将交与其内部类Client来完成。CameraService层的startPreview的具体实现由CameraService::Client类的startPreviewMode函数完成相应的操作。

status_t CameraService::Client::startPreviewMode() {

    // if preview has been enabled, nothing needs to be done

    if (mHardware->previewEnabled()) {

        return NO_ERROR;

    }

    // start preview mode

    status_t ret = NO_ERROR;

    if (mUseOverlay) {

              ….

    } else {

        mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);

        ret = mHardware->startPreview();

        if (ret != NO_ERROR) return ret;

        // If preview display has been set, register preview buffers now.

        if (mSurface != 0) {

           // Unregister here because the surface registered with raw heap.

           mSurface->unregisterBuffers();

           ret = registerPreviewBuffers();

        }

    }

    return ret;

}

status_t CameraService::Client::registerPreviewBuffers()

{

    int width, height;

    CameraParameters params(mHardware->getParameters());

    params.getPreviewSize(&width, &height);

    // don't use a hardcoded format here

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

PIXEL_FORMAT_RGB_565,

                            mOrientation, 0,

mHardware->getPreviewHeap());

    status_t ret = mSurface->registerBuffers(buffers);

    if (ret != NO_ERROR) {

        LOGE("registerBuffers failed with status %d", ret);

    }

    return ret;

}
 
     

 从上面的代码我们可以看到,ISurface为Camera Preview Display专门注册了显示缓冲区,该缓冲区映射到mHardware->getPreviewHeap()指向的内存空间,缓冲区接收的数据格式为PIXEL_FORMAT_RGB_565。

CameraService已经为Camera Preview Display准备好了显示缓冲区,哪谁为注册的这块Buffer填充Preview数据呢?为了完成Camera Preview,Camera HAL层的CameraHardware类提供了previewThread线程,来完成底层数据到ISurface缓冲区的投递。通过线程Loop最终将Camera硬件设备采集的数据不断送到显示缓冲区,最后显示到AP界面上。

int CameraHardware::previewThread()

{

    int width, height;

    mParameters.getPreviewSize(&width, &height);

    if (!previewStopped && mPreviewBuffer != 0 && mRawBuffer !=0 && mDataFn) {

          int delay = (int)(1000000.0f / float(previewFrameRate));

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

              if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME){

                     ②mCamera.GrabPreviewFrame((mHeap->getBase(),

mPreviewHeap->getBase());

                ③mDataFn(CAMERA_MSG_PREVIEW_FRAME,

mPreviewBuffer, mUser);

                     delay-=100;

              }

              ………

    }

    return NO_ERROR;

}
 
     

从代码中我们可以看到,previewThread线程针对Preview Display,主要完成三个步骤的操作,


首先调用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& mem) {

    ssize_t offset,size;

    sp 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

 

在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 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& mem)

{

    ssize_t offset;

    size_t size;

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

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

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

        mSurface->postBuffer(offset);

    }

 

    sp 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,上层针对该消息会做一些简单的处理,主要是记录消息到达的系统时间。

Step3:获取JPEG Image,并存储JPEG Image,生成JPEG Image的缩略图显示在Camera窗口的右上角。在GrabRawFrame函数的基础上,我们需要将获取的原始数据转化成JPEG格式的数据,所以我们将之前GrabRawFrame获得的原始数据传给GrabJpegFrame(void * buffer)函数,返回满足要求的JPEG格式的数据。随后通过回调函数,向CameraService发送CAMERA_MSG_COMPRESSED_IMAGE消息,CameraService收到该消息之后调用JPEG Image处理函数handleCompressedPicture。


void CameraService::Client::handleCompressedPicture(const sp& mem)

{

    sp c = mCameraClient;

    if (c != NULL) {

        c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem);

    }

    mHardware->disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);

}
 


 

handleCompressedPicture和之前的处理函数不同,而是将消息和数据直接(其实是间接,还要通过Camera Client端,Camera JNI, Android.hardware.Camera)交给上层AP来处理。包括JPEG Image Storage和 Create Image Thumbnail。

在定义的延迟时间内,在Preview Layout中显示Capture image,之后通过调用restartPreview,恢复到Preview Mode状态下。

(3)VideoCamera Preview Display

当由Capture Preview状态切换到VideoPreview状态进入VideoCamera模式时,首先VideoCamera模式提供给用户的是Preview Display,这部分同Camera Preview Display。

int CameraHardware::previewThread()

{

    mLock.lock();

    int previewFrameRate = mParameters.getPreviewFrameRate();

    mLock.unlock();

    Mutex::Autolock lock(mPreviewLock);

    if (!previewStopped && mPreviewBuffer != 0

&& mRawBuffer !=0 && mDataFn) {

          int delay = (int)(1000000.0f / float(previewFrameRate));

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

              if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME){

                     ②mCamera.GrabPreviewFrame(mHeap->getBase(),

mPreviewHeap->getBase());

                ③mDataFn(CAMERA_MSG_PREVIEW_FRAME,

mPreviewBuffer, mUser);

                     delay-=100;

              }

              ①mRecordingLock.lock();

              if ((mMsgEnabled & CAMERA_MSG_VIDEO_FRAME)

&& mRecordBuffer != 0 && mTimestampFn) {

                  ②mCamera.GrabRecordFrame(mHeap->getBase(),

                                         mRecordHeap->getBase());

                     ③nsecs_t timeStamp = systemTime(SYSTEM_TIME_MONOTONIC);

                     ④mTimestampFn(timeStamp,

CAMERA_MSG_VIDEO_FRAME, mRecordBuffer, mUser);

                     delay-=100;

        }

              mRecordingLock.unlock();

        usleep(delay);

    }

    return NO_ERROR;

}
 
 

在VideoCamera模式下,当用户通过ClickShutterButton进入Camera Recording状态时,用户看到的是Camera Recording Preview Display,从数据的显示过程同Camera Preview Display,但在此状态下,需要考虑到向Opencore框架,也就是CameraInput模块投递由Camera硬件采集的Record数据。CameraHardware不仅需要向Preview缓冲区投递数据,同时还要向CameraInput传送数据。如上图所示。

在Camera Recording状态下,libcamera_client.so端的回调函数(也就是CameraListener类定义的回调函数)不再由JNICameraContext类来实现,而是由AndroidCameraInputListener实现,换句话说,在CameraInput中的mListener成员变量是由AndroidCameraInputListener来初始化的。

Location:frameworks/base/include/camera/Camera.h

class CameraListener: virtual public RefBase

{

public:

    virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;

    virtual void postData(int32_t msgType, const sp& dataPtr) = 0;

    virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType,

const sp& dataPtr) = 0;

};
 
 

 在整个Androi系统中,总共有三个类来分别实现这个抽象类,他们分别是JNICameraContext、AndroidCameraInputListener、CameraSourceListener类。

①Location:frameworks/base/core/jni/Android_hardware_Camera.cpp

class JNICameraContext: public CameraListener

 

②Location:external/opencore/Android/author/Android_camera_input.h

class AndroidCameraInputListener: public CameraListener

 

③Location:frameworks/base/core/jni/Android_hardware_Camera.cpp

class CameraSourceListener: public CameraListener
 
 

而具体实现上,由于CameraInput只需要带时间戳的数据,所以AndroidCameraInputListener只实现了postDataTimestamp回调函数。

void AndroidCameraInputListener::postDataTimestamp(nsecs_t timestamp,

int32_t msgType, const sp& dataPtr)

{

    if ((mCameraInput != NULL)

&& (msgType == CAMERA_MSG_VIDEO_FRAME)) {

        mCameraInput->postWriteAsync(timestamp, dataPtr);

    }

}
 
 

根据Opencore框架中CameraInput中的实现,CameraInput可以作为CameraClient端得一个实例,通过Camera和CameraService架构实现包括预览,录像在内的所有功能。

但在目前的Camera子系统中,Camera Recording模式与Camera Capture模式共享同一个CameraDevice实例,Camera Recording的预览是通过使用Camera Capture模式下的Surface实现的,即Camera Recording通过调用Camera Capture中的setPreviewDisplay和底层CameraHardware层的previewThread线程实现Camera Recording预览。


本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2011-09/42501p5.htm