Android 13 Camera预览流程详解

欢迎关注微信公众号 无限无羡

环境介绍

环境 说明
硬件设备 Google Pixel5
AOSP版本 android-13.0.0_r40
CameraProvider android.hardware.camera.provider@2.4-service_64
Camera HAL So库 Google提供的参考实现 camera.v4l2

以上环境看起来似乎有些奇怪,因为Android 13的时候其实已经不再用camera.provider@2.4了,我们之所以拿这个来分析,是因为目前很多公司使用的AOSP版本并不是最新的,这个2.4版本使用的是比较多的。当然,我们分析完2.4后,后面也会分析最新的基于AIDL实现的camera.provider进程。需要2跟大家说明的是,由于HAL层代码厂商是不开源的,我手上的Pixel5手机用的是高通芯片,其中的Camera HAL部分无法看到源码,所以使用了Google的参考实现camera.v4l2来分析流程。上面表格中的环境配置并没有真正在Pixel5上运行起来(尝试过使其正常运行,最后发现高通的Camera HAL预览时并没有用到/dev/video节点,而camera.v4l2是基于这个节点来实现的,所以无法调通),我们这篇文章按图索骥,根据代码流程来进行梳理。

流程分析

预览流程的核心API调用基本都在下面的这个函数之中,我们会对其中的关键流程做详细分析。

scss 复制代码
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对象,包含了显示控件TextureView中的SurfaceTexture对象,
            // 而SurfaceTexture又包含了预览的分辨率大小。
            Surface surface = new Surface(texture);

            // We set up a CaptureRequest.Builder with the output Surface.
            // 其实下面的过程主要分为两步,一是创建CameraCaptureSession对象;
            // 二是创建CaptureRequest对象,不过创建之前要先设置一些参数
            mPreviewRequestBuilder
                    = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            mPreviewRequestBuilder.addTarget(surface);

            // Here, we create a CameraCaptureSession for camera preview.
            mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                    new CameraCaptureSession.StateCallback() {

                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                            // The camera is already closed
                            if (null == mCameraDevice) {
                                return;
                            }

                            // When the session is ready, we start displaying the preview.
                            mCaptureSession = cameraCaptureSession;
                            try {
                                // Auto focus should be continuous for camera preview.
                                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                        CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                                // Flash is automatically enabled when necessary.
                                setAutoFlash(mPreviewRequestBuilder);

                                // Finally, we start displaying the camera preview.
                                mPreviewRequest = mPreviewRequestBuilder.build();
                                // 这里使用创建好的CameraCaptureSession对象和CaptureRequest对象
                                // 开始预览操作的调用
                                mCaptureSession.setRepeatingRequest(mPreviewRequest,
                                        mCaptureCallback, mBackgroundHandler);
                            } catch (CameraAccessException e) {
                                e.printStackTrace();
                            }
                        }

                        @Override
                        public void onConfigureFailed(
                                @NonNull CameraCaptureSession cameraCaptureSession) {
                            showToast("Failed");
                        }
                    }, null
            );
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

创建CameraCaptureSession对象

我们主要看下createCaptureSession的实现,如果执行成功,则会在回调函数中获取到CameraCaptureSession对象。

scss 复制代码
// frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@Override
// outputs: 这里我们传入了两个surface对象,分别是预览和拍照的
// callback: 执行结果的回调,成功后会在onConfigured中传回CameraCaptureSession对象
// handler: 该函数执行在哪个是线程上
public void createCaptureSession(List<Surface> outputs,
        CameraCaptureSession.StateCallback callback, Handler handler)
        throws CameraAccessException {
    // 以surface对象为参数创建OutputConfiguration对象,并构建成列表
    List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
    for (Surface surface : outputs) {
        outConfigurations.add(new OutputConfiguration(surface));
    }
    // 继续调用这个封装函数
    createCaptureSessionInternal(null, outConfigurations, callback,
            checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
            /*sessionParams*/ null);
}


