mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
camera: Add physical camera metadata in CaptureResult
- When physical stream of a logical multi-camera is requested, HAL needs to generate metadata for the physical cameras. - In case no physical stream is requested for the logical multi-camera, no capture result metadata is required for physical camera. - Batch physical and logical metadata within one capture_result call. Test: testLogicalCamera CTS test Bug: 64691172 Change-Id: Id040620f3f0c350711d49341ab31ab88ecd94888
This commit is contained in:
@@ -34,7 +34,23 @@ CameraDeviceSession::CameraDeviceSession(
|
||||
camera3_device_t* device,
|
||||
const camera_metadata_t* deviceInfo,
|
||||
const sp<V3_2::ICameraDeviceCallback>& callback) :
|
||||
V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback) {
|
||||
V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback),
|
||||
mResultBatcher_3_4(callback) {
|
||||
|
||||
mHasCallback_3_4 = false;
|
||||
|
||||
auto castResult = ICameraDeviceCallback::castFrom(callback);
|
||||
if (castResult.isOk()) {
|
||||
sp<ICameraDeviceCallback> callback3_4 = castResult;
|
||||
if (callback3_4 != nullptr) {
|
||||
process_capture_result = sProcessCaptureResult_3_4;
|
||||
notify = sNotify_3_4;
|
||||
mHasCallback_3_4 = true;
|
||||
if (!mInitFail) {
|
||||
mResultBatcher_3_4.setResultMetadataQueue(mResultMetadataQueue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CameraDeviceSession::~CameraDeviceSession() {
|
||||
@@ -54,6 +70,18 @@ Return<void> CameraDeviceSession::configureStreams_3_4(
|
||||
Status status = initStatus();
|
||||
HalStreamConfiguration outStreams;
|
||||
|
||||
// If callback is 3.2, make sure no physical stream is configured
|
||||
if (!mHasCallback_3_4) {
|
||||
for (size_t i = 0; i < requestedConfiguration.streams.size(); i++) {
|
||||
if (requestedConfiguration.streams[i].physicalCameraId.size() > 0) {
|
||||
ALOGE("%s: trying to configureStreams with physical camera id with V3.2 callback",
|
||||
__FUNCTION__);
|
||||
_hidl_cb(Status::INTERNAL_ERROR, outStreams);
|
||||
return Void();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hold the inflight lock for entire configureStreams scope since there must not be any
|
||||
// inflight request/results during stream configuration.
|
||||
Mutex::Autolock _l(mInflightLock);
|
||||
@@ -205,7 +233,7 @@ void CameraDeviceSession::postProcessConfigurationLocked_3_4(
|
||||
mVideoStreamIds.push_back(stream.v3_2.id);
|
||||
}
|
||||
}
|
||||
mResultBatcher.setBatchedStreams(mVideoStreamIds);
|
||||
mResultBatcher_3_4.setBatchedStreams(mVideoStreamIds);
|
||||
}
|
||||
|
||||
Return<void> CameraDeviceSession::processCaptureRequest_3_4(
|
||||
@@ -224,7 +252,7 @@ Return<void> CameraDeviceSession::processCaptureRequest_3_4(
|
||||
}
|
||||
|
||||
if (s == Status::OK && requests.size() > 1) {
|
||||
mResultBatcher.registerBatch(requests[0].v3_2.frameNumber, requests.size());
|
||||
mResultBatcher_3_4.registerBatch(requests[0].v3_2.frameNumber, requests.size());
|
||||
}
|
||||
|
||||
_hidl_cb(s, numRequestProcessed);
|
||||
@@ -237,6 +265,14 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const V3_4::CaptureRequ
|
||||
ALOGE("%s: camera init failed or disconnected", __FUNCTION__);
|
||||
return status;
|
||||
}
|
||||
// If callback is 3.2, make sure there are no physical settings.
|
||||
if (!mHasCallback_3_4) {
|
||||
if (request.physicalCameraSettings.size() > 0) {
|
||||
ALOGE("%s: trying to call processCaptureRequest_3_4 with physical camera id "
|
||||
"and V3.2 callback", __FUNCTION__);
|
||||
return Status::INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
camera3_capture_request_t halRequest;
|
||||
halRequest.frame_number = request.v3_2.frameNumber;
|
||||
@@ -407,6 +443,228 @@ Status CameraDeviceSession::processOneCaptureRequest_3_4(const V3_4::CaptureRequ
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static callback forwarding methods from HAL to instance
|
||||
*/
|
||||
void CameraDeviceSession::sProcessCaptureResult_3_4(
|
||||
const camera3_callback_ops *cb,
|
||||
const camera3_capture_result *hal_result) {
|
||||
CameraDeviceSession *d =
|
||||
const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
|
||||
|
||||
CaptureResult result;
|
||||
d->constructCaptureResult(result.v3_2, hal_result);
|
||||
result.physicalCameraMetadata.resize(hal_result->num_physcam_metadata);
|
||||
for (uint32_t i = 0; i < hal_result->num_physcam_metadata; i++) {
|
||||
std::string physicalId = hal_result->physcam_ids[i];
|
||||
V3_2::CameraMetadata physicalMetadata;
|
||||
V3_2::implementation::convertToHidl(hal_result->physcam_metadata[i], &physicalMetadata);
|
||||
PhysicalCameraMetadata physicalCameraMetadata = {
|
||||
.fmqMetadataSize = 0,
|
||||
.physicalCameraId = physicalId,
|
||||
.metadata = physicalMetadata };
|
||||
result.physicalCameraMetadata[i] = physicalCameraMetadata;
|
||||
}
|
||||
d->mResultBatcher_3_4.processCaptureResult_3_4(result);
|
||||
}
|
||||
|
||||
void CameraDeviceSession::sNotify_3_4(
|
||||
const camera3_callback_ops *cb,
|
||||
const camera3_notify_msg *msg) {
|
||||
CameraDeviceSession *d =
|
||||
const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
|
||||
V3_2::NotifyMsg hidlMsg;
|
||||
V3_2::implementation::convertToHidl(msg, &hidlMsg);
|
||||
|
||||
if (hidlMsg.type == (V3_2::MsgType) CAMERA3_MSG_ERROR &&
|
||||
hidlMsg.msg.error.errorStreamId != -1) {
|
||||
if (d->mStreamMap.count(hidlMsg.msg.error.errorStreamId) != 1) {
|
||||
ALOGE("%s: unknown stream ID %d reports an error!",
|
||||
__FUNCTION__, hidlMsg.msg.error.errorStreamId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (static_cast<camera3_msg_type_t>(hidlMsg.type) == CAMERA3_MSG_ERROR) {
|
||||
switch (hidlMsg.msg.error.errorCode) {
|
||||
case V3_2::ErrorCode::ERROR_DEVICE:
|
||||
case V3_2::ErrorCode::ERROR_REQUEST:
|
||||
case V3_2::ErrorCode::ERROR_RESULT: {
|
||||
Mutex::Autolock _l(d->mInflightLock);
|
||||
auto entry = d->mInflightAETriggerOverrides.find(
|
||||
hidlMsg.msg.error.frameNumber);
|
||||
if (d->mInflightAETriggerOverrides.end() != entry) {
|
||||
d->mInflightAETriggerOverrides.erase(
|
||||
hidlMsg.msg.error.frameNumber);
|
||||
}
|
||||
|
||||
auto boostEntry = d->mInflightRawBoostPresent.find(
|
||||
hidlMsg.msg.error.frameNumber);
|
||||
if (d->mInflightRawBoostPresent.end() != boostEntry) {
|
||||
d->mInflightRawBoostPresent.erase(
|
||||
hidlMsg.msg.error.frameNumber);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case V3_2::ErrorCode::ERROR_BUFFER:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
d->mResultBatcher_3_4.notify(hidlMsg);
|
||||
}
|
||||
|
||||
CameraDeviceSession::ResultBatcher_3_4::ResultBatcher_3_4(
|
||||
const sp<V3_2::ICameraDeviceCallback>& callback) :
|
||||
V3_3::implementation::CameraDeviceSession::ResultBatcher(callback) {
|
||||
auto castResult = ICameraDeviceCallback::castFrom(callback);
|
||||
if (castResult.isOk()) {
|
||||
mCallback_3_4 = castResult;
|
||||
}
|
||||
}
|
||||
|
||||
void CameraDeviceSession::ResultBatcher_3_4::processCaptureResult_3_4(CaptureResult& result) {
|
||||
auto pair = getBatch(result.v3_2.frameNumber);
|
||||
int batchIdx = pair.first;
|
||||
if (batchIdx == NOT_BATCHED) {
|
||||
processOneCaptureResult_3_4(result);
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<InflightBatch> batch = pair.second;
|
||||
{
|
||||
Mutex::Autolock _l(batch->mLock);
|
||||
// Check if the batch is removed (mostly by notify error) before lock was acquired
|
||||
if (batch->mRemoved) {
|
||||
// Fall back to non-batch path
|
||||
processOneCaptureResult_3_4(result);
|
||||
return;
|
||||
}
|
||||
|
||||
// queue metadata
|
||||
if (result.v3_2.result.size() != 0) {
|
||||
// Save a copy of metadata
|
||||
batch->mResultMds[result.v3_2.partialResult].mMds.push_back(
|
||||
std::make_pair(result.v3_2.frameNumber, result.v3_2.result));
|
||||
}
|
||||
|
||||
// queue buffer
|
||||
std::vector<int> filledStreams;
|
||||
std::vector<V3_2::StreamBuffer> nonBatchedBuffers;
|
||||
for (auto& buffer : result.v3_2.outputBuffers) {
|
||||
auto it = batch->mBatchBufs.find(buffer.streamId);
|
||||
if (it != batch->mBatchBufs.end()) {
|
||||
InflightBatch::BufferBatch& bb = it->second;
|
||||
pushStreamBuffer(std::move(buffer), bb.mBuffers);
|
||||
filledStreams.push_back(buffer.streamId);
|
||||
} else {
|
||||
pushStreamBuffer(std::move(buffer), nonBatchedBuffers);
|
||||
}
|
||||
}
|
||||
|
||||
// send non-batched buffers up
|
||||
if (nonBatchedBuffers.size() > 0 || result.v3_2.inputBuffer.streamId != -1) {
|
||||
CaptureResult nonBatchedResult;
|
||||
nonBatchedResult.v3_2.frameNumber = result.v3_2.frameNumber;
|
||||
nonBatchedResult.v3_2.fmqResultSize = 0;
|
||||
nonBatchedResult.v3_2.outputBuffers.resize(nonBatchedBuffers.size());
|
||||
for (size_t i = 0; i < nonBatchedBuffers.size(); i++) {
|
||||
moveStreamBuffer(
|
||||
std::move(nonBatchedBuffers[i]), nonBatchedResult.v3_2.outputBuffers[i]);
|
||||
}
|
||||
moveStreamBuffer(std::move(result.v3_2.inputBuffer), nonBatchedResult.v3_2.inputBuffer);
|
||||
nonBatchedResult.v3_2.partialResult = 0; // 0 for buffer only results
|
||||
processOneCaptureResult_3_4(nonBatchedResult);
|
||||
}
|
||||
|
||||
if (result.v3_2.frameNumber == batch->mLastFrame) {
|
||||
// Send data up
|
||||
if (result.v3_2.partialResult > 0) {
|
||||
sendBatchMetadataLocked(batch, result.v3_2.partialResult);
|
||||
}
|
||||
// send buffer up
|
||||
if (filledStreams.size() > 0) {
|
||||
sendBatchBuffersLocked(batch, filledStreams);
|
||||
}
|
||||
}
|
||||
} // end of batch lock scope
|
||||
|
||||
// see if the batch is complete
|
||||
if (result.v3_2.frameNumber == batch->mLastFrame) {
|
||||
checkAndRemoveFirstBatch();
|
||||
}
|
||||
}
|
||||
|
||||
void CameraDeviceSession::ResultBatcher_3_4::processOneCaptureResult_3_4(CaptureResult& result) {
|
||||
hidl_vec<CaptureResult> results;
|
||||
results.resize(1);
|
||||
results[0] = std::move(result);
|
||||
invokeProcessCaptureResultCallback_3_4(results, /* tryWriteFmq */true);
|
||||
freeReleaseFences_3_4(results);
|
||||
return;
|
||||
}
|
||||
|
||||
void CameraDeviceSession::ResultBatcher_3_4::invokeProcessCaptureResultCallback_3_4(
|
||||
hidl_vec<CaptureResult> &results, bool tryWriteFmq) {
|
||||
if (mProcessCaptureResultLock.tryLock() != OK) {
|
||||
ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
|
||||
if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
|
||||
ALOGE("%s: cannot acquire lock in 1s, cannot proceed",
|
||||
__FUNCTION__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
|
||||
for (CaptureResult &result : results) {
|
||||
if (result.v3_2.result.size() > 0) {
|
||||
if (mResultMetadataQueue->write(result.v3_2.result.data(),
|
||||
result.v3_2.result.size())) {
|
||||
result.v3_2.fmqResultSize = result.v3_2.result.size();
|
||||
result.v3_2.result.resize(0);
|
||||
} else {
|
||||
ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
|
||||
result.v3_2.fmqResultSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& onePhysMetadata : result.physicalCameraMetadata) {
|
||||
if (mResultMetadataQueue->write(onePhysMetadata.metadata.data(),
|
||||
onePhysMetadata.metadata.size())) {
|
||||
onePhysMetadata.fmqMetadataSize = onePhysMetadata.metadata.size();
|
||||
onePhysMetadata.metadata.resize(0);
|
||||
} else {
|
||||
ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
|
||||
onePhysMetadata.fmqMetadataSize = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mCallback_3_4->processCaptureResult_3_4(results);
|
||||
mProcessCaptureResultLock.unlock();
|
||||
}
|
||||
|
||||
void CameraDeviceSession::ResultBatcher_3_4::freeReleaseFences_3_4(hidl_vec<CaptureResult>& results) {
|
||||
for (auto& result : results) {
|
||||
if (result.v3_2.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
|
||||
native_handle_t* handle = const_cast<native_handle_t*>(
|
||||
result.v3_2.inputBuffer.releaseFence.getNativeHandle());
|
||||
native_handle_close(handle);
|
||||
native_handle_delete(handle);
|
||||
}
|
||||
for (auto& buf : result.v3_2.outputBuffers) {
|
||||
if (buf.releaseFence.getNativeHandle() != nullptr) {
|
||||
native_handle_t* handle = const_cast<native_handle_t*>(
|
||||
buf.releaseFence.getNativeHandle());
|
||||
native_handle_close(handle);
|
||||
native_handle_delete(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V3_4
|
||||
} // namespace device
|
||||
|
||||
Reference in New Issue
Block a user