Android Camera框架

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值