// inputConfig: null
// outputConfigurations: 对surface的封装
// callback: 同上
// executor: 对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 {
    // 记录开始时间
    long createSessionStartTime = SystemClock.uptimeMillis();
    synchronized(mInterfaceLock) {
        if (DEBUG) {
            Log.d(TAG, "createCaptureSessionInternal");
        }

        checkIfCameraClosedOrInError();

        // isConstrainedHighSpeed为false,当调用createConstrainedHighSpeedCaptureSession这个函数时
        // 这里为true,这个后面会单开章节来讲
        boolean isConstrainedHighSpeed =
                (operatingMode == ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE);
        // isConstrainedHighSpeed为true时,inputConfig必须为空,inputConfig干嘛的,后面会讲
        if (isConstrainedHighSpeed && inputConfig != null) {
            throw new IllegalArgumentException("Constrained high speed session doesn't support"
                    + " input configuration yet.");
        }

        // 先释放一些旧的资源
        // Notify current session that it's going away, before starting camera operations
        // After this call completes, the session is not allowed to call into CameraDeviceImpl
        if (mCurrentSession != null) {
            mCurrentSession.replaceSessionClose();
        }

        if (mCurrentExtensionSession != null) {
            mCurrentExtensionSession.release(false /*skipCloseNotification*/);
            mCurrentExtensionSession = null;
        }

        if (mCurrentAdvancedExtensionSession != null) {
            mCurrentAdvancedExtensionSession.release(false /*skipCloseNotification*/);
            mCurrentAdvancedExtensionSession = null;
        }

        // TODO: dont block for this
        boolean configureSuccess = true;
        CameraAccessException pendingException = null;
        Surface input = null;
        try {
            // configure streams and then block until IDLE
            // 重点函数来了,在这里
            configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations,
                    operatingMode, sessionParams, createSessionStartTime);
            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.
        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
            newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
                    callback, executor, this, mDeviceExecutor, configureSuccess);
        }

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

        if (pendingException != null) {
            throw pendingException;
        }

        mSessionStateCallback = mCurrentSession.getDeviceStateCallback();
    }
}


// 接下来该讲解configureStreamsChecked的实现了
// inputConfig: null
// outputs: surface的封装
// operatingMode: ICameraDeviceUser.NORMAL_MODE
// sessionParams: null
// createSessionStartTime: 开始时间
public boolean configureStreamsChecked(InputConfiguration inputConfig,
        List<OutputConfiguration> outputs, int operatingMode, CaptureRequest sessionParams,
        long createSessionStartTime)
                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");
    }

    // inputConfig为空,这个略过,后面我们单独开章节讲解inputConfig不为空的场景
    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
        // mConfiguredOutputs: 现在已经有的配置
        for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
            int streamId = mConfiguredOutputs.keyAt(i);
            OutputConfiguration outConfig = mConfiguredOutputs.valueAt(i);
            // 如果mConfiguredOutputs中的元素在传进来的列表outputs中不存在,或者
            // mConfiguredOutputs中的元素isDeferredConfiguration为true,
            // 则将mConfiguredOutputs中的元素放到deleteList
            // 比如传进来的是1、2, 原有的是2、3,则把3放到deleteList
            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 {
                // 否则说明mConfiguredOutputs中的元素在传进来的outputs中存在,存在则将其删除。
                // 这样就可以避免重复创建stream,后面会有调用createStream的地方。
                // 比如传进来的是1、2, 原有的是2,则把传进来的2删除,后面只需要创建1的stream就行了。
                addSet.remove(outConfig);  // Don't create a stream previously created
            }
        }
        // 这里执行的是mSessionStateCallback的onBusy方法,
        // 不过现在mSessionStateCallback还是空,要等
        // createCaptureSession函数执行完毕之后才会赋值,
        // 也就是那时这里的mCalOnBusy才会执行,
        // 因为此时会等待handler队列的mCallOnOpened执行完毕。
        // createCaptureSession是在onOpened回调里调用的。
        mDeviceExecutor.execute(mCallOnBusy);
        // 如果现在已经有请求,则停止
        stopRepeating();

        try {
            // 里面调用了mRemoteDevice.waitUntilIdle();
            // 这里的mRemoteDevice其实就是CameraDeviceClient
            // 到这里就非常有必要梳理一下mRemoteDevice在各个进程和各个模块中的对应关系,
            // 当我们后面看到mRemoteDevice的调用时就可以直接找到底层的函数调用
            // mRemoteDevice-->CameraDeviceClient-->HidlCamera3Device or AidlCamera3Device
            // --> Camera3Device
            // 基本上安装上面的找到同名函数就行了,当然也有不同名的,按照上面的顺序去找函数的实现就可以。
            waitUntilIdle();

            // 这里我们发现走到CameraDeviceClient时只打印了一行日志就返回了
            /*
            binder::Status CameraDeviceClient::beginConfigure() {
                // TODO: Implement this.
                ATRACE_CALL();
                ALOGV("%s: Not implemented yet.", __FUNCTION__);
                return binder::Status::ok();
            }
            */
            mRemoteDevice.beginConfigure();

            // input为null, 这里我们先不管
            // 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(),
                            inputConfig.isMultiResolution());
                    mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(
                            streamId, inputConfig);
                }
            }

            // 处理deleteList, 也就是旧的output,并且没有包含在新传进来的列表中。
            // 我们先看了下面的createStream流程再分析deleteStream流程
            // Delete all streams first (to free up HW resources)
            for (Integer streamId : deleteList) {
                // 我们这里做个标记,后面根据序号来顺序分析
                // 2. mRemoteDevice.deleteStream
                mRemoteDevice.deleteStream(streamId);
                mConfiguredOutputs.delete(streamId);
            }

            // Add all new streams
            // 现在,addSet中的就是需要createStream的了
            for (OutputConfiguration outConfig : outputs) {
                if (addSet.contains(outConfig)) {
                    // 1. mRemoteDevice.createStream
                    int streamId = mRemoteDevice.createStream(outConfig);
                    mConfiguredOutputs.put(streamId, outConfig);
                }
            }

            int offlineStreamIds[];
            // sessionParams = null
            if (sessionParams != null) {
                offlineStreamIds = mRemoteDevice.endConfigure(operatingMode,
                        sessionParams.getNativeCopy(), createSessionStartTime);
            } else {
                // 3. mRemoteDevice.endConfigure
                offlineStreamIds = mRemoteDevice.endConfigure(operatingMode, null,
                        createSessionStartTime);
            }

            mOfflineSupport.clear();
            if ((offlineStreamIds != null) && (offlineStreamIds.length > 0)) {
                for (int offlineStreamId : offlineStreamIds) {
                    mOfflineSupport.add(offlineStreamId);
                }
            }

            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) {
                // 4. mCallOnIdle
                mDeviceExecutor.execute(mCallOnIdle);
            } else {
                // 5. mCallOnUnconfigured
                // Always return to the 'unconfigured' state if we didn't hit a fatal error
                mDeviceExecutor.execute(mCallOnUnconfigured);
            }
        }
    }

    return success;
}

