基于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线程轮询处理逻辑;