基于Android Camera2_preview&capture_request流程分析

基于Android P版本分析

createCaptureRequest时序图:

一般情况下,openCamera()之后会执行回调方法Onopened(),在这个方法中,会执行createCaptureSession(),同时也会执行createCaptureRequest(),都是由CameraDeviceImpl实现的。

1 CameraDeviceImpl.createCaptureRequest()

java 复制代码
@Override
public CaptureRequest.Builder createCaptureRequest(int templateType)
        throws CameraAccessException {
    synchronized(mInterfaceLock) {
        checkIfCameraClosedOrInError();
​
        CameraMetadataNative templatedRequest = null;
​
        // 会根据传入的templateType创建对应的CameraMetadata数据,其中封装了对应Camera1中需要配置的setParameter参数
        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);
        }
​
        // 在创建Builder对象的时候,传入的参数为CameraMetadataNative对象
        CaptureRequest.Builder builder = new CaptureRequest.Builder(
                templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE,
                getId(), /*physicalCameraIdSet*/ null);
​
        return builder;
    }
}

根据templateType创建对应的新的Capture request,参数templateType代表了请求类型,例如templateType = CameraDevice.TEMPLATE_PREVIEW,返回类型为CaptureRequest.Builder,为建造者模型,所以需要通过build()方法创建真正的request;

参数templateType代表了请求类型,请求类型一共分为六种:

  • TEMPLATE_PREVIEW : 创建预览的请求
  • TEMPLATE_STILL_CAPTURE: 创建一个适合于静态图像捕获的请求,图像质量优先于帧速率
  • TEMPLATE_RECORD : 创建视频录制的请求
  • TEMPLATE_VIDEO_SNAPSHOT : 创建视视频录制时截屏的请求
  • TEMPLATE_ZERO_SHUTTER_LAG : 创建一个适用于零快门延迟的请求。在不影响预览帧率的情况下最大化图像质量
  • TEMPLATE_MANUAL : 创建一个基本捕获请求,这种请求中所有的自动控制都是禁用的(自动曝光,自动白平衡、自动焦点)

1.1 mRemoteDevice.createDefaultRequest(templateType)

因为mRemoteDevice的类型为ICameraDeviceUser,在Framework中体现为CameraDeviceClient,所以直接分析CameraDeviceClient::createDefaultRequest()方法:

php 复制代码
// Create a request object from a template.
binder::Status CameraDeviceClient::createDefaultRequest(int templateId,
        /*out*/
        hardware::camera2::impl::CameraMetadataNative* request)
{
    ATRACE_CALL();
    ALOGV("%s (templateId = 0x%x)", __FUNCTION__, templateId);
​
    binder::Status res;
    if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
​
    Mutex::Autolock icl(mBinderSerializationLock);
​
    if (!mDevice.get()) {
        return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
    }
​
    CameraMetadata metadata;
    status_t err;
    if ( (err = mDevice->createDefaultRequest(templateId, &metadata) ) == OK &&
        request != NULL) {
​
        // 保存CameraMetadata对象的camera_metadata_t变量
        request->swap(metadata);
    } else if (err == BAD_VALUE) {
        res = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
                "Camera %s: Template ID %d is invalid or not supported: %s (%d)",
                mCameraIdStr.string(), templateId, strerror(-err), err);
​
    } else {
        res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
                "Camera %s: Error creating default request for template %d: %s (%d)",
                mCameraIdStr.string(), templateId, strerror(-err), err);
    }
    return res;
}

调用了Camera3Device::createDefaultRequest()方法;

ini 复制代码
status_t Camera3Device::createDefaultRequest(int templateId,
        CameraMetadata *request) {
    ATRACE_CALL();
    ALOGV("%s: for template %d", __FUNCTION__, templateId);
​
    if (templateId <= 0 || templateId >= CAMERA3_TEMPLATE_COUNT) {
        android_errorWriteWithInfoLog(CameraService::SN_EVENT_LOG_ID, "26866110",
                IPCThreadState::self()->getCallingUid(), nullptr, 0);
        return BAD_VALUE;
    }
​
    Mutex::Autolock il(mInterfaceLock);
​
    {
        Mutex::Autolock l(mLock);
        switch (mStatus) {
            case STATUS_ERROR:
                CLOGE("Device has encountered a serious error");
                return INVALID_OPERATION;
            case STATUS_UNINITIALIZED:
                CLOGE("Device is not initialized!");
                return INVALID_OPERATION;
            case STATUS_UNCONFIGURED:
            case STATUS_CONFIGURED:
            case STATUS_ACTIVE:
                // OK
                break;
            default:
                SET_ERR_L("Unexpected status: %d", mStatus);
                return INVALID_OPERATION;
        }
​
        if (!mRequestTemplateCache[templateId].isEmpty()) {
            *request = mRequestTemplateCache[templateId];
            mLastTemplateId = templateId;
            return OK;
        }
    }
​
    camera_metadata_t *rawRequest;
    status_t res = mInterface->constructDefaultRequestSettings(
            (camera3_request_template_t) templateId, &rawRequest);
​
    {
        Mutex::Autolock l(mLock);
        if (res == BAD_VALUE) {
            ALOGI("%s: template %d is not supported on this camera device",
                  __FUNCTION__, templateId);
            return res;
        } else if (res != OK) {
            CLOGE("Unable to construct request template %d: %s (%d)",
                    templateId, strerror(-res), res);
            return res;
        }
​
        set_camera_metadata_vendor_id(rawRequest, mVendorTagId);
        // 在一块逻辑中,将创建好的rawRequest保存到mRequestTemplateCache中,即保存到request(mRequestTemplateCache类型)中,这样就创建好了对应的
        mRequestTemplateCache[templateId].acquire(rawRequest);
​
        *request = mRequestTemplateCache[templateId];
        mLastTemplateId = templateId;
    }
    return OK;
}