我们根据上面的序号来进行分步分析

1. mRemoteDevice.createStream

ini 复制代码
// mRemoteDevice对应cameraserver中的CameraDeviceClient
// frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
binder::Status CameraDeviceClient::createStream(
        const hardware::camera2::params::OutputConfiguration &outputConfiguration,
        /*out*/
        int32_t* newStreamId) {
    ATRACE_CALL();

    binder::Status res;
    if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;

    Mutex::Autolock icl(mBinderSerializationLock);

    // OutputConfiguration对象中有个mIsShared属性,默认为false,这样的话每个
    // OutputConfiguration对象就只包含一个Surface,bufferProducers的size为1
    // 这里要注意的是每个stream的最大Surface数量为4,也就是bufferProducers.size
    // 最大为4
    // constexpr int32_t MAX_SURFACES_PER_STREAM = 4;
    const std::vector<sp<IGraphicBufferProducer>>& bufferProducers =
            outputConfiguration.getGraphicBufferProducers();
    // numBufferProducers = 1,最大为4
    size_t numBufferProducers = bufferProducers.size();
    // 默认为false
    bool deferredConsumer = outputConfiguration.isDeferred();
    // 默认为false
    bool isShared = outputConfiguration.isShared();
    // 默认为null
    String8 physicalCameraId = String8(outputConfiguration.getPhysicalCameraId());
    // false
    bool deferredConsumerOnly = deferredConsumer && numBufferProducers == 0;
    // false
    bool isMultiResolution = outputConfiguration.isMultiResolution();
    // DynamicRangeProfiles.STANDARD
    int64_t dynamicRangeProfile = outputConfiguration.getDynamicRangeProfile();
    // CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT
    int64_t streamUseCase = outputConfiguration.getStreamUseCase();
    // TIMESTAMP_BASE_DEFAULT 0
    int timestampBase = outputConfiguration.getTimestampBase();
    // MIRROR_MODE_AUTO 0
    int mirrorMode = outputConfiguration.getMirrorMode();

    // 此处省略一些简单代码
    ...

    std::vector<sp<Surface>> surfaces;
    std::vector<sp<IBinder>> binders;
    status_t err;

    // Create stream for deferred surface case.
    if (deferredConsumerOnly) {
        return createDeferredSurfaceStreamLocked(outputConfiguration, isShared, newStreamId);
    }

    OutputStreamInfo streamInfo;
    bool isStreamInfoValid = false;
    const std::vector<int32_t> &sensorPixelModesUsed =
            outputConfiguration.getSensorPixelModesUsed();
    for (auto& bufferProducer : bufferProducers) {
        // Don't create multiple streams for the same target surface
        sp<IBinder> binder = IInterface::asBinder(bufferProducer);
        ssize_t index = mStreamMap.indexOfKey(binder);
        if (index != NAME_NOT_FOUND) {
            String8 msg = String8::format("Camera %s: Surface already has a stream created for it "
                    "(ID %zd)", mCameraIdStr.string(), index);
            ALOGW("%s: %s", __FUNCTION__, msg.string());
            return STATUS_ERROR(CameraService::ERROR_ALREADY_EXISTS, msg.string());
        }

        // 这里用上面的一堆参数创建了一个Surface对象
        sp<Surface> surface;
        res = SessionConfigurationUtils::createSurfaceFromGbp(streamInfo,
                isStreamInfoValid, surface, bufferProducer, mCameraIdStr,
                mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile,
                streamUseCase, timestampBase, mirrorMode);

        if (!res.isOk())
            return res;

        if (!isStreamInfoValid) {
            isStreamInfoValid = true;
        }

        // 放入列表中,一般情况下列表长度为1
        binders.push_back(IInterface::asBinder(bufferProducer));
        surfaces.push_back(surface);
    }

    // If mOverrideForPerfClass is true, do not fail createStream() for small
    // JPEG sizes because existing createSurfaceFromGbp() logic will find the
    // closest possible supported size.

    int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
    std::vector<int> surfaceIds;
    bool isDepthCompositeStream =
            camera3::DepthCompositeStream::isDepthCompositeStream(surfaces[0]);
    bool isHeicCompisiteStream = camera3::HeicCompositeStream::isHeicCompositeStream(surfaces[0]);
    // false
    if (isDepthCompositeStream || isHeicCompisiteStream) {
        sp<CompositeStream> compositeStream;
        if (isDepthCompositeStream) {
            compositeStream = new camera3::DepthCompositeStream(mDevice, getRemoteCallback());
        } else {
            compositeStream = new camera3::HeicCompositeStream(mDevice, getRemoteCallback());
        }

        err = compositeStream->createStream(surfaces, deferredConsumer, streamInfo.width,
                streamInfo.height, streamInfo.format,
                static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
                &streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,
                outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution);
        if (err == OK) {
            Mutex::Autolock l(mCompositeLock);
            mCompositeStreamMap.add(IInterface::asBinder(surfaces[0]->getIGraphicBufferProducer()),
                    compositeStream);
        }
    } else {
        // 再调用mDevice->createStream函数,看了下有19个参数,Google就不能优化一下吗,跟代码跟丢了怎么办
        // 这里mDevice是HidlCamera3Device或者AidlCamera3Device, 二者都继承了Camera3Device,
        // 最终会调用到Camera3Device.cpp里的createStream方法,这个我们下面详细再跟踪
        err = mDevice->createStream(surfaces, deferredConsumer, streamInfo.width,
                streamInfo.height, streamInfo.format, streamInfo.dataSpace,
                static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
                &streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,
                outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution,
                /*consumerUsage*/0, streamInfo.dynamicRangeProfile, streamInfo.streamUseCase,
                streamInfo.timestampBase, streamInfo.mirrorMode);
    }

    if (err != OK) {
        res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
                "Camera %s: Error creating output stream (%d x %d, fmt %x, dataSpace %x): %s (%d)",
                mCameraIdStr.string(), streamInfo.width, streamInfo.height, streamInfo.format,
                streamInfo.dataSpace, strerror(-err), err);
    } else {
        int i = 0;
        for (auto& binder : binders) {
            ALOGV("%s: mStreamMap add binder %p streamId %d, surfaceId %d",
                    __FUNCTION__, binder.get(), streamId, i);
            // 创建成功,加入map
            mStreamMap.add(binder, StreamSurfaceId(streamId, surfaceIds[i]));
            i++;
        }

        // 更新列表
        mConfiguredOutputs.add(streamId, outputConfiguration);
        mStreamInfoMap[streamId] = streamInfo;

        ALOGV("%s: Camera %s: Successfully created a new stream ID %d for output surface"
                    " (%d x %d) with format 0x%x.",
                  __FUNCTION__, mCameraIdStr.string(), streamId, streamInfo.width,
                  streamInfo.height, streamInfo.format);
        // 省略部分代码
        .....

        // 返回streamId
        *newStreamId = streamId;
    }

    return res;
}

