QCamera3: Initial support for PB HDR+
Initialize HDR+ client when HDR+ is enabled and create a HDR+
RAW channel to request an additional RAW for every request
from camera service.
Get sensor resolution and output pixel clock from mm-camera2.
Configure streams with HDR+ client using sensor mode
information and configured streams with camera service.
HDR+ mode is OFF by default and can be enabled by setting
persist.camera.hdrplus to 1.
Bug: 28637032
Change-Id: Id79077baefe426014cd489ae7380ad6ced1738b0
diff --git a/msm8998/QCamera2/HAL3/QCamera3HWI.cpp b/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
index 1abd515..443c5f1 100644
--- a/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
+++ b/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
@@ -373,6 +373,7 @@
mSupportChannel(NULL),
mAnalysisChannel(NULL),
mRawDumpChannel(NULL),
+ mHdrPlusRawSrcChannel(NULL),
mDummyBatchChannel(NULL),
mPerfLockMgr(),
mCommon(),
@@ -549,6 +550,10 @@
mRawDumpChannel->stop();
}
+ if (mHdrPlusRawSrcChannel) {
+ mHdrPlusRawSrcChannel->stop();
+ }
+
// NOTE: 'camera3_stream_t *' objects are already freed at
// this stage by the framework
for (List<stream_info_t *>::iterator it = mStreamInfo.begin();
@@ -593,6 +598,10 @@
delete mRawDumpChannel;
mRawDumpChannel = NULL;
}
+ if (mHdrPlusRawSrcChannel) {
+ delete mHdrPlusRawSrcChannel;
+ mHdrPlusRawSrcChannel = NULL;
+ }
if (mDummyBatchChannel) {
delete mDummyBatchChannel;
mDummyBatchChannel = NULL;
@@ -914,6 +923,12 @@
rc = mCameraHandle->ops->close_camera(mCameraHandle->camera_handle);
mCameraHandle = NULL;
+ // Disconnect from HDR+ client.
+ if (mHdrPlusClient != nullptr) {
+ mHdrPlusClient->disconnect();
+ mHdrPlusClient = nullptr;
+ }
+
//reset session id to some invalid id
pthread_mutex_lock(&gCamLock);
sessionId[mCameraId] = 0xDEADBEEF;
@@ -1172,19 +1187,19 @@
}
/*==============================================================================
- * FUNCTION : getSensorOutputSize
+ * FUNCTION : sensor_mode_info
*
- * DESCRIPTION: Get sensor output size based on current stream configuratoin
+ * DESCRIPTION: Get sensor mode information based on current stream configuratoin
*
* PARAMETERS :
- * @sensor_dim : sensor output dimension (output)
+ * @sensor_mode_info : sensor mode information (output)
*
* RETURN : int32_t type of status
* NO_ERROR -- success
* none-zero failure code
*
*==========================================================================*/
-int32_t QCamera3HardwareInterface::getSensorOutputSize(cam_dimension_t &sensor_dim)
+int32_t QCamera3HardwareInterface::getSensorModeInfo(cam_sensor_mode_info_t &sensorModeInfo)
{
int32_t rc = NO_ERROR;
@@ -1212,17 +1227,20 @@
}
clear_metadata_buffer(mParameters);
- ADD_GET_PARAM_ENTRY_TO_BATCH(mParameters, CAM_INTF_PARM_RAW_DIMENSION);
+ ADD_GET_PARAM_ENTRY_TO_BATCH(mParameters, CAM_INTF_PARM_SENSOR_MODE_INFO);
rc = mCameraHandle->ops->get_parms(mCameraHandle->camera_handle,
mParameters);
if (rc != NO_ERROR) {
- LOGE("Failed to get CAM_INTF_PARM_RAW_DIMENSION");
+ LOGE("Failed to get CAM_INTF_PARM_SENSOR_MODE_INFO");
return rc;
}
- READ_PARAM_ENTRY(mParameters, CAM_INTF_PARM_RAW_DIMENSION, sensor_dim);
- LOGH("sensor output dimension = %d x %d", sensor_dim.width, sensor_dim.height);
+ READ_PARAM_ENTRY(mParameters, CAM_INTF_PARM_SENSOR_MODE_INFO, sensorModeInfo);
+ LOGH("%s: active array size %dx%d, pixel array size %dx%d, output pixel clock %u", __FUNCTION__,
+ sensorModeInfo.active_array_size.width, sensorModeInfo.active_array_size.height,
+ sensorModeInfo.pixel_array_size.width, sensorModeInfo.pixel_array_size.height,
+ sensorModeInfo.op_pixel_clk);
return rc;
}
@@ -1451,6 +1469,12 @@
mRawDumpChannel = NULL;
}
+ if (mHdrPlusRawSrcChannel) {
+ mHdrPlusRawSrcChannel->stop();
+ delete mHdrPlusRawSrcChannel;
+ mHdrPlusRawSrcChannel = NULL;
+ }
+
if (mSupportChannel)
mSupportChannel->stop();
@@ -1469,6 +1493,41 @@
pthread_mutex_lock(&mMutex);
+ // Check if HDR+ is enabled.
+ char prop[PROPERTY_VALUE_MAX];
+ property_get("persist.camera.hdrplus", prop, "0");
+ bool enableHdrPlus = atoi(prop);
+ if (enableHdrPlus) {
+ ALOGD("%s: HDR+ in Camera HAL enabled.", __FUNCTION__);
+ // Connect to HDR+ client if not yet.
+ if (mHdrPlusClient == nullptr) {
+ mHdrPlusClient = std::make_shared<HdrPlusClient>();
+ rc = mHdrPlusClient->connect(this);
+ if (rc < 0) {
+ LOGE("%s: Failed to connect to HDR+ client: %s (%d).", __FUNCTION__,
+ strerror(-rc), rc);
+ pthread_mutex_unlock(&mMutex);
+ return -ENODEV;
+ }
+
+ // Set static metadata.
+ rc = mHdrPlusClient->setStaticMetadata(*gStaticMetadata[mCameraId]);
+ if (rc < 0) {
+ LOGE("%s: Failed set static metadata in HDR+ client: %s (%d).", __FUNCTION__,
+ strerror(-rc), rc);
+ pthread_mutex_unlock(&mMutex);
+ return -ENODEV;
+ }
+ }
+ } else {
+ ALOGD("%s: HDR+ in Camera HAL disabled.", __FUNCTION__);
+ // Disconnect from HDR+ client if HDR+ is not enabled.
+ if (mHdrPlusClient != nullptr) {
+ mHdrPlusClient->disconnect();
+ mHdrPlusClient = nullptr;
+ }
+ }
+
// Check state
switch (mState) {
case INITIALIZED:
@@ -2280,6 +2339,33 @@
}
}
+ // Initialize HDR+ Raw Source channel.
+ if (mHdrPlusClient != nullptr) {
+ if (isRawStreamRequested || mRawDumpChannel) {
+ ALOGE("%s: Enabling HDR+ while RAW output stream is configured is not supported.",
+ __FUNCTION__);
+ mHdrPlusClient->disconnect();
+ mHdrPlusClient = nullptr;
+ } else {
+ cam_dimension_t rawSize = getMaxRawSize(mCameraId);
+ cam_feature_mask_t hdrPlusRawFeatureMask = CAM_QCOM_FEATURE_NONE;
+ setPAAFSupport(hdrPlusRawFeatureMask,
+ CAM_STREAM_TYPE_RAW,
+ gCamCapability[mCameraId]->color_arrangement);
+ mHdrPlusRawSrcChannel = new QCamera3HdrPlusRawSrcChannel(mCameraHandle->camera_handle,
+ mChannelHandle,
+ mCameraHandle->ops,
+ rawSize,
+ &padding_info,
+ this, hdrPlusRawFeatureMask);
+ if (!mHdrPlusRawSrcChannel) {
+ LOGE("HDR+ Raw Source channel cannot be created");
+ pthread_mutex_unlock(&mMutex);
+ return -ENOMEM;
+ }
+ }
+ }
+
if (mAnalysisChannel) {
cam_analysis_info_t analysisInfo;
@@ -2369,6 +2455,19 @@
gCamCapability[mCameraId]->color_arrangement);
mStreamConfigInfo.num_streams++;
}
+
+ if (mHdrPlusRawSrcChannel) {
+ cam_dimension_t rawSize;
+ rawSize = getMaxRawSize(mCameraId);
+ mStreamConfigInfo.stream_sizes[mStreamConfigInfo.num_streams] = rawSize;
+ mStreamConfigInfo.type[mStreamConfigInfo.num_streams] = CAM_STREAM_TYPE_RAW;
+ mStreamConfigInfo.postprocess_mask[mStreamConfigInfo.num_streams] = CAM_QCOM_FEATURE_NONE;
+ setPAAFSupport(mStreamConfigInfo.postprocess_mask[mStreamConfigInfo.num_streams],
+ mStreamConfigInfo.type[mStreamConfigInfo.num_streams],
+ gCamCapability[mCameraId]->color_arrangement);
+ mStreamConfigInfo.num_streams++;
+ }
+
/* In HFR mode, if video stream is not added, create a dummy channel so that
* ISP can create a batch mode even for preview only case. This channel is
* never 'start'ed (no stream-on), it is only 'initialized' */
@@ -3978,6 +4077,48 @@
return NO_ERROR;
}
+status_t QCamera3HardwareInterface::fillPbStreamConfig(
+ pbcamera::StreamConfiguration *config, uint32_t pbStreamId, int pbStreamFormat,
+ QCamera3Channel *channel, uint32_t streamIndex) {
+ if (config == nullptr) {
+ LOGE("%s: config is null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ if (channel == nullptr) {
+ LOGE("%s: channel is null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ QCamera3Stream *stream = channel->getStreamByIndex(streamIndex);
+ if (stream == nullptr) {
+ LOGE("%s: Failed to get stream %d in channel.", __FUNCTION__, streamIndex);
+ return NAME_NOT_FOUND;
+ }
+
+ const cam_stream_info_t* streamInfo = stream->getStreamInfo();
+ if (streamInfo == nullptr) {
+ LOGE("%s: Failed to get stream info for stream %d in channel.", __FUNCTION__, streamIndex);
+ return NAME_NOT_FOUND;
+ }
+
+ config->id = pbStreamId;
+ config->image.width = streamInfo->dim.width;
+ config->image.height = streamInfo->dim.height;
+ config->image.padding = 0;
+ config->image.format = pbStreamFormat;
+
+ // Fill plane information.
+ for (uint32_t i = 0; i < streamInfo->buf_planes.plane_info.num_planes; i++) {
+ pbcamera::PlaneConfiguration plane;
+ plane.stride = streamInfo->buf_planes.plane_info.mp[i].stride_in_bytes;
+ plane.scanline = streamInfo->buf_planes.plane_info.mp[i].scanline;
+ config->image.planes.push_back(plane);
+ }
+
+ return OK;
+}
+
/*===========================================================================
* FUNCTION : processCaptureRequest
*
@@ -4233,9 +4374,9 @@
LOGE("set_parms failed for hal version, stream info");
}
- cam_dimension_t sensor_dim;
- memset(&sensor_dim, 0, sizeof(sensor_dim));
- rc = getSensorOutputSize(sensor_dim);
+ cam_sensor_mode_info_t sensor_mode_info;
+ memset(&sensor_mode_info, 0, sizeof(sensor_mode_info));
+ rc = getSensorModeInfo(sensor_mode_info);
if (rc != NO_ERROR) {
LOGE("Failed to get sensor output size");
pthread_mutex_unlock(&mMutex);
@@ -4244,7 +4385,8 @@
mCropRegionMapper.update(gCamCapability[mCameraId]->active_array_size.width,
gCamCapability[mCameraId]->active_array_size.height,
- sensor_dim.width, sensor_dim.height);
+ sensor_mode_info.active_array_size.width,
+ sensor_mode_info.active_array_size.height);
/* Set batchmode before initializing channel. Since registerBuffer
* internally initializes some of the channels, better set batchmode
@@ -4297,6 +4439,14 @@
goto error_exit;
}
}
+ if (mHdrPlusRawSrcChannel) {
+ rc = mHdrPlusRawSrcChannel->initialize(IS_TYPE_NONE);
+ if (rc != NO_ERROR) {
+ LOGE("Error: HDR+ RAW Source Channel init failed");
+ pthread_mutex_unlock(&mMutex);
+ goto error_exit;
+ }
+ }
if (mSupportChannel) {
rc = mSupportChannel->initialize(IS_TYPE_NONE);
if (rc < 0) {
@@ -4328,6 +4478,77 @@
}
}
+ if (mHdrPlusClient != nullptr) {
+ pbcamera::InputConfiguration inputConfig;
+ std::vector<pbcamera::StreamConfiguration> outputStreamConfigs;
+
+ // Configure HDR+ client streams.
+ // Get input config.
+ if (mHdrPlusRawSrcChannel) {
+ // HDR+ input buffers will be provided by HAL.
+ rc = fillPbStreamConfig(&inputConfig.streamConfig, kPbRaw10InputStreamId,
+ HAL_PIXEL_FORMAT_RAW10, mHdrPlusRawSrcChannel, /*stream index*/0);
+ if (rc != OK) {
+ LOGE("%s: Failed to get fill stream config for HDR+ raw src stream.",
+ __FUNCTION__);
+ pthread_mutex_unlock(&mMutex);
+ goto error_exit;
+ }
+
+ inputConfig.isSensorInput = false;
+ } else {
+ // Sensor MIPI will send data to Easel.
+ inputConfig.isSensorInput = true;
+ inputConfig.sensorMode.pixelArrayWidth =
+ sensor_mode_info.pixel_array_size.width;
+ inputConfig.sensorMode.pixelArrayHeight =
+ sensor_mode_info.pixel_array_size.height;
+ inputConfig.sensorMode.activeArrayWidth =
+ sensor_mode_info.active_array_size.width;
+ inputConfig.sensorMode.activeArrayHeight =
+ sensor_mode_info.active_array_size.height;
+ inputConfig.sensorMode.outputPixelClkHz =
+ sensor_mode_info.op_pixel_clk;
+ }
+
+ // Get output configurations.
+ // Easel may need to output RAW16 buffers if mRawChannel was created.
+ if (mRawChannel != nullptr) {
+ pbcamera::StreamConfiguration outputConfig;
+ rc = fillPbStreamConfig(&outputConfig, kPbRaw16OutputStreamId,
+ HAL_PIXEL_FORMAT_RAW16, mRawChannel, /*stream index*/0);
+ if (rc != OK) {
+ LOGE("%s: Failed to get fill stream config for raw stream.", __FUNCTION__);
+ pthread_mutex_unlock(&mMutex);
+ goto error_exit;
+ }
+ outputStreamConfigs.push_back(outputConfig);
+ }
+
+ // Easel may need to output YUV output buffers if mPictureChannel was created.
+ if (mPictureChannel != nullptr) {
+ pbcamera::StreamConfiguration outputConfig;
+ rc = fillPbStreamConfig(&outputConfig, kPbYuvOutputStreamId,
+ HAL_PIXEL_FORMAT_YCrCb_420_SP, mPictureChannel, /*stream index*/0);
+ if (rc != OK) {
+ LOGE("%s: Failed to get fill stream config for YUV stream.", __FUNCTION__);
+ pthread_mutex_unlock(&mMutex);
+ goto error_exit;
+ }
+ outputStreamConfigs.push_back(outputConfig);
+ }
+
+ // TODO: consider other channels for YUV output buffers.
+
+ rc = mHdrPlusClient->configureStreams(inputConfig, outputStreamConfigs);
+ if (rc != OK) {
+ LOGE("%d: Failed to configure streams with HDR+ client: %s (%d)", __FUNCTION__,
+ strerror(-rc), rc);
+ pthread_mutex_unlock(&mMutex);
+ goto error_exit;
+ }
+ }
+
// Set bundle info
rc = setBundleInfo();
if (rc < 0) {
@@ -4473,6 +4694,33 @@
}
}
+ if (mHdrPlusRawSrcChannel) {
+ LOGD("Starting HDR+ RAW stream");
+ rc = mHdrPlusRawSrcChannel->start();
+ if (rc != NO_ERROR) {
+ LOGE("Error Starting HDR+ RAW Channel");
+ for (List<stream_info_t *>::iterator it = mStreamInfo.begin();
+ it != mStreamInfo.end(); it++) {
+ QCamera3Channel *channel =
+ (QCamera3Channel *)(*it)->stream->priv;
+ LOGH("Stopping Processing Channel mask=%d",
+ channel->getStreamTypeMask());
+ channel->stop();
+ }
+ if (mSupportChannel)
+ mSupportChannel->stop();
+ if (mAnalysisChannel) {
+ mAnalysisChannel->stop();
+ }
+ if (mRawDumpChannel) {
+ mRawDumpChannel->stop();
+ }
+ mMetadataChannel->stop();
+ pthread_mutex_unlock(&mMutex);
+ goto error_exit;
+ }
+ }
+
if (mChannelHandle) {
rc = mCameraHandle->ops->start_channel(mCameraHandle->camera_handle,
@@ -4577,6 +4825,12 @@
streamsArray.stream_request[streamsArray.num_streams++].buf_index = CAM_FREERUN_IDX;
}
+ if (mHdrPlusRawSrcChannel) {
+ streamsArray.stream_request[streamsArray.num_streams].streamID =
+ mHdrPlusRawSrcChannel->getStreamID(mHdrPlusRawSrcChannel->getStreamTypeMask());
+ streamsArray.stream_request[streamsArray.num_streams++].buf_index = CAM_FREERUN_IDX;
+ }
+
if(request->input_buffer == NULL) {
/* Parse the settings:
* - For every request in NORMAL MODE
@@ -12098,6 +12352,9 @@
if (mRawDumpChannel) {
mRawDumpChannel->stop();
}
+ if (mHdrPlusRawSrcChannel) {
+ mHdrPlusRawSrcChannel->stop();
+ }
if (mMetadataChannel) {
/* If content of mStreamInfo is not 0, there is metadata stream */
mMetadataChannel->stop();
@@ -12160,6 +12417,13 @@
return rc;
}
}
+ if (mHdrPlusRawSrcChannel) {
+ rc = mHdrPlusRawSrcChannel->start();
+ if (rc < 0) {
+ LOGE("HDR+ RAW channel start failed");
+ return rc;
+ }
+ }
LOGD("All channels started");
return rc;
@@ -12361,6 +12625,9 @@
if (mRawDumpChannel) {
mRawDumpChannel->setBundleInfo(bundleInfo);
}
+ if (mHdrPlusRawSrcChannel) {
+ mHdrPlusRawSrcChannel->setBundleInfo(bundleInfo);
+ }
}
return rc;
@@ -12638,4 +12905,15 @@
break;
}
}
+
+void QCamera3HardwareInterface::onCaptureResult(__unused pbcamera::CaptureResult *result,
+ __unused const camera_metadata_t &resultMetadata) {
+ // TODO: Handle HDR+ capture results.
+}
+
+void QCamera3HardwareInterface::onFailedCaptureResult(
+ __unused pbcamera::CaptureResult *failedResult) {
+ // TODO: Handle HDR+ capture failures.
+}
+
}; //end namespace qcamera