Android 上Camera分析

http://blog.csdn.net/u010503912/article/details/52315721

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

Camera Architecture
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.Camera Service的启动

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

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

camMethods, NELEM(camMethods));

其中camMethods定义如下:

  1. static JNINativeMethod camMethods[] = {
  2. { "native_setup",
  3. "(Ljava/lang/Object;)V",
  4. (void*)android_hardware_Camera_native_setup },
  5. { "native_release",
  6. "()V",
  7. (void*)android_hardware_Camera_release },
  8. { "setPreviewDisplay",
  9. "(Landroid/view/Surface;)V",
  10. (void *)android_hardware_Camera_setPreviewDisplay },
  11. { "startPreview",
  12. "()V",
  13. (void *)android_hardware_Camera_startPreview },
  14. { "stopPreview",
  15. "()V",
  16. (void *)android_hardware_Camera_stopPreview },
  17. { "previewEnabled",
  18. "()Z",
  19. (void *)android_hardware_Camera_previewEnabled },
  20. { "setHasPreviewCallback",
  21. "(ZZ)V",
  22. (void *)android_hardware_Camera_setHasPreviewCallback },
  23. { "native_autoFocus",
  24. "()V",
  25. (void *)android_hardware_Camera_autoFocus },
  26. { "native_takePicture",
  27. "()V",
  28. (void *)android_hardware_Camera_takePicture },
  29. { "native_setParameters",
  30. "(Ljava/lang/String;)V",
  31. (void *)android_hardware_Camera_setParameters },
  32. { "native_getParameters",
  33. "()Ljava/lang/String;",
  34. (void *)android_hardware_Camera_getParameters },
  35. { "reconnect",
  36. "()V",
  37. (void*)android_hardware_Camera_reconnect },
  38. { "lock",
  39. "()I",
  40. (void*)android_hardware_Camera_lock },
  41. { "unlock",
  42. "()I",
  43. (void*)android_hardware_Camera_unlock },
  44. };

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

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

  1. int main(int argc, char** argv)
  2. {
  3. sp proc(ProcessState::self());
  4. sp sm = defaultServiceManager();
  5. LOGI("ServiceManager: %p", sm.get());
  6. AudioFlinger::instantiate();
  7. MediaPlayerService::instantiate();
  8. CameraService::instantiate();
  9. ProcessState::self()->startThreadPool();
  10. IPCThreadState::self()->joinThreadPool();
  11. }

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

2.client端向service发送请求

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

  1. public void onCreate(Bundle icicle) {
  2. super.onCreate(icicle);
  3. Thread openCameraThread = new Thread(
  4. new Runnable() {
  5. public void run() {
  6. mCameraDevice = android.hardware.Camera.open();
  7. }
  8. }
  9. );
  10. ………………………
  11. }

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

③. Binder Kernel Driver接收到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设备的系统集成主要通过移植Camera Linux驱动和修改libcameraservice.so库来完成。

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

  1. LOCAL_PATH:= $(call my-dir)
  2. #
  3. # Set USE_CAMERA_STUB for non-emulator and non-simulator builds, if you want
  4. # the camera service to use the fake camera.  For emulator or simulator builds,
  5. # we always use the fake camera.
  6. ifeq ($(USE_CAMERA_STUB),)
  7. USE_CAMERA_STUB:=false
  8. ifneq ($(filter sooner generic sim,$(TARGET_DEVICE)),)
  9. USE_CAMERA_STUB:=true
  10. endif #libcamerastub
  11. endif ifeq ($(USE_CAMERA_STUB),true)
  12. #
  13. # libcamerastub
  14. #
  15. include $(CLEAR_VARS)
  16. LOCAL_SRC_FILES:=               \
  17. CameraHardwareStub.cpp      \
  18. FakeCamera.cpp
  19. LOCAL_MODULE:= libcamerastub
  20. LOCAL_SHARED_LIBRARIES:= libui
  21. include $(BUILD_STATIC_LIBRARY)
  22. endif # USE_CAMERA_STUB
  23. #
  24. # libcameraservice
  25. #
  26. include $(CLEAR_VARS)
  27. LOCAL_SRC_FILES:=               \
  28. CameraService.cpp
  29. LOCAL_SHARED_LIBRARIES:= \
  30. libui \
  31. libutils \
  32. libcutils \
  33. libmedia
  34. LOCAL_MODULE:= libcameraservice
  35. LOCAL_CFLAGS+=-DLOG_TAG=\"CameraService\"
  36. ifeq ($(USE_CAMERA_STUB), true)
  37. LOCAL_STATIC_LIBRARIES += libcamerastub
  38. LOCAL_CFLAGS += -include CameraHardwareStub.h
  39. else
  40. LOCAL_SHARED_LIBRARIES += libcamera
  41. endif
  42. 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” );

  1. class CameraHardwareInterface : public virtual RefBase {
  2. public:
  3. virtual ~CameraHardwareInterface() { }
  4. virtual sp         getPreviewHeap() const;
  5. virtual sp         getRawHeap() const;
  6. virtual status_t    startPreview(preview_callback cb, void* user);
  7. virtual bool useOverlay() {return false;}
  8. virtual status_t setOverlay(const sp &overlay) {return BAD_VALUE;}
  9. virtual void        stopPreview();
  10. virtual bool        previewEnabled();
  11. virtual status_t    startRecording(recording_callback cb, void* user);
  12. virtual void        stopRecording();
  13. virtual bool        recordingEnabled();
  14. virtual void        releaseRecordingFrame(const sp& mem);
  15. virtual status_t    autoFocus(autofocus_callback,
  16. void* user);
  17. virtual status_t    takePicture(shutter_callback,
  18. raw_callback,
  19. jpeg_callback,
  20. void* user);
  21. virtual status_t    cancelPicture(bool cancel_shutter,
  22. bool cancel_raw,
  23. bool cancel_jpeg);
  24. virtual status_t    setParameters(const CameraParameters& params);
  25. virtual CameraParameters  getParameters() const;
  26. virtual void release();
  27. virtual status_t dump(int fd, const Vector& args) const ;
  28. };

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

  1. extern "C" sp openCameraHardware()
  2. {
  3. CameraHardwareInterface realCamera;
  4. return &realCamera;
  5. }

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

  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_MODULE := libcamera
  4. LOCAL_SHARED_LIBRARIES := \
  5. libutils \
  6. librpc \
  7. liblog
  8. LOCAL_SRC_FILES += MyCameraHardware.cpp
  9. LOCAL_CFLAGS +=
  10. LOCAL_C_INCLUDES +=
  11. LOCAL_STATIC_LIBRARIES += \
  12. libcamera-common \
  13. libclock-rpc \
  14. libcommondefs-rpc
  15. 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中很少代码即可。

