上篇介绍了openCamera的流程,从hal3_2v6到oem的过程。
本篇介绍下openCamera之后紧接着的动作,configureStreams 和 processCaptureRequest。
configureStreams 配流
普通Photo模式会配两路流,预览和拍照。
1,传入一个 camera3_stream_configuration_t 类型的参数
int SprdCamera3HWI::configureStreams(camera3_stream_configuration_t *streamList)
2,创建三个channel
SprdCamera3MetadataChannel:参数
SprdCamera3RegularChannel:预览
SprdCamera3PicChannel :拍照
注意:在new这三个对象的时候,第二个参数都传如了 captureResultCb
// Create metadata channel and initialize it
if (mMetadataChannel == NULL) {
mMetadataChannel = new SprdCamera3MetadataChannel(
mOEMIf, captureResultCb, mSetting, this);
if (mMetadataChannel == NULL) {
HAL_LOGE("failed to allocate metadata channel");
}
} else {
mMetadataChannel->stop(mFrameNum);
}
// regular channel
if (mRegularChan == NULL) {
mRegularChan = new SprdCamera3RegularChannel(
mOEMIf, captureResultCb, mSetting, mMetadataChannel,
CAMERA_CHANNEL_TYPE_REGULAR, this);
if (mRegularChan == NULL) {
HAL_LOGE("channel created failed");
return INVALID_OPERATION;
}
} else {
// for performance: dont delay for dc/dv switch or front/back switch
mOEMIf->setSensorCloseFlag();
mRegularChan->stop(mFrameNum);
}
// picture channel
if (mPicChan == NULL) {
mPicChan = new SprdCamera3PicChannel(mOEMIf, captureResultCb, mSetting,
mMetadataChannel,
CAMERA_CHANNEL_TYPE_PICTURE, this);
if (mPicChan == NULL) {
HAL_LOGE("channel created failed");
return INVALID_OPERATION;
}
} else {
mPicChan->stop(mFrameNum);
}
在SprdCamera3HIW中看到 captureResultCb 是:
void SprdCamera3HWI::captureResultCb(cam_result_data_info_t *result_info) {
// Mutex::Autolock l(mLock);
if (NULL == result_info) {
HAL_LOGE("param invalid");
return;
}
HAL_LOGD("SprdCamera3HWI");
handleCbDataWithLock(result_info);
return;
}
void SprdCamera3HWI::captureResultCb(cam_result_data_info_t *result_info,
void *userdata) {
SprdCamera3HWI *hw = (SprdCamera3HWI *)userdata;
if (hw == NULL) {
HAL_LOGE("Invalid hw %p", hw);
return;
}
hw->captureResultCb(result_info);
return;
}
即调用 handleCbDataWithLock ,我们在开启预览的流程中会看到当预览帧数据会调的时候会调用 handleCbDataWithLock
3,遍历参数的类型和格式
对我们当前普通Photo模式下有两路流:
472 944 D Cam3HWI : 719, configureStreams: stream_type=0 format=34
472 944 D Cam3HWI : 719, configureStreams: stream_type=0 format=33
stream_type都为0,即 CAMERA3_STREAM_OUTPUT = 0,
format的对应关系是:
HAL_PIXEL_FORMAT_RAW16=32,
HAL_PIXEL_FORMAT_BLOB=33, //拍照
HAL_PIXEL_FORMAT_YV12=842094169,
HAL_PIXEL_FORMAT_YCrCb_420_SP=17
HAL_PIXEL_FORMAT_YCbCr_420_888=35
HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED=34 //预览
for (i = 0; i < streamList->num_streams; i++) {
HAL_LOGD("stream_type=%d format=%d", streamList->streams[i]->stream_type, streamList->streams[i]->format);
}
4,根据上述参数的stream_type和 format 得到 : stream_type 和 channel_type
预览:
stream_type = CAMERA_STREAM_TYPE_PREVIEW;
channel_type = CAMERA_CHANNEL_TYPE_REGULAR;
拍照:
stream_type = CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT;
channel_type = CAMERA_CHANNEL_TYPE_PICTURE;
5,根据channel_type配置mStreamConfiguration
代码省略了与本篇不相关的分支
switch (channel_type) {
case CAMERA_CHANNEL_TYPE_REGULAR: {
ret = mRegularChan->addStream(stream_type, newStream);
if (ret) {
HAL_LOGE("addStream failed");
}
if (stream_type == CAMERA_STREAM_TYPE_PREVIEW) {
preview_size.width = newStream->width;
preview_size.height = newStream->height;
previewFormat = newStream->format;
previewStreamType = CAMERA_STREAM_TYPE_PREVIEW;
mStreamConfiguration.preview.status = CONFIGURED;
mStreamConfiguration.preview.width = newStream->width;
mStreamConfiguration.preview.height = newStream->height;
mStreamConfiguration.preview.format = newStream->format;
mStreamConfiguration.preview.type = CAMERA_STREAM_TYPE_PREVIEW;
mStreamConfiguration.preview.stream = newStream;
}
case CAMERA_CHANNEL_TYPE_PICTURE: {
ret = mPicChan->addStream(stream_type, newStream);
if (ret) {
HAL_LOGE("addStream failed");
}
if (stream_type == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT) {
capture_size.width = newStream->width;
capture_size.height = newStream->height;
captureFormat = newStream->format;
captureStreamType = CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT;
mStreamConfiguration.snapshot.status = CONFIGURED;
mStreamConfiguration.snapshot.width = newStream->width;
mStreamConfiguration.snapshot.height = newStream->height;
mStreamConfiguration.snapshot.format = newStream->format;
mStreamConfiguration.snapshot.type =
CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT;
mStreamConfiguration.snapshot.stream = newStream;
}
newStream->priv = mPicChan;
newStream->max_buffers = SprdCamera3PicChannel::kMaxBuffers;//1
mPictureRequest = false;
break;
}
default:
HAL_LOGE("channel type is invalid channel");
break;
}
}
6,将上一步得到的参数,通过SprdCamera3OEMIf继续设下去
mOEMIf->setCamStreamInfo(preview_size, previewFormat, previewStreamType);
mOEMIf->setCamStreamInfo(capture_size, captureFormat, captureStreamType);
mOEMIf->setCamStreamInfo(video_size, videoFormat, videoStreamType);
mOEMIf->setCamStreamInfo(callback_size, callbackFormat, callbackStreamType);
mOEMIf->setCamStreamInfo(yuv2_size, yuv2Format, yuv2StreamType);
// need to update crop region each time when ConfigureStreams
mOEMIf->setCameraConvertCropRegion();
mSetting->setPreviewSize(preview_size);
mSetting->setVideoSize(video_size);
mSetting->setPictureSize(capture_size);
mSetting->setCallbackSize(callback_size);
7,SprdCamera3OEMIf的处理
代码去除了与本篇不相关的分支逻辑
case CAMERA_STREAM_TYPE_PREVIEW:
设置了mPreviewWidth 和 mPreviewHeight ,在后面的开启预览阶段会在使用这两个参数
case CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT:
通过 SET_PARM(mHalOem, mCameraHandle, CAMERA_PARAM_RAW_CAPTURE_SIZE, (cmr_uint)&req_size);将拍照的size进一步设下去
int SprdCamera3OEMIf::setCamStreamInfo(struct img_size size, int format,
int stream_tpye) {
int i;
SPRD_DEF_Tag *sprddefInfo;
char value[PROPERTY_VALUE_MAX];
struct img_size req_size;
struct sensor_mode_info mode_info[SENSOR_MODE_MAX];
switch (stream_tpye) {
case CAMERA_STREAM_TYPE_PREVIEW:
mPreviewWidth = size.width;
mPreviewHeight = size.height;
if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP ||
format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED ||
format == HAL_PIXEL_FORMAT_YCBCR_420_888) {
mPreviewFormat = CAM_IMG_FMT_YUV420_NV21;
} else if (format == HAL_PIXEL_FORMAT_RAW16) {
mPreviewFormat = CAM_IMG_FMT_BAYER_MIPI_RAW;
}
break;
case CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT:
mCaptureWidth = size.width;
mCaptureHeight = size.height;
if (format == HAL_PIXEL_FORMAT_BLOB) {
mPictureFormat = CAM_IMG_FMT_YUV420_NV21;
}
if (getMultiCameraMode() != MODE_TUNING) {
if (mIsRawCapture == 1) {
mHalOem->ops->camera_get_sensor_info_for_raw(mCameraHandle,
mode_info);
for (i = SENSOR_MODE_PREVIEW_ONE; i < SENSOR_MODE_MAX; i++) {
HAL_LOGD("trim w=%d, h=%d", mode_info[i].trim_width,
mode_info[i].trim_height);
if (mode_info[i].trim_width >= mCaptureWidth) {
mCaptureWidth = mode_info[i].trim_width;
mCaptureHeight = mode_info[i].trim_height;
break;
}
}
req_size.width = mCaptureWidth;
req_size.height = mCaptureHeight;
SET_PARM(mHalOem, mCameraHandle, CAMERA_PARAM_RAW_CAPTURE_SIZE,
(cmr_uint)&req_size);
HAL_LOGD(
"raw capture mode: mCaptureWidth=%d, mCaptureHeight=%d",
mCaptureWidth, mCaptureHeight);
}
}
break;
default:
break;
}
return NO_ERROR;
}
configureStreams的流程到此就结束了,总的来说,就是将传入的 camera3_stream_configuration_t 类型的参数中的数据,进一步设下去
processCaptureRequest流程
请求预览和请求拍照都叫Request,并且预览的每一帧都代表一个Request。
我们以预览为例,看下processCaptureRequest的流程。
1,根据参数 camera3_capture_request_t 中的stream状态去setCapturePara
int SprdCamera3HWI::processCaptureRequest(camera3_capture_request_t *request) {
switch (captureIntent) {
case ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW:
if (mStreamConfiguration.num_streams == 2 &&
mStreamConfiguration.preview.status == CONFIGURED &&
mStreamConfiguration.snapshot.status == CONFIGURED) {
if (mOldCapIntent == SPRD_CONTROL_CAPTURE_INTENT_CONFIGURE) {
{
// when sensor_rotation is 1 for volte, volte dont need capture
if ((mOEMIf->isYuvSensor() == 0) && (sprddefInfo->sensor_rotation == 0)) {
mOEMIf->setStreamOnWithZsl();
}
mFirstRegularRequest = 1;
}
mOEMIf->setCapturePara(CAMERA_CAPTURE_MODE_PREVIEW, mFrameNum);
if (streamType[0] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT ||
streamType[1] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT ||
streamType[2] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT) {
mPictureRequest = 1;
mOEMIf->setCapturePara(CAMERA_CAPTURE_MODE_STILL_CAPTURE,
mFrameNum);
}
break;
}
if (streamType[0] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT ||
streamType[1] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT ||
streamType[2] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT) {
mPictureRequest = 1;
mOEMIf->setCapturePara(CAMERA_CAPTURE_MODE_STILL_CAPTURE,
mFrameNum);
}
break;
}
if (mOldCapIntent == SPRD_CONTROL_CAPTURE_INTENT_CONFIGURE) {
if (mStreamConfiguration.snapshot.status == CONFIGURED) {
if (mOEMIf->isYuvSensor() == 0) {
mOEMIf->setStreamOnWithZsl();
}
}
mFirstRegularRequest = 1;
mOEMIf->setCapturePara(CAMERA_CAPTURE_MODE_PREVIEW, mFrameNum);
if (streamType[0] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT ||
streamType[1] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT ||
streamType[2] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT) {
mPictureRequest = 1;
mOEMIf->setCapturePara(CAMERA_CAPTURE_MODE_STILL_CAPTURE,
mFrameNum);
}
break;
}
if (streamType[0] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT ||
streamType[1] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT ||
streamType[2] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT) {
mPictureRequest = 1;
mOEMIf->setCapturePara(CAMERA_CAPTURE_MODE_STILL_CAPTURE,
mFrameNum);
}
break;
mOEMIf->setCapturePara(CAMERA_CAPTURE_MODE_PREVIEW, mFrameNum);
mOEMIf->setCapturePara(CAMERA_CAPTURE_MODE_STILL_CAPTURE, mFrameNum);
是向SprdCamera3OEMIf中设置 mTakePictureMode、mCaptureMode、mPicCaptureCnt等值的状态
2,acquireFence
for (size_t i = 0; i < request->num_output_buffers; i++) {
const camera3_stream_buffer_t &output = request->output_buffers[i];
sp<Fence> acquireFence = new Fence(output.acquire_fence);
ret = acquireFence->wait(Fence::TIMEOUT_NEVER);
if (ret) {
HAL_LOGE("fence wait failed %d", ret);
goto exit;
}
acquireFence = NULL;
}
3,构建 pendingRequestInfo
pendingRequest.meta_info.flash_mode = flashInfo.mode;
pendingRequest.meta_info.ae_mode = controlInfo.ae_mode;
memcpy(pendingRequest.meta_info.ae_regions, controlInfo.ae_regions,
5 * sizeof(controlInfo.ae_regions[0]));
memcpy(pendingRequest.meta_info.af_regions, controlInfo.af_regions,
5 * sizeof(controlInfo.af_regions[0]));
pendingRequest.frame_number = frameNumber;
pendingRequest.threeA_info.af_trigger = controlInfo.af_trigger;
pendingRequest.threeA_info.af_state = controlInfo.af_state;
pendingRequest.threeA_info.ae_precap_trigger =
controlInfo.ae_precap_trigger;
pendingRequest.threeA_info.ae_state = controlInfo.ae_state;
pendingRequest.threeA_info.ae_manual_trigger =
controlInfo.ae_manual_trigger;
#ifdef SUPPORT_EXPOSURE_SENSITIVITY
pendingRequest.threeA_info.exposure_time = streamParaInfo.exposure_time;
pendingRequest.threeA_info.sensitivity= streamParaInfo.sensitivity;
#endif
pendingRequest.num_buffers = request->num_output_buffers;
pendingRequest.request_id = captureRequestId;
pendingRequest.bNotified = 0;
pendingRequest.input_buffer = request->input_buffer;
pendingRequest.pipeline_depth = 0;
并将该pendingRequest : mPendingRequestsList.push_back(pendingRequest);
4,将Setting信息更新下去
mMetadataChannel->start(mFrameNum);
5,开启预览
在上面的case ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW 中会将 mFirstRegularRequest 置为 1。开启预览只在第一次调用processCaptureRequest的时候走,就将
if (mFirstRegularRequest == 1) {
HAL_LOGD(" mRegularChan->start num_output_buffers:%d", request->num_output_buffers);
ret = mRegularChan->start(mFrameNum);//开启预览
if (ret) {
HAL_LOGE("mRegularChan->start failed, ret=%d", ret);
goto exit;
}
mFirstRegularRequest = 0;
}
6,调用SprdCamera3RegularChannel 的 request,请求预览帧数据
for (i = 0; i < request->num_output_buffers; i++) {
const camera3_stream_buffer_t &output = request->output_buffers[i];
camera3_stream_t *stream = output.stream;
SprdCamera3Channel *channel = (SprdCamera3Channel *)stream->priv;
if (channel == NULL) {
HAL_LOGE("invalid channel pointer for stream");
continue;
}
HAL_LOGD(" getStreamType:%d",getStreamType(stream));
ret = channel->request(stream, output.buffer, frameNumber);
if (ret) {
HAL_LOGE("channel->request failed %p (%d)", output.buffer,
frameNumber);
continue;
}
}
ReguarChannel的request主要做两个动作
1,map buffer
2,queue buffer
7,触发拍照
mPictureRequest == 1 的条件是在 case ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE 中设置的1
if (mPictureRequest == 1) {
ret = mPicChan->start(mFrameNum);
if (ret) {
HAL_LOGE("mPicChan->start failed, ret=%d", ret);
goto exit;
}
mPictureRequest = 0;
}
8, case ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE
case ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE:
if (streamType[0] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT ||
streamType[1] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT ||
streamType[2] == CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT) {
mPictureRequest = 1;
mOEMIf->setCapturePara(CAMERA_CAPTURE_MODE_STILL_CAPTURE,
mFrameNum);
}
break;
}
processCaptureRequest的流程到这里就完成了,请求了预览帧,那就会有预览帧数据的回调。
我们在configureStreams的第二步中提到,创建三个Channel对象,都传入了 captureResultCb ,该回调会调用 handleCbDataWithLock 函数
void SprdCamera3HWI::handleCbDataWithLock(cam_result_data_info_t *result_info) {
for (List<PendingRequestInfo>::iterator i = mPendingRequestsList.begin();
i != mPendingRequestsList.end();) {
if (i->frame_number < frame_number) {
//比当前 frame_number 小,调用 process_capture_result
if (!i->bNotified) {
mCallbackOps->process_capture_result(mCallbackOps, &result);
free_camera_metadata(const_cast<camera_metadata_t *>(result.result));
}
} else if (i->frame_number == frame_number) {
//与当前 frame_number 相等,调用 process_capture_result
if (!i->bNotified) {
mCallbackOps->process_capture_result(mCallbackOps, &result);
free_camera_metadata(const_cast<camera_metadata_t *>(result.result));
}
//遍历当前 pendingRequestInfo 中的所有buffer,result.result 置为 null,然后在调用 process_capture_result
for (List<RequestedBufferInfo>::iterator j = i->buffers.begin();
j != i->buffers.end();) {
if (j->stream == stream && j->buffer == buffer) {
camera3_stream_buffer_t *result_buffers =
new camera3_stream_buffer_t[1];
result_buffers->stream = stream;
result_buffers->buffer = buffer;
if (mBufferStatusError || sprddefInfo ->return_previewframe_after_nozsl_cap == 1||
(mSuperExposeNonzsl == 1 && sprddefInfo ->return_previewframe_after_nozsl_cap == 1)) {
result_buffers->status = CAMERA3_BUFFER_STATUS_ERROR;
HAL_LOGI("bufferstatus:%d",result_buffers->status);
} else {
result_buffers->status = buffer_status;
}
result_buffers->acquire_fence = -1;
result_buffers->release_fence = -1;
result.result = NULL;
result.frame_number = i->frame_number;
result.num_output_buffers = 1;
result.output_buffers = result_buffers;
result.input_buffer = i->input_buffer;
result.partial_result = 0;
if (mMultiCameraMode == MODE_3D_VIDEO) {
setVideoBufferTimestamp(capture_time);
}
mCallbackOps->process_capture_result(mCallbackOps, &result);
HAL_LOGV("data frame_number = %d, input_buffer = %p",
result.frame_number, i->input_buffer);
delete[] result_buffers;
i->num_buffers--;
j = i->buffers.erase(j);
break;
} else {
++j;
}
}
} else if (i->frame_number > frame_number) {
//不做任何操作
}
}
}
可见,在预览帧回调handleCbDataWithLock的时候,或判断参数 cam_result_data_info_t 中的frame_number,与在processCaptureRequest中push的pendingRequestsInfo的frame_number的关系。
- mPendingRequestsList 中的 frame_number < cam_result_data_info_t 的 frame_number ==> process_capture_result
- mPendingRequestsList 中的 frame_number = cam_result_data_info_t 的 frame_number ==> process_capture_result 并且遍历当前 pendingRequestsInfo 中的buffer
- mPendingRequestsList 中的 frame_number > cam_result_data_info_t 的 frame_number ==>不处理
process_capture_result 是将当前帧数据向上回调。
到这里,我们就完整的讲了 配置、请求预览、预览数据回调的流程。