Android Camera 打开预览流程分析-- Camera 连接到CameraService 过程分析

Posted Give.Me.Five

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Camera 打开预览流程分析-- Camera 连接到CameraService 过程分析相关的知识,希望对你有一定的参考价值。

上篇已经分析了CameraService 的初始化过程,之前分析到ICameraService.connectDevice(…), 通过CameraService建立起cameraID 与CameraDevice的联系,那我们继续往下分析, CameraPreview创建的过程:

   private void createCameraPreviewSession() 
        try 
            SurfaceTexture texture = mTextureView.getSurfaceTexture();
            assert texture != null;

            // We configure the size of default buffer to be the size of camera preview we want.
            texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());

            // This is the output Surface we need to start preview.
            //初始化一个surface,当成一个preview的一个buffer数据
            Surface surface = new Surface(texture);

            // We set up a CaptureRequest.Builder with the output Surface.
            mPreviewRequestBuilder
                    = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            mPreviewRequestBuilder.addTarget(surface);

            // Here, we create a CameraCaptureSession for camera preview.
            //把surface 和 mImageReader的buffer 当成preview的一个surface 的集合
            mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                    new CameraCaptureSession.StateCallback() 
                    ...
                    
             

    public void createCaptureSession(List<Surface> outputs,
            CameraCaptureSession.StateCallback callback, Handler handler)
            throws CameraAccessException 
        List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
        //将之前的surface集合 转化成OutputConfiguration的集合
        for (Surface surface : outputs) 
            outConfigurations.add(new OutputConfiguration(surface));
        
        //根据OutputConfiguration集合, 再来创建captureSession
        createCaptureSessionInternal(null, outConfigurations, callback,
                checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
                /*sessionParams*/ null);
    


    private void createCaptureSessionInternal(InputConfiguration inputConfig,
            List<OutputConfiguration> outputConfigurations,
            CameraCaptureSession.StateCallback callback, Executor executor,
            int operatingMode, CaptureRequest sessionParams) throws CameraAccessException 
        synchronized(mInterfaceLock) 

            checkIfCameraClosedOrInError();
			//检查是否是高速模式
            boolean isConstrainedHighSpeed =
                    (operatingMode == ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE);

            // TODO: dont block for this
            boolean configureSuccess = true;
            CameraAccessException pendingException = null;
            Surface input = null;
            try 
                //在空闲时,配置stream流
                configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations,
                        operatingMode, sessionParams);
                if (configureSuccess == true && inputConfig != null) 
                    input = mRemoteDevice.getInputSurface();
                
             catch (CameraAccessException e) 
                configureSuccess = false;
                pendingException = e;
                input = null;
                if (DEBUG) 
                    Log.v(TAG, "createCaptureSession - failed with exception ", e);
                
            

            // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
            //遍历outputConfigurations中的surface, 然后再添加到surfaces中
            CameraCaptureSessionCore newSession = null;
            if (isConstrainedHighSpeed) 
                ArrayList<Surface> surfaces = new ArrayList<>(outputConfigurations.size());
                for (OutputConfiguration outConfig : outputConfigurations) 
                    surfaces.add(outConfig.getSurface());
                
                StreamConfigurationMap config =
                    getCharacteristics().get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                SurfaceUtils.checkConstrainedHighSpeedSurfaces(surfaces, /*fpsRange*/null, config);

                newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
                        callback, executor, this, mDeviceExecutor, configureSuccess,
                        mCharacteristics);
             else 
                newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
                        callback, executor, this, mDeviceExecutor, configureSuccess);
            

            // TODO: wait until current session closes, then create the new session
            mCurrentSession = newSession;

            if (pendingException != null) 
                throw pendingException;
            

            mSessionStateCallback = mCurrentSession.getDeviceStateCallback();
        
    