创建CameraMetadataNative对象,内在是创建CameraMetadata对象(CameraMetadata.cpp),对CameraMetadataNative对象的操作本质上都是操作CameraMetadata对象,即camera_metadata_t * metadata;

至此我们就创建了CameraMetadata对象,其管理着一块buffer,buffer中保存的是某个场景预览、录像或拍照的默认metadata;

1.2 new CaptureRequest.Builder

java 复制代码
        CaptureRequest.Builder builder = new CaptureRequest.Builder(
                templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE,
                getId(), /*physicalCameraIdSet*/ null);
java 复制代码
public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
        implements Parcelable {
    
    private final ArraySet<Surface> mSurfaceSet = new ArraySet<Surface>();
    
    /**
     * Clone from source capture request.
     *
     * Used by the Builder to create an immutable copy.
     */
    @SuppressWarnings("unchecked")
    private CaptureRequest(CaptureRequest source) {
        mLogicalCameraId = new String(source.mLogicalCameraId);
        for (Map.Entry<String, CameraMetadataNative> entry :
                source.mPhysicalCameraSettings.entrySet()) {
            mPhysicalCameraSettings.put(new String(entry.getKey()),
                    new CameraMetadataNative(entry.getValue()));
        }
        mLogicalCameraSettings = mPhysicalCameraSettings.get(mLogicalCameraId);
        setNativeInstance(mLogicalCameraSettings);
        mSurfaceSet.addAll(source.mSurfaceSet);
        mIsReprocess = source.mIsReprocess;
        mIsPartOfCHSRequestList = source.mIsPartOfCHSRequestList;
        mReprocessableSessionId = source.mReprocessableSessionId;
        mUserTag = source.mUserTag;
    }
    
    /**
     * Take ownership of passed-in settings.
     *
     * Used by the Builder to create a mutable CaptureRequest.
     *
     * @param settings Settings for this capture request.
     * @param isReprocess Indicates whether to create a reprocess capture request. {@code true}
     *                    to create a reprocess capture request. {@code false} to create a regular
     *                    capture request.
     * @param reprocessableSessionId The ID of the camera capture session this capture is created
     *                               for. This is used to validate if the application submits a
     *                               reprocess capture request to the same session where
     *                               the {@link TotalCaptureResult}, used to create the reprocess
     *                               capture, came from.
     * @param logicalCameraId Camera Id of the actively open camera that instantiates the
     *                        Builder.
     *
     * @param physicalCameraIdSet A set of physical camera ids that can be used to customize
     *                            the request for a specific physical camera.
     *
     * @throws IllegalArgumentException If creating a reprocess capture request with an invalid
     *                                  reprocessableSessionId, or multiple physical cameras.
     *
     * @see CameraDevice#createReprocessCaptureRequest
     */
    private CaptureRequest(CameraMetadataNative settings, boolean isReprocess,
            int reprocessableSessionId, String logicalCameraId, Set<String> physicalCameraIdSet) {
​
        // isReprocess这个值在new CaptureRequest.Builder的时候传入的是false,所以该流程不执行
        if ((physicalCameraIdSet != null) && isReprocess) {
            throw new IllegalArgumentException("Create a reprocess capture request with " +
                    "with more than one physical camera is not supported!");
        }
​
        mLogicalCameraId = logicalCameraId;
        mLogicalCameraSettings = CameraMetadataNative.move(settings);
        mPhysicalCameraSettings.put(mLogicalCameraId, mLogicalCameraSettings);
​
        // physicalCameraIdSet CaptureRequest.Builder的时候传入的是null,所以该流程不执行
        if (physicalCameraIdSet != null) {
            for (String physicalId : physicalCameraIdSet) {
                mPhysicalCameraSettings.put(physicalId, new CameraMetadataNative(
                            mLogicalCameraSettings));
            }
        }
​
        setNativeInstance(mLogicalCameraSettings);
        mIsReprocess = isReprocess;
        if (isReprocess) {
            if (reprocessableSessionId == CameraCaptureSession.SESSION_ID_NONE) {
                throw new IllegalArgumentException("Create a reprocess capture request with an " +
                        "invalid session ID: " + reprocessableSessionId);
            }
            mReprocessableSessionId = reprocessableSessionId;
        } else {
            mReprocessableSessionId = CameraCaptureSession.SESSION_ID_NONE;
        }
    }
    
    /**
     * A builder for capture requests.
     *
     * <p>To obtain a builder instance, use the
     * {@link CameraDevice#createCaptureRequest} method, which initializes the
     * request fields to one of the templates defined in {@link CameraDevice}.
     *
     * @see CameraDevice#createCaptureRequest
     * @see CameraDevice#TEMPLATE_PREVIEW
     * @see CameraDevice#TEMPLATE_RECORD
     * @see CameraDevice#TEMPLATE_STILL_CAPTURE
     * @see CameraDevice#TEMPLATE_VIDEO_SNAPSHOT
     * @see CameraDevice#TEMPLATE_MANUAL
     */
    public final static class Builder {
​
        private final CaptureRequest mRequest;
​
        /**
         * Initialize the builder using the template; the request takes
         * ownership of the template.
         *
         * @param template Template settings for this capture request.
         * @param reprocess Indicates whether to create a reprocess capture request. {@code true}
         *                  to create a reprocess capture request. {@code false} to create a regular
         *                  capture request.
         * @param reprocessableSessionId The ID of the camera capture session this capture is
         *                               created for. This is used to validate if the application
         *                               submits a reprocess capture request to the same session
         *                               where the {@link TotalCaptureResult}, used to create the
         *                               reprocess capture, came from.
         * @param logicalCameraId Camera Id of the actively open camera that instantiates the
         *                        Builder.
         * @param physicalCameraIdSet A set of physical camera ids that can be used to customize
         *                            the request for a specific physical camera.
         *
         * @throws IllegalArgumentException If creating a reprocess capture request with an invalid
         *                                  reprocessableSessionId.
         * @hide
         */
        public Builder(CameraMetadataNative template, boolean reprocess,
                int reprocessableSessionId, String logicalCameraId,
                Set<String> physicalCameraIdSet) {
            mRequest = new CaptureRequest(template, reprocess, reprocessableSessionId,
                    logicalCameraId, physicalCameraIdSet);
        }
        
        ......
        
        /**
         * Build a request using the current target Surfaces and settings.
         * <p>Note that, although it is possible to create a {@code CaptureRequest} with no target
         * {@link Surface}s, passing such a request into {@link CameraCaptureSession#capture},
         * {@link CameraCaptureSession#captureBurst},
         * {@link CameraCaptureSession#setRepeatingBurst}, or
         * {@link CameraCaptureSession#setRepeatingRequest} will cause that method to throw an
         * {@link IllegalArgumentException}.</p>
         *
         * @return A new capture request instance, ready for submission to the
         * camera device.
         */
        @NonNull
        public CaptureRequest build() {
            return new CaptureRequest(mRequest);
        }
        
        /**
         * <p>Add a surface to the list of targets for this request</p>
         *
         * <p>The Surface added must be one of the surfaces included in the most
         * recent call to {@link CameraDevice#createCaptureSession}, when the
         * request is given to the camera device.</p>
         *
         * <p>Adding a target more than once has no effect.</p>
         *
         * @param outputTarget Surface to use as an output target for this request
         */
        public void addTarget(@NonNull Surface outputTarget) {
            mRequest.mSurfaceSet.add(outputTarget);
        }
        
        ......
    }
}