接下来我们具体看下Camera3Device.cpp里的createStream方法的具体实现

arduino 复制代码
status_t Camera3Device::createStream(const std::vector<sp<Surface>>& consumers,
        bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
        android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
        const String8& physicalCameraId, const std::unordered_set<int32_t> &sensorPixelModesUsed,
        std::vector<int> *surfaceIds, int streamSetId, bool isShared, bool isMultiResolution,
        uint64_t consumerUsage, int64_t dynamicRangeProfile, int64_t streamUseCase,
        int timestampBase, int mirrorMode) {
    ATRACE_CALL();

    // 此处省略部分代码
    ......
    // 下面根据不同的format来进行OutputStream的创建
    // 拍照时imagereader如果是yuv_420_888,则进入下面的if语句
    if (format == HAL_PIXEL_FORMAT_BLOB) {
        ssize_t blobBufferSize;
        if (dataSpace == HAL_DATASPACE_DEPTH) {
            blobBufferSize = getPointCloudBufferSize(infoPhysical(physicalCameraId));
            if (blobBufferSize <= 0) {
                SET_ERR_L("Invalid point cloud buffer size %zd", blobBufferSize);
                return BAD_VALUE;
            }
        } else if (dataSpace == static_cast<android_dataspace>(HAL_DATASPACE_JPEG_APP_SEGMENTS)) {
            blobBufferSize = width * height;
        } else {
            blobBufferSize = getJpegBufferSize(infoPhysical(physicalCameraId), width, height);
            if (blobBufferSize <= 0) {
                SET_ERR_L("Invalid jpeg buffer size %zd", blobBufferSize);
                return BAD_VALUE;
            }
        }
        ALOGV("new Camera3OutputStream......");
        newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
                width, height, blobBufferSize, format, dataSpace, rotation,
                mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
                isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
                timestampBase, mirrorMode);
    } else if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
        bool maxResolution =
                sensorPixelModesUsed.find(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) !=
                        sensorPixelModesUsed.end();
        ssize_t rawOpaqueBufferSize = getRawOpaqueBufferSize(infoPhysical(physicalCameraId), width,
                height, maxResolution);
        if (rawOpaqueBufferSize <= 0) {
            SET_ERR_L("Invalid RAW opaque buffer size %zd", rawOpaqueBufferSize);
            return BAD_VALUE;
        }
        newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
                width, height, rawOpaqueBufferSize, format, dataSpace, rotation,
                mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
                isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
                timestampBase, mirrorMode);
    } else if (isShared) {
        newStream = new Camera3SharedOutputStream(mNextStreamId, consumers,
                width, height, format, consumerUsage, dataSpace, rotation,
                mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
                mUseHalBufManager, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
                timestampBase, mirrorMode);
    } else if (consumers.size() == 0 && hasDeferredConsumer) {
        newStream = new Camera3OutputStream(mNextStreamId,
                width, height, format, consumerUsage, dataSpace, rotation,
                mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
                isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
                timestampBase, mirrorMode);
    } else {
        // 预览和imagereader设置为JPEG时走这里
        ALOGV("Camera3OutputStream...........");
        newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
                width, height, format, dataSpace, rotation,
                mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
                isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
                timestampBase, mirrorMode);
    }

    // 由上不难看出,除了isShared为true的情况,都是创建的Camera3OutputStream对象。
    // 而Camera3SharedOutputStream也是继承自Camera3OutputStream,
    // Camera3OutputStream的构造函数就不带大家看了,比较简单

    size_t consumerCount = consumers.size();
    for (size_t i = 0; i < consumerCount; i++) {
        int id = newStream->getSurfaceId(consumers[i]);
        if (id < 0) {
            SET_ERR_L("Invalid surface id");
            return BAD_VALUE;
        }
        if (surfaceIds != nullptr) {
            surfaceIds->push_back(id);
        }
    }

    newStream->setStatusTracker(mStatusTracker);

    newStream->setBufferManager(mBufferManager);

    newStream->setImageDumpMask(mImageDumpMask);

    res = mOutputStreams.add(mNextStreamId, newStream);
    if (res < 0) {
        SET_ERR_L("Can't add new stream to set: %s (%d)", strerror(-res), res);
        return res;
    }

    mSessionStatsBuilder.addStream(mNextStreamId);

    *id = mNextStreamId++;
    mNeedConfig = true;

    // 省略部分代码
    ......
    ALOGV("Camera %s: Created new stream", mId.string());
    return OK;
}

