看展讯平台的Camera有一段时间了,今天来整理下openCamera的流程。
其实,CameraAPP的主要逻辑可分为两大部分:界面显示 + camera处理

展讯和MTK平台CameraAPP的共同点是两者都有Module的概念,即不同的Module处理app中不同的模式,比如拍照模式、美颜模式、录像模式等等。
但是在与camera这个硬件设备打交道的时候,设计却明显不同。MTK平台app是将UI的处理与camera处理均放在当前Module中处理,而展讯平台是Module只处理与当前模式相关的界面逻辑,而将camera操作统一封装,由专门的类去处理。

如下是处理与camera相关逻辑的类的继承关系

从图明显看出,在CameraAgent处分支了,一支类名中带有2,一支没有,这是与camera使用api1还是api2有关的。显然我们现在都是使用的api2,因此我们关注左边的分支。
与camera相关的打开、预览、拍照、数据callback、关闭等操作均在这几个类里面处理。

现在我们以普通的photo模式为例,来看下openCamera流程调用。

从PhotoModule的resume开始,

@Override
public void resume() {Log.i(TAG, "resume start!");//---此处省略与UI相关的处理requestCameraOpen();
}

流程转到requestCameraOpen方法

/*** Uses the {@link CameraProvider} to open the currently-selected camera* device, using {@link GservicesHelper} to choose between API-1 and API-2.*/protected void requestCameraOpen() {/*** SPRD: fix bug47362 Log.v(TAG, "requestCameraOpen");*//** SPRD:Fix bug 513841 KEY_CAMERA_ID may be changed during the camera in* background if user do switch camera action in contacts, and then we* resume the camera, the init function will not be called, so the* mCameraId will not be the latest one. Which will cause the switch* camera function can not be used. @{*/int mCameraID = mDataModule.getInt(Keys.KEY_CAMERA_ID);if(mIsImageCaptureIntent) {mCameraID = mDataModule.getInt(Keys.KEY_INTENT_CAMERA_ID);}if(mCameraID != mCameraId){mCameraId = mCameraID;mActivity.getCameraAppUI().updateModeList();}if (mCameraId == DreamUtil.FRONT_CAMERA && isSupportSensoSelfShotModule()) {mCameraId = CameraUtil.SENSOR_SELF_SHOT_CAMERA_ID;}/* @} *//*start add for w+t*/if (CameraUtil.isWPlusTAbility(mActivity,mActivity.getCurrentModuleIndex(),mCameraId)){mCameraId = CameraUtil.BACK_W_PLUS_T_PHOTO_ID;}/*end add for w+t*///        if (mActivity.getCurrentModuleIndex() == SettingsScopeNamespaces.AUTO_PHOTO && !DreamUtil.isFrontCamera(mActivity,mCameraId)) {if (CameraUtil.isTcamAbility(mActivity,mActivity.getCurrentModuleIndex(),mCameraId)) {mCameraId = CameraUtil.BACK_TRI_CAMERA_ID;}/*** SPRD: Change for New Feature VGesture and dream camera* original code* @{mActivity.getCameraProvider().requestCamera(mCameraId,GservicesHelper.useCamera2ApiThroughPortabilityLayer(mActivity.getContentResolver()));*/Log.i(TAG, "requestCameraOpen mCameraId:" + mCameraId);doCameraOpen(mCameraId);/*** @}*/}

此方法的前半部分是对mCameraId各种情况下的校验,最后是调用doCameraOpen(mCameraId)

protected void doCameraOpen(int cameraId){mActivity.getCameraProvider().requestCamera(cameraId, useNewApi());}

doCameraOpen方法很简单,就是将流程又转到 requestCamera,这里我们关注下 mActivity.getCameraProvider()是个什么类型。

在CameraActivity中,我们看到getCameraProvider就是CameraController类, 去看下CameraController。

public class CameraController implements CameraAgent.CameraOpenCallback, CameraProvider

CameraController 内容不多,因为实现了CameraAgent.CameraOpenCallback,所以其主要内容是camera状态的回调,但是并不处理这些回调,是在在接收到回调后,转发给相应的处理者。

还是回到从PhotoModule跟过来的requestCamera方法。

@Overridepublic void requestCamera(int id, boolean useNewApi) {Log.i(TAG, "requestCamera id="+id);Log.i(TAG, "mRequestingCameraId = " + mRequestingCameraId + "mInfo = " + mInfo);if (mRequestingCameraId != EMPTY_REQUEST || mRequestingCameraId == id) {return;}mRequestingCameraId = id;mActiveCameraDeviceTracker.onCameraOpening(CameraId.fromLegacyId(id));// Only actually use the new API if it's supported on this device.useNewApi = mCameraAgentNg != null && useNewApi;CameraAgent cameraManager = useNewApi ? mCameraAgentNg : mCameraAgent;if (mCameraProxy == null) {// No camera yet.checkAndOpenCamera(cameraManager, id, mCallbackHandler, this);} else if (mCameraProxy.getCameraId() != id || mUsingNewApi != useNewApi) {boolean syncClose = GservicesHelper.useCamera2ApiThroughPortabilityLayer(mContext.getContentResolver());Log.v(TAG, "different camera already opened, closing then reopening");mCameraProxy = null;// Already has camera opened, and is switching cameras and/or APIs.if (mUsingNewApi) {if (mCameraAgentNg != null)mCameraAgentNg.closeCamera(mCameraProxy, true);} else {// if using API2 ensure API1 usage is also syncedmCameraAgent.closeCamera(mCameraProxy, syncClose);}checkAndOpenCamera(cameraManager, id, mCallbackHandler, this);} else {// The same camera, just do a reconnect.Log.v(TAG, "reconnecting to use the existing camera");mCameraProxy.reconnect(mCallbackHandler, this);mCameraProxy = null;}mUsingNewApi = useNewApi;}

有与CameraAgent相关的:
CameraAgent cameraManager = useNewApi ? mCameraAgentNg : mCameraAgent;
我们在CameraAPP中可以看到很多类似的,通过useNewApi 这个boolean值判断使用哪个Agent,这其实就是我们前面说的api1与api2的兼容处理。

我们以打开CameraAPP,第一次请求openCamera的流程来跟踪,那么 mCameraProxy == null 是符合的,进入第一个if分支:checkAndOpenCamera

private static void checkAndOpenCamera(CameraAgent cameraManager,final int cameraId, Handler handler, final CameraAgent.CameraOpenCallback cb) {Log.i(TAG, "checkAndOpenCamera");try {CameraUtil.throwIfCameraDisabled();cameraManager.openCamera(handler, cameraId, cb);} catch (CameraDisabledException ex) {handler.post(new Runnable() {@Overridepublic void run() {cb.onCameraDisabled(cameraId);}});}}

关键代码:cameraManager.openCamera(handler, cameraId, cb);
而cameraManager就是前面通过useNewApi的boolean值判断得来的api2的那支的CameraAgent。
还记得最前面的那张继承关系图吗?
现在就要从CameraController中的openCamera方法转到那张继承关系图中的类了。

因为是继承关系,我也不知道具体的openCamera方法是在继承关系中的哪个类实现的,我们就一个个找吧。
最终在CameraAgent中找到了openCamera的实现:

public void openCamera(final Handler handler, final int cameraId,final CameraOpenCallback callback) {Log.e(TAG,"openCamera "+android.util.Log.getStackTraceString(new Throwable()));try {getDispatchThread().runJob(new Runnable() {@Overridepublic void run() {synchronized (mOpenCloseSyncLock) {isOpeningAndCloseNeedWait = true;}getCameraHandler().obtainMessage(CameraActions.OPEN_CAMERA, cameraId, 0,CameraOpenCallbackForward.getNewInstance(handler, callback)).sendToTarget();}});} catch (final RuntimeException ex) {getCameraExceptionHandler().onDispatchThreadException(ex);}}

看来CameraAgent的openCamera也没做什么事情,就是通过handler–message机制转发了下CameraActions.OPEN_CAMERA消息。
再来追CameraActions.OPEN_CAMERA消息的处理
我们在AndoridCamera2AgentImpl中找到了

case CameraActions.OPEN_CAMERA:{CameraOpenCallback openCallback = (CameraOpenCallback) msg.obj;int cameraIndex = msg.arg1;if (mCameraState.getState() > AndroidCamera2StateHolder.CAMERA_UNOPENED) {openCallback.onDeviceOpenedAlready(cameraIndex,generateHistoryString(cameraIndex));break;}mOpenCallback = openCallback;mCameraIndex = cameraIndex;/** SPRD: Fix bug 591216 that add new feature 3d range finding, only support API2 currently @{* Original Code*mCameraId = mCameraDevices.get(mCameraIndex);*/mCameraId = "" + mCameraIndex;/* @} */Log.i(TAG, String.format("Opening camera index %d (id %s) with camera2 API",cameraIndex, mCameraId));if (mCameraId == null) {mOpenCallback.onCameraDisabled(msg.arg1);break;}reconnect = false;mCameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, this);break;
}

mCameraManager.openCamera,追到了CameraManager了。至此APP端的openCamera流程已经完成了。

最后,我们将上述流程画成时序图来总结下:

AndroidR上展讯CameraAPP的openCamera流程相关推荐

  1. Android R上展讯平台CameraAPP的Settings设置项管理

    CameraAPP的设置项管理是CameraAPP中客户需求比较偏重的一部分,一般客户要添加新功能,都需要提供一个设置项开关出来.今天我们来整理下设置项的逻辑,先来看下设置项的截图: 我们知道,不同M ...

  2. 展讯 Camera 驱动流程 576 i 480i CVBS NTSC 摄像头调试

    本文主要研究展讯平台Camera驱动和HAL层代码架构,熟悉展讯Camera的控制流程. 平台:Sprd-展讯平台 Hal版本:[HAL3] 知识点如下: 从HAL层到deiver层 1.Camera ...

  3. 展讯软件开发的一般流程

    在开始前,得先在XP系统中配置好展讯平台的编译环境,并装好相关软件.然后接到 任务,说要将MP3界面做成什么样子,或是将主菜单改成什么样子,或是将系统中的 List控件做成什么什么风格,或是开发一个独 ...

  4. 展讯sprd_battery.c 充电驱动

    sprd_battery.c 是充电驱动,这个是充电功能的核心内容,电量显示策略.温度检测策略.充电保护机制等功能在这里实现,功能实现与硬件细节剥离,调用通用接口实现逻辑控制: 1 sprdbat_p ...

  5. 揭秘财报:展讯击退联发科第一波攻势

    先看一组数据: 上表体现了自展讯CEO李力游自2009年2月上任以来合计七个季度财报的表现,其中2009年Q1为李力游刚刚上任,Q2展讯财报步入谷底,巨亏1310万美元,之后五个季度连续实现盈利,老杳 ...

  6. 上任半年股票涨四倍,展讯CEO做了啥?

    2009年7月28日,展讯股票飙升23.5%达到每股3.15美元,距离展讯CEO李力游2月13日上任不到5个月时间,展讯股票已经由之前的不到8毛美金升幅接近四倍,李力游这几个月做了什么? 半年不到,展 ...

  7. [置顶] 展讯充电管理模块浅析(一)

    展讯充电管理模块浅析 电池在电子产品中所占的地位就不用说了.不过电池在物理接口上比较简单,就两条线:正极.负极,这个小学生科普知识都知道:不过真正用到电子产品中时,有关电池方面的东西还是有点多的. 参 ...

  8. 展讯充电管理模块浅析(一)

    展讯充电管理模块浅析 电池在电子产品中所占的地位就不用说了.不过电池在物理接口上比较简单,就两条线:正极.负极,这个小学生科普知识都知道:不过真正用到电子产品中时,有关电池方面的东西还是有点多的. 参 ...

  9. 展讯android智能机平台FDL1,FDL2,SPL文件下载问题简析

    首先,我们要了解这样一个背景知识:展讯的每颗智能芯片(其他智能机平台应该也是如此)内部都有IROM和IRAM,IROM里有固化的Romcode(用于与PC端工具通讯,下载程序). 但是...... 但 ...

  10. 展讯平台-sensor驱动

        驱动者,三分硬件,三分格式,四分软件.     在手机中,我们常将camera直接称为sensor,展讯平台的sensor就像lcd一样,已经十分的成熟了.沿袭前面的模式,先介绍一下硬件的基本 ...

最新文章

  1. 缓存技术比拼:Redis与Memcached的同与不同
  2. SmartQuery WebPart 2.0 发布。
  3. 中小学python、人工智能书籍(2022.02.02)
  4. Vmware拓展虚拟机硬盘容量
  5. ACCESS模糊查询出现的变态问题,不知道该问题的希望注意,知道内幕的高手还望给小弟一个解释 Thanks...
  6. 对象数组根据某属性列的灵活排序
  7. 转 Silverlight开发历程—(画刷与着色之线性渐变画刷)
  8. android 声音突然变小,手机明明没坏,为什么声音开到最大依然很小?这个方法你知道吗...
  9. a标签提交form表单_Web前端开发基础知识,HTML中表单元素的理解
  10. 光猫上网问题 看我如何解决
  11. c语言运算符优先级(c语言运算符优先级由高到低的顺序)
  12. 阿里云服务器公网带宽下载上传速度及测速Ping值测试工具
  13. 20sccm_SCCM 完全手册
  14. 投影仪买哪个好?家用投影仪哪种好
  15. UnExpected Error, Quitting
  16. itext文本域自动换行_iText+Flying Saucer生成pdf文档,中文不显示和不自动换行问题...
  17. 如何修改QColorDialog窗口的背景颜色和上面的字体
  18. ios 简书 获取通讯录信息_ios 各种权限整理
  19. Python使用 matplotlib的basemap绘图之一--几行代码画世界地图和中国地图
  20. Autodesk Inventor Routed Systems: Harness Autodesk Inventor Routed Systems: Harness Lynda课程中文字幕

热门文章

  1. 漫画:揭秘程序员快速变有钱的方法
  2. linux nfs配置权限不够,nfs服务权限配置
  3. 美国投资移民EB-5或将关闭,投资者寻求投资入籍备选方案
  4. 数据结构与算法 精讲
  5. MFC+opencv244眼部追踪的问题
  6. FineBI如何在web页面中嵌入式集成
  7. 咖啡汪推荐————基于Redisson缓存映射MapCache,实现会员到期前N天邮件提醒
  8. 前端实现 AWS s3 (亚马逊)云储存 上传文件/照片/视频 代码实现
  9. 【Unity工具,简单学习】PUN 2,多人在线游戏开发,初步使用
  10. 触控科技CEO陈昊芝:引擎技术推动行业升级