AndroidR上展讯平台Camera创建会话和开启预览流程

2024-05-24 02:08

本文主要是介绍AndroidR上展讯平台Camera创建会话和开启预览流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上篇绘制了CameraApp启动在onResume中去openCamera的流程,本篇来总结在openCamera之后得到CameraDevice对象之后创建会话,即得到CameraCaptureSession 和 通过会话session对象开启预览的流程。

openCamera流程结束之后,会回调PhotoModule的 onCameraAvailable 方法,并传入得到的cameraProxy对象。在该方法中会调用 startPreview(true); 去开启预览,下面我们重点来看下此方法。

protected void startPreview(boolean optimize) {/*SPRD Bug Fix 1398364 null pointer*/inflateStub();if (mCameraDevice == null) {Log.i(TAG, "attempted to start preview before camera device");// do nothingreturn;}//1,setPreviewDisplay 创建会话 if (isUseSurfaceView()) {if (optimize) {mCameraDevice.setPreviewDisplay(mActivity.getCameraAppUI().getSurfaceHolder());// --- 走此分支} else {mCameraDevice.setPreviewDisplayWithoutOptimize(mActivity.getCameraAppUI().getSurfaceHolder());}} else {if (optimize) {mCameraDevice.setPreviewTexture(mActivity.getCameraAppUI().getSurfaceTexture());} else {mCameraDevice.setPreviewTextureWithoutOptimize(mActivity.getCameraAppUI().getSurfaceTexture());}}doStartPreviewSpecial(isCameraIdle(), isHdr(), mActivity, mCameraDevice, mHandler,mDisplayOrientation, isCameraFrontFacing(), mUI.getRootView(), mCameraSettings);//SPRD:fix bug624871//2,通过上面创建会话的流程得到Session对象去开启预览doStartPreview(startPreviewCallback, mCameraDevice);if((getModuleTpye() != DreamModule.AUDIOPICTURE_MODULE ||!isShutterClicked()) && !isAlgorithmProcessing()){mAppController.getCameraAppUI().setBottomPanelLeftRightClickable(true);}Log.i(TAG, "startPreview end!");}

1. setPreviewDisplay 创建会话
2. 通过上面创建会话的流程得到Session对象去开启预览

我们具体追下上面两个步骤
1,setPreviewDisplay 创建会话

mCameraDevice.setPreviewDisplay(mActivity.getCameraAppUI().getSurfaceHolder());

此处cameraDevice便是在openCamera结束后回调的CameraProxy对象。
在CameraAgent的CameraProxy中实现

public void setPreviewDisplay(final SurfaceHolder surfaceHolder) {try {getDispatchThread().runJob(new Runnable() {@Overridepublic void run() {getCameraHandler().obtainMessage(CameraActions.SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder).sendToTarget();}});} catch (final RuntimeException ex) {getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);}}

还是啥都没干,发送SET_PREVIEW_DISPLAY_ASYNC消息
该消息的处理是在SprdAndroidCamera2AgentImpl中的 SprdCamera2Handler处理

case CameraActions.SET_PREVIEW_DISPLAY_ASYNC: {if(!reconnect){mUsingSurfaceView = true;setPreviewDisplay((SurfaceHolder) msg.obj);break;}// fall throughLog.i(TAG, "reconnecting, forward to SET_PREVIEW_DISPLAY_ASYNC_WITHOUT_OPTIMIZE");reconnect = false;
}
case CameraActions.SET_PREVIEW_DISPLAY_ASYNC_WITHOUT_OPTIMIZE: {mUsingSurfaceView = true;setPreviewDisplayWithoutOptimize((SurfaceHolder) msg.obj);break;
}

SET_PREVIEW_DISPLAY_ASYNC 后面没有break,再进入 SET_PREVIEW_DISPLAY_ASYNC_WITHOUT_OPTIMIZE的处理逻辑中

protected void setPreviewDisplayWithoutOptimize(SurfaceHolder surfaceHolder) {// TODO: Must be called after providing a .*Settings populated with sizes// TODO: We don't technically offer a selection of sizes tailored to SurfaceTextures!// TODO: Handle this error condition with a callback or exceptionif (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_CONFIGURED) {Log.w(TAG, "Ignoring texture setting at inappropriate time");return;}if (mSession != null) {closePreviewSession();}mSurfaceHolder = surfaceHolder;mPreviewSurface = mSurfaceHolder.getSurface();if (mCaptureReader != null) {mCaptureReader.close();}mCaptureReader = ImageReader.newInstance(mPhotoSize.width(), mPhotoSize.height(), ImageFormat.JPEG, 1);if (mThumbnailReader != null) {mThumbnailReader.close();}if (mPreviewReader != null) {mPreviewReader.close();}List<OutputConfiguration> outConfigurations = new ArrayList<>();
//            outConfigurations.add(new OutputConfiguration(mPreviewSurface, mPreviewSize.width(), mPreviewSize.height()));OutputConfiguration surfaceViewOutputConfiguration= new OutputConfiguration(new Size(mPreviewSize.width(), mPreviewSize.height()), SurfaceHolder.class);surfaceViewOutputConfiguration.addSurface(mPreviewSurface);surfaceViewOutputConfiguration.enableSprd();outConfigurations.add(surfaceViewOutputConfiguration);outConfigurations.add(new OutputConfiguration(mCaptureReader.getSurface()));if(mCameraProxy.recordSurfaces != null){for (Surface recordSurface : mCameraProxy.recordSurfaces){outConfigurations.add(new OutputConfiguration(recordSurface));}}if (mNeedThumb) {mThumbnailReader = ImageReader.newInstance(mThumbnailSize.width(), mThumbnailSize.height(), ImageFormat.YUV_420_888, 1);outConfigurations.add(new OutputConfiguration(mThumbnailReader.getSurface()));}if (mPreviewCallback != null || mConfigPreivewCallback) {mPreviewReader = ImageReader.newInstance(mCallbackSize.width(), mCallbackSize.height(), ImageFormat.YUV_420_888, 1);outConfigurations.add(new OutputConfiguration(mPreviewReader.getSurface()));}try {mCamera.createCaptureSessionByOutputConfigurations(outConfigurations,mCameraPreviewStateCallback, this); //创建会话} catch (CameraAccessException ex) {Log.e(TAG, "Failed to create camera capture session", ex);}}

配置会话参数,最后通过 mCamera.createCaptureSessionByOutputConfigurations 创建会话,此处的mCamera对象就是在openCamera流程中回调的底层CameraDevice对象

private CameraDevice.StateCallback mCameraDeviceStateCallback =new CameraDevice.StateCallback() {@Overridepublic void onOpened(CameraDevice camera) {// SPRDLog.i(TAG,"onOpened CameraDevice will camera=" + camera);if (mCameraId == null) {Log.e(TAG,"onOpened return");synchronized (mOpenCloseSyncLock) {mOpenCloseSyncLock.notifyAll();isOpeningAndCloseNeedWait = false;}return;}mCamera = camera;//此处得到底层的CameraDevice对象}};

继续回到上面的创建会话流程,在创建会话时传入了 mCameraPreviewStateCallback回调

protected CameraCaptureSession.StateCallback mCameraPreviewStateCallback =new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(CameraCaptureSession session) {mSession = session; //得到会话session对象changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);// Bug 915151. callback be set to null after null-judgementCameraStartVideoCallback tmpCallback = getCameraStartVideoCallback();Log.i(TAG, " getCameraStartVideoCallback = " + tmpCallback);if (tmpCallback != null) {startRecoderRequest();tmpCallback.onVideoStart();}}@Overridepublic void onConfigureFailed(CameraCaptureSession session) {// TODO: Invoke a callbackLog.e(TAG, "Failed to configure the camera for capture");}@Overridepublic void onActive(CameraCaptureSession session) {if (mOneshotPreviewingCallback != null) {// The session is up and processing preview requests. Inform the caller.mOneshotPreviewingCallback.onPreviewStarted();mOneshotPreviewingCallback = null;}}};

创建会话成功之后会回调 onConfigured ,并得到会话session的对象。

至此 我们在PhotoModule的startPreview方法中做的第一步 创建会话 就完成了。下面进入第二步

2, 通过上面创建会话的流程得到Session对象去开启预览
PhotoModule的startPreview中第二个关键步骤 doStartPreview

protected void doStartPreview(CameraAgent.CameraStartPreviewCallback startPreviewCallback, CameraAgent.CameraProxy cameraDevice) {if (useNewApi()) {mCameraDevice.startPreview();//开启预览startPreviewCallback.onPreviewStarted();} else {mCameraDevice.startPreviewWithCallback(new Handler(Looper.getMainLooper()),startPreviewCallback);}mPreviewing = true;// SPRD: Fix bug 659315, optimize camera launch timemUI.onPreviewStarted();updateUIAfterStartPreview();//SPRD: Fix bug 1200379mUI.enableUIAfterTakepicture();OrientationManager orientationManager = mAppController.getOrientationManager();orientationManager.addOnOrientationChangeListener(this);mUI.onOrientationChanged(orientationManager,orientationManager.getDeviceOrientation());}

mCameraDevice.startPreview();//开启预览

同理,mCameraDevice还是CameraProxy对象,我们在CameraAgent的CameraProxy中找到startPreview的实现

public void startPreview() {try {getDispatchThread().runJob(new Runnable() {@Overridepublic void run() {getCameraHandler().obtainMessage(CameraActions.START_PREVIEW_ASYNC, null).sendToTarget();}});} catch (final RuntimeException ex) {getAgent().getCameraExceptionHandler().onDispatchThreadException(ex);}
}

此方法也是只发送一个 START_PREVIEW_ASYNC 消息,此消息在AndroidCamera2AgentImpl的Camera2Handler中处理

case CameraActions.START_PREVIEW_ASYNC: {if (mCameraState.getState() !=AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) {// TODO: Provide better feedback here?Log.w(TAG, "Refusing to start preview at inappropriate time");break;}mOneshotPreviewingCallback = (CameraStartPreviewCallback) msg.obj;changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE);try {int template = CameraDevice.TEMPLATE_PREVIEW;if (mIsVideMode) {template = CameraDevice.TEMPLATE_RECORD;}if (mPreviewCallback != null && mPreviewReader != null) {ArrayList<Surface> surfaceList = new ArrayList<>();surfaceList.add(mPreviewSurface);surfaceList.add(mPreviewReader.getSurface());if(mCameraProxy.isMotionPhotoOn){for (int i = 0; i< mCameraProxy.recordSurfaces.size(); i++){surfaceList.add(mCameraProxy.recordSurfaces.get(i));}}Surface[] surfaces = new Surface[surfaceList.size()];surfaceList.toArray(surfaces);mPreviewReader.setOnImageAvailableListener(mPreviewCallback, this);mSession.setRepeatingRequest(mPersistentSettings.createRequest(mCamera,template, surfaces),/*listener*/mCameraResultStateCallback, /*handler*/this);} else {ArrayList<Surface> surfaceList = new ArrayList<>();surfaceList.add(mPreviewSurface);if(mCameraProxy.isMotionPhotoOn && mCameraProxy.recordSurfaces != null){for (int i = 0; i< mCameraProxy.recordSurfaces.size(); i++){surfaceList.add(mCameraProxy.recordSurfaces.get(i));}}Surface[] surfaces = new Surface[surfaceList.size()];surfaceList.toArray(surfaces);mSession.setRepeatingRequest(mPersistentSettings.createRequest(mCamera,template, surfaces),/*listener*/mCameraResultStateCallback, /*handler*/this);//开启预览}} catch(CameraAccessException ex) {Log.w(TAG, "Unable to start preview", ex);changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);}break;
}

通过在第一步 创建会话中得到的mSession对象去开启预览
mSession.setRepeatingRequest( mPersistentSettings.createRequest(mCamera, template, surfaces),/listener/mCameraResultStateCallback, /handler/this);//开启预览

至此,openCamera之后的 创建会话和开启预览 的流程就结束了。

下面把整个流程的时序图绘制出来。

在这里插入图片描述

这篇关于AndroidR上展讯平台Camera创建会话和开启预览流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/997064

相关文章

Git打标签从本地创建到远端推送的详细流程

《Git打标签从本地创建到远端推送的详细流程》在软件开发中,Git标签(Tag)是为发布版本、标记里程碑量身定制的“快照锚点”,它能永久记录项目历史中的关键节点,然而,仅创建本地标签往往不够,如何将其... 目录一、标签的两种“形态”二、本地创建与查看1. 打附注标http://www.chinasem.cn

通过Docker容器部署Python环境的全流程

《通过Docker容器部署Python环境的全流程》在现代化开发流程中,Docker因其轻量化、环境隔离和跨平台一致性的特性,已成为部署Python应用的标准工具,本文将详细演示如何通过Docker容... 目录引言一、docker与python的协同优势二、核心步骤详解三、进阶配置技巧四、生产环境最佳实践

MyBatis分页查询实战案例完整流程

《MyBatis分页查询实战案例完整流程》MyBatis是一个强大的Java持久层框架,支持自定义SQL和高级映射,本案例以员工工资信息管理为例,详细讲解如何在IDEA中使用MyBatis结合Page... 目录1. MyBATis框架简介2. 分页查询原理与应用场景2.1 分页查询的基本原理2.1.1 分

redis-sentinel基础概念及部署流程

《redis-sentinel基础概念及部署流程》RedisSentinel是Redis的高可用解决方案,通过监控主从节点、自动故障转移、通知机制及配置提供,实现集群故障恢复与服务持续可用,核心组件包... 目录一. 引言二. 核心功能三. 核心组件四. 故障转移流程五. 服务部署六. sentinel部署

SpringBoot集成XXL-JOB实现任务管理全流程

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl... 目录一、前言二、项目结构简述三、Maven 依赖四、Controller 代码详解五、Service

Spring创建Bean的八种主要方式详解

《Spring创建Bean的八种主要方式详解》Spring(尤其是SpringBoot)提供了多种方式来让容器创建和管理Bean,@Component、@Configuration+@Bean、@En... 目录引言一、Spring 创建 Bean 的 8 种主要方式1. @Component 及其衍生注解

MySQL 数据库表操作完全指南:创建、读取、更新与删除实战

《MySQL数据库表操作完全指南:创建、读取、更新与删除实战》本文系统讲解MySQL表的增删查改(CURD)操作,涵盖创建、更新、查询、删除及插入查询结果,也是贯穿各类项目开发全流程的基础数据交互原... 目录mysql系列前言一、Create(创建)并插入数据1.1 单行数据 + 全列插入1.2 多行数据

MySQL 临时表与复制表操作全流程案例

《MySQL临时表与复制表操作全流程案例》本文介绍MySQL临时表与复制表的区别与使用,涵盖生命周期、存储机制、操作限制、创建方法及常见问题,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小... 目录一、mysql 临时表(一)核心特性拓展(二)操作全流程案例1. 复杂查询中的临时表应用2. 临时

MySQL 临时表创建与使用详细说明

《MySQL临时表创建与使用详细说明》MySQL临时表是存储在内存或磁盘的临时数据表,会话结束时自动销毁,适合存储中间计算结果或临时数据集,其名称以#开头(如#TempTable),本文给大家介绍M... 目录mysql 临时表详细说明1.定义2.核心特性3.创建与使用4.典型应用场景5.生命周期管理6.注

MySQL的触发器全解析(创建、查看触发器)

《MySQL的触发器全解析(创建、查看触发器)》MySQL触发器是与表关联的存储程序,当INSERT/UPDATE/DELETE事件发生时自动执行,用于维护数据一致性、日志记录和校验,优点包括自动执行... 目录触发器的概念:创建触www.chinasem.cn发器:查看触发器:查看当前数据库的所有触发器的定