(转)Camera构架分析

一.Camera构架分析

Android的Camera包含取景(preview)和拍摄照片(takepicture)的功能。目前Android发布版的Camera程序虽然功能比较简单,但是其程序的架构分成客户端和服务器两个部分,它们建立在Android的进程间通讯Binder的结构上。Android中Camera模块同样遵循Andorid的框架,如下图所示

CameraArchitecture

Camera模块主要包含了libandroid_runtime.so、libui.so和libcameraservice.so等几个库文件,它们之间的调用关系如下所示:

在Camera模块的各个库中,libui.so位于核心的位置,它对上层的提供的接口主要是Camera类。

libcameraservice.so是Camera的server程序,它通过继承libui.so中的类实现server的功能,并且与libui.so中的另外一部分内容通过进程间通讯(即Binder机制)的方式进行通讯。

libandroid_runtime.so和libui.so两个库是公用的,其中除了Camera还有其他方面的功能。整个Camera在运行的时候,可以大致上分成Client和Server两个部分,它们分别在两个进程中运行,它们之间使用Binder机制实现进程间通讯。这样在client调用接口,功能则在server中实现,但是在client中调用就好像直接调用server中的功能,进程间通讯的部分对上层程序不可见。

从框架结构上来看,源码中ICameraService.h、ICameraClient.h和ICamera.h三个类定义了MeidaPlayer的接口和架构,ICameraService.cpp和Camera.cpp两个文件则用于Camera架构的实现,Camera的具体功能在下层调用硬件相关的接口来实现。

从Camera的整体结构上,类Camera是整个系统核心,ICamera类提供了Camera主要功能的接口,在客户端方面调用;CameraService是Camera服务,它通过调用实际的Camera硬件接口来实现功能。事实上,图中红色虚线框的部分都是Camera程序的框架部分,它主要利用了Android的系统的Binder机制来完成通讯。蓝色的部分通过调用Camera硬件相关的接口完成具体的Camera服务功能,其它的部分是为上层的JAVA程序提供JNI接口。在整体结构上,左边可以视为一个客户端,右边是一个可以视为服务器,二者通过Android的Bimder来实现进程间的通讯。

二.Camera工作流程概述

1.CameraService的启动

①.App_mainprocess:进程通过AndroidRuntime调用register_jni_procs向JNI注册模块的native函数供JVM调用。

AndroidRuntime::registerNativeMethods(env,"android/hardware/Camera",

camMethods,NELEM(camMethods));

其中camMethods定义如下:

staticJNINativeMethodcamMethods[]={

{"native_setup",

"(Ljava/lang/Object;)V",

(void*)android_hardware_Camera_native_setup},

{"native_release",

"()V",

(void*)android_hardware_Camera_release},

{"setPreviewDisplay",

"(Landroid/view/Surface;)V",

(void*)android_hardware_Camera_setPreviewDisplay},

{"startPreview",

"()V",

(void*)android_hardware_Camera_startPreview},

{"stopPreview",

"()V",

(void*)android_hardware_Camera_stopPreview},

{"previewEnabled",

"()Z",

(void*)android_hardware_Camera_previewEnabled},

{"setHasPreviewCallback",

"(ZZ)V",

(void*)android_hardware_Camera_setHasPreviewCallback},

{"native_autoFocus",

"()V",

(void*)android_hardware_Camera_autoFocus},

{"native_takePicture",

"()V",

(void*)android_hardware_Camera_takePicture},

{"native_setParameters",

"(Ljava/lang/String;)V",

(void*)android_hardware_Camera_setParameters},

{"native_getParameters",

"()Ljava/lang/String;",

(void*)android_hardware_Camera_getParameters},

{"reconnect",

"()V",

(void*)android_hardware_Camera_reconnect},

{"lock",

"()I",

(void*)android_hardware_Camera_lock},

{"unlock",

"()I",

(void*)android_hardware_Camera_unlock},

};