综上,createStream最终并没有走到Camera HAL里面去,只是创建了一些中间的变量到内存中供后续操作使用。

2. mRemoteDevice.deleteStream

deleteStream跟createStream是相反的操作,删除一些数据结构中的数据而已,这部分大家自己看即可。

3. mRemoteDevice.endConfigure

php 复制代码
// endConfigure是createCaptureSession流程中的重点
binder::Status CameraDeviceClient::endConfigure(int operatingMode,
        const hardware::camera2::impl::CameraMetadataNative& sessionParams, int64_t startTimeMs,
        std::vector<int>* offlineStreamIds /*out*/) {
    ATRACE_CALL();
    ALOGV("%s: ending configure (%d input stream, %zu output surfaces)",
            __FUNCTION__, mInputStream.configured ? 1 : 0,
            mStreamMap.size());

    // 省略部分代码
    ......
    // 不错,这一句是重点,其他代码我们都省略了
    status_t err = mDevice->configureStreams(sessionParams, operatingMode);
   // 省略部分代码
   ......

    return res;
}
scss 复制代码
status_t Camera3Device::configureStreams(const CameraMetadata& sessionParams, int operatingMode) {
    ATRACE_CALL();
    ALOGV("%s: E", __FUNCTION__);

    Mutex::Autolock il(mInterfaceLock);
    Mutex::Autolock l(mLock);

    // In case the client doesn't include any session parameter, try a
    // speculative configuration using the values from the last cached
    // default request.
    if (sessionParams.isEmpty() &&
            ((mLastTemplateId > 0) && (mLastTemplateId < CAMERA_TEMPLATE_COUNT)) &&
            (!mRequestTemplateCache[mLastTemplateId].isEmpty())) {
        ALOGV("%s: Speculative session param configuration with template id: %d", __func__,
                mLastTemplateId);
        return filterParamsAndConfigureLocked(mRequestTemplateCache[mLastTemplateId],
                operatingMode);
    }

    return filterParamsAndConfigureLocked(sessionParams, operatingMode);
}

