summaryrefslogtreecommitdiff
path: root/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
diff options
context:
space:
mode:
authorSteven Laver <lavers@google.com>2020-02-04 22:57:22 -0800
committerSteven Laver <lavers@google.com>2020-02-06 14:27:42 -0800
commit89ec9480cf4430b6728b16396a408c1aa26f19a9 (patch)
treef9a888e63588b25c457d8871f6fbb6b673044f1a /camera/device/3.6/default/ExternalCameraDeviceSession.cpp
parent4e64db5a184f0734778df5e1c12d32f702220b35 (diff)
parent146a5a28331209aa145c0af2f883b7e023ce4800 (diff)
Merge RP1A.200204.001
Change-Id: Icdc452e8cf70e432759c112a5b5b12b61e40f0bc
Diffstat (limited to 'camera/device/3.6/default/ExternalCameraDeviceSession.cpp')
-rw-r--r--camera/device/3.6/default/ExternalCameraDeviceSession.cpp357
1 files changed, 357 insertions, 0 deletions
diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
new file mode 100644
index 0000000000..0cc81bbe9e
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2020 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 "ExtCamDevSsn@3.6"
+#include <android/log.h>
+
+#include <utils/Trace.h>
+#include "ExternalCameraDeviceSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+ExternalCameraDeviceSession::ExternalCameraDeviceSession(
+ const sp<V3_2::ICameraDeviceCallback>& callback,
+ const ExternalCameraConfig& cfg,
+ const std::vector<SupportedV4L2Format>& sortedFormats,
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ unique_fd v4l2Fd) :
+ V3_5::implementation::ExternalCameraDeviceSession(
+ callback, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)) {
+}
+
+ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {}
+
+
+Return<void> ExternalCameraDeviceSession::configureStreams_3_6(
+ const StreamConfiguration& requestedConfiguration,
+ ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb) {
+ V3_2::StreamConfiguration config_v32;
+ V3_3::HalStreamConfiguration outStreams_v33;
+ V3_6::HalStreamConfiguration outStreams;
+ const V3_4::StreamConfiguration& requestedConfiguration_3_4 = requestedConfiguration.v3_4;
+ Mutex::Autolock _il(mInterfaceLock);
+
+ config_v32.operationMode = requestedConfiguration_3_4.operationMode;
+ config_v32.streams.resize(requestedConfiguration_3_4.streams.size());
+ uint32_t blobBufferSize = 0;
+ int numStallStream = 0;
+ for (size_t i = 0; i < config_v32.streams.size(); i++) {
+ config_v32.streams[i] = requestedConfiguration_3_4.streams[i].v3_2;
+ if (config_v32.streams[i].format == PixelFormat::BLOB) {
+ blobBufferSize = requestedConfiguration_3_4.streams[i].bufferSize;
+ numStallStream++;
+ }
+ }
+
+ // Fail early if there are multiple BLOB streams
+ if (numStallStream > kMaxStallStream) {
+ ALOGE("%s: too many stall streams (expect <= %d, got %d)", __FUNCTION__,
+ kMaxStallStream, numStallStream);
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, outStreams);
+ return Void();
+ }
+
+ Status status = configureStreams(config_v32, &outStreams_v33, blobBufferSize);
+
+ fillOutputStream3_6(outStreams_v33, &outStreams);
+
+ _hidl_cb(status, outStreams);
+ return Void();
+}
+
+Return<void> ExternalCameraDeviceSession::switchToOffline(
+ const hidl_vec<int32_t>& streamsToKeep,
+ ICameraDeviceSession::switchToOffline_cb _hidl_cb) {
+ std::vector<NotifyMsg> msgs;
+ std::vector<CaptureResult> results;
+ CameraOfflineSessionInfo info;
+ sp<ICameraOfflineSession> session;
+
+ Status st = switchToOffline(streamsToKeep, &msgs, &results, &info, &session);
+
+ mCallback->notify(msgs);
+ hidl_vec<CaptureResult> hidlResults(std::move(results));
+ invokeProcessCaptureResultCallback(hidlResults, /* tryWriteFmq */true);
+ V3_4::implementation::freeReleaseFences(hidlResults);
+
+ _hidl_cb(st, info, session);
+ return Void();
+}
+
+void ExternalCameraDeviceSession::fillOutputStream3_6(
+ const V3_3::HalStreamConfiguration& outStreams_v33,
+ /*out*/V3_6::HalStreamConfiguration* outStreams_v36) {
+ if (outStreams_v36 == nullptr) {
+ ALOGE("%s: outStreams_v36 must not be null!", __FUNCTION__);
+ return;
+ }
+ Mutex::Autolock _l(mLock);
+ outStreams_v36->streams.resize(outStreams_v33.streams.size());
+ for (size_t i = 0; i < outStreams_v36->streams.size(); i++) {
+ outStreams_v36->streams[i].v3_4.v3_3 = outStreams_v33.streams[i];
+ outStreams_v36->streams[i].supportOffline =
+ supportOfflineLocked(outStreams_v33.streams[i].v3_2.id);
+ }
+}
+
+bool ExternalCameraDeviceSession::supportOfflineLocked(int32_t streamId) {
+ const Stream& stream = mStreamMap[streamId];
+ if (stream.format == PixelFormat::BLOB &&
+ stream.dataSpace == static_cast<int32_t>(Dataspace::V0_JFIF)) {
+ return true;
+ }
+ // TODO: support YUV output stream?
+ return false;
+}
+
+bool ExternalCameraDeviceSession::canDropRequest(const hidl_vec<int32_t>& offlineStreams,
+ std::shared_ptr<V3_4::implementation::HalRequest> halReq) {
+ for (const auto& buffer : halReq->buffers) {
+ for (auto offlineStreamId : offlineStreams) {
+ if (buffer.streamId == offlineStreamId) {
+ return false;
+ }
+ }
+ }
+ // Only drop a request completely if it has no offline output
+ return true;
+}
+
+void ExternalCameraDeviceSession::fillOfflineSessionInfo(const hidl_vec<int32_t>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*out*/CameraOfflineSessionInfo* info) {
+ if (info == nullptr) {
+ ALOGE("%s: output info must not be null!", __FUNCTION__);
+ return;
+ }
+
+ info->offlineStreams.resize(offlineStreams.size());
+ info->offlineRequests.resize(offlineReqs.size());
+
+ std::unordered_map<int32_t, uint32_t> outstandingBufs(offlineStreams.size());
+ for (const auto streamId : offlineStreams) {
+ outstandingBufs.insert({streamId, 0});
+ }
+ // Fill in offline reqs and count outstanding buffers
+ for (size_t i = 0; i < offlineReqs.size(); i++) {
+ info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber;
+ info->offlineRequests[i].pendingStreams.resize(offlineReqs[i]->buffers.size());
+ for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) {
+ int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId;
+ info->offlineRequests[i].pendingStreams[bIdx] = streamId;
+ outstandingBufs[streamId]++;
+ }
+ }
+
+ for (size_t i = 0; i < offlineStreams.size(); i++) {
+ int32_t streamId = offlineStreams[i];
+ info->offlineStreams[i].id = streamId;
+ info->offlineStreams[i].numOutstandingBuffers = outstandingBufs[streamId];
+ const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId);
+ info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size());
+ size_t bIdx = 0;
+ for (const auto& pair : bufIdMap) {
+ // Fill in bufferId
+ info->offlineStreams[i].circulatingBufferIds[bIdx++] = pair.first;
+ }
+
+ }
+}
+
+Status ExternalCameraDeviceSession::switchToOffline(const hidl_vec<int32_t>& offlineStreams,
+ /*out*/std::vector<NotifyMsg>* msgs,
+ /*out*/std::vector<CaptureResult>* results,
+ /*out*/CameraOfflineSessionInfo* info,
+ /*out*/sp<ICameraOfflineSession>* session) {
+ ATRACE_CALL();
+ if (offlineStreams.size() > 1) {
+ ALOGE("%s: more than one offline stream is not supported", __FUNCTION__);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) {
+ ALOGE("%s: output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__,
+ msgs, results, info, session);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ msgs->clear();
+ results->clear();
+
+ Mutex::Autolock _il(mInterfaceLock);
+ Status status = initStatus();
+ if (status != Status::OK) {
+ return status;
+ }
+
+ Mutex::Autolock _l(mLock);
+ for (auto streamId : offlineStreams) {
+ if (!supportOfflineLocked(streamId)) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ }
+
+ // pause output thread and get all remaining inflight requests
+ auto remainingReqs = mOutputThread->switchToOffline();
+ std::vector<std::shared_ptr<V3_4::implementation::HalRequest>> halReqs;
+
+ // Send out buffer/request error for remaining requests and filter requests
+ // to be handled in offline mode
+ for (auto& halReq : remainingReqs) {
+ bool dropReq = canDropRequest(offlineStreams, halReq);
+ if (dropReq) {
+ // Request is dropped completely. Just send request error and
+ // there is no need to send the request to offline session
+ processCaptureRequestError(halReq, msgs, results);
+ continue;
+ }
+
+ // All requests reach here must have at least one offline stream output
+ NotifyMsg shutter;
+ shutter.type = MsgType::SHUTTER;
+ shutter.msg.shutter.frameNumber = halReq->frameNumber;
+ shutter.msg.shutter.timestamp = halReq->shutterTs;
+ msgs->push_back(shutter);
+
+ std::vector<V3_4::implementation::HalStreamBuffer> offlineBuffers;
+ for (const auto& buffer : halReq->buffers) {
+ bool dropBuffer = true;
+ for (auto offlineStreamId : offlineStreams) {
+ if (buffer.streamId == offlineStreamId) {
+ dropBuffer = false;
+ break;
+ }
+ }
+ if (dropBuffer) {
+ NotifyMsg error;
+ error.type = MsgType::ERROR;
+ error.msg.error.frameNumber = halReq->frameNumber;
+ error.msg.error.errorStreamId = buffer.streamId;
+ error.msg.error.errorCode = ErrorCode::ERROR_BUFFER;
+ msgs->push_back(error);
+
+ CaptureResult result;
+ result.frameNumber = halReq->frameNumber;
+ result.partialResult = 0; // buffer only result
+ result.inputBuffer.streamId = -1;
+ result.outputBuffers.resize(1);
+ result.outputBuffers[0].streamId = buffer.streamId;
+ result.outputBuffers[0].bufferId = buffer.bufferId;
+ result.outputBuffers[0].status = BufferStatus::ERROR;
+ if (buffer.acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = buffer.acquireFence;
+ result.outputBuffers[0].releaseFence.setTo(handle, /*shouldOwn*/false);
+ }
+ results->push_back(result);
+ } else {
+ offlineBuffers.push_back(buffer);
+ }
+ }
+ halReq->buffers = offlineBuffers;
+ halReqs.push_back(halReq);
+ }
+
+ // convert hal requests to offline request
+ std::deque<std::shared_ptr<HalRequest>> offlineReqs(halReqs.size());
+ for (auto& v4lReq : halReqs) {
+ std::shared_ptr<HalRequest> halReq = std::make_shared<HalRequest>();
+ halReq->frameNumber = v4lReq->frameNumber;
+ halReq->setting = v4lReq->setting;
+ halReq->shutterTs = v4lReq->shutterTs;
+ halReq->buffers = v4lReq->buffers;
+ sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+ static_cast<V3_4::implementation::V4L2Frame*>(v4lReq->frameIn.get());
+ halReq->frameIn = new AllocatedV4L2Frame(v4l2Frame);
+ offlineReqs.push_back(halReq);
+ // enqueue V4L2 frame
+ enqueueV4l2Frame(v4l2Frame);
+ }
+
+ // Collect buffer caches/streams
+ hidl_vec<Stream> streamInfos;
+ streamInfos.resize(offlineStreams.size());
+ std::map<int, CirculatingBuffers> circulatingBuffers;
+ {
+ Mutex::Autolock _l(mCbsLock);
+ size_t idx = 0;
+ for(auto streamId : offlineStreams) {
+ circulatingBuffers[streamId] = mCirculatingBuffers.at(streamId);
+ mCirculatingBuffers.erase(streamId);
+ streamInfos[idx++] = mStreamMap.at(streamId);
+ mStreamMap.erase(streamId);
+ }
+ }
+
+ fillOfflineSessionInfo(offlineStreams, offlineReqs, circulatingBuffers, info);
+
+ // create the offline session object
+ bool afTrigger;
+ {
+ std::lock_guard<std::mutex> lk(mAfTriggerLock);
+ afTrigger = mAfTrigger;
+ }
+ sp<ExternalCameraOfflineSession> sessionImpl = new ExternalCameraOfflineSession(
+ mCroppingType, mCameraCharacteristics, mCameraId,
+ mExifMake, mExifModel, mBlobBufferSize, afTrigger,
+ streamInfos, offlineReqs, circulatingBuffers);
+
+ bool initFailed = sessionImpl->initialize();
+ if (initFailed) {
+ ALOGE("%s: offline session initialize failed!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+
+ // cleanup stream and buffer caches
+ {
+ Mutex::Autolock _l(mCbsLock);
+ for(auto pair : mStreamMap) {
+ cleanupBuffersLocked(/*Stream ID*/pair.first);
+ }
+ mCirculatingBuffers.clear();
+ }
+ mStreamMap.clear();
+
+ // update inflight records
+ {
+ std::lock_guard<std::mutex> lk(mInflightFramesLock);
+ mInflightFrames.clear();
+ }
+
+ // stop v4l2 streaming
+ if (v4l2StreamOffLocked() !=0) {
+ ALOGE("%s: stop V4L2 streaming failed!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+
+ *session = sessionImpl->getInterface();
+ return Status::OK;
+}
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android