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 nothing
            return;
        }
        //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() {
                    @Override
                    public 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 through
    Log.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 exception
            if (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() {
            @Override
            public void onOpened(CameraDevice camera) {
                // SPRD
                Log.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() {
 @Override
 public void onConfigured(CameraCaptureSession session) {
     mSession = session; //得到会话session对象
     changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
     // Bug 915151. callback be set to null after null-judgement
     CameraStartVideoCallback tmpCallback = getCameraStartVideoCallback();
     Log.i(TAG, " getCameraStartVideoCallback = " + tmpCallback);
     if (tmpCallback != null) {
         startRecoderRequest();
         tmpCallback.onVideoStart();
     }
 }

 @Override
 public void onConfigureFailed(CameraCaptureSession session) {
     // TODO: Invoke a callback
     Log.e(TAG, "Failed to configure the camera for capture");
 }

 @Override
 public 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 time
        mUI.onPreviewStarted();

        updateUIAfterStartPreview();

        //SPRD: Fix bug 1200379
        mUI.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() {
        @Override
        public 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之后的 创建会话和开启预览 的流程就结束了。

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

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值