mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:50:18 +00:00
- Extend RequestTemplate with two new values - Add legacy wrapper support for the new templates Test: Builds, camera continues to run. CTS coverage of templates tests new templates as expected. Bug: 63629224 Change-Id: I2a44d86a815690798fa4b8327794c64716d134ee
416 lines
16 KiB
C++
416 lines
16 KiB
C++
/*
|
|
* Copyright (C) 2017-2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define LOG_TAG "CamDevSession@3.4-impl"
|
|
#include <android/log.h>
|
|
|
|
#include <set>
|
|
#include <utils/Trace.h>
|
|
#include <hardware/gralloc.h>
|
|
#include <hardware/gralloc1.h>
|
|
#include "CameraDeviceSession.h"
|
|
|
|
namespace android {
|
|
namespace hardware {
|
|
namespace camera {
|
|
namespace device {
|
|
namespace V3_4 {
|
|
namespace implementation {
|
|
|
|
CameraDeviceSession::CameraDeviceSession(
|
|
camera3_device_t* device,
|
|
const camera_metadata_t* deviceInfo,
|
|
const sp<V3_2::ICameraDeviceCallback>& callback) :
|
|
V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback) {
|
|
}
|
|
|
|
CameraDeviceSession::~CameraDeviceSession() {
|
|
}
|
|
|
|
Return<void> CameraDeviceSession::constructDefaultRequestSettings_3_4(
|
|
RequestTemplate type, ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) {
|
|
V3_2::CameraMetadata outMetadata;
|
|
Status status = constructDefaultRequestSettingsRaw( (int) type, &outMetadata);
|
|
_hidl_cb(status, outMetadata);
|
|
return Void();
|
|
}
|
|
|
|
Return<void> CameraDeviceSession::configureStreams_3_4(
|
|
const StreamConfiguration& requestedConfiguration,
|
|
ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb) {
|
|
Status status = initStatus();
|
|
HalStreamConfiguration outStreams;
|
|
|
|
// hold the inflight lock for entire configureStreams scope since there must not be any
|
|
// inflight request/results during stream configuration.
|
|
Mutex::Autolock _l(mInflightLock);
|
|
if (!mInflightBuffers.empty()) {
|
|
ALOGE("%s: trying to configureStreams while there are still %zu inflight buffers!",
|
|
__FUNCTION__, mInflightBuffers.size());
|
|
_hidl_cb(Status::INTERNAL_ERROR, outStreams);
|
|
return Void();
|
|
}
|
|
|
|
if (!mInflightAETriggerOverrides.empty()) {
|
|
ALOGE("%s: trying to configureStreams while there are still %zu inflight"
|
|
" trigger overrides!", __FUNCTION__,
|
|
mInflightAETriggerOverrides.size());
|
|
_hidl_cb(Status::INTERNAL_ERROR, outStreams);
|
|
return Void();
|
|
}
|
|
|
|
if (!mInflightRawBoostPresent.empty()) {
|
|
ALOGE("%s: trying to configureStreams while there are still %zu inflight"
|
|
" boost overrides!", __FUNCTION__,
|
|
mInflightRawBoostPresent.size());
|
|
_hidl_cb(Status::INTERNAL_ERROR, outStreams);
|
|
return Void();
|
|
}
|
|
|
|
if (status != Status::OK) {
|
|
_hidl_cb(status, outStreams);
|
|
return Void();
|
|
}
|
|
|
|
const camera_metadata_t *paramBuffer = nullptr;
|
|
if (0 < requestedConfiguration.sessionParams.size()) {
|
|
::android::hardware::camera::common::V1_0::helper::CameraMetadata sessionParams;
|
|
V3_2::implementation::convertFromHidl(requestedConfiguration.sessionParams, ¶mBuffer);
|
|
}
|
|
|
|
camera3_stream_configuration_t stream_list{};
|
|
hidl_vec<camera3_stream_t*> streams;
|
|
stream_list.session_parameters = paramBuffer;
|
|
if (!preProcessConfigurationLocked_3_4(requestedConfiguration, &stream_list, &streams)) {
|
|
_hidl_cb(Status::INTERNAL_ERROR, outStreams);
|
|
return Void();
|
|
}
|
|
|
|
ATRACE_BEGIN("camera3->configure_streams");
|
|
status_t ret = mDevice->ops->configure_streams(mDevice, &stream_list);
|
|
ATRACE_END();
|
|
|
|
// In case Hal returns error most likely it was not able to release
|
|
// the corresponding resources of the deleted streams.
|
|
if (ret == OK) {
|
|
postProcessConfigurationLocked_3_4(requestedConfiguration);
|
|
}
|
|
|
|
if (ret == -EINVAL) {
|
|
status = Status::ILLEGAL_ARGUMENT;
|
|
} else if (ret != OK) {
|
|
status = Status::INTERNAL_ERROR;
|
|
} else {
|
|
V3_4::implementation::convertToHidl(stream_list, &outStreams);
|
|
mFirstRequest = true;
|
|
}
|
|
|
|
_hidl_cb(status, outStreams);
|
|
return Void();
|
|
}
|
|
|
|
bool CameraDeviceSession::preProcessConfigurationLocked_3_4(
|
|
const StreamConfiguration& requestedConfiguration,
|
|
camera3_stream_configuration_t *stream_list /*out*/,
|
|
hidl_vec<camera3_stream_t*> *streams /*out*/) {
|
|
|
|
if ((stream_list == nullptr) || (streams == nullptr)) {
|
|
return false;
|
|
}
|
|
|
|
stream_list->operation_mode = (uint32_t) requestedConfiguration.operationMode;
|
|
stream_list->num_streams = requestedConfiguration.streams.size();
|
|
streams->resize(stream_list->num_streams);
|
|
stream_list->streams = streams->data();
|
|
|
|
for (uint32_t i = 0; i < stream_list->num_streams; i++) {
|
|
int id = requestedConfiguration.streams[i].v3_2.id;
|
|
|
|
if (mStreamMap.count(id) == 0) {
|
|
Camera3Stream stream;
|
|
convertFromHidl(requestedConfiguration.streams[i], &stream);
|
|
mStreamMap[id] = stream;
|
|
mPhysicalCameraIdMap[id] = requestedConfiguration.streams[i].physicalCameraId;
|
|
mStreamMap[id].data_space = mapToLegacyDataspace(
|
|
mStreamMap[id].data_space);
|
|
mStreamMap[id].physical_camera_id = mPhysicalCameraIdMap[id].c_str();
|
|
mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{});
|
|
} else {
|
|
// width/height/format must not change, but usage/rotation might need to change
|
|
if (mStreamMap[id].stream_type !=
|
|
(int) requestedConfiguration.streams[i].v3_2.streamType ||
|
|
mStreamMap[id].width != requestedConfiguration.streams[i].v3_2.width ||
|
|
mStreamMap[id].height != requestedConfiguration.streams[i].v3_2.height ||
|
|
mStreamMap[id].format != (int) requestedConfiguration.streams[i].v3_2.format ||
|
|
mStreamMap[id].data_space !=
|
|
mapToLegacyDataspace( static_cast<android_dataspace_t> (
|
|
requestedConfiguration.streams[i].v3_2.dataSpace)) ||
|
|
mPhysicalCameraIdMap[id] != requestedConfiguration.streams[i].physicalCameraId) {
|
|
ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id);
|
|
return false;
|
|
}
|
|
mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].v3_2.rotation;
|
|
mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].v3_2.usage;
|
|
}
|
|
(*streams)[i] = &mStreamMap[id];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CameraDeviceSession::postProcessConfigurationLocked_3_4(
|
|
const StreamConfiguration& requestedConfiguration) {
|
|
// delete unused streams, note we do this after adding new streams to ensure new stream
|
|
// will not have the same address as deleted stream, and HAL has a chance to reference
|
|
// the to be deleted stream in configure_streams call
|
|
for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
|
|
int id = it->first;
|
|
bool found = false;
|
|
for (const auto& stream : requestedConfiguration.streams) {
|
|
if (id == stream.v3_2.id) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
// Unmap all buffers of deleted stream
|
|
// in case the configuration call succeeds and HAL
|
|
// is able to release the corresponding resources too.
|
|
cleanupBuffersLocked(id);
|
|
it = mStreamMap.erase(it);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
|
|
// Track video streams
|
|
mVideoStreamIds.clear();
|
|
for (const auto& stream : requestedConfiguration.streams) {
|
|
if (stream.v3_2.streamType == StreamType::OUTPUT &&
|
|
stream.v3_2.usage &
|
|
graphics::common::V1_0::BufferUsage::VIDEO_ENCODER) {
|
|
mVideoStreamIds.push_back(stream.v3_2.id);
|
|
}
|
|
}
|
|
mResultBatcher.setBatchedStreams(mVideoStreamIds);
|
|
}
|
|
|
|
Return<void> CameraDeviceSession::processCaptureRequest_3_4(
|
|
const hidl_vec<V3_4::CaptureRequest>& requests,
|
|
const hidl_vec<V3_2::BufferCache>& cachesToRemove,
|
|
ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) {
|
|
updateBufferCaches(cachesToRemove);
|
|
|
|
uint32_t numRequestProcessed = 0;
|
|
Status s = Status::OK;
|
|
for (size_t i = 0; i < requests.size(); i++, numRequestProcessed++) {
|
|
s = processOneCaptureRequest_3_4(requests[i]);
|
|
if (s != Status::OK) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (s == Status::OK && requests.size() > 1) {
|
|
mResultBatcher.registerBatch(requests[0].v3_2.frameNumber, requests.size());
|
|
}
|
|
|
|
_hidl_cb(s, numRequestProcessed);
|
|
return Void();
|
|
}
|
|
|
|
Status CameraDeviceSession::processOneCaptureRequest_3_4(const V3_4::CaptureRequest& request) {
|
|
Status status = initStatus();
|
|
if (status != Status::OK) {
|
|
ALOGE("%s: camera init failed or disconnected", __FUNCTION__);
|
|
return status;
|
|
}
|
|
|
|
camera3_capture_request_t halRequest;
|
|
halRequest.frame_number = request.v3_2.frameNumber;
|
|
|
|
bool converted = true;
|
|
V3_2::CameraMetadata settingsFmq; // settings from FMQ
|
|
if (request.v3_2.fmqSettingsSize > 0) {
|
|
// non-blocking read; client must write metadata before calling
|
|
// processOneCaptureRequest
|
|
settingsFmq.resize(request.v3_2.fmqSettingsSize);
|
|
bool read = mRequestMetadataQueue->read(settingsFmq.data(), request.v3_2.fmqSettingsSize);
|
|
if (read) {
|
|
converted = V3_2::implementation::convertFromHidl(settingsFmq, &halRequest.settings);
|
|
} else {
|
|
ALOGE("%s: capture request settings metadata couldn't be read from fmq!", __FUNCTION__);
|
|
converted = false;
|
|
}
|
|
} else {
|
|
converted = V3_2::implementation::convertFromHidl(request.v3_2.settings,
|
|
&halRequest.settings);
|
|
}
|
|
|
|
if (!converted) {
|
|
ALOGE("%s: capture request settings metadata is corrupt!", __FUNCTION__);
|
|
return Status::ILLEGAL_ARGUMENT;
|
|
}
|
|
|
|
if (mFirstRequest && halRequest.settings == nullptr) {
|
|
ALOGE("%s: capture request settings must not be null for first request!",
|
|
__FUNCTION__);
|
|
return Status::ILLEGAL_ARGUMENT;
|
|
}
|
|
|
|
hidl_vec<buffer_handle_t*> allBufPtrs;
|
|
hidl_vec<int> allFences;
|
|
bool hasInputBuf = (request.v3_2.inputBuffer.streamId != -1 &&
|
|
request.v3_2.inputBuffer.bufferId != 0);
|
|
size_t numOutputBufs = request.v3_2.outputBuffers.size();
|
|
size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
|
|
|
|
if (numOutputBufs == 0) {
|
|
ALOGE("%s: capture request must have at least one output buffer!", __FUNCTION__);
|
|
return Status::ILLEGAL_ARGUMENT;
|
|
}
|
|
|
|
status = importRequest(request.v3_2, allBufPtrs, allFences);
|
|
if (status != Status::OK) {
|
|
return status;
|
|
}
|
|
|
|
hidl_vec<camera3_stream_buffer_t> outHalBufs;
|
|
outHalBufs.resize(numOutputBufs);
|
|
bool aeCancelTriggerNeeded = false;
|
|
::android::hardware::camera::common::V1_0::helper::CameraMetadata settingsOverride;
|
|
{
|
|
Mutex::Autolock _l(mInflightLock);
|
|
if (hasInputBuf) {
|
|
auto streamId = request.v3_2.inputBuffer.streamId;
|
|
auto key = std::make_pair(request.v3_2.inputBuffer.streamId, request.v3_2.frameNumber);
|
|
auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{};
|
|
convertFromHidl(
|
|
allBufPtrs[numOutputBufs], request.v3_2.inputBuffer.status,
|
|
&mStreamMap[request.v3_2.inputBuffer.streamId], allFences[numOutputBufs],
|
|
&bufCache);
|
|
bufCache.stream->physical_camera_id = mPhysicalCameraIdMap[streamId].c_str();
|
|
halRequest.input_buffer = &bufCache;
|
|
} else {
|
|
halRequest.input_buffer = nullptr;
|
|
}
|
|
|
|
halRequest.num_output_buffers = numOutputBufs;
|
|
for (size_t i = 0; i < numOutputBufs; i++) {
|
|
auto streamId = request.v3_2.outputBuffers[i].streamId;
|
|
auto key = std::make_pair(streamId, request.v3_2.frameNumber);
|
|
auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{};
|
|
convertFromHidl(
|
|
allBufPtrs[i], request.v3_2.outputBuffers[i].status,
|
|
&mStreamMap[streamId], allFences[i],
|
|
&bufCache);
|
|
bufCache.stream->physical_camera_id = mPhysicalCameraIdMap[streamId].c_str();
|
|
outHalBufs[i] = bufCache;
|
|
}
|
|
halRequest.output_buffers = outHalBufs.data();
|
|
|
|
AETriggerCancelOverride triggerOverride;
|
|
aeCancelTriggerNeeded = handleAePrecaptureCancelRequestLocked(
|
|
halRequest, &settingsOverride /*out*/, &triggerOverride/*out*/);
|
|
if (aeCancelTriggerNeeded) {
|
|
mInflightAETriggerOverrides[halRequest.frame_number] =
|
|
triggerOverride;
|
|
halRequest.settings = settingsOverride.getAndLock();
|
|
}
|
|
}
|
|
|
|
std::vector<const char *> physicalCameraIds;
|
|
std::vector<const camera_metadata_t *> physicalCameraSettings;
|
|
std::vector<V3_2::CameraMetadata> physicalFmq;
|
|
size_t settingsCount = request.physicalCameraSettings.size();
|
|
if (settingsCount > 0) {
|
|
physicalCameraIds.reserve(settingsCount);
|
|
physicalCameraSettings.reserve(settingsCount);
|
|
physicalFmq.reserve(settingsCount);
|
|
|
|
for (size_t i = 0; i < settingsCount; i++) {
|
|
uint64_t settingsSize = request.physicalCameraSettings[i].fmqSettingsSize;
|
|
const camera_metadata_t *settings;
|
|
if (settingsSize > 0) {
|
|
physicalFmq.push_back(V3_2::CameraMetadata(settingsSize));
|
|
bool read = mRequestMetadataQueue->read(physicalFmq[i].data(), settingsSize);
|
|
if (read) {
|
|
converted = V3_2::implementation::convertFromHidl(physicalFmq[i], &settings);
|
|
physicalCameraSettings.push_back(settings);
|
|
} else {
|
|
ALOGE("%s: physical camera settings metadata couldn't be read from fmq!",
|
|
__FUNCTION__);
|
|
converted = false;
|
|
}
|
|
} else {
|
|
converted = V3_2::implementation::convertFromHidl(
|
|
request.physicalCameraSettings[i].settings, &settings);
|
|
physicalCameraSettings.push_back(settings);
|
|
}
|
|
|
|
if (!converted) {
|
|
ALOGE("%s: physical camera settings metadata is corrupt!", __FUNCTION__);
|
|
return Status::ILLEGAL_ARGUMENT;
|
|
}
|
|
physicalCameraIds.push_back(request.physicalCameraSettings[i].physicalCameraId.c_str());
|
|
}
|
|
}
|
|
halRequest.num_physcam_settings = settingsCount;
|
|
halRequest.physcam_id = physicalCameraIds.data();
|
|
halRequest.physcam_settings = physicalCameraSettings.data();
|
|
|
|
ATRACE_ASYNC_BEGIN("frame capture", request.v3_2.frameNumber);
|
|
ATRACE_BEGIN("camera3->process_capture_request");
|
|
status_t ret = mDevice->ops->process_capture_request(mDevice, &halRequest);
|
|
ATRACE_END();
|
|
if (aeCancelTriggerNeeded) {
|
|
settingsOverride.unlock(halRequest.settings);
|
|
}
|
|
if (ret != OK) {
|
|
Mutex::Autolock _l(mInflightLock);
|
|
ALOGE("%s: HAL process_capture_request call failed!", __FUNCTION__);
|
|
|
|
cleanupInflightFences(allFences, numBufs);
|
|
if (hasInputBuf) {
|
|
auto key = std::make_pair(request.v3_2.inputBuffer.streamId, request.v3_2.frameNumber);
|
|
mInflightBuffers.erase(key);
|
|
}
|
|
for (size_t i = 0; i < numOutputBufs; i++) {
|
|
auto key = std::make_pair(request.v3_2.outputBuffers[i].streamId,
|
|
request.v3_2.frameNumber);
|
|
mInflightBuffers.erase(key);
|
|
}
|
|
if (aeCancelTriggerNeeded) {
|
|
mInflightAETriggerOverrides.erase(request.v3_2.frameNumber);
|
|
}
|
|
|
|
if (ret == BAD_VALUE) {
|
|
return Status::ILLEGAL_ARGUMENT;
|
|
} else {
|
|
return Status::INTERNAL_ERROR;
|
|
}
|
|
}
|
|
|
|
mFirstRequest = false;
|
|
return Status::OK;
|
|
}
|
|
|
|
} // namespace implementation
|
|
} // namespace V3_4
|
|
} // namespace device
|
|
} // namespace camera
|
|
} // namespace hardware
|
|
} // namespace android
|