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的接口分析就暂时告一个段落了。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Linux下的Camera驱动分析主要涉及以下几个方面: 1.硬件支持:Linux内核需要支持相应的摄像头硬件,这需要在内核编译时进行配置。一般来说,Linux内核已经支持大部分常见的摄像头硬件。 2.驱动程序:Linux下的摄像头驱动程序通常是V4L2(Video for Linux 2)驱动程序。V4L2是Linux内核中的一个视频设备驱动框架,它提供了一套标准的API,用于访问视频设备。 3.应用程序:在Linux下,可以使用一些应用程序来访问摄像头,如Cheese、Guvcview等。这些应用程序使用V4L2 API来访问摄像头,从而实现视频采集、录制等功能。 总之,Linux下的Camera驱动分析需要了解V4L2驱动框架以及相关的硬件支持和应用程序。 ### 回答2: Linux下的Camera驱动是指针对硬件摄像头设备的驱动程序,通过驱动设备,可以让Linux系统匹配摄像头硬件设备的固件,并且使用Linux本身的API(接口)来进行图像处理。 目前,Linux系统已经支持了多种不同的摄像头设备,支持摄像头硬件设备的厂商包括Logitech、Creative、Microsoft等。这些厂商提供的摄像头设备在Linux系统下可以通过预装的驱动程序和用户自行下载的驱动程序安装来使用。 摄像头设备对于现代计算机系统来说已经是非常重要的一种外设,尤其是在多种应用场合下开始被广泛应用,如视频会议、视频监控、虚拟现实、图像识别等应用。Linux系统下摄像头驱动的分析和开发能力,对于这些应用的实现和推广也产生了很大的影响。 在Linux系统下,摄像头驱动程序主要有以下几个部分构成: 1. V4L核心驱动 V4L(Video4Linux)核心驱动是Linux系统中用于支持摄像头设备的核心驱动程序,主要提供一些通用的API函数,如打开、关闭、读取、写入、控制摄像头设备的函数等。 2. V4L2硬件驱动 V4L2(Video4Linux2)硬件驱动是针对具体的摄像头设备所编写的驱动程序。每种摄像头硬件设备都需要编写一个与之对应的V4L2驱动程序。这些驱动程序通常被编写为内核模块的形式,在用户开机时动态加载到内核中。 3. 应用层驱动程序 应用驱动程序位于Linux系统的上层,用于针对某一具体摄像头设备的用户界面和图形操作。这些驱动程序通常是由厂商针对自己提供的摄像头设备所编写的。 总体来说,Linux下的摄像头驱动程序的分析和开发,需要对Linux系统和硬件设备的特性有深入的了解,同时还需要具备一定的编程技巧和开发能力。对于想要从事Linux下摄像头驱动领域的工程师和科研人员来说,需要扎实的理论基础和丰富的实际经验。 ### 回答3: 在Linux操作系统中,相机驱动是内核中一个非常重要的部分,它可以控制系统中所有的相机设备。相机驱动的作用是将设备和操作系统进行连接,使得用户可以使用相机功能。 首先需要了解的是Linux内核下的相机驱动类型。目前常用的相机驱动有两种,一种是V4L2驱动,另一种是USB相机驱动。V4L2是一个通用的视频输入输出设备驱动,用于媒体框架,能够支持不同类型的视频捕捉设备。而USB相机驱动则是一种特定的相机设备驱动,只支持USB接口的相机设备。 其次需要了解的是相机驱动的工作原理。相机驱动通常是由内核模块或者用户空间程序来控制的。当用户需要使用相机时,应用程序将会通过系统调用请求操作系统,操作系统再通过设备节点与相机驱动进行交互,从而控制相机的工作。 最后需要注意的是相机驱动的配置。为了使相机驱动能够正确地运行,需要对其进行配置。配置的方法有两种,一种是在内核配置中进行设置,另一种是通过命令行或配置文件进行设置。在配置过程中需要考虑到硬件平台的适配性、相机驱动的版本等因素。 总之,在Linux下相机驱动的分析包括了驱动类型、工作原理和配置等多个方面,是建立在对Linux操作系统深入了解的基础上的重要工作。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值