首页 > 代码库 > android camera 学习

android camera 学习

总体介绍

  Android Camera框架从整体上看是一个client/service架构。有两个进程,一个是client进程,可以看成AP端

,主要包括Java代码和一些native层的c/c++代码;另一个是service进程,属于服务端,是native c/c++代码,

主要负责和linux kernel中的camera driver交互,搜集linux kernel中driver层传上来的数据,并交给显示系统(surface)显示。client 和 service 进程通过Binder机制进行通信,client端通过调用service端的接口实现各个具体的功能。

  对于preview数据不会通过Binder机制从service端copy 到client端,但会通过回调函数与消息机制将preview数据的buffer地址传到client端,最终可在Java ap中操作处理preview数据。

2.调用层次划分

Android中Camera的调用流程可分为以下几个层次:

Package->Framework->JNI->Camera(cpp)--(binder)-->CameraService->Camera HAL->Camera Driver

client端:

Package 中的 camera.java 调用Framework中的 camera.java(framework/base/core/java/android/hardware).Framework中的 camera.java 调用 JNI层的native 函数。JNI层的调用实现在android_hardware_camera.cpp(framework/base/core/jni文件下的文件都被 编译进libandroid_runtime.so)文件中,android_hardware_camera.cpp文件中的 register_android_hardware_camera(JNIEnv *env)函数会将native函数注册到虚拟机中,以供framework层的JAVA代码调用,这些native函数通过调用 libcamera_client.so中的camera类实现具体功能。

  核心的libcamera_client.so动态库源代码位于:framework/base/libs/camera中,其中 Icamera,IcameraClient,IcameraService三个类按照Binder IPC通信要求的框架实现的,用来与service端通信。

service端:

service端的实现在动态库libcameraservice.so中,源代码位于:frameworks/base/services/camera。CameraService相关类通过调用Camera HAL层来实现具体的功能,从HAL层向下就不是Android的标准代码了,各个厂商有自己不 同的实现。但思路应该都是相同的:Camera遵循V4L2架构,利用ioctl发送VIDIOC_DQBUF命令得到有效的图像数据,接着回调HAL层 的data callback接口以通知CameraService,CameraService会通过binder通知Camera.cpp。

ps查看进程,类似 com.android.camera是为客户端Camera进程,/system/bin/mediaserver是为服务端守护进程,由系统启动时开启。


麦库截图20141420140552825.jpg 

n1, camera打开线程与预览线程n

2,参数设置n

3,自动对焦与触摸对焦n

4,位置管理n

5,旋转管理n

6,拍照nA,对焦nB,拍照nC,接受图片nD,保存图片


1.打开camera与预览线程

onCreate()里会先后开启CameraOpenThread和CameraPreviewThread。

打开camera还需要线程?CameraOpenThread名为打开camera,实为C/S connect连接服务端,binder进程间通信,开销较大。预览线程必须在打开线程完成以后执行,它贯穿始终直到进程消亡为止,整个预览过程相对复 杂,在抽象层和底层驱动实现.


2.设置参数

预览拍照录像之前,用户需要设置很多参数,比如闪光,白平衡,场景,对比度等。程序里这些参数保存在SharedPreferences共享优选项和Parameters两个地方,Preferences包含Parameters,打开程序读取优选项参数,关闭程序保存优选项参数,考虑到用户经常会调整参数,引入Parameters来保存从打开以后到关闭以前这个中间过程的参数变量,Parameters的键值由抽象层根据硬件sensor的能力决定。

3.自动对焦与触摸对焦

外界事物由光线经凸透镜聚焦到sensor上成像,camera模组开启马达前后平移镜头取得最佳成像效果,这个过程称之为对焦。5.1 自动对焦1)camera模组会因感光强度变化而自动开启对焦,驱动控制。2) 用户长按快门,软件控制自动对焦。3) 用户按下快门拍照,拍摄前自动对焦。程序里,Camera对象实现类ShutterButton的接口OnShutterButtonListener里的方法onShutterButtonFocus(booleanpressed)和onShutterButtonClick(),后者是拍照,下节讨论,先看onShutterButtonFocus(booleanpressed),这个pressed判断是否为一次有效的长按,如果是的话,执行autoFocus(),这个autoFocus()也是Camera对象实现类FocusManager的接口Listener里的方法,由binder交给cameraservice,最后在底层驱动实现自动对焦。5.2 触摸对焦自动对焦的对焦区域位于屏幕正中,用户也可触摸特定区域对焦。Camera对象实现类View的接口OnTouchListener里的方法onTouch(),输入系统上报MotionEvent的xy坐标,保存在Parameters,执行autoFocus(),抽象层读取Paramters的触摸点坐标,实现区域对焦。

4.存储位置管理

位置管理LocationManager用来记录拍摄图片的GPS位置信息(经维度),存入JPEG头部插入的Exif里。用户在菜单“相机设置”里的"保存所在位置"选择打开(前提是GPS已开启),屏幕左上方会出现一个GPS图标,表示现在可以记录GPS信息了。程序里,Camera对象实现了位置管理监听器LocationManager.Listener的接口showGpsOnScreenIndicator()和hideGpsOnScreenIndicator(),显示或者隐藏GPS图标。程序第一次初始化时initializeFirstTime(),通过读取优选项Preference得到bool值recordLocation,判断是否需要记录GPS信息,如果需要,在拍照capture()里调用LocationManager的方法得到Locationloc,并将其存入Exif。

5.旋转管理

假设一台手机,camera正常安装,竖直方向作为默认方向(orientation== 0)拍摄照片,即拍摄“肖像照”(portrait),得到的照片显示在屏幕上也是竖直方向。如果把手机旋转90度水平过来拍摄“山水照”(landscape),对于camerasensor来说,没有旋转的概念,所以软件上要把图片旋转90度回来。————————软件上,需要借助方向监听器随时更新方向信息,并保存在Parameters里,抽象层实现拍照功能时从Parameters里读取方向。具体的,camera对象内部类MyOrientationEventListener的方法onOrientationChanged()保存方向orientation的值,MyOrientationEventListener继承OrientationEventListener,OrientationEventListener的onSensorChanged()把从sensorManager拿到的xyz坐标转换成方向。程序启动,注册sensor监听器并使能,sensorManager不断上报底层sensor数据,通过消息机制发送到camera对象,后者计算坐标数据得到方向orientation的值(实际外包给orientationListener完成),最后保存Parameters。

麦库截图20141420141056762.jpg 



6.拍照

拍照分四步,对焦,拍照,接收图片,保存图片。mCameraDevice.takePicture(mShutterCallback,mRawPictureCallback,                mPostViewPictureCallback, newJpegPictureCallback(loc));1)对焦拍照前如果已经区域对焦,则取消自动对焦,反之,开启一次自动对焦。对焦完成后,底层发送对焦成功与否的消息给camera对象,FocusManager把状态mState保存起来,如果正在对焦未完成(mState== STATE_FOCUSING)则不可拍照,直到对焦完毕。2)拍照onShutterButtonClick()-> doSnap() -> capture() -> takePicture(),具体实现在抽象层和底层驱动,实质就是拿一张预览的图像,抽象层读取拍照时的Parameters参数配置,包括用户选择的照片大小。3)接收图片通过回调,由底层发送图片给camera对象。RawPictureCallback,得到原始图片,需要软件压缩Jpeg。(YUV转Jpeg)JpegPictureCallback,直接得到Jpeg图片,需要硬件压缩Jpeg。PostViewPictureCallback,拍完后预览图片。4)保存图片交由线程ImageSaver保存图片和生成thumbnails。默认路径位于/mnt/sdcard/DCIM/Camera/