最后createCaptureRequest()方法返回的就是CaptureRequest.Builder对象;

然后执行build()方法就可以创建一个CaptureRequest类型实例;

2 addTarget()

build()执行完成之后,紧接着会调用CaptureRequest.Builder.addTarget()方法;

less 复制代码
public void addTarget(@NonNull Surface outputTarget) {
    mRequest.mSurfaceSet.add(outputTarget);
}

这个方法主要是用于确认哪些surface需要作为CaptureRequest.Builder的目标;

这个mSurfaceSet会在后续setRepeatingRequest()过程中与create session中绑定的SurfaceList进行一一对比;

3 setRepeatingRequest()

在createCaptureRequest()执行完成,同时createCaptureSession()也成功执行后,会执行onConfigured()回调方法,就可以在该回调方法中执行CameraCaptureSessionImpl.setRepeatingRequest()方法发送请求;

一般情况下,createCaptureRequest()传入的参数为Preview,如果想在openCamera之后就开启preview画面的话,就需要执行setRepeatingRequest()方法,否则RequestThread判断没有request,所以不会上报camera数据;

scss 复制代码
@Override
public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
                               Handler handler) throws CameraAccessException {
    // 这个主要是对request进行判空和重复请求异常处理
    checkRepeatingRequest(request);
​
    synchronized (mDeviceImpl.mInterfaceLock) {
        checkNotClosed();
​
        handler = checkHandler(handler, callback);
​
        if (DEBUG) {
            Log.v(TAG, mIdString + "setRepeatingRequest - request " + request + ", callback " +
                    callback + " handler" + " " + handler);
        }
​
        return addPendingSequence(mDeviceImpl.setRepeatingRequest(request,
                createCaptureCallbackProxy(handler, callback), mDeviceExecutor));
    }
}

第一个参数request,这个就是通过build()方法创建的request,标识当前capture请求的属性,是请求一个camera还是多个camera,是否复用之前的请求等;

第二个参数callback,这个是捕捉回调,这个可以为null;

java 复制代码
public interface CaptureCallback {
    public static final int NO_FRAMES_CAPTURED = -1;
    public void onCaptureStarted(CameraDevice camera,
                                 CaptureRequest request, long timestamp, long frameNumber);
    public void onCapturePartial(CameraDevice camera,
                                 CaptureRequest request, CaptureResult result);
    public void onCaptureProgressed(CameraDevice camera,
                                    CaptureRequest request, CaptureResult partialResult);
    public void onCaptureCompleted(CameraDevice camera,
                                   CaptureRequest request, TotalCaptureResult result);
    public void onCaptureFailed(CameraDevice camera,
                                CaptureRequest request, CaptureFailure failure);
    public void onCaptureSequenceCompleted(CameraDevice camera,
                                           int sequenceId, long frameNumber);
    public void onCaptureSequenceAborted(CameraDevice camera,
                                         int sequenceId);
    public void onCaptureBufferLost(CameraDevice camera,
                                    CaptureRequest request, Surface target, long frameNumber);
}