在createCaptureSessionInternal函数中,在空闲中会创建和配置数据流,同时放入到配置中去,最后再来创建session会话,关键是在configureStreamsChecked时,如何创建和配置流的,我们继续去分析这个函数

    public boolean configureStreamsChecked(InputConfiguration inputConfig,
            List<OutputConfiguration> outputs, int operatingMode, CaptureRequest sessionParams)
                    throws CameraAccessException 
        // Treat a null input the same an empty list
        if (outputs == null) 
            outputs = new ArrayList<OutputConfiguration>();
        
        if (outputs.size() == 0 && inputConfig != null) 
            throw new IllegalArgumentException("cannot configure an input stream without " +
                    "any output streams");
        

        checkInputConfiguration(inputConfig);

        boolean success = false;

        synchronized(mInterfaceLock) 
            checkIfCameraClosedOrInError();
            // Streams to create
            HashSet<OutputConfiguration> addSet = new HashSet<OutputConfiguration>(outputs);
            // Streams to delete
            List<Integer> deleteList = new ArrayList<Integer>();

            // Determine which streams need to be created, which to be deleted
            for (int i = 0; i < mConfiguredOutputs.size(); ++i) 
                int streamId = mConfiguredOutputs.keyAt(i);
                OutputConfiguration outConfig = mConfiguredOutputs.valueAt(i);

                if (!outputs.contains(outConfig) || outConfig.isDeferredConfiguration()) 
                    // Always delete the deferred output configuration when the session
                    // is created, as the deferred output configuration doesn't have unique surface
                    // related identifies.
                    deleteList.add(streamId);
                 else 
                    addSet.remove(outConfig);  // Don't create a stream previously created
                
            

            mDeviceExecutor.execute(mCallOnBusy);
            stopRepeating();

            try 
            	//当空闲的时候,配置outputconfig
                waitUntilIdle();

                mRemoteDevice.beginConfigure();

                // reconfigure the input stream if the input configuration is different.
                InputConfiguration currentInputConfig = mConfiguredInput.getValue();
                if (inputConfig != currentInputConfig &&
                        (inputConfig == null || !inputConfig.equals(currentInputConfig))) 
                    if (currentInputConfig != null) 
                        mRemoteDevice.deleteStream(mConfiguredInput.getKey());
                        mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(
                                REQUEST_ID_NONE, null);
                    
                    if (inputConfig != null) 
                        int streamId = mRemoteDevice.createInputStream(inputConfig.getWidth(),
                                inputConfig.getHeight(), inputConfig.getFormat());
                        mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(
                                streamId, inputConfig);
                    
                

                // Delete all streams first (to free up HW resources)
                for (Integer streamId : deleteList) 
                    mRemoteDevice.deleteStream(streamId);
                    mConfiguredOutputs.delete(streamId);
                

                //基于新的config创建stream流,然后将stream流放入到ConfigureOutput中 
                for (OutputConfiguration outConfig : outputs) 
                    if (addSet.contains(outConfig)) 
                        int streamId = mRemoteDevice.createStream(outConfig);
                        mConfiguredOutputs.put(streamId, outConfig);
                    
                
                operatingMode = (operatingMode | (customOpMode << 16));

                if (sessionParams != null) 
                    mRemoteDevice.endConfigure(operatingMode, sessionParams.getNativeCopy());
                 else 
                    mRemoteDevice.endConfigure(operatingMode, null);
                

                success = true;
             catch (IllegalArgumentException e) 
                // OK. camera service can reject stream config if it's not supported by HAL
                // This is only the result of a programmer misusing the camera2 api.
                Log.w(TAG, "Stream configuration failed due to: " + e.getMessage());
                return false;
             catch (CameraAccessException e) 
                if (e.getReason() == CameraAccessException.CAMERA_IN_USE) 
                    throw new IllegalStateException("The camera is currently busy." +
                            " You must wait until the previous operation completes.", e);
                
                throw e;
             finally 
                if (success && outputs.size() > 0) 
                    mDeviceExecutor.execute(mCallOnIdle);
                 else 
                    // Always return to the 'unconfigured' state if we didn't hit a fatal error
                    mDeviceExecutor.execute(mCallOnUnconfigured);
                
            
        

        return success;
    

这个函数中会将所有的configs 创建addset 集合,然后将已经包含了重复的config 删掉,最后在空闲时,创建stream流,然后将streamID 和config配置到mConfiguredOutputs中。
分析到这里,CameraDevice 创建createCameraPreviewSession会话就分析完了,也看到创建的surface 绑定到cameraDevice上了。到这里Camera2的接口分析就暂时告一个段落了。

以上是关于Android Camera 打开预览流程分析-- Camera 连接到CameraService 过程分析的主要内容,如果未能解决你的问题,请参考以下文章

Android Camera 打开预览流程分析--CameraService中的打开流程

Android Camera 打开预览流程分析--打开camera的SDK流程

Android Camera 打开预览流程分析--打开camera的SDK流程

Android Camera 打开预览流程分析--打开camera的SDK流程

Android Camera 打开预览流程分析--打开camera的SDK流程

Android Camera 打开预览流程分析-- Camera 连接到CameraService 过程分析