介绍 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>