第三个参数handler,这个和openCamera的handler是一样的,都是用于指定哪个线程需要执行callback;

typescript 复制代码
private void checkRepeatingRequest(CaptureRequest request) {
    if (request == null) {
        throw new IllegalArgumentException("request must not be null");
    } else if (request.isReprocess()) {
        throw new IllegalArgumentException("repeating reprocess requests are not supported");
    }
}

最后返回addPendingSequence(),将本次调用时序加入到PendingSequence中;

arduino 复制代码
/**
 * Notify the session that a pending capture sequence has just been queued.
 *
 * <p>During a shutdown/close, the session waits until all pending sessions are finished
 * before taking any further steps to shut down itself.</p>
 *
 * @see #finishPendingSequence
 */
private int addPendingSequence(int sequenceId) {
    mSequenceDrainer.taskStarted(sequenceId);
    return sequenceId;
}

其中在调用该方法的时候,传入的参数为mDeviceImpl.setRepeatingRequest(request, createCaptureCallbackProxy(handler, callback), mDeviceExecutor);

csharp 复制代码
public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
                               Executor executor) throws CameraAccessException {
    List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
    requestList.add(request);
    return submitCaptureRequest(requestList, callback, executor, /*streaming*/true);
}

streaming = true是repeating的request,后面有用到;

将request加入到list中,然后submit request;

scss 复制代码
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);
​
    // Make sure that there all requests have at least 1 surface; all surfaces are non-null;
    // the surface isn't a physical stream surface for reprocessing request
    // 验证当前CaptureRequest列表中的request是否合理:核心就是验证与request绑定的Surface是否存在
    for (CaptureRequest request : requestList) {
        // request.getTargets():判断mSurfaceSet是否为空
        // public Collection<Surface> getTargets() {
        //     return Collections.unmodifiableCollection(mSurfaceSet);
        // }
        if (request.getTargets().isEmpty()) {
            throw new IllegalArgumentException(
                    "Each request must have at least one Surface target");
        }
​
        for (Surface surface : request.getTargets()) {
            // 确保所有的request至少含有一个Surface,所有Surface非空
            if (surface == null) {
                throw new IllegalArgumentException("Null Surface targets are not allowed");
            }
​
            for (int i = 0; i < mConfiguredOutputs.size(); i++) {
                OutputConfiguration configuration = mConfiguredOutputs.valueAt(i);
                // 判断surface对应的request是否是重复请求
                // public boolean isForPhysicalCamera() {
                //     return (mPhysicalCameraId != null);
                // }
                // 默认isForPhysicalCamera()返回结果为false,因为在封装surface成为configuration时,configuration对象的mPhysicalCameraId属性赋值为了null
                if (configuration.isForPhysicalCamera()
                        && configuration.getSurfaces().contains(surface)) {
                    // isReprocess 为 false,在定义Builder实例的时候传入的
                    if (request.isReprocess()) {
                        throw new IllegalArgumentException(
                                "Reprocess request on physical stream is not allowed");
                    }
                }
            }
        }
    }
​
    synchronized(mInterfaceLock) {
        checkIfCameraClosedOrInError();
        if (repeating) {
            stopRepeating();
        }
​
        // 一个实体类,用于定义成功提交捕获请求时返回的状态信息,里面包含两个属性:mRequestId和mLastFrameNumber
        SubmitInfo requestInfo;
​
        // 将requestList转换为CaptureRequest数组
        CaptureRequest[] requestArray = requestList.toArray(new CaptureRequest[requestList.size()]);
        // 转换surface到streamIdx和surfaceIdx
        // Convert Surface to streamIdx and surfaceIdx
        for (CaptureRequest request : requestArray) {
            // 根据streamId转换surface
            request.convertSurfaceToStreamId(mConfiguredOutputs);
        }
​
        // 向底层发送请求信息
        requestInfo = mRemoteDevice.submitRequestList(requestArray, repeating);
        if (DEBUG) {
            Log.v(TAG, "last frame number " + requestInfo.getLastFrameNumber());
        }
​
        for (CaptureRequest request : requestArray) {
            // 根据streamId恢复surface
            request.recoverStreamIdToSurface();
        }
​
        if (callback != null) {
            mCaptureCallbackMap.put(requestInfo.getRequestId(),
                    new CaptureCallbackHolder(
                            callback, requestList, executor, repeating, mNextSessionId - 1));
        } else {
            if (DEBUG) {
                Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null");
            }
        }
​
        if (repeating) {
            if (mRepeatingRequestId != REQUEST_ID_NONE) {
                checkEarlyTriggerSequenceComplete(mRepeatingRequestId,
                        requestInfo.getLastFrameNumber());
            }
            mRepeatingRequestId = requestInfo.getRequestId();
        } else {
            mRequestLastFrameNumbersList.add(
                    new RequestLastFrameNumbersHolder(requestList, requestInfo));
        }
​
        if (mIdle) {
            mDeviceExecutor.execute(mCallOnActive);
        }
        mIdle = false;
​
        return requestInfo.getRequestId();
    }
}

3.1 验证当前CaptureRequest列表中的request

scss 复制代码
// 验证当前CaptureRequest列表中的request是否合理:核心就是验证与request绑定的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()) {
        // 确保所有的request至少含有一个Surface,所有Surface非空
        if (surface == null) {
            throw new IllegalArgumentException("Null Surface targets are not allowed");
        }
