345 lines
15 KiB
C++
345 lines
15 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.
|
|
*/
|
|
|
|
#define LOG_TAG "AidlCamera3-OutputUtils"
|
|
#define ATRACE_TAG ATRACE_TAG_CAMERA
|
|
//#define LOG_NDEBUG 0
|
|
//#define LOG_NNDEBUG 0 // Per-frame verbose logging
|
|
|
|
#ifdef LOG_NNDEBUG
|
|
#define ALOGVV(...) ALOGV(__VA_ARGS__)
|
|
#else
|
|
#define ALOGVV(...) ((void)0)
|
|
#endif
|
|
|
|
// Convenience macros for transitioning to the error state
|
|
#define SET_ERR(fmt, ...) states.setErrIntf.setErrorState( \
|
|
"%s: " fmt, __FUNCTION__, \
|
|
##__VA_ARGS__)
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <utils/Log.h>
|
|
#include <utils/SortedVector.h>
|
|
#include <utils/Trace.h>
|
|
|
|
#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
|
|
#include <aidlcommonsupport/NativeHandle.h>
|
|
|
|
#include <camera/CameraUtils.h>
|
|
#include <camera_metadata_hidden.h>
|
|
|
|
#include "device3/aidl/AidlCamera3OutputUtils.h"
|
|
#include "device3/Camera3OutputUtilsTemplated.h"
|
|
|
|
#include "system/camera_metadata.h"
|
|
|
|
using namespace android::camera3;
|
|
using namespace android::hardware::camera;
|
|
|
|
namespace android {
|
|
namespace camera3 {
|
|
|
|
void processOneCaptureResultLocked(
|
|
AidlCaptureOutputStates& states,
|
|
const aidl::android::hardware::camera::device::CaptureResult& result,
|
|
const std::vector<aidl::android::hardware::camera::device::PhysicalCameraMetadata>
|
|
&physicalCameraMetadata) {
|
|
processOneCaptureResultLockedT<AidlCaptureOutputStates,
|
|
aidl::android::hardware::camera::device::CaptureResult,
|
|
std::vector<aidl::android::hardware::camera::device::PhysicalCameraMetadata>,
|
|
std::vector<uint8_t>, AidlResultMetadataQueue,
|
|
aidl::android::hardware::camera::device::BufferStatus, int8_t>(states, result,
|
|
physicalCameraMetadata);
|
|
}
|
|
|
|
void notify(CaptureOutputStates& states,
|
|
const aidl::android::hardware::camera::device::NotifyMsg& msg) {
|
|
|
|
using ErrorCode = aidl::android::hardware::camera::device::ErrorCode;
|
|
using Tag = aidl::android::hardware::camera::device::NotifyMsg::Tag;
|
|
|
|
ATRACE_CALL();
|
|
camera_notify_msg m;
|
|
|
|
switch (msg.getTag()) {
|
|
case Tag::error:
|
|
m.type = CAMERA_MSG_ERROR;
|
|
m.message.error.frame_number = msg.get<Tag::error>().frameNumber;
|
|
if (msg.get<Tag::error>().errorStreamId >= 0) {
|
|
sp<Camera3StreamInterface> stream =
|
|
states.outputStreams.get(msg.get<Tag::error>().errorStreamId);
|
|
if (stream == nullptr) {
|
|
ALOGE("%s: Frame %d: Invalid error stream id %d", __FUNCTION__,
|
|
m.message.error.frame_number, msg.get<Tag::error>().errorStreamId);
|
|
return;
|
|
}
|
|
m.message.error.error_stream = stream->asHalStream();
|
|
} else {
|
|
m.message.error.error_stream = nullptr;
|
|
}
|
|
switch (msg.get<Tag::error>().errorCode) {
|
|
case ErrorCode::ERROR_DEVICE:
|
|
m.message.error.error_code = CAMERA_MSG_ERROR_DEVICE;
|
|
break;
|
|
case ErrorCode::ERROR_REQUEST:
|
|
m.message.error.error_code = CAMERA_MSG_ERROR_REQUEST;
|
|
break;
|
|
case ErrorCode::ERROR_RESULT:
|
|
m.message.error.error_code = CAMERA_MSG_ERROR_RESULT;
|
|
break;
|
|
case ErrorCode::ERROR_BUFFER:
|
|
m.message.error.error_code = CAMERA_MSG_ERROR_BUFFER;
|
|
break;
|
|
}
|
|
break;
|
|
case Tag::shutter:
|
|
m.type = CAMERA_MSG_SHUTTER;
|
|
m.message.shutter.frame_number = msg.get<Tag::shutter>().frameNumber;
|
|
m.message.shutter.timestamp = msg.get<Tag::shutter>().timestamp;
|
|
m.message.shutter.readout_timestamp_valid = true;
|
|
m.message.shutter.readout_timestamp = msg.get<Tag::shutter>().readoutTimestamp;
|
|
break;
|
|
}
|
|
notify(states, &m);
|
|
}
|
|
|
|
|
|
// The buffers requested through this call are not tied to any CaptureRequest in
|
|
// particular. They may used by the hal for a particular frame's output buffer
|
|
// or for its internal use as well. In the case that the hal does use any buffer
|
|
// from the requested list here, for a particular frame's output buffer, the
|
|
// buffer will be returned with the processCaptureResult call corresponding to
|
|
// the frame. The other buffers will be returned through returnStreamBuffers.
|
|
// The buffers returned via returnStreamBuffers will not have a valid
|
|
// timestamp(0) and will be dropped by the bufferqueue.
|
|
void requestStreamBuffers(RequestBufferStates& states,
|
|
const std::vector<aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
|
|
std::vector<::aidl::android::hardware::camera::device::StreamBufferRet>* outBuffers,
|
|
::aidl::android::hardware::camera::device::BufferRequestStatus* status) {
|
|
using aidl::android::hardware::camera::device::BufferStatus;
|
|
using aidl::android::hardware::camera::device::StreamBuffer;
|
|
using aidl::android::hardware::camera::device::BufferRequestStatus;
|
|
using aidl::android::hardware::camera::device::StreamBufferRet;
|
|
using aidl::android::hardware::camera::device::StreamBufferRequestError;
|
|
using Tag = aidl::android::hardware::camera::device::StreamBuffersVal::Tag;
|
|
if (outBuffers == nullptr || status == nullptr) {
|
|
ALOGE("%s outBuffers / buffer status nullptr", __FUNCTION__);
|
|
return;
|
|
}
|
|
std::lock_guard<std::mutex> lock(states.reqBufferLock);
|
|
std::vector<StreamBufferRet> bufRets;
|
|
outBuffers->clear();
|
|
if (!states.useHalBufManager) {
|
|
ALOGE("%s: Camera %s does not support HAL buffer management",
|
|
__FUNCTION__, states.cameraId.string());
|
|
*status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
|
|
return;
|
|
}
|
|
|
|
SortedVector<int32_t> streamIds;
|
|
ssize_t sz = streamIds.setCapacity(bufReqs.size());
|
|
if (sz < 0 || static_cast<size_t>(sz) != bufReqs.size()) {
|
|
ALOGE("%s: failed to allocate memory for %zu buffer requests",
|
|
__FUNCTION__, bufReqs.size());
|
|
*status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
|
|
return;
|
|
}
|
|
|
|
if (bufReqs.size() > states.outputStreams.size()) {
|
|
ALOGE("%s: too many buffer requests (%zu > # of output streams %zu)",
|
|
__FUNCTION__, bufReqs.size(), states.outputStreams.size());
|
|
*status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
|
|
return;
|
|
}
|
|
|
|
// Check for repeated streamId
|
|
for (const auto& bufReq : bufReqs) {
|
|
if (streamIds.indexOf(bufReq.streamId) != NAME_NOT_FOUND) {
|
|
ALOGE("%s: Stream %d appear multiple times in buffer requests",
|
|
__FUNCTION__, bufReq.streamId);
|
|
*status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
|
|
return;
|
|
}
|
|
streamIds.add(bufReq.streamId);
|
|
}
|
|
|
|
if (!states.reqBufferIntf.startRequestBuffer()) {
|
|
ALOGE("%s: request buffer disallowed while camera service is configuring",
|
|
__FUNCTION__);
|
|
*status = BufferRequestStatus::FAILED_CONFIGURING;
|
|
return;
|
|
}
|
|
|
|
bufRets.resize(bufReqs.size());
|
|
|
|
bool allReqsSucceeds = true;
|
|
bool oneReqSucceeds = false;
|
|
for (size_t i = 0; i < bufReqs.size(); i++) {
|
|
const auto& bufReq = bufReqs[i];
|
|
auto& bufRet = bufRets[i];
|
|
int32_t streamId = bufReq.streamId;
|
|
sp<Camera3OutputStreamInterface> outputStream = states.outputStreams.get(streamId);
|
|
if (outputStream == nullptr) {
|
|
ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId);
|
|
std::vector<StreamBufferRet> emptyBufRets;
|
|
*status = BufferRequestStatus::FAILED_CONFIGURING;
|
|
states.reqBufferIntf.endRequestBuffer();
|
|
return;
|
|
}
|
|
|
|
bufRet.streamId = streamId;
|
|
if (outputStream->isAbandoned()) {
|
|
bufRet.val.set<Tag::error>(StreamBufferRequestError::STREAM_DISCONNECTED);
|
|
allReqsSucceeds = false;
|
|
continue;
|
|
}
|
|
|
|
size_t handOutBufferCount = outputStream->getOutstandingBuffersCount();
|
|
uint32_t numBuffersRequested = bufReq.numBuffersRequested;
|
|
size_t totalHandout = handOutBufferCount + numBuffersRequested;
|
|
uint32_t maxBuffers = outputStream->asHalStream()->max_buffers;
|
|
if (totalHandout > maxBuffers) {
|
|
// Not able to allocate enough buffer. Exit early for this stream
|
|
ALOGE("%s: request too much buffers for stream %d: at HAL: %zu + requesting: %d"
|
|
" > max: %d", __FUNCTION__, streamId, handOutBufferCount,
|
|
numBuffersRequested, maxBuffers);
|
|
bufRet.val.set<Tag::error>(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
|
|
allReqsSucceeds = false;
|
|
continue;
|
|
}
|
|
|
|
std::vector<StreamBuffer> tmpRetBuffers(numBuffersRequested);
|
|
bool currentReqSucceeds = true;
|
|
std::vector<camera_stream_buffer_t> streamBuffers(numBuffersRequested);
|
|
std::vector<buffer_handle_t> newBuffers;
|
|
size_t numAllocatedBuffers = 0;
|
|
size_t numPushedInflightBuffers = 0;
|
|
for (size_t b = 0; b < numBuffersRequested; b++) {
|
|
camera_stream_buffer_t& sb = streamBuffers[b];
|
|
// Since this method can run concurrently with request thread
|
|
// We need to update the wait duration everytime we call getbuffer
|
|
nsecs_t waitDuration = states.reqBufferIntf.getWaitDuration();
|
|
status_t res = outputStream->getBuffer(&sb, waitDuration);
|
|
if (res != OK) {
|
|
if (res == NO_INIT || res == DEAD_OBJECT) {
|
|
ALOGV("%s: Can't get output buffer for stream %d: %s (%d)",
|
|
__FUNCTION__, streamId, strerror(-res), res);
|
|
bufRet.val.set<Tag::error>(StreamBufferRequestError::STREAM_DISCONNECTED);
|
|
states.sessionStatsBuilder.stopCounter(streamId);
|
|
} else {
|
|
ALOGE("%s: Can't get output buffer for stream %d: %s (%d)",
|
|
__FUNCTION__, streamId, strerror(-res), res);
|
|
if (res == TIMED_OUT || res == NO_MEMORY) {
|
|
bufRet.val.set<Tag::error>(StreamBufferRequestError::NO_BUFFER_AVAILABLE);
|
|
} else if (res == INVALID_OPERATION) {
|
|
bufRet.val.set<Tag::error>(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
|
|
} else {
|
|
bufRet.val.set<Tag::error>(StreamBufferRequestError::UNKNOWN_ERROR);
|
|
}
|
|
}
|
|
currentReqSucceeds = false;
|
|
break;
|
|
}
|
|
numAllocatedBuffers++;
|
|
|
|
buffer_handle_t *buffer = sb.buffer;
|
|
auto pair = states.bufferRecordsIntf.getBufferId(*buffer, streamId);
|
|
bool isNewBuffer = pair.first;
|
|
uint64_t bufferId = pair.second;
|
|
StreamBuffer& hBuf = tmpRetBuffers[b];
|
|
|
|
hBuf.streamId = streamId;
|
|
hBuf.bufferId = bufferId;
|
|
|
|
hBuf.buffer = (isNewBuffer) ? camera3::dupToAidlIfNotNull(*buffer) :
|
|
aidl::android::hardware::common::NativeHandle();
|
|
hBuf.status = BufferStatus::OK;
|
|
hBuf.releaseFence = aidl::android::hardware::common::NativeHandle();
|
|
if (isNewBuffer) {
|
|
newBuffers.push_back(*buffer);
|
|
}
|
|
|
|
native_handle_t *acquireFence = nullptr;
|
|
if (sb.acquire_fence != -1) {
|
|
acquireFence = native_handle_create(1,0);
|
|
acquireFence->data[0] = sb.acquire_fence;
|
|
}
|
|
//makeToAidl passes ownership to aidl NativeHandle made. Ownership
|
|
//is passed : see system/window.h : dequeueBuffer
|
|
hBuf.acquireFence = makeToAidlIfNotNull(acquireFence);
|
|
if (acquireFence != nullptr) {
|
|
native_handle_delete(acquireFence);
|
|
}
|
|
hBuf.releaseFence = aidl::android::hardware::common::NativeHandle();
|
|
|
|
res = states.bufferRecordsIntf.pushInflightRequestBuffer(bufferId, buffer, streamId);
|
|
if (res != OK) {
|
|
ALOGE("%s: Can't get register request buffers for stream %d: %s (%d)",
|
|
__FUNCTION__, streamId, strerror(-res), res);
|
|
bufRet.val.set<Tag::error>(StreamBufferRequestError::UNKNOWN_ERROR);
|
|
currentReqSucceeds = false;
|
|
break;
|
|
}
|
|
numPushedInflightBuffers++;
|
|
}
|
|
if (currentReqSucceeds) {
|
|
bufRet.val.set<Tag::buffers>(std::move(tmpRetBuffers));
|
|
oneReqSucceeds = true;
|
|
} else {
|
|
allReqsSucceeds = false;
|
|
for (size_t b = 0; b < numPushedInflightBuffers; b++) {
|
|
StreamBuffer& hBuf = tmpRetBuffers[b];
|
|
buffer_handle_t* buffer;
|
|
status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(
|
|
hBuf.bufferId, &buffer);
|
|
if (res != OK) {
|
|
SET_ERR("%s: popInflightRequestBuffer failed for stream %d: %s (%d)",
|
|
__FUNCTION__, streamId, strerror(-res), res);
|
|
}
|
|
}
|
|
for (size_t b = 0; b < numAllocatedBuffers; b++) {
|
|
camera_stream_buffer_t& sb = streamBuffers[b];
|
|
sb.acquire_fence = -1;
|
|
sb.status = CAMERA_BUFFER_STATUS_ERROR;
|
|
}
|
|
returnOutputBuffers(states.useHalBufManager, nullptr,
|
|
streamBuffers.data(), numAllocatedBuffers, 0,
|
|
0, false,
|
|
0, states.sessionStatsBuilder);
|
|
for (auto buf : newBuffers) {
|
|
states.bufferRecordsIntf.removeOneBufferCache(streamId, buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
*status = allReqsSucceeds ? BufferRequestStatus::OK :
|
|
oneReqSucceeds ? BufferRequestStatus::FAILED_PARTIAL :
|
|
BufferRequestStatus::FAILED_UNKNOWN,
|
|
// Transfer ownership of buffer fds to outBuffers
|
|
*outBuffers = std::move(bufRets);
|
|
|
|
states.reqBufferIntf.endRequestBuffer();
|
|
}
|
|
|
|
void returnStreamBuffers(ReturnBufferStates& states,
|
|
const std::vector<aidl::android::hardware::camera::device::StreamBuffer>& buffers) {
|
|
returnStreamBuffersT(states, buffers);
|
|
}
|
|
|
|
} // camera3
|
|
} // namespace android
|