JNINativeMethod的第一个成员是一个字符串,表示了JAVA本地调用方法的名称,这个名称是在JAVA程序中调用的名称;第二个成员也是一个字符串,表示JAVA本地调用方法的参数和返回值;第三个成员是JAVA本地调用方法对应的C语言函数。

②.Mediaserverproces:进程注册了以下几个server:AudioFlinger、MediaPlayerServer、CameraService.

intmain(intargc,char**argv)

{

sp<ProcessState>proc(ProcessState::self());

sp<IServiceManager>sm=defaultServiceManager();

LOGI("ServiceManager:%p",sm.get());

AudioFlinger::instantiate();

MediaPlayerService::instantiate();

CameraService::instantiate();

ProcessState::self()->startThreadPool();

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

}

当向ServiceManager注册了CameraService服务后就可以响应client的请求了

2.client端向service发送请求

①.在java应用层调用onCreate()函数得到一个上层的Camera对象

publicvoidonCreate(Bundleicicle){

super.onCreate(icicle);

ThreadopenCameraThread=newThread(

newRunnable(){

publicvoidrun(){

mCameraDevice=android.hardware.Camera.open();

}

}

);

………………………

}

②.通过Camera对象的调用成员函数,而这些成员函数会调用已向JNI注册过的native函数来调用ICamera接口的成员函数向BinderKernelDriver发送服务请求。

③.BinderKernelDriver接收到client的请求后,通过唤醒service的进程来处理client的请求,处理完后通过回调函数传回数据并通知上层处理已完成。

三.Camera库文件分析

上面已提到Camera模块主要包含libandroid_runtime.so、libui.so、libcameraservice.so和一个与Camera硬件相关的底层库。其中libandroid_runtime.so、libui.so是与Android系统构架相关的不需要对其进行修改,libcameraservice.so和Camera硬件相关的底层库则是和硬件设备相关联的,而Canera硬件相关的底层库实际上就是设备的Linux驱动,所以Camera设备的系统集成主要通过移植CameraLinux驱动和修改libcameraservice.so库来完成。

libcameraservice.so库通过以下规则来构建:

LOCAL_PATH:=$(callmy-dir)

#

#SetUSE_CAMERA_STUBfornon-emulatorandnon-simulatorbuilds,ifyouwant

#thecameraservicetousethefakecamera.Foremulatororsimulatorbuilds,

#wealwaysusethefakecamera.

ifeq($(USE_CAMERA_STUB),)

USE_CAMERA_STUB:=false

ifneq($(filtersoonergenericsim,$(TARGET_DEVICE)),)

USE_CAMERA_STUB:=true

endif#libcamerastub

endif

ifeq($(USE_CAMERA_STUB),true)

#

#libcamerastub

#

include$(CLEAR_VARS)

LOCAL_SRC_FILES:=\

CameraHardwareStub.cpp\

FakeCamera.cpp

LOCAL_MODULE:=libcamerastub

LOCAL_SHARED_LIBRARIES:=libui

include$(BUILD_STATIC_LIBRARY)

endif#USE_CAMERA_STUB

#

#libcameraservice

#

include$(CLEAR_VARS)

LOCAL_SRC_FILES:=\

CameraService.cpp

LOCAL_SHARED_LIBRARIES:=\

libui\

libutils\

libcutils\

libmedia

LOCAL_MODULE:=libcameraservice

LOCAL_CFLAGS+=-DLOG_TAG=\"CameraService\"

ifeq($(USE_CAMERA_STUB),true)

LOCAL_STATIC_LIBRARIES+=libcamerastub

LOCAL_CFLAGS+=-includeCameraHardwareStub.h

else

LOCAL_SHARED_LIBRARIES+=libcamera

endif

include$(BUILD_SHARED_LIBRARY)

在上面的构建规则中可以看到使用了宏USE_CAMERA_STUB决定是否使用真的Camera,如果宏为真,则使用CameraHardwareStub.cpp和FakeCamera.cpp构造一个假的Camera,如果为假则使用libcamera来构造一个实际上的Camera服务。