status_t Camera3Device::filterParamsAndConfigureLocked(const CameraMetadata& sessionParams,
        int operatingMode) {
    //Filter out any incoming session parameters
    const CameraMetadata params(sessionParams);
    camera_metadata_entry_t availableSessionKeys = mDeviceInfo.find(
            ANDROID_REQUEST_AVAILABLE_SESSION_KEYS);
    CameraMetadata filteredParams(availableSessionKeys.count);
    camera_metadata_t *meta = const_cast<camera_metadata_t *>(
            filteredParams.getAndLock());
    set_camera_metadata_vendor_id(meta, mVendorTagId);
    filteredParams.unlock(meta);
    if (availableSessionKeys.count > 0) {
        for (size_t i = 0; i < availableSessionKeys.count; i++) {
            camera_metadata_ro_entry entry = params.find(
                    availableSessionKeys.data.i32[i]);
            if (entry.count > 0) {
                filteredParams.update(entry);
            }
        }
    }

    return configureStreamsLocked(operatingMode, filteredParams);
}

// 最后调用到configureStreamsLocked
status_t Camera3Device::configureStreamsLocked(int operatingMode,
        const CameraMetadata& sessionParams, bool notifyRequestThread) {
    // 省略部分代码
    ......
    mGroupIdPhysicalCameraMap.clear();
    bool composerSurfacePresent = false;
    for (size_t i = 0; i < mOutputStreams.size(); i++) {

        // Don't configure bidi streams twice, nor add them twice to the list
        if (mOutputStreams[i].get() ==
            static_cast<Camera3StreamInterface*>(mInputStream.get())) {

            config.num_streams--;
            continue;
        }

        camera3::camera_stream_t *outputStream;
        // 这个outputStream就是之前createStream的
        outputStream = mOutputStreams[i]->startConfiguration();
        if (outputStream == NULL) {
            CLOGE("Can't start output stream configuration");
            cancelStreamsConfigurationLocked();
            return INVALID_OPERATION;
        }
        streams.add(outputStream);
        // 省略部分代码
        ......
    }

    config.streams = streams.editArray();

    // Do the HAL configuration; will potentially touch stream
    // max_buffers, usage, and priv fields, as well as data_space and format
    // fields for IMPLEMENTATION_DEFINED formats.

    const camera_metadata_t *sessionBuffer = sessionParams.getAndLock();
    // 这里继续调用mInterface->configureStreams,而mInterface又是谁呢?
    // 这里的mInterface是AidlHalInterface或者HidlHalInterface,本篇文章
    // 我们以HidlInterface为例进行讲解。HidlHalInterface的configureStreams实现里
    // 主要根据HidlSession的版本来调用对应的configureStreams,最终又调用到了
    // CameraDeviceSession::configureStreams_3_4_Impl
    res = mInterface->configureStreams(sessionBuffer, &config, bufferSizes);

    // 省略部分代码
    ......
    return OK;
}

接下来看下CameraDeviceSession::configureStreams_3_4_Impl实现,不重要的代码我们会忽略,后面有时间再讲解每一步的细节。

scss 复制代码
// hardware/interfaces/camera/device/3.4/default/CameraDeviceSession.cpp
void CameraDeviceSession::configureStreams_3_4_Impl(
        const StreamConfiguration& requestedConfiguration,
        ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb,
        uint32_t streamConfigCounter, bool useOverriddenFields)  {

    // 省略部分代码
    ......
    ATRACE_BEGIN("camera3->configure_streams");
    // 这里的mDevice是camera_device_t* 类型,我们其实直接去HAL的so库里找实现就可以了。
    status_t ret = mDevice->ops->configure_streams(mDevice, &stream_list);    
    // 省略部分代码
    ......

    _hidl_cb(status, outStreams);
    return;
}

// 我们参考Google的实现
// hardware/libhardware/modules/camera/3_4/camera.cpp
static int configure_streams(const camera3_device_t *dev,
        camera3_stream_configuration_t *stream_list)
{
    return camdev_to_camera(dev)->configureStreams(stream_list);
}

int Camera::configureStreams(camera3_stream_configuration_t *stream_config)
{
    ......
    // Verify the set of streams in aggregate, and perform configuration if valid.
    int res = validateStreamConfiguration(stream_config);
    if (res) {
        ALOGE("%s:%d: Failed to validate stream set", __func__, mId);
    } else {
        // Set up all streams. Since they've been validated,
        // this should only result in fatal (-ENODEV) errors.
        // This occurs after validation to ensure that if there
        // is a non-fatal error, the stream configuration doesn't change states.
        // 重点在这里
        res = setupStreams(stream_config);
        if (res) {
            ALOGE("%s:%d: Failed to setup stream set", __func__, mId);
        }
    }
    ......
    return res;
}

