/* * 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 #include #include #include #include #include #include #include #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 &physicalCameraMetadata) { processOneCaptureResultLockedT, std::vector, 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().frameNumber; if (msg.get().errorStreamId >= 0) { sp stream = states.outputStreams.get(msg.get().errorStreamId); if (stream == nullptr) { ALOGE("%s: Frame %d: Invalid error stream id %d", __FUNCTION__, m.message.error.frame_number, msg.get().errorStreamId); return; } m.message.error.error_stream = stream->asHalStream(); } else { m.message.error.error_stream = nullptr; } switch (msg.get().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().frameNumber; m.message.shutter.timestamp = msg.get().timestamp; m.message.shutter.readout_timestamp_valid = true; m.message.shutter.readout_timestamp = msg.get().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& 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 lock(states.reqBufferLock); std::vector 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 streamIds; ssize_t sz = streamIds.setCapacity(bufReqs.size()); if (sz < 0 || static_cast(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 outputStream = states.outputStreams.get(streamId); if (outputStream == nullptr) { ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId); std::vector emptyBufRets; *status = BufferRequestStatus::FAILED_CONFIGURING; states.reqBufferIntf.endRequestBuffer(); return; } bufRet.streamId = streamId; if (outputStream->isAbandoned()) { bufRet.val.set(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(StreamBufferRequestError::MAX_BUFFER_EXCEEDED); allReqsSucceeds = false; continue; } std::vector tmpRetBuffers(numBuffersRequested); bool currentReqSucceeds = true; std::vector streamBuffers(numBuffersRequested); std::vector 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(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(StreamBufferRequestError::NO_BUFFER_AVAILABLE); } else if (res == INVALID_OPERATION) { bufRet.val.set(StreamBufferRequestError::MAX_BUFFER_EXCEEDED); } else { bufRet.val.set(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(StreamBufferRequestError::UNKNOWN_ERROR); currentReqSucceeds = false; break; } numPushedInflightBuffers++; } if (currentReqSucceeds) { bufRet.val.set(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& buffers) { returnStreamBuffersT(states, buffers); } } // camera3 } // namespace android