介绍 Android 的 Camera 框架

jopen 13年前
     总体介绍    <br /> Android Camera 框架从整体上看是一个 client/service 的架构,有两个进程:一个是 client 进    <br /> 程,可以看成是 AP 端,主要包括 JAVA 代码与一些 native c/c++代码;另一个是 service 进    <br /> 程,属于服务端,是 native c/c++代码,主要负责和 linux kernel 中的 camera driver 交互,搜    <br /> 集 linux kernel 中 camera driver 传上来的数据,并交给显示系统(surface)显示。client 进程与    <br /> service 进程通过 Binder 机制通信,       client 端通过调用 service 端的接口实现各个具体的功能。    <br /> 需要注意的是真正的 preview 数据不会通过 Binder IPC 机制从 service 端复制到 client 端,   但    <br /> 会通过回调函数与消息的机制将 preview 数据 buffer 的地址传到 client 端, 最终可在 JAVA AP    <br /> 中操作处理这个 preview 数据。    <br />          client 端    <br /> 从 JAVA AP 的角度看 camera ap 就是调用 FrameWork 层的 android.hardware.camera 类来实现    <br /> 具体的功能。JAVA Ap 最终被打包成 APK。    <br /> FrameWork 层主要提供了 android.hardware.camera 类给应用层使用,这个类也是 JAVA 代码    <br /> 实 现 。 Android.hardware.camera 类 通 过 JNI 调 用 native 代 码 实 现 具 体 的 功 能 。    <br /> Android.hardware.camera 类中提供了如下的一个参数类给应用层使用:    <br /> public class Parameters {    <br />         // Parameter keys to communicate with the camera driver。    <br />         private static final String KEY_PREVIEW_SIZE = "preview-size";    <br />         private static final String KEY_PREVIEW_FORMAT = "preview-format";    <br />         ......    <br /> }    <br /> 参数会以字典(map)的方式组织存储起来,关键字就是 Parameters 类中的这些静态字符    <br /> 串。这些参数最终会以形如“preview-size=640X480;preview-format=yuv422sp;....”格式的    <br /> 字符串传到 service 端。     源代码位于:framework/base/core/java/android/hardware/camera.java    <br />    <p>提供的接口示例:</p>    <p>获得一个 android.hardware.camera 类的实例</p> public static Camera open() {    <br />         return new Camera();    <br /> }    <br />  接口直接调用 native 代码(android_hardware_camera.cpp 中的代码)    <br /> public native final void startPreview();    <br /> public native final void stopPreview();    <br /> android.hardware.camera 类的 JNI 调用实现在 android_hardware_camera.cpp 文件中,源代码    <br /> 位置:  framework/base/core/jni/android_hardware_camera.cpp    <br /> (framework/base/core/jni/文件夹下的文件都被编译进 libandroid_runtime.so 公共库中  )    <br />    <p>android_hardware_camera.cpp 文件中的 JNI 调用实现函数都如下图:</p>    <p><img alt="介绍 Android 的 Camera 框架" src="https://simg.open-open.com/show/61a84567595a146bf13d8be322d56439.png" width="374" height="396" /></p> android_hardware_camera.cpp 文件中的 register_android_hardware_Camera(JNIEnv *env)函数    <br /> 会将上面的 native 函数注册到虚拟机中,以供 FrameWork 层的 JAVA 代码调用。这些 native    <br /> 函数通过调用 libcamera_client.so 中的 Camera 类实现具体的功能。    <br /> 核心的 libcamera_client.so 动态库源代码位于:   frameworks/base/libs/camera/,  实现了如下几    <br /> 个类:    <br />  Camera---->Camera.cpp/Camera.h    <br />  CameraParameters--->CameraParameters.cpp/CameraParameters.h    <br />  Icamera--->ICamera.cpp/ICamera.h    <br />  IcameraClient--->ICameraClient.cpp/ICameraClient.h    <br />  IcameraService--->ICameraService.cpp/ICameraService.h    <br /> Icamera、IcameraClient、IcameraService 三个类是按照 Binder IPC 通信要求的框架实现的,用    <br /> 来与 service 端通信。    <br /> 类 CameraParameters 接收 FrameWork 层的 android.hardware.camera::Parameters 类为参数,    <br /> 解析与格式化所有的参数设置。    <br /> Camera 是一个很重要的类,     它与 CameraService 端通过 Binder IPC 机制交互来实现具体功能。    <br /> Camera 继承自 BnCameraClient,并最终继承自 ICameraClient。    <br /> Camera 类通过:    <br /> sp    <iservicemanager>     sm = defaultServiceManager();     <br /> sp     <ibinder>      binder = sm->getService(String16("media.camera"));      <br /> sp      <icameraservice>       mCameraService = interface_cast       <icameraservice>        (binder);        <br /> 得到名字为“media.camera”的 CameraService。通过调用 CameraService 的接口 connect()返        <br /> 回得到 sp        <icamera>         mCamera,并在 CameraService 端 new 一个 CameraService::Client 类         <br /> mClient。mClient 继承自 BnCamera,并最终继承自 ICamera。         <br /> 之 后 Camera 类 通 过 这 个 sp         <icamera>          mCamera 对 象 调 用 函 数 就 像 直 接 调 用          <br /> CameraService::Client 类 mClient 的函数。CameraService::Client 类实现具体的功能。          <br />           service 端          <br />          <p>实现在动态库 libcameraservice.so 中,  源代码位于:  frameworks/base/camera/libcameraservice</p> Libcameraservice.so 中主要有下面两个类:          <br /> Libcameraservice.so::CameraService 类 , 继 承 自 BnCameraService , 并 最 终 继 承 自          <br />      ICameraService          <br />   Libcameraservice.so::CameraService::Client 类, 继承自 BnCamera,    并最终继承自 ICamera          <br /> CameraService::Client 类通过调用 Camera HAL 层来实现具体的功能。目前的 code 中只支持          <br /> 一个 CameraService::Client 实例。          <br /> Camera Service 在 系 统 启 动 时 new 了 一 个 实 例 , 以 “ media.camera ” 为 名 字 注 册 到          <br /> ServiceManager 中。在 init.rc 中有如下代码执行可执行文件/system/bin/mediaserver,启动多          <br /> 媒体服务进程。          <br /> service media /system/bin/mediaserver          <br /> Mediaserver 的 c 代码如下:          <br /> int main(int argc,char** argv)          <br /> {          <br />     sp          <processstate>           proc(ProcessState::self());           <br />     sp           <iservicemanager>            sm = defaultServiceManager();            <br />     LOGI("ServiceManager: %p",sm。get());            <br />     AudioFlinger::instantiate();            <br />     MediaPlayerService::instantiate();            <br />     CameraService::instantiate();            <br />     AudioPolicyService::instantiate();            <br />     ProcessState::self()->startThreadPool();            <br />     IPCThreadState::self()->joinThreadPool();            <br /> }            <br />                                                       <br />  Camera HAL(硬件抽象层)            <br /> Libcameraservice.so::CameraService::Client 类调用 camera HAL 的代码实现具体功能,camera            <br /> HAL 一般实现为一个动态库 libcamera.so(动态库名字可以改,只需要与 Android.mk 一致即            <br /> 可)。Android 只给了一个定义文件:            <br /> /home/miracle/Work/android/android_src/froyo/frameworks/base/include/camera/CameraHard            <br /> wareInterface.h            <br /> class CameraHardwareInterface : public virtual RefBase {            <br /> public:            <br />      virtual ~CameraHardwareInterface() { }            <br />      virtual sp            <imemoryheap>             getPreviewHeap() const = 0;             <br />      virtual sp             <imemoryheap>              getRawHeap() const = 0;              <br />      virtual void setCallbacks(notify_callback notify_cb,data_callback data_cb,              <br />                      data_callback_timestamp data_cb_timestamp,void* user) = 0;              <br />      virtual void       enableMsgType(int32_t msgType) = 0;              <br />      virtual void       disableMsgType(int32_t msgType) = 0;              <br />      virtual bool       msgTypeEnabled(int32_t msgType) = 0;              <br />      virtual status_t startPreview() = 0;              <br />      virtual bool        useOverlay() {return false;}              <br />      virtual status_t setOverlay(const sp              <overlay>               &overlay) {return BAD_VALUE;}               <br />      virtual void         stopPreview() = 0;               <br />      virtual bool         previewEnabled() = 0;               <br />      virtual status_t      startRecording() = 0;               <br />      virtual bool         recordingEnabled() = 0;               <br />      virtual status_t      autoFocus() = 0;               <br />      virtual status_t      cancelAutoFocus() = 0;               <br />      virtual status_t      takePicture() = 0;               <br />      virtual status_t      cancelPicture() = 0;               <br />      virtual status_t      setParameters(const CameraParameters& params) = 0;               <br />      virtual CameraParameters getParameters() const = 0;               <br />      virtual status_t sendCommand(int32_t cmd,int32_t arg1,int32_t arg2) = 0;               <br />      virtual void release() = 0;               <br />      virtual status_t dump(int fd,const Vector               <string16>                & args) const = 0;                <br /> };                <br /> extern "C" sp                <camerahardwareinterface>                 openCameraHardware();                 <br /> }; // namespace android                 <br /> 可以看到在 JAVA Ap 中的功能调用最终会调用到 HAL 层这里,Camera HAL 层的实现是主要                 <br /> 的工作,      它一般通过 V4L2 command 从 linux kernel 中的 camera driver 得到 preview 数据。然                 <br /> 后交给 surface(overlay)显示或者保存为文件。在 HAL 层需要打开对应的设备文件,并通过                 <br /> ioctrl 访问 camera driver。Android 通过这个 HAL 层来保证底层硬件(驱动)改变,只需修改                 <br /> 对应的 HAL 层代码,FrameWork 层与 JAVA Ap 的都不用改变。                 <br />            Preview 数据流程                 <br /> Android 框架中 preview 数据的显示过程如下:                 <br /> 1、 打开内核设备文件。CameraHardwareInterface.h 中定义的 openCameraHardware()打开                 <br />       linux kernel 中的 camera driver 的设备文件(如/dev/video0)      ,创建初始化一些相关的类                 <br />       的实例。                 <br /> 2、 设置摄像头的工作参数。CameraHardwareInterface.h 中定义的 setParameters()函数,在                 <br />       这一步可以通过参数告诉 camera HAL 使用哪一个硬件摄像头,  以及它工作的参数  (size,                 <br />     format 等) ,并在 HAL 层分配存储 preview 数据的 buffers(如果 buffers 是在 linux kernel                 <br />     中的 camera driver 中分配的,在这一步也会拿到这些 buffers mmap 后的地址指针)                      。                 <br /> 3、 设置显示目标。需在 JAVA APP 中创建一个 surface 然后传递到 CameraService 中。会调                 <br />     用到 libcameraservice.so 中的 setPreviewDisplay(const sp                 <isurface>                  & surface)函数中。在                  <br />     这里分两种情况考虑:一种是不使用 overlay;一种是使用 overlay 显示。如果不使用                  <br />     overlay 那设置显示目标最后就在 libcameraservice.so 中,不会进 Camera HAL 动态库。                  <br />     并将上一步拿到的 preview 数据 buffers 地址注册到 surface 中。 如果使用 overlay 那在                  <br />     libcameraservice.so 中会通过传进来的 Isurface 创建 Overlay 类的实例,然后调用                  <br />     CameraHardwareInterface.h 中定义的 setOverlay()设置到 Camera HAL 动态库中。                  <br /> 4、 开始 preview 工作。最终调用到 CameraHardwareInterface.h 中定义的 startPreview()函数。                  <br />     如果不使用 overlay,Camera HAL 得到 linux kernel 中的 preview 数据后回调通知到                  <br />     libcameraservice.so 中。在 libcameraservice.so 中会使用上一步的 surface 进行显示。如                  <br />     果使用 overlay,    Camera HAL 得到 linux kernel 中的 preview 数据后直接交给 Overlay 对象,                  <br />     然后有 Overlay HAL 去显示。                  <br />          模拟器中的虚拟 camera                  <br /> 如果没有 camera 硬件,不实现真正的 Camera HAL 动态库,可以使用虚拟 camera。源代码                  <br /> 位于:                  <br /> frameworks/base/camera/libcameraservice/FakeCamera.cpp                  <br /> frameworks/base/camera/libcameraservice/CameraHardwareStub.cpp                  <br /> FakeCamera.cpp 文件提供虚拟的 preview 数据。CameraHardwareStub.cpp 文件中实现了                  <br /> camera HAL(硬件抽象层)的功能。当宏 USE_CAMERA_STUB 为 true 时可以使用这个虚拟的                  <br /> camera。                  <br /> ifeq ($(USE_CAMERA_STUB),true)                  <br />     LOCAL_STATIC_LIBRARIES += libcamerastub //虚拟的 camera                  <br /> #if want show LOGV message,should use follow define。 add 0929                  <br /> #LOCAL_CFLAGS += -DLOG_NDEBUG=0                  <br />     LOCAL_CFLAGS += -include CameraHardwareStub。h                  <br /> else                  <br />     LOCAL_SHARED_LIBRARIES += libcamera //真正的 camera HAL 库                  <br /> endif                  <br />                  <p>           框架图</p>                  <p><img style="width:684px;height:434px;" alt="介绍 Android 的 Camera 框架" src="https://simg.open-open.com/show/4c8a6637a8c7e5233a1a43647d5f401d.png" /></p>            Overlay 简单介绍                  <br /> overlay 一般用在 camera preview,视频播放等需要高帧率的地方,还有可能 UI 界面设计                  <br /> 的需求, 如map 地图查看软件需两层显示信息。 overlay 需要硬件与驱动的支持。  Overlay 没                  <br /> 有 java 层的 code,也就没有 JNI 调用。一般都在 native 中使用。                  <br /> Overlay 的使用方法                  <br /> 1. 头文件                  <br /> overlay object 对外的接口                  <br /> #include                  <ui overlay。h="">                   <br /> 下面三个用于从 HAL 得到 overlay object                   <br /> #include                   <surfaceflinger surface。h="">                    <br /> #include                    <surfaceflinger isurface。h="">                     <br /> #include                     <surfaceflinger surfacecomposerclient。h="">                      <br />    2.  相关动态库文件                      <br /> libui.so                      <br /> libsurfaceflinger_client.so                      <br />     3.  调用步骤                      <br />   创建 surfaceflinger 的客户端                      <br /> sp                      <surfacecomposerclient>                       client = new SurfaceComposerClient();                       <br />    创建推模式 surface                       <br /> sp                       <surface>                        surface = client->createSurface(getpid(),0,320,240,                        <br /> PIXEL_FORMAT_UNKNOWN,IsurfaceComposer::ePushBuffers);                        <br />   获得 surface 接口                        <br /> sp                        <isurface>                         isurface = surface->getISurface();                         <br />    获得 overlay 设备                         <br /> sp                         <overlayref>                          ref = isurface->createOverlay(320,240,PIXEL_FORMAT_RGB_565);                          <br /> 这里会通过调用 overlay hal 层的 createoverlay()打开对应的设备文件。                          <br />   创建 overlay 对象                          <br /> sp                          <overlay>                           overlay = new Overlay(ref);                           <br />    使用 overlay API                           <br /> overlay_buffer_t buffer; //typedef void* overlay_buffer_t;                           <br /> void* address = overlay->getBufferAddress(buffer);                           <br /> address 指针就是 mmap 后的 overlay buffer 指针,   只需将数据填充到这个 address 指针就可                           <br /> 以看到画面了。                           <br /> Android overlay 框架                           <br />                           <img style="width:691px;height:376px;" alt="介绍 Android 的 Camera 框架" src="https://simg.open-open.com/show/17c64e3ba2b03efea9cfc3c7100a37f7.png" />                           <br /> overlay 本地框架代码                           <br /> 源代码位于:frameworks/base/libs/ui/ ,编译到 libui.so 中。                           <br />   Overlay.cpp : 提 供 给 外 部 程 序 调 用 的 Overlay object 接 口 与 API 。 定 义 在                           <br />       frameworks/base/include/ui/Overlay.h 中。实现了两个类:OverlayRef 与 Overlay。外部                           <br />       程序通过这个 Overlay 对象来使用 overlay 的功能。Overlay.cpp 内部通过 binder 与                           <br />       surfaceFlinger service 通信,最终调用到 Overlay HAL。                           <br />  IOVerlay.cpp:  定义提供 binder 所需的类,        其中 LayerBuffer::OverlaySource::OverlayChannel                           <br />   继承自 BnOverlay。                           <br /> overlay 的服务部分代码                           <br /> 源代码位于:frameworks/base/libs/surfaceflinger/                           <br /> overlay 系统被包在 Surface 系统中, 通过 surface 来控制 overlay 或者在不使用 overlay 的情                           <br /> 况下统一的来管理。所以 overlay 的 service 部分也包含在 SurfaceFlinger service 中,主要的                           <br /> 类 LayerBuffer。                           <br /> android 启动的时候会启动 SurfaceFlinger service,SurfaceFlinger 启动时会实例化一个                           <br /> DisplayHardware:                           <br /> DisplayHardware* const hw = new DisplayHardware(this,dpy);                           <br /> DisplayHardware 构造函数调用函数 init:                           <br /> DisplayHardware::DisplayHardware(const sp                           <surfaceflinger>                            & flinger,                            <br />                                          uint32_t dpy)                            <br /> : DisplayHardwareBase(flinger,dpy)                            <br /> {                            <br />   init(dpy);                            <br /> }                            <br /> Init 函数中:                            <br /> if(hw_get_module(OVERLAY_HARDWARE_MODULE_ID,&module) == 0) {                            <br />      overlay_control_open(module,&mOverlayEngine);                            <br /> }                            <br /> 获得 overlay 的 module 参数,       调用 overlay_control_open 获取控制设备结构 mOverlayEngine。                            <br /> 拥有了控制设备结构体就可以创建数据设备结构体 ,并具体控制使用 overlay 了。                            <br /> overlay HAL 层                            <br /> 源代码位于:hardware/libhardware/include/hardware/overlay.h                            <br /> android 只给出了接口的定义,需要我们自己实现具体的功能。 overlay hal 层生成的动态库                            <br /> 在 SurfaceFlinger 中显式的加载。Overlay HAL 层具体功能如何实现取决于硬件与驱动程序。                            <br /> Android 提供了一个 Overlay Hal 层实现的框架代码,                hardware/libhardware/modules/overlay/。                            <br /> 因为 overlay hal 层生成的动态库是显式的动态打开(hw_get_module -> dlopen),所以这个库                            <br /> 文件必须放在文件系统的 system/lib/hw/下。                            <br /> 多层 overlay                            <br /> 例如需要同时支持 overlay1 与 overlay2。                            <br />  1. overlay hal 的 overlay_control_device_t 中要添加 overlay1 与 overlay2 的结构:                            <br /> struct overlay_control_context_t {                            <br />    struct overlay_control_device_t device;                            <br />    /* our private state goes below here */                            <br />    struct overlay_t* overlay_video1;//overlay1                            <br />    struct overlay_t* overlay_video2;//overlay2                            <br /> };                            <br /> 每个 overlay_t 代表一层 overlay,每层 ovelay 有自己的 handle。                            <br /> 在构造 OverlayRef 之前需指明使用哪一层 overlay:                            <br /> sp                            <overlayref>                             ref = isurface->createOverlay(320,240,PIXEL_FORMAT_RGB_565);                             <br /> 可以使用自定义参数调用 overlay_control_device_t::setParameter()来指定 Hal 层具体实现。                             <br /> 2,通过 Overlay object 来拿到 overlay1 与 overlay2 的 buffer 指针。                            </overlayref>                           </surfaceflinger>                          </overlay>                         </overlayref>                        </isurface>                       </surface>                      </surfacecomposerclient>                     </surfaceflinger>                    </surfaceflinger>                   </surfaceflinger>                  </ui>                 </isurface>                </camerahardwareinterface>               </string16>              </overlay>             </imemoryheap>            </imemoryheap>           </iservicemanager>          </processstate>         </icamera>        </icamera>       </icameraservice>      </icameraservice>     </ibinder>    </iservicemanager>