时间: 2024-08-05 15:57:39

Android 上Camera分析的相关文章

Android 上千实例源码分析以及开源分析

Android 上千实例源码分析以及开源分析(百度云分享) 要下载的直接翻到最后吧,项目实例有点多. 首先 介绍几本书籍(下载包中)吧. 01_Android系统概述 02_Android系统的开发综述 03_Android的Linux内核与驱动程序 04_Android的底层库和程序 05_Android的JAVA虚拟机和JAVA环境 06_Android的GUI系统 07_Android的Audio系统 08_Android的Video 输入输出系统 09_Android的多媒体系统 10_

Android手势识别 Camera 预览界面上显示文字 布局注意事项(merge布局)

通常在Surfaceview作为预览视频帧的载体,有时需在上面显示提示文字.以前我弄的都好好的,今天忽然发现叠加的TextView不管咋弄都出不来文字了,跟Surfaceview一起放在FrameLayout也不行,后来想到merge布局,发现也不行.大爷的,奇了怪了,最后发现了原因,原来是顺序问题.也即无论是在RelativeLayout里还是merge布局里,View是逐个叠加上去的,一层一层铺上去的.如果你先放TextView在最前面,那肯定被后面的全屏Surfaceview覆盖了.用常规

android开源应用(主要是博客上带有分析的)收集 【持续更新】

2014.5.24更新: (android高仿系列)今日头条    http://blog.csdn.net/vipzjyno1/article/details/26514543 CSDN Android客户端的制作    http://blog.csdn.net/lmj623565791/article/details/26676137 LookAround开元之旅         http://blog.csdn.net/lancees/article/details/17696805 如果

Android上使用camera拍照,把获取的照片上传到远程服务器

使用Java上传文件 从Apache Software Foundation下载HttpClient 4.3.4. 在工程中添加下面的jar包: 参考sample,写一个简单的上传: public static void main(String[] args) throws Exception {         // TODO Auto-generated method stub         CloseableHttpClient httpclient = HttpClients.crea

Android学习十二---在android上实现图像匹配

一.效果图及功能描述 效果图 点击ShowImg后 点击match,然后点击showmatch,可以不断点击showmatch. 主要功能描述:显示在SD卡上已经存在的图片test.jpg,根据图片在cameraframe对于每一帧计算和test.ipg的匹配并显示. 二.界面设计 一个JavaCameraView用来显示帧相当于是相机的预览,两个ImgView一个用来显示要匹配的图像,一个用来显示最后得到的匹配图.三个Button对应三个View,ShowImg用来显示SD卡上的test.jp

Android的Framework分析---4硬件抽象HAL

大家都知道android是基于linux的kernel上的.android可以 运行在intel,高通,nvidia等硬件平台.但是涉及到一些GPU,显卡和一些设备的驱动问题,因为这些驱动都不是开源的,google位了兼容这些设备厂商的驱动源码,提出了硬件抽象层HAL的概念.HAL层对上为framework和native开发提供统一的API接口,为下层驱动的代码提供统一的调用接口.本文主要讲解HAL是如何实现的. 1.HAL的数据结构 HAL的通用写法里面有两个重要的结构体: 1.1 hw_mo

Android内存泄露分析简要思路

工作中遇到挺多需要分析内存泄露问题的情况,现在大致简要写下思路,等之后时间相对比较充裕再进行补充. 1.明白内存泄露的判断依据? 个人总结为:持续增加,只增不减! 理解一下这8个字,配合几个命令和工具来确定一下你的应用是否存在内存泄露问题,这是很关键的,如果一开始就判断错误了,那么没有继续往下进行的理由. 命令如下: adb shell dumpsys meminfo 应用包名 [当然,比较粗略地话,可以用adb shell procrank] 这时候你可以看到一个内存使用情况表 而我们首先关注

ffmpeg在android上输出滑屏问题处理

ffmpeg部分机器上有花屏的问题 原代码如下: while(av_read_frame(formatCtx, &packet)>=0 && !_stop && NULL!=window && bInit) { // Is this a packet from the video stream? if(packet.stream_index==videoStream) { // Decode video frame avcodec_decode

Cordova Android源码分析系列一(项目总览和CordovaActivity分析)

PhoneGap/Cordova是一个专业的移动应用开发框架,是一个全面的WEB APP开发的框架,提供了以WEB形式来访问终端设备的API的功能.这对于采用WEB APP进行开发者来说是个福音,这可以避免了原生开发的某些功能.Cordova 只是个原生外壳,app的内核是一个完整的webapp,需要调用的原生功能将以原生插件的形式实现,以暴露js接口的方式调用. Cordova Android项目是Cordova Android原生部分的Java代码实现,提供了Android原生代码和上层We