​
        for (int i = 0; i < mConfiguredOutputs.size(); i++) {
            OutputConfiguration configuration = mConfiguredOutputs.valueAt(i);
            // 判断surface对应的request是否是重复请求
            if (configuration.isForPhysicalCamera()
                    && configuration.getSurfaces().contains(surface)) {
                if (request.isReprocess()) {
                    throw new IllegalArgumentException(
                            "Reprocess request on physical stream is not allowed");
                }
            }
        }
    }
}

核心就是验证与request绑定的Surface是否存在,这个Surface就是通过addTarget的方式添到request中的surface,和createCaptureSession中传入的surfaces是不一样的;

3.2 底层发送请求信息

scss 复制代码
SubmitInfo requestInfo;
​
// 将requestList转换为CaptureRequest数组
CaptureRequest[] requestArray = requestList.toArray(new CaptureRequest[requestList.size()]);
// 转换surface到streamIdx和surfaceIdx
// Convert Surface to streamIdx and surfaceIdx
for (CaptureRequest request : requestArray) {
    // 根据streamId转换surface
    request.convertSurfaceToStreamId(mConfiguredOutputs);
}
​
// 向底层发送请求信息
requestInfo = mRemoteDevice.submitRequestList(requestArray, repeating);
if (DEBUG) {
    Log.v(TAG, "last frame number " + requestInfo.getLastFrameNumber());
}
​
for (CaptureRequest request : requestArray) {
    // 根据streamId恢复surface
    request.recoverStreamIdToSurface();
}

这一逻辑是该方法的核心逻辑;

1.CaptureRequest.convertSurfaceToStreamId(mConfiguredOutputs)

ini 复制代码
/**
 * @hide
 */
public void convertSurfaceToStreamId(
        final SparseArray<OutputConfiguration> configuredOutputs) {
    synchronized (mSurfacesLock) {
        if (mSurfaceConverted) {
            Log.v(TAG, "Cannot convert already converted surfaces!");
            return;
        }
​
        mStreamIdxArray = new int[mSurfaceSet.size()];
        mSurfaceIdxArray = new int[mSurfaceSet.size()];
        int i = 0;
        for (Surface s : mSurfaceSet) {
            boolean streamFound = false;
            for (int j = 0; j < configuredOutputs.size(); ++j) {
                int streamId = configuredOutputs.keyAt(j);
                OutputConfiguration outConfig = configuredOutputs.valueAt(j);
                int surfaceId = 0;
                // 其实outConfig.getSurfaces()只能获取到一个surface,这个surface就是outconfig对应的surface
                for (Surface outSurface : outConfig.getSurfaces()) {
                    if (s == outSurface) {
                        streamFound = true;
                        mStreamIdxArray[i] = streamId;
                        mSurfaceIdxArray[i] = surfaceId;
                        i++;
                        break;
                    }
                    surfaceId++;
                }
                if (streamFound) {
                    break;
                }
            }
​
            // 需要确认这一块的逻辑是否就是用于延时绑定surface的逻辑
            if (!streamFound) {
                // Check if we can match s by native object ID
                long reqSurfaceId = SurfaceUtils.getSurfaceId(s);
                for (int j = 0; j < configuredOutputs.size(); ++j) {
                    int streamId = configuredOutputs.keyAt(j);
                    OutputConfiguration outConfig = configuredOutputs.valueAt(j);
                    int surfaceId = 0;
                    for (Surface outSurface : outConfig.getSurfaces()) {
                        if (reqSurfaceId == SurfaceUtils.getSurfaceId(outSurface)) {
                            streamFound = true;
                            mStreamIdxArray[i] = streamId;
                            mSurfaceIdxArray[i] = surfaceId;
                            i++;
                            break;
                        }
                        surfaceId++;
                    }
                    if (streamFound) {
                        break;
                    }
                }
            }
​
            if (!streamFound) {
                mStreamIdxArray = null;
                mSurfaceIdxArray = null;
                throw new IllegalArgumentException(
                        "CaptureRequest contains unconfigured Input/Output Surface!");
            }
        }
        mSurfaceConverted = true;
    }
}

将本地已经缓存的surface和stream记录在内存(mStreamIdxArray数组和mSurfaceIdxArray数组)中,并binder传输到camera service层中,通过mSurfaceConverted变量防止camera service端重复请求;

2.CameraDeviceClient.submitRequestList(requestArray, repeating)

php 复制代码
binder::Status CameraDeviceClient::submitRequestList(
        const std::vector<hardware::camera2::CaptureRequest>& requests,
        bool streaming,
        /*out*/
        hardware::camera2::utils::SubmitInfo *submitInfo) {
    ATRACE_CALL();
    ALOGV("%s-start of function. Request list size %zu", __FUNCTION__, requests.size());
    
    List<const CameraDeviceBase::PhysicalCameraSettingsList> metadataRequestList;
    std::list<const SurfaceMap> surfaceMapList;
​
    ............
        // 这个函数代码很多,前面很多执行都是在复用检索之前的缓存是否可用
        metadataRequestList.push_back(physicalSettingsList);
        surfaceMapList.push_back(surfaceMap);
    }