// hardware/libhardware/modules/camera/3_4/v4l2_camera.cpp
int V4L2Camera::setupStreams(camera3_stream_configuration_t* stream_config) {
  HAL_LOG_ENTER();

  ......
  // 这里调用v4l2的streamoff
  // Ensure the stream is off.
  int res = device_->StreamOff();
  if (res) {
    HAL_LOGE("Device failed to turn off stream for reconfiguration: %d.", res);
    return -ENODEV;
  }

  StreamFormat stream_format(format, width, height);
  uint32_t max_buffers = 0;
  // 这里面调用了v4l2的IoctlLocked(VIDIOC_S_FMT, &new_format)和
  // IoctlLocked(VIDIOC_REQBUFS, &req_buffers)
  res = device_->SetFormat(stream_format, &max_buffers);
  if (res) {
    HAL_LOGE("Failed to set device to correct format for stream: %d.", res);
    return -ENODEV;
  }
  ......
  return 0;
}

由上可以看出,createStreams最终是通过HAL设置了参数并且申请对应的buffer。

创建CaptureRequest对象

1. createCaptureRequest

我们开始分析CaptureRequest对象的创建,也是缘起于CameraDeviceImpl对象。

scss 复制代码
// frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
// 这个函数返回的是一个CaptureRequest.Builder对象。
// 参数templateType表示的是预览、拍照、或者录像等等。
@Override
public CaptureRequest.Builder createCaptureRequest(int templateType)
        throws CameraAccessException {
    synchronized(mInterfaceLock) {
        checkIfCameraClosedOrInError();

        // 创建camerametadata对象,通过binder调用返回,可见最后是通过
        // HAL进程创建返回的,事实也确实如此。
        CameraMetadataNative templatedRequest = null;

        // 这个调用经过CameraDeviceClient、HidlCamera3Device::HidlHalInterface、
        // CameraDeviceSession、camera_device_t最终又调用到了
        // hardware/libhardware/modules/camera/3_4/camera.cpp中的
        // construct_default_request_settings函数
        templatedRequest = mRemoteDevice.createDefaultRequest(templateType);

        // If app target SDK is older than O, or it's not a still capture template, enableZsl
        // must be false in the default request.
        if (mAppTargetSdkVersion < Build.VERSION_CODES.O ||
                templateType != TEMPLATE_STILL_CAPTURE) {
            overrideEnableZsl(templatedRequest, false);
        }

        // 以binder调用返回的CameraMetadataNative对象为参数构造CaptureRequest.Builder
        // 并返回。这个Builder的构造函数中会创建CaptureRequest对象mRequest
        CaptureRequest.Builder builder = new CaptureRequest.Builder(
                templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE,
                getId(), /*physicalCameraIdSet*/ null);

        return builder;
    }
}

// hardware/libhardware/modules/camera/3_4/camera.cpp
static const camera_metadata_t *construct_default_request_settings(
        const camera3_device_t *dev, int type)
{
    return camdev_to_camera(dev)->constructDefaultRequestSettings(type);
}

const camera_metadata_t* Camera::constructDefaultRequestSettings(int type)
{
    ALOGV("%s:%d: type=%d", __func__, mId, type);

    if (!isValidTemplateType(type)) {
        ALOGE("%s:%d: Invalid template request type: %d", __func__, mId, type);
        return NULL;
    }

    if (!mTemplates[type]) {
        // Check if the device has the necessary features
        // for the requested template. If not, don't bother.
        if (!mStaticInfo->TemplateSupported(type)) {
            ALOGW("%s:%d: Camera does not support template type %d",
                  __func__, mId, type);
            return NULL;
        }

        // Initialize this template if it hasn't been initialized yet.
        // 重点在这里,创建了CameraMetadata对象,并且将type传入了进去
        std::unique_ptr<android::CameraMetadata> new_template =
            std::make_unique<android::CameraMetadata>();
        int res = initTemplate(type, new_template.get());
        if (res || !new_template) {
            ALOGE("%s:%d: Failed to generate template of type: %d",
                  __func__, mId, type);
            return NULL;
        }
        mTemplates[type] = std::move(new_template);
    }

    // The "locking" here only causes non-const methods to fail,
    // which is not a problem since the CameraMetadata being locked
    // is already const. Destructing automatically "unlocks".
    return mTemplates[type]->getAndLock();
}

2. CaptureRequest.Builder.addTarget

less 复制代码
// frameworks/base/core/java/android/hardware/camera2/CaptureRequest.java
// 将Surface保存到了mSurfaceSet中,这个后面肯定会用到。
public void addTarget(@NonNull Surface outputTarget) {
    mRequest.mSurfaceSet.add(outputTarget);
}