在CameraHardwareStub.cpp中定义了CameraHardwareStub类,它继承并实现了抽象类CameraHardwareInterface中定义的真正操作Camera设备的所有的纯虚函数。通过openCameraHardware()将返回一个CameraHardwareInterface类的对象,但由于CameraHardwareInterface类是抽象类所以它并不能创建对象,而它的派生类CameraHardwareStub完全实现了其父类的纯虚函数所以openCameraHardware()返回一个指向派生类对象的基类指针用于底层设备的操作。由于CameraHardwareStub类定义的函数是去操作一个假的Camera,故通过openCameraHardware返回的指针主要用于仿真环境对Camera的模拟操作,要想通过openCameraHardware返回的指针操作真正的硬件设备则需完成以下步骤:

1.将CameraHardwareInterface类中的所有纯虚函数的声明改为虚函数的声明(即去掉虚函数声明后的“=0”);

classCameraHardwareInterface:publicvirtualRefBase{

public:

virtual~CameraHardwareInterface(){}

virtualsp<IMemoryHeap>getPreviewHeap()const;

virtualsp<IMemoryHeap>getRawHeap()const;

virtualstatus_tstartPreview(preview_callbackcb,void*user);

virtualbooluseOverlay(){returnfalse;}

virtualstatus_tsetOverlay(constsp<Overlay>&overlay){returnBAD_VALUE;}

virtualvoidstopPreview();

virtualboolpreviewEnabled();

virtualstatus_tstartRecording(recording_callbackcb,void*user);

virtualvoidstopRecording();

virtualboolrecordingEnabled();

virtualvoidreleaseRecordingFrame(constsp<IMemory>&mem);

virtualstatus_tautoFocus(autofocus_callback,

void*user);

virtualstatus_ttakePicture(shutter_callback,

raw_callback,

jpeg_callback,

void*user);

virtualstatus_tcancelPicture(boolcancel_shutter,

boolcancel_raw,

boolcancel_jpeg);

virtualstatus_tsetParameters(constCameraParameters&params);

virtualCameraParametersgetParameters()const;

virtualvoidrelease();

virtualstatus_tdump(intfd,constVector<String16>&args)const;

};

2.编写一个源文件去定义CameraHardwareInterface类中声明的所有虚函数,并实现openCameraHardware()函数让该函数返回一个CameraHardwareInterface类对象的指针;例如:

extern"C"sp<CameraHardwareInterface>openCameraHardware()

{

CameraHardwareInterfacerealCamera;

return&realCamera;

}

3.仿照其他.mk文件编写Android.mk文件用于生成一个包含步骤2编写的源文件和其他相关文件的libcamera.so文件;例如

LOCAL_PATH:=$(callmy-dir)

include$(CLEAR_VARS)

LOCAL_MODULE:=libcamera

LOCAL_SHARED_LIBRARIES:=\

libutils\

librpc\

liblog

LOCAL_SRC_FILES+=MyCameraHardware.cpp

LOCAL_CFLAGS+=

LOCAL_C_INCLUDES+=

LOCAL_STATIC_LIBRARIES+=\

libcamera-common\

libclock-rpc\

libcommondefs-rpc

include$(BUILD_SHARED_LIBRARY)

4.将宏USE_CAMERA_STUB改成false,这样生成libcameraservice.so时就会包含libcamera.so库。(注:如果CameraHardwareInterface类的成员函数并没有直接操作硬件而是调用Camera的linux驱动来间接对硬件操作,那么包含这样的CameraHardwareInterface类的libcamera.so库就相当于一个HAL)

上面左图中libcamera.so库直接操作Camera设备,这样相对于右图来说就相当于libcamera.so库包含了Camera驱动,而右图则将驱动从库中分离出来并形成一层HAL这样做的好处是:移植不同型号或不同厂商的同类设备时只需修改HAL中很少代码即可。

相关推荐