​
    // 从一步开始,通过setRepeatingRequest()方法传入的request就停止向下传递了,后续过程中需要重新配置新的CaptureRequest,这个创建过程就在Camera3Device::setUpRequestLocked()方法中体现
    // 预览的情况下传入的streaming是true
    // 拍照的情况下传入的streaming是false
    if (streaming) {
        err = mDevice->setStreamingRequestList(metadataRequestList, surfaceMapList,
                &(submitInfo->mLastFrameNumber));
        if (err != OK) {
            String8 msg = String8::format(
                "Camera %s:  Got error %s (%d) after trying to set streaming request",
                mCameraIdStr.string(), strerror(-err), err);
            ALOGE("%s: %s", __FUNCTION__, msg.string());
            res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
                    msg.string());
        } else {
            Mutex::Autolock idLock(mStreamingRequestIdLock);
            mStreamingRequestId = submitInfo->mRequestId;
        }
    } else {
        err = mDevice->captureList(metadataRequestList, surfaceMapList,
                &(submitInfo->mLastFrameNumber));
        if (err != OK) {
            String8 msg = String8::format(
                "Camera %s: Got error %s (%d) after trying to submit capture request",
                mCameraIdStr.string(), strerror(-err), err);
            ALOGE("%s: %s", __FUNCTION__, msg.string());
            res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
                    msg.string());
        }
        ALOGV("%s: requestId = %d ", __FUNCTION__, submitInfo->mRequestId);
    }
​
    ALOGV("%s: Camera %s: End of function", __FUNCTION__, mCameraIdStr.string());
    return res;
}

现在分析preview情况;

3.mDevice->setStreamingRequestList

rust 复制代码
mDevice->setStreamingRequestList(metadataRequestList, surfaceMapList,
                &(submitInfo->mLastFrameNumber));
c 复制代码
status_t Camera3Device::setStreamingRequestList(
        const List<const PhysicalCameraSettingsList> &requestsList,
        const std::list<const SurfaceMap> &surfaceMaps, int64_t *lastFrameNumber) {
    ATRACE_CALL();
​
    return submitRequestsHelper(requestsList, surfaceMaps, /*repeating*/true, lastFrameNumber);
}
scss 复制代码
status_t Camera3Device::submitRequestsHelper(
        const List<const PhysicalCameraSettingsList> &requests,
        const std::list<const SurfaceMap> &surfaceMaps,
        bool repeating,
        /*out*/
        int64_t *lastFrameNumber) {
    ATRACE_CALL();
    Mutex::Autolock il(mInterfaceLock);
    Mutex::Autolock l(mLock);
​
    status_t res = checkStatusOkToCaptureLocked();
    if (res != OK) {
        // error logged by previous call
        return res;
    }
​
    RequestList requestList;
​
    res = convertMetadataListToRequestListLocked(requests, surfaceMaps,
            repeating, /*out*/&requestList);
    if (res != OK) {
        // error logged by previous call
        return res;
    }
​
    // preview - true    capture - false
    if (repeating) {
        res = mRequestThread->setRepeatingRequests(requestList, lastFrameNumber);
    } else {
        res = mRequestThread->queueRequestList(requestList, lastFrameNumber);
    }
​
    if (res == OK) {
        // 执行等待直到 state 为 STATUS_ACTIVE
        waitUntilStateThenRelock(/*active*/true, kActiveTimeout);
        if (res != OK) {
            SET_ERR_L("Can't transition to active in %f seconds!",
                    kActiveTimeout/1e9);
        }
        ALOGV("Camera %s: Capture request %" PRId32 " enqueued", mId.string(),
              (*(requestList.begin()))->mResultExtras.requestId);
    } else {
        CLOGE("Cannot queue request. Impossible.");
        return BAD_VALUE;
    }
​
    return res;
}

convertMetadataListToRequestListLocked();

ini 复制代码
status_t Camera3Device::convertMetadataListToRequestListLocked(
        const List<const PhysicalCameraSettingsList> &metadataList,
        const std::list<const SurfaceMap> &surfaceMaps,
        bool repeating,
        RequestList *requestList) {
    if (requestList == NULL) {
        CLOGE("requestList cannot be NULL.");
        return BAD_VALUE;
    }
​
    int32_t burstId = 0;
    List<const PhysicalCameraSettingsList>::const_iterator metadataIt = metadataList.begin();
    std::list<const SurfaceMap>::const_iterator surfaceMapIt = surfaceMaps.begin();
    for (; metadataIt != metadataList.end() && surfaceMapIt != surfaceMaps.end();
            ++metadataIt, ++surfaceMapIt) {
        sp<CaptureRequest> newRequest = setUpRequestLocked(*metadataIt, *surfaceMapIt);
        ............
​
        requestList->push_back(newRequest);
​
        ALOGV("%s: requestId = %" PRId32, __FUNCTION__, newRequest->mResultExtras.requestId);
    }
    ............
​
    return OK;
}

该方法中调用了setUpRequestLocked();

scss 复制代码
sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked(
        const PhysicalCameraSettingsList &request, const SurfaceMap &surfaceMap) {
    status_t res;
​
    if (mStatus == STATUS_UNCONFIGURED || mNeedConfig) {
        // This point should only be reached via API1 (API2 must explicitly call configureStreams)
        // so unilaterally select normal operating mode.
        res = filterParamsAndConfigureLocked(request.begin()->metadata,
                CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE);
        // Stream configuration failed. Client might try other configuraitons.
        if (res != OK) {
            CLOGE("Can't set up streams: %s (%d)", strerror(-res), res);
            return NULL;
        } else if (mStatus == STATUS_UNCONFIGURED) {
            // Stream configuration successfully configure to empty stream configuration.
            CLOGE("No streams configured");
            return NULL;
        }
    }
​
    // 通过PhysicalCameraSettings和Surface创建对应的request
    sp<CaptureRequest> newRequest = createCaptureRequest(request, surfaceMap);
    return newRequest;
}