3. CaptureRequest.Builder.build

typescript 复制代码
// 以之前创建的CaptureRequest对象为参数重新构建一个新的对象
@NonNull
public CaptureRequest build() {
    return new CaptureRequest(mRequest);
}

setRepeatingRequest流程分析

执行这一步的话就开始预览出图了或者拍照出图了,调用者是之前创建的CameraCaptureSessionImpl对象。

scss 复制代码
// frameworks/base/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@Override
public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
        Handler handler) throws CameraAccessException {
    checkRepeatingRequest(request);

    synchronized (mDeviceImpl.mInterfaceLock) {
        checkNotClosed();

        handler = checkHandler(handler, callback);

        if (DEBUG) {
            Log.v(TAG, mIdString + "setRepeatingRequest - request " + request + ", callback " +
                    callback + " handler" + " " + handler);
        }
        // mDeviceImpl是CameraDeviceImpl
        return addPendingSequence(mDeviceImpl.setRepeatingRequest(request,
                createCaptureCallbackProxy(handler, callback), mDeviceExecutor));
    }
}

// frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
        Executor executor) throws CameraAccessException {
    // 将request放入列表中
    List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
    requestList.add(request);
    return submitCaptureRequest(requestList, callback, executor, /*streaming*/true);
}

// 这里的repeating为true表示预览,为false表示拍照
private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
        Executor executor, boolean repeating) throws CameraAccessException {

    // Need a valid executor, or current thread needs to have a looper, if
    // callback is valid
    executor = checkExecutor(executor, callback);

    synchronized(mInterfaceLock) {
        checkIfCameraClosedOrInError();

        // Make sure that there all requests have at least 1 surface; all surfaces are non-null;
        // 检查surface是否为空
        for (CaptureRequest request : requestList) {
            if (request.getTargets().isEmpty()) {
                throw new IllegalArgumentException(
                        "Each request must have at least one Surface target");
            }

            for (Surface surface : request.getTargets()) {
                if (surface == null) {
                    throw new IllegalArgumentException("Null Surface targets are not allowed");
                }
            }
        }
        // repeating为true,先stop
        if (repeating) {
            stopRepeating();
        }

        SubmitInfo requestInfo;

        CaptureRequest[] requestArray = requestList.toArray(new CaptureRequest[requestList.size()]);
        // Convert Surface to streamIdx and surfaceIdx
        for (CaptureRequest request : requestArray) {
            // surface转为对应的streamid
            request.convertSurfaceToStreamId(mConfiguredOutputs);
        }

        // 这里是重点,详细代码不贴了,整体调用流程如下
        // mRemoteDevice.submitRequestList->
        // mDevice->setStreamingRequestList->
        // HidlCamera3Device::HidlHalInterface::processBatchCaptureRequests->
        // CameraDeviceSession::processCaptureRequest_3_4->
        // mDevice->ops->process_capture_request->
        // Camera::processCaptureRequest->
        // V4L2Camera::enqueueRequest->
        // V4L2Wrapper::EnqueueRequest-> (IoctlLocked(VIDIOC_QBUF, &device_buffer))
        // V4L2Wrapper::DequeueRequest->(IoctlLocked(VIDIOC_DQBUF, &buffer))
        requestInfo = mRemoteDevice.submitRequestList(requestArray, repeating);
        if (DEBUG) {
            Log.v(TAG, "last frame number " + requestInfo.getLastFrameNumber());
        }

        ......

        return requestInfo.getRequestId();
    }
}

好的,到现在为止,预览的基本调用路程基本整理完毕了。我知道的是,这其中很多的细节还没有讲清楚。原因有很多,一是内容实在太多,想要在一篇文章中讲清楚所有那是不可能的。还因为我才疏学浅,并没有把整个流程都完全掌握。所以后面会退出很多的章节来继续细化预览的流程,到时候会尽量的把每一个重要的细节到讲到,并且将清楚。

本章完。

相关推荐
找藉口是失败者的习惯3 小时前
Jetpack Compose 如何布局解析
android·xml·ui
Estar.Lee8 小时前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
温辉_xh8 小时前
uiautomator案例
android
工业甲酰苯胺9 小时前
MySQL 主从复制之多线程复制
android·mysql·adb
少说多做34310 小时前
Android 不同情况下使用 runOnUiThread
android·java
Estar.Lee11 小时前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
找藉口是失败者的习惯12 小时前
从传统到未来:Android XML布局 与 Jetpack Compose的全面对比
android·xml
Jinkey13 小时前
FlutterBasic - GetBuilder、Obx、GetX<Controller>、GetxController 有啥区别
android·flutter·ios
大白要努力!14 小时前
Android opencv使用Core.hconcat 进行图像拼接
android·opencv
天空中的野鸟15 小时前
Android音频采集
android·音视频