Camera对象实现类View的接口OnTouchListener里的方法onTouch(),输入系统上报MotionEvent的xy坐标,保存在Parameters,执行autoFocus(),抽象层读取Paramters的触摸点坐标,实现区域对焦。
6. 拍照
拍照分四步,对焦,拍照,接收图片,保存图片。
mCameraDevice.takePicture(mShutterCallback, mRawPictureCallback,
mPostViewPictureCallback, new JpegPictureCallback(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/
7. 人脸检测
人脸检测可以软件实现,可以硬件实现,软件实现增加CPU开销,硬件实现增大耗电,鼓励硬件实现...
上层Camera对象实现了 framework层Camera的接口FaceDetectionListener的方法onFaceDetection(Face[] faces, Camera camera),回调机制同上,硬件sensor识别脸部信息,发送face给camera对象,framework定义face的特征,比如眼睛,嘴巴,上层保存mFaces数据,更新UI。
8. 位置管理
位置管理LocationManager用来记录拍摄图片的GPS位置信息(经维度),存入JPEG头部插入的Exif里。
用户在菜单“相机设置”里的"保存所在位置"选择打开(前提是GPS已开启),屏幕左上方会出现一个GPS图标,表示现在可以记录GPS信息了。
程序里,Camera对象实现了位置管理监听器LocationManager.Listener的接口showGpsOnScreenIndicator()和hideGpsOnScreenIndicator(),显示或者隐藏GPS图标。
程序第一次初始化时initializeFirstTime(),通过读取优选项Preference得到bool值recordLocation,判断是否需要记录GPS信息,如果需要,在拍照capture()里调用LocationManager的方法得到Location loc,并将其存入Exif。
9. 旋转管理
假设一台手机,camera正常安装,竖直方向作为默认方向(orientation == 0)拍摄照片,即拍摄“肖像照”(portrait),得到的照片显示在屏幕上也是竖直方向。
如果把手机旋转90度水平过来拍摄“山水照”(landscape),对于camera sensor来说,没有旋转的概念,所以软件上要把图片旋转90度回来。
软件上,需要借助方向监听器随时更新方向信息,并保存在Parameters里,抽象层实现拍照功能时从Parameters里读取方向。
具体的,camera对象内部类MyOrientationEventListener的方法onOrientationChanged()保存方向orientation的值,MyOrientationEventListener继承OrientationEventListener,OrientationEventListener的onSensorChanged()把从sensorManager拿到的xyz坐标转换成方向。
程序启动,注册sensor监听器并使能,sensorManager不断上报底层sensor数据,通过消息机制发送到camera对象,后者计算坐标数据得到方向orientation的值(实际外包给orientationListener完成),最后保存Parameters。
10. 变焦
用户拖动Zoom横条可放大缩小预览画面连续变焦,另一种所谓状态变焦,其原理是一样的。
camera对象的内部类ZoomChangeListener实现ZoomControl的方法,实质是把变焦的任务全权交给ZoomControl。ZoomControl监听处理用户的触摸事件dispatchTouchEvent(),用来得到并处理变焦倍数mListener.onZoomValueChanged(index),它由mCameraDevice.startSmoothZoom()通过 binder交给camera service,camera service再通过sendComand命令机制交给抽象层实现变焦,抽象层开启变焦线程,变焦改变预览,通过回调机制发送消息CAMERA_MSG_ZOOM把变焦倍数返还给camera对象,最终camera对象收到消息后,ZoomListener.onZoomChange()把变焦倍数保存到Parameters.
11. 录像
ModePicker负责切换模式,一共有三种模式,普通模式,录像模式和全景模式,Manifest里依次声明这三个activity。
切换模式,销毁原有activity,开启新activity,伴随关闭preview,重启preview,保存配置,读取配置,开销很大。
录像VideoCamera.java同预览Camera.java的思路类似,按下录像按钮,程序监听用户事件,开启录像,录像交给MediaRecoder,StagefrightRecorder负责。