mStatus和mNeedConfig这两个变量因为在执行configureStreamsLocked()的时候,将mStatus设置为了STATUS_CONFIGURED,mNeedConfig修改为了false;

但是在setUpRequestLocked()之前没有配置完成config,那就会执行filterParamsAndConfigureLocked()方法,而这个方法在上一节中已经讲解过,其核心就是调用configureStreamsLocked(),所以也会将mStatus和mNeedConfig两个变量的状态修改,然后再执行后续逻辑;

waitUntilStateThenRelock(/active/true, kActiveTimeout):执行等待直到 state 为 STATUS_ACTIVE;

arduino 复制代码
status_t Camera3Device::waitUntilStateThenRelock(bool active, nsecs_t timeout) {
    status_t res = OK;
​
    size_t startIndex = 0;
    if (mStatusWaiters == 0) {
        // Clear the list of recent statuses if there are no existing threads waiting on updates to
        // this status list
        mRecentStatusUpdates.clear();
    } else {
        // If other threads are waiting on updates to this status list, set the position of the
        // first element that this list will check rather than clearing the list.
        startIndex = mRecentStatusUpdates.size();
    }
​
    mStatusWaiters++;
​
    bool stateSeen = false;
    do {
        if (active == (mStatus == STATUS_ACTIVE)) {
            // Desired state is current
            break;
        }
        ............
​
        // Encountered desired state since we began waiting
        for (size_t i = startIndex; i < mRecentStatusUpdates.size(); i++) {
            if (active == (mRecentStatusUpdates[i] == STATUS_ACTIVE) ) {
                stateSeen = true;
                break;
            }
        }
    } while (!stateSeen);
​
    mStatusWaiters--;
​
    return res;
}

该方法主要是为了防止在还没有将mStatus的状态值修改时,执行后续有依赖于mStatus的逻辑。该方法对应于上述的filterParamsAndConfigureLocked()方法,使用stateSeen变量控制该do-while循环;

scss 复制代码
status_t Camera3Device::RequestThread::setRepeatingRequests(
        const RequestList &requests,
        /*out*/
        int64_t *lastFrameNumber) {
    ATRACE_CALL();
    Mutex::Autolock l(mRequestLock);
    // 第一次进入为 null
    if (lastFrameNumber != NULL) {
        *lastFrameNumber = mRepeatingLastFrameNumber;
    }
    mRepeatingRequests.clear();
    // 最终将request通过insert()方法添加到mRepeatingRequests请求队列中,mRepeatingRequests请求队列是专门用于preview request的
    mRepeatingRequests.insert(mRepeatingRequests.begin(),
            requests.begin(), requests.end());
​
    unpauseForNewRequests();
​
    mRepeatingLastFrameNumber = hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES;
    return OK;
}

mRepeatingRequests变量定义:

Camera3Device.h

arduino 复制代码
typedef List<sp<CaptureRequest> > RequestList;
arduino 复制代码
/**
 * Thread for managing capture request submission to HAL device.
 */
class RequestThread : public Thread {
​
    public:
    ............ // 省略
​
    // Used to prepare a batch of requests.
    struct NextRequest {
        sp<CaptureRequest>              captureRequest;
        camera3_capture_request_t       halRequest;
        Vector<camera3_stream_buffer_t> outputBuffers;
        bool                            submitted;
    };
    ............ // 省略
​
    const String8&     mId;       // The camera ID
    int                mStatusId; // The RequestThread's component ID for
    // status tracking
​
    Mutex              mRequestLock;
    Condition          mRequestSignal;
    RequestList        mRequestQueue;
    RequestList        mRepeatingRequests;
    // The next batch of requests being prepped for submission to the HAL, no longer
    // on the request queue. Read-only even with mRequestLock held, outside
    // of threadLoop
    Vector<NextRequest> mNextRequests;

将当前提交的CaptureRequest请求放入之前的预览请求队列中,告知HAL层有新的request请求,HAL层连接请求开始工作,源源不断地输出信息到上层。

unpauseForNewRequests():

scss 复制代码
void Camera3Device::RequestThread::unpauseForNewRequests() {
    ATRACE_CALL();
    // With work to do, mark thread as unpaused.
    // If paused by request (setPaused), don't resume, to avoid
    // extra signaling/waiting overhead to waitUntilPaused
    mRequestSignal.signal();
    Mutex::Autolock p(mPauseLock);
    if (!mDoPause) {
        ALOGV("%s: RequestThread: Going active", __FUNCTION__);
        if (mPaused) {
            sp<StatusTracker> statusTracker = mStatusTracker.promote();
            if (statusTracker != 0) {
                statusTracker->markComponentActive(mStatusId);
            }
        }
        mPaused = false;
    }
}

调用unpauseForNewRequests()向相关线程发送信号,即RequestThread线程;

该方法触发了mRequestSignal的信号,它对应的是Camera3Device::RequestThread::waitForNextRequestLocked()中的 waitRelative() 动作,可以保证在预览的时候不断地捕获信息流,camera就不断处于预览的状态了;

4.CaptureRequest.recoverStreamIdToSurface()

ini 复制代码
/**
 * @hide
 */
public void recoverStreamIdToSurface() {
    synchronized (mSurfacesLock) {
        if (!mSurfaceConverted) {
            Log.v(TAG, "Cannot convert already converted surfaces!");
            return;
        }
​
        mStreamIdxArray = null;
        mSurfaceIdxArray = null;
        mSurfaceConverted = false;
    }
}

释放内存,恢复Surface;

3.3 将返回请求信息和 CaptureCallback 绑定

CameraDeviceImpl.java

swift 复制代码
/** map request IDs to callback/request data */
    private final SparseArray<CaptureCallbackHolder> mCaptureCallbackMap =
            new SparseArray<CaptureCallbackHolder>();
scss 复制代码
if (callback != null) {
    mCaptureCallbackMap.put(requestInfo.getRequestId(),
            new CaptureCallbackHolder(
                    callback, requestList, executor, repeating, mNextSessionId - 1));
} else {
    if (DEBUG) {
        Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null");
    }
}
arduino 复制代码
static class CaptureCallbackHolder {
​
    private final boolean mRepeating;
    private final CaptureCallback mCallback;
    private final List<CaptureRequest> mRequestList;
    private final Executor mExecutor;
    private final int mSessionId;
    /**
     * <p>Determine if the callback holder is for a constrained high speed request list that
     * expects batched capture results. Capture results will be batched if the request list
     * is interleaved with preview and video requests. Capture results won't be batched if the
     * request list only contains preview requests, or if the request doesn't belong to a
     * constrained high speed list.
     */
    private final boolean mHasBatchedOutputs;
​
    CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList,
                          Executor executor, boolean repeating, int sessionId) {
        if (callback == null || executor == null) {
            throw new UnsupportedOperationException(
                    "Must have a valid handler and a valid callback");
        }
        mRepeating = repeating;
        mExecutor = executor;
        mRequestList = new ArrayList<CaptureRequest>(requestList);
        mCallback = callback;
        mSessionId = sessionId;
​
        // Check whether this callback holder is for batched outputs.
        // The logic here should match createHighSpeedRequestList.
        boolean hasBatchedOutputs = true;
        for (int i = 0; i < requestList.size(); i++) {
            CaptureRequest request = requestList.get(i);
            if (!request.isPartOfCRequestList()) {
                hasBatchedOutputs = false;
                break;
            }
            if (i == 0) {
                Collection<Surface> targets = request.getTargets();
                if (targets.size() != 2) {
                    hasBatchedOutputs = false;
                    break;
                }
            }
        }
        mHasBatchedOutputs = hasBatchedOutputs;
    }
​
    public boolean isRepeating() {
        return mRepeating;
    }
​
    public CaptureCallback getCallback() {
        return mCallback;
    }
​
    public CaptureRequest getRequest(int subsequenceId) {
        if (subsequenceId >= mRequestList.size()) {
            throw new IllegalArgumentException(
                    String.format(
                            "Requested subsequenceId %d is larger than request list size %d.",
                            subsequenceId, mRequestList.size()));
        } else {
            if (subsequenceId < 0) {
                throw new IllegalArgumentException(String.format(
                        "Requested subsequenceId %d is negative", subsequenceId));
            } else {
                return mRequestList.get(subsequenceId);
            }
        }
    }
​
    public CaptureRequest getRequest() {
        return getRequest(0);
    }
​
    public Executor getExecutor() {
        return mExecutor;
    }
​
    public int getSessionId() {
        return mSessionId;
    }
​
    public int getRequestCount() {
        return mRequestList.size();
    }
​
    public boolean hasBatchedOutputs() {
        return mHasBatchedOutputs;
    }
}

requestInfo变量的类型为SubmitInfo;

ini 复制代码
public class SubmitInfo implements Parcelable {
​
    private int mRequestId;
    private long mLastFrameNumber;
​
    public SubmitInfo() {
        mRequestId = -1;
        mLastFrameNumber = ICameraDeviceUser.NO_IN_FLIGHT_REPEATING_FRAMES;
    }
​
    public SubmitInfo(int requestId, long lastFrameNumber) {
        mRequestId = requestId;
        mLastFrameNumber = lastFrameNumber;
    }
}

requestIinfo表示当前capture request的结果,将requestInfo.getRequestId()与CaptureCallbackHolder绑定,因为Camera 2架构支持发送多次CaptureRequest请求,如果不使用这种绑定机制,后续的回调会造成严重的错乱,甚至回调不上来,那么开发者无法继续使用了;

综上,至此在调用完mRepeatingRequests.insert()和unpauseForNewRequests()这两个方法之后,setRepeatingRequest()核心逻辑就基本上结束了;

紧接着下来的就是RequestThread线程轮询处理逻辑;

相关推荐
你的小1025 分钟前
JavaWeb项目-----博客系统
android
风和先行1 小时前
adb 命令查看设备存储占用情况
android·adb
AaVictory.2 小时前
Android 开发 Java中 list实现 按照时间格式 yyyy-MM-dd HH:mm 顺序
android·java·list
似霰3 小时前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder
大风起兮云飞扬丶3 小时前
Android——网络请求
android
干一行,爱一行3 小时前
android camera data -> surface 显示
android
断墨先生3 小时前
uniapp—android原生插件开发(3Android真机调试)
android·uni-app
无极程序员5 小时前
PHP常量
android·ide·android studio
58沈剑5 小时前
80后聊架构:架构设计中两个重要指标,延时与吞吐量(Latency vs Throughput) | 架构师之路...
架构
萌面小侠Plus6 小时前
Android笔记(三十三):封装设备性能级别判断工具——低端机还是高端机
android·性能优化·kotlin·工具类·低端机