350 lines
13 KiB
C++
350 lines
13 KiB
C++
/*
|
|
* Copyright (C) 2022 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.
|
|
*/
|
|
|
|
#ifndef ANDROID_SERVERS_CAMERA3_OUTPUT_TEMPLUTILS_H
|
|
#define ANDROID_SERVERS_CAMERA3_OUTPUT_TEMPLUTILS_H
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <utils/Log.h>
|
|
#include <utils/SortedVector.h>
|
|
#include <utils/Trace.h>
|
|
|
|
#include <aidl/android/hardware/common/NativeHandle.h>
|
|
#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
|
|
|
|
#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
|
|
#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
|
|
#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
|
|
|
|
#include <camera/CameraUtils.h>
|
|
#include <camera_metadata_hidden.h>
|
|
|
|
#include "device3/Camera3OutputUtils.h"
|
|
|
|
#include "system/camera_metadata.h"
|
|
|
|
using namespace android::camera3;
|
|
using namespace android::hardware::camera;
|
|
|
|
namespace android {
|
|
namespace camera3 {
|
|
|
|
template <class BufferStatusType>
|
|
camera_buffer_status_t mapBufferStatus(BufferStatusType status) {
|
|
switch (status) {
|
|
case BufferStatusType::OK: return CAMERA_BUFFER_STATUS_OK;
|
|
case BufferStatusType::ERROR: return CAMERA_BUFFER_STATUS_ERROR;
|
|
}
|
|
return CAMERA_BUFFER_STATUS_ERROR;
|
|
}
|
|
|
|
inline void readBufferFromVec(hardware::hidl_vec<uint8_t> &dst,
|
|
const hardware::hidl_vec<uint8_t> &src) {
|
|
// Not cloning here since that will be done in processCaptureResult whil
|
|
// assigning to CameraMetadata.
|
|
dst.setToExternal(const_cast<uint8_t *>(src.data()), src.size());
|
|
}
|
|
|
|
inline void readBufferFromVec(std::vector<uint8_t> &dst, const std::vector<uint8_t> &src) {
|
|
dst = src;
|
|
}
|
|
|
|
// Reading one camera metadata from result argument via fmq or from the result
|
|
// Assuming the fmq is protected by a lock already
|
|
template <class FmqType, class FmqPayloadType, class MetadataType>
|
|
status_t readOneCameraMetadataLockedT(
|
|
std::unique_ptr<FmqType>& fmq,
|
|
uint64_t fmqResultSize,
|
|
MetadataType& resultMetadata,
|
|
const MetadataType& result) {
|
|
if (fmqResultSize > 0) {
|
|
resultMetadata.resize(fmqResultSize);
|
|
if (fmq == nullptr) {
|
|
return NO_MEMORY; // logged in initialize()
|
|
}
|
|
if (!fmq->read(reinterpret_cast<FmqPayloadType *>(resultMetadata.data()), fmqResultSize)) {
|
|
ALOGE("%s: Cannot read camera metadata from fmq, size = %" PRIu64,
|
|
__FUNCTION__, fmqResultSize);
|
|
return INVALID_OPERATION;
|
|
}
|
|
} else {
|
|
readBufferFromVec(resultMetadata, result);
|
|
}
|
|
|
|
if (resultMetadata.size() != 0) {
|
|
status_t res;
|
|
const camera_metadata_t* metadata =
|
|
reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
|
|
size_t expected_metadata_size = resultMetadata.size();
|
|
if ((res = validate_camera_metadata_structure(metadata, &expected_metadata_size)) != OK) {
|
|
ALOGE("%s: Invalid camera metadata received by camera service from HAL: %s (%d)",
|
|
__FUNCTION__, strerror(-res), res);
|
|
return INVALID_OPERATION;
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
inline bool isHandleNull(const hardware::hidl_handle &handle) {
|
|
return handle == nullptr;
|
|
}
|
|
|
|
inline bool isHandleNull(const aidl::android::hardware::common::NativeHandle &handle) {
|
|
return (handle.fds.size() == 0) && (handle.ints.size() == 0);
|
|
}
|
|
|
|
inline size_t numFdsInHandle(const hardware::hidl_handle &handle) {
|
|
return handle->numFds;
|
|
}
|
|
|
|
inline size_t numFdsInHandle(const aidl::android::hardware::common::NativeHandle &handle) {
|
|
return handle.fds.size();
|
|
}
|
|
|
|
inline int32_t getHandleFirstFd(const hardware::hidl_handle &handle) {
|
|
if (handle->numFds != 1) {
|
|
return -1;
|
|
}
|
|
return handle->data[0];
|
|
}
|
|
|
|
inline int32_t getHandleFirstFd(const aidl::android::hardware::common::NativeHandle &handle) {
|
|
if (handle.fds.size() != 1) {
|
|
return -1;
|
|
}
|
|
return handle.fds[0].get();
|
|
}
|
|
|
|
inline const hardware::hidl_vec<uint8_t>&
|
|
getResultMetadata(const android::hardware::camera::device::V3_2::CameraMetadata &result) {
|
|
return result;
|
|
}
|
|
|
|
inline const std::vector<uint8_t>&
|
|
getResultMetadata(const aidl::android::hardware::camera::device::CameraMetadata &result) {
|
|
return result.metadata;
|
|
}
|
|
|
|
// Fmqpayload type is needed since AIDL generates an fmq of payload type int8_t
|
|
// for a byte fmq vs MetadataType which is uint8_t. For HIDL, the same type is
|
|
// generated for metadata and fmq payload : uint8_t.
|
|
template <class StatesType, class CaptureResultType, class PhysMetadataType, class MetadataType,
|
|
class FmqType, class BufferStatusType, class FmqPayloadType = uint8_t>
|
|
void processOneCaptureResultLockedT(
|
|
StatesType& states,
|
|
const CaptureResultType& result,
|
|
const PhysMetadataType &physicalCameraMetadata) {
|
|
std::unique_ptr<FmqType>& fmq = states.fmq;
|
|
BufferRecordsInterface& bufferRecords = states.bufferRecordsIntf;
|
|
camera_capture_result r;
|
|
status_t res;
|
|
r.frame_number = result.frameNumber;
|
|
|
|
// Read and validate the result metadata.
|
|
MetadataType resultMetadata;
|
|
res = readOneCameraMetadataLockedT<FmqType, FmqPayloadType, MetadataType>(
|
|
fmq, result.fmqResultSize,
|
|
resultMetadata, getResultMetadata(result.result));
|
|
if (res != OK) {
|
|
ALOGE("%s: Frame %d: Failed to read capture result metadata",
|
|
__FUNCTION__, result.frameNumber);
|
|
return;
|
|
}
|
|
r.result = reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
|
|
|
|
// Read and validate physical camera metadata
|
|
size_t physResultCount = physicalCameraMetadata.size();
|
|
std::vector<const char*> physCamIds(physResultCount);
|
|
std::vector<const camera_metadata_t *> phyCamMetadatas(physResultCount);
|
|
std::vector<MetadataType> physResultMetadata;
|
|
physResultMetadata.resize(physResultCount);
|
|
for (size_t i = 0; i < physicalCameraMetadata.size(); i++) {
|
|
res = readOneCameraMetadataLockedT<FmqType, FmqPayloadType, MetadataType>(fmq,
|
|
physicalCameraMetadata[i].fmqMetadataSize,
|
|
physResultMetadata[i], getResultMetadata(physicalCameraMetadata[i].metadata));
|
|
if (res != OK) {
|
|
ALOGE("%s: Frame %d: Failed to read capture result metadata for camera %s",
|
|
__FUNCTION__, result.frameNumber,
|
|
physicalCameraMetadata[i].physicalCameraId.c_str());
|
|
return;
|
|
}
|
|
physCamIds[i] = physicalCameraMetadata[i].physicalCameraId.c_str();
|
|
phyCamMetadatas[i] =
|
|
reinterpret_cast<const camera_metadata_t*>(physResultMetadata[i].data());
|
|
}
|
|
r.num_physcam_metadata = physResultCount;
|
|
r.physcam_ids = physCamIds.data();
|
|
r.physcam_metadata = phyCamMetadatas.data();
|
|
|
|
std::vector<camera_stream_buffer_t> outputBuffers(result.outputBuffers.size());
|
|
std::vector<buffer_handle_t> outputBufferHandles(result.outputBuffers.size());
|
|
for (size_t i = 0; i < result.outputBuffers.size(); i++) {
|
|
auto& bDst = outputBuffers[i];
|
|
const auto &bSrc = result.outputBuffers[i];
|
|
|
|
sp<Camera3StreamInterface> stream = states.outputStreams.get(bSrc.streamId);
|
|
if (stream == nullptr) {
|
|
ALOGE("%s: Frame %d: Buffer %zu: Invalid output stream id %d",
|
|
__FUNCTION__, result.frameNumber, i, bSrc.streamId);
|
|
return;
|
|
}
|
|
bDst.stream = stream->asHalStream();
|
|
|
|
bool noBufferReturned = false;
|
|
buffer_handle_t *buffer = nullptr;
|
|
if (states.useHalBufManager) {
|
|
// This is suspicious most of the time but can be correct during flush where HAL
|
|
// has to return capture result before a buffer is requested
|
|
if (bSrc.bufferId == BUFFER_ID_NO_BUFFER) {
|
|
if (bSrc.status == BufferStatusType::OK) {
|
|
ALOGE("%s: Frame %d: Buffer %zu: No bufferId for stream %d",
|
|
__FUNCTION__, result.frameNumber, i, bSrc.streamId);
|
|
// Still proceeds so other buffers can be returned
|
|
}
|
|
noBufferReturned = true;
|
|
}
|
|
if (noBufferReturned) {
|
|
res = OK;
|
|
} else {
|
|
res = bufferRecords.popInflightRequestBuffer(bSrc.bufferId, &buffer);
|
|
}
|
|
} else {
|
|
res = bufferRecords.popInflightBuffer(result.frameNumber, bSrc.streamId, &buffer);
|
|
}
|
|
|
|
if (res != OK) {
|
|
ALOGE("%s: Frame %d: Buffer %zu: No in-flight buffer for stream %d",
|
|
__FUNCTION__, result.frameNumber, i, bSrc.streamId);
|
|
return;
|
|
}
|
|
|
|
bDst.buffer = buffer;
|
|
bDst.status = mapBufferStatus<BufferStatusType>(bSrc.status);
|
|
bDst.acquire_fence = -1;
|
|
if (isHandleNull(bSrc.releaseFence)) {
|
|
bDst.release_fence = -1;
|
|
} else if (numFdsInHandle(bSrc.releaseFence) == 1) {
|
|
if (noBufferReturned) {
|
|
ALOGE("%s: got releaseFence without output buffer!", __FUNCTION__);
|
|
}
|
|
bDst.release_fence = dup(getHandleFirstFd(bSrc.releaseFence));
|
|
} else {
|
|
ALOGE("%s: Frame %d: Invalid release fence for buffer %zu, fd count is %d, not 1",
|
|
__FUNCTION__, result.frameNumber, i, (int)numFdsInHandle(bSrc.releaseFence));
|
|
return;
|
|
}
|
|
}
|
|
r.num_output_buffers = outputBuffers.size();
|
|
r.output_buffers = outputBuffers.data();
|
|
|
|
camera_stream_buffer_t inputBuffer;
|
|
if (result.inputBuffer.streamId == -1) {
|
|
r.input_buffer = nullptr;
|
|
} else {
|
|
if (states.inputStream->getId() != result.inputBuffer.streamId) {
|
|
ALOGE("%s: Frame %d: Invalid input stream id %d", __FUNCTION__,
|
|
result.frameNumber, result.inputBuffer.streamId);
|
|
return;
|
|
}
|
|
inputBuffer.stream = states.inputStream->asHalStream();
|
|
buffer_handle_t *buffer;
|
|
res = bufferRecords.popInflightBuffer(result.frameNumber, result.inputBuffer.streamId,
|
|
&buffer);
|
|
if (res != OK) {
|
|
ALOGE("%s: Frame %d: Input buffer: No in-flight buffer for stream %d",
|
|
__FUNCTION__, result.frameNumber, result.inputBuffer.streamId);
|
|
return;
|
|
}
|
|
inputBuffer.buffer = buffer;
|
|
inputBuffer.status = mapBufferStatus<BufferStatusType>(result.inputBuffer.status);
|
|
inputBuffer.acquire_fence = -1;
|
|
if (isHandleNull(result.inputBuffer.releaseFence)) {
|
|
inputBuffer.release_fence = -1;
|
|
} else if (numFdsInHandle(result.inputBuffer.releaseFence) == 1) {
|
|
inputBuffer.release_fence = dup(getHandleFirstFd(result.inputBuffer.releaseFence));
|
|
} else {
|
|
ALOGE("%s: Frame %d: Invalid release fence for input buffer, fd count is %d, not 1",
|
|
__FUNCTION__, result.frameNumber,
|
|
(int)numFdsInHandle(result.inputBuffer.releaseFence));
|
|
return;
|
|
}
|
|
r.input_buffer = &inputBuffer;
|
|
}
|
|
|
|
r.partial_result = result.partialResult;
|
|
|
|
processCaptureResult(states, &r);
|
|
}
|
|
|
|
template <class VecStreamBufferType>
|
|
void returnStreamBuffersT(ReturnBufferStates& states,
|
|
const VecStreamBufferType& buffers) {
|
|
if (!states.useHalBufManager) {
|
|
ALOGE("%s: Camera %s does not support HAL buffer managerment",
|
|
__FUNCTION__, states.cameraId.string());
|
|
return;
|
|
}
|
|
|
|
for (const auto& buf : buffers) {
|
|
if (buf.bufferId == BUFFER_ID_NO_BUFFER) {
|
|
ALOGE("%s: cannot return a buffer without bufferId", __FUNCTION__);
|
|
continue;
|
|
}
|
|
|
|
buffer_handle_t* buffer;
|
|
status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(buf.bufferId, &buffer);
|
|
|
|
if (res != OK) {
|
|
ALOGE("%s: cannot find in-flight buffer %" PRIu64 " for stream %d",
|
|
__FUNCTION__, buf.bufferId, buf.streamId);
|
|
continue;
|
|
}
|
|
|
|
camera_stream_buffer_t streamBuffer;
|
|
streamBuffer.buffer = buffer;
|
|
streamBuffer.status = CAMERA_BUFFER_STATUS_ERROR;
|
|
streamBuffer.acquire_fence = -1;
|
|
streamBuffer.release_fence = -1;
|
|
|
|
if (isHandleNull(buf.releaseFence)) {
|
|
streamBuffer.release_fence = -1;
|
|
} else if (numFdsInHandle(buf.releaseFence) == 1) {
|
|
streamBuffer.release_fence = dup(getHandleFirstFd(buf.releaseFence));
|
|
} else {
|
|
ALOGE("%s: Invalid release fence, fd count is %d, not 1",
|
|
__FUNCTION__, (int)numFdsInHandle(buf.releaseFence));
|
|
continue;
|
|
}
|
|
|
|
sp<Camera3StreamInterface> stream = states.outputStreams.get(buf.streamId);
|
|
if (stream == nullptr) {
|
|
ALOGE("%s: Output stream id %d not found!", __FUNCTION__, buf.streamId);
|
|
continue;
|
|
}
|
|
streamBuffer.stream = stream->asHalStream();
|
|
returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
|
|
&streamBuffer, /*size*/1, /*timestamp*/ 0, /*readoutTimestamp*/0,
|
|
/*requested*/false, /*requestTimeNs*/0, states.sessionStatsBuilder);
|
|
}
|
|
}
|
|
|
|
} // camera3
|
|
} // namespace android
|
|
|
|
#endif
|