Camera: fill in Camera3Device offline processing impl
Move shared method implementations to Camera3OutputUtils.cpp/h
Defined interfaces to handle Camera3Device/Camera3OfflineSession
behavior differences in Camera3OutputInterface.h.
Bug: 135142453
Test: N/A (not enough implementation yet)
Change-Id: I57476ca5a1edf69c02a22241ad776d6f02636033
diff --git a/services/camera/libcameraservice/device3/BufferUtils.cpp b/services/camera/libcameraservice/device3/BufferUtils.cpp
new file mode 100644
index 0000000..cc29390
--- /dev/null
+++ b/services/camera/libcameraservice/device3/BufferUtils.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2019 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 "Camera3-BufUtils"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0 // Per-frame verbose logging
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+
+#include "device3/BufferUtils.h"
+
+namespace android {
+namespace camera3 {
+
+camera3_buffer_status_t mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status) {
+ using hardware::camera::device::V3_2::BufferStatus;
+
+ switch (status) {
+ case BufferStatus::OK: return CAMERA3_BUFFER_STATUS_OK;
+ case BufferStatus::ERROR: return CAMERA3_BUFFER_STATUS_ERROR;
+ }
+ return CAMERA3_BUFFER_STATUS_ERROR;
+}
+
+void BufferRecords::takeInflightBufferMap(BufferRecords& other) {
+ std::lock_guard<std::mutex> oLock(other.mInflightLock);
+ std::lock_guard<std::mutex> lock(mInflightLock);
+ if (mInflightBufferMap.size() > 0) {
+ ALOGE("%s: inflight map is set in non-empty state!", __FUNCTION__);
+ }
+ mInflightBufferMap = std::move(other.mInflightBufferMap);
+ other.mInflightBufferMap.clear();
+}
+
+void BufferRecords::takeRequestedBufferMap(BufferRecords& other) {
+ std::lock_guard<std::mutex> oLock(other.mRequestedBuffersLock);
+ std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
+ if (mRequestedBufferMap.size() > 0) {
+ ALOGE("%s: requested buffer map is set in non-empty state!", __FUNCTION__);
+ }
+ mRequestedBufferMap = std::move(other.mRequestedBufferMap);
+ other.mRequestedBufferMap.clear();
+}
+
+void BufferRecords::takeBufferCaches(BufferRecords& other, const std::vector<int32_t>& streams) {
+ std::lock_guard<std::mutex> oLock(other.mBufferIdMapLock);
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ if (mBufferIdMaps.size() > 0) {
+ ALOGE("%s: buffer ID map is set in non-empty state!", __FUNCTION__);
+ }
+ for (auto streamId : streams) {
+ mBufferIdMaps.insert({streamId, std::move(other.mBufferIdMaps.at(streamId))});
+ }
+ other.mBufferIdMaps.clear();
+}
+
+std::pair<bool, uint64_t> BufferRecords::getBufferId(
+ const buffer_handle_t& buf, int streamId) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+
+ BufferIdMap& bIdMap = mBufferIdMaps.at(streamId);
+ auto it = bIdMap.find(buf);
+ if (it == bIdMap.end()) {
+ bIdMap[buf] = mNextBufferId++;
+ ALOGV("stream %d now have %zu buffer caches, buf %p",
+ streamId, bIdMap.size(), buf);
+ return std::make_pair(true, mNextBufferId - 1);
+ } else {
+ return std::make_pair(false, it->second);
+ }
+}
+
+void BufferRecords::tryCreateBufferCache(int streamId) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ if (mBufferIdMaps.count(streamId) == 0) {
+ mBufferIdMaps.emplace(streamId, BufferIdMap{});
+ }
+}
+
+void BufferRecords::removeInactiveBufferCaches(const std::set<int32_t>& activeStreams) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ for(auto it = mBufferIdMaps.begin(); it != mBufferIdMaps.end();) {
+ int streamId = it->first;
+ bool active = activeStreams.count(streamId) > 0;
+ if (!active) {
+ it = mBufferIdMaps.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+uint64_t BufferRecords::removeOneBufferCache(int streamId, const native_handle_t* handle) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ uint64_t bufferId = BUFFER_ID_NO_BUFFER;
+ auto mapIt = mBufferIdMaps.find(streamId);
+ if (mapIt == mBufferIdMaps.end()) {
+ // streamId might be from a deleted stream here
+ ALOGI("%s: stream %d has been removed",
+ __FUNCTION__, streamId);
+ return BUFFER_ID_NO_BUFFER;
+ }
+ BufferIdMap& bIdMap = mapIt->second;
+ auto it = bIdMap.find(handle);
+ if (it == bIdMap.end()) {
+ ALOGW("%s: cannot find buffer %p in stream %d",
+ __FUNCTION__, handle, streamId);
+ return BUFFER_ID_NO_BUFFER;
+ } else {
+ bufferId = it->second;
+ bIdMap.erase(it);
+ ALOGV("%s: stream %d now have %zu buffer caches after removing buf %p",
+ __FUNCTION__, streamId, bIdMap.size(), handle);
+ }
+ return bufferId;
+}
+
+std::vector<uint64_t> BufferRecords::clearBufferCaches(int streamId) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ std::vector<uint64_t> ret;
+ auto mapIt = mBufferIdMaps.find(streamId);
+ if (mapIt == mBufferIdMaps.end()) {
+ ALOGE("%s: streamId %d not found!", __FUNCTION__, streamId);
+ return ret;
+ }
+ BufferIdMap& bIdMap = mapIt->second;
+ ret.reserve(bIdMap.size());
+ for (const auto& it : bIdMap) {
+ ret.push_back(it.second);
+ }
+ bIdMap.clear();
+ return ret;
+}
+
+bool BufferRecords::isStreamCached(int streamId) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ return mBufferIdMaps.find(streamId) != mBufferIdMaps.end();
+}
+
+bool BufferRecords::verifyBufferIds(
+ int32_t streamId, std::vector<uint64_t>& bufIds) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ camera3::BufferIdMap& bIdMap = mBufferIdMaps.at(streamId);
+ if (bIdMap.size() != bufIds.size()) {
+ ALOGE("%s: stream ID %d buffer cache number mismatch: %zu/%zu (service/HAL)",
+ __FUNCTION__, streamId, bIdMap.size(), bufIds.size());
+ return false;
+ }
+ std::vector<uint64_t> internalBufIds;
+ internalBufIds.reserve(bIdMap.size());
+ for (const auto& pair : bIdMap) {
+ internalBufIds.push_back(pair.second);
+ }
+ std::sort(bufIds.begin(), bufIds.end());
+ std::sort(internalBufIds.begin(), internalBufIds.end());
+ for (size_t i = 0; i < bufIds.size(); i++) {
+ if (bufIds[i] != internalBufIds[i]) {
+ ALOGE("%s: buffer cache mismatch! Service %" PRIu64 ", HAL %" PRIu64,
+ __FUNCTION__, internalBufIds[i], bufIds[i]);
+ return false;
+ }
+ }
+ return true;
+}
+
+void BufferRecords::getInflightBufferKeys(
+ std::vector<std::pair<int32_t, int32_t>>* out) {
+ std::lock_guard<std::mutex> lock(mInflightLock);
+ out->clear();
+ out->reserve(mInflightBufferMap.size());
+ for (auto& pair : mInflightBufferMap) {
+ uint64_t key = pair.first;
+ int32_t streamId = key & 0xFFFFFFFF;
+ int32_t frameNumber = (key >> 32) & 0xFFFFFFFF;
+ out->push_back(std::make_pair(frameNumber, streamId));
+ }
+ return;
+}
+
+status_t BufferRecords::pushInflightBuffer(
+ int32_t frameNumber, int32_t streamId, buffer_handle_t *buffer) {
+ std::lock_guard<std::mutex> lock(mInflightLock);
+ uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
+ mInflightBufferMap[key] = buffer;
+ return OK;
+}
+
+status_t BufferRecords::popInflightBuffer(
+ int32_t frameNumber, int32_t streamId,
+ /*out*/ buffer_handle_t **buffer) {
+ std::lock_guard<std::mutex> lock(mInflightLock);
+
+ uint64_t key = static_cast<uint64_t>(frameNumber) << 32 | static_cast<uint64_t>(streamId);
+ auto it = mInflightBufferMap.find(key);
+ if (it == mInflightBufferMap.end()) return NAME_NOT_FOUND;
+ if (buffer != nullptr) {
+ *buffer = it->second;
+ }
+ mInflightBufferMap.erase(it);
+ return OK;
+}
+
+void BufferRecords::popInflightBuffers(
+ const std::vector<std::pair<int32_t, int32_t>>& buffers) {
+ for (const auto& pair : buffers) {
+ int32_t frameNumber = pair.first;
+ int32_t streamId = pair.second;
+ popInflightBuffer(frameNumber, streamId, nullptr);
+ }
+}
+
+status_t BufferRecords::pushInflightRequestBuffer(
+ uint64_t bufferId, buffer_handle_t* buf, int32_t streamId) {
+ std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
+ auto pair = mRequestedBufferMap.insert({bufferId, {streamId, buf}});
+ if (!pair.second) {
+ ALOGE("%s: bufId %" PRIu64 " is already inflight!",
+ __FUNCTION__, bufferId);
+ return BAD_VALUE;
+ }
+ return OK;
+}
+
+// Find and pop a buffer_handle_t based on bufferId
+status_t BufferRecords::popInflightRequestBuffer(
+ uint64_t bufferId,
+ /*out*/ buffer_handle_t** buffer,
+ /*optional out*/ int32_t* streamId) {
+ if (buffer == nullptr) {
+ ALOGE("%s: buffer (%p) must not be null", __FUNCTION__, buffer);
+ return BAD_VALUE;
+ }
+ std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
+ auto it = mRequestedBufferMap.find(bufferId);
+ if (it == mRequestedBufferMap.end()) {
+ ALOGE("%s: bufId %" PRIu64 " is not inflight!",
+ __FUNCTION__, bufferId);
+ return BAD_VALUE;
+ }
+ *buffer = it->second.second;
+ if (streamId != nullptr) {
+ *streamId = it->second.first;
+ }
+ mRequestedBufferMap.erase(it);
+ return OK;
+}
+
+void BufferRecords::getInflightRequestBufferKeys(
+ std::vector<uint64_t>* out) {
+ std::lock_guard<std::mutex> lock(mRequestedBuffersLock);
+ out->clear();
+ out->reserve(mRequestedBufferMap.size());
+ for (auto& pair : mRequestedBufferMap) {
+ out->push_back(pair.first);
+ }
+ return;
+}
+
+
+} // camera3
+} // namespace android