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: I57476ca5a1edf69c02a22241ad776d6f02636033gugelfrei
parent
56d98ba800
commit
5fd603ea87
@ -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
|
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_SERVERS_CAMERA3_BUFFER_UTILS_H
|
||||
#define ANDROID_SERVERS_CAMERA3_BUFFER_UTILS_H
|
||||
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
|
||||
#include <cutils/native_handle.h>
|
||||
|
||||
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
|
||||
|
||||
// TODO: remove legacy camera3.h references
|
||||
#include "hardware/camera3.h"
|
||||
|
||||
#include <device3/Camera3OutputInterface.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
namespace camera3 {
|
||||
|
||||
struct BufferHasher {
|
||||
size_t operator()(const buffer_handle_t& buf) const {
|
||||
if (buf == nullptr)
|
||||
return 0;
|
||||
|
||||
size_t result = 1;
|
||||
result = 31 * result + buf->numFds;
|
||||
for (int i = 0; i < buf->numFds; i++) {
|
||||
result = 31 * result + buf->data[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct BufferComparator {
|
||||
bool operator()(const buffer_handle_t& buf1, const buffer_handle_t& buf2) const {
|
||||
if (buf1->numFds == buf2->numFds) {
|
||||
for (int i = 0; i < buf1->numFds; i++) {
|
||||
if (buf1->data[i] != buf2->data[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Per stream buffer native handle -> bufId map
|
||||
typedef std::unordered_map<const buffer_handle_t, uint64_t,
|
||||
BufferHasher, BufferComparator> BufferIdMap;
|
||||
|
||||
// streamId -> BufferIdMap
|
||||
typedef std::unordered_map<int, BufferIdMap> BufferIdMaps;
|
||||
|
||||
// Map of inflight buffers sent along in capture requests.
|
||||
// Key is composed by (frameNumber << 32 | streamId)
|
||||
typedef std::unordered_map<uint64_t, buffer_handle_t*> InflightBufferMap;
|
||||
|
||||
// Map of inflight buffers dealt by requestStreamBuffers API
|
||||
typedef std::unordered_map<uint64_t, std::pair<int32_t, buffer_handle_t*>> RequestedBufferMap;
|
||||
|
||||
// A struct containing all buffer tracking information like inflight buffers
|
||||
// and buffer ID caches
|
||||
class BufferRecords : public BufferRecordsInterface {
|
||||
|
||||
public:
|
||||
BufferRecords() {}
|
||||
|
||||
BufferRecords(BufferRecords&& other) :
|
||||
mBufferIdMaps(other.mBufferIdMaps),
|
||||
mNextBufferId(other.mNextBufferId),
|
||||
mInflightBufferMap(other.mInflightBufferMap),
|
||||
mRequestedBufferMap(other.mRequestedBufferMap) {}
|
||||
|
||||
virtual ~BufferRecords() {}
|
||||
|
||||
// Helper methods to help moving buffer records
|
||||
void takeInflightBufferMap(BufferRecords& other);
|
||||
void takeRequestedBufferMap(BufferRecords& other);
|
||||
void takeBufferCaches(BufferRecords& other, const std::vector<int32_t>& streams);
|
||||
|
||||
// method to extract buffer's unique ID
|
||||
// return pair of (newlySeenBuffer?, bufferId)
|
||||
virtual std::pair<bool, uint64_t> getBufferId(
|
||||
const buffer_handle_t& buf, int streamId) override;
|
||||
|
||||
void tryCreateBufferCache(int streamId);
|
||||
|
||||
void removeInactiveBufferCaches(const std::set<int32_t>& activeStreams);
|
||||
|
||||
// Return the removed buffer ID if input cache is found.
|
||||
// Otherwise return BUFFER_ID_NO_BUFFER
|
||||
uint64_t removeOneBufferCache(int streamId, const native_handle_t* handle);
|
||||
|
||||
// Clear all caches for input stream, but do not remove the stream
|
||||
// Removed buffers' ID are returned
|
||||
std::vector<uint64_t> clearBufferCaches(int streamId);
|
||||
|
||||
bool isStreamCached(int streamId);
|
||||
|
||||
// Return true if the input caches match what we have; otherwise false
|
||||
bool verifyBufferIds(int32_t streamId, std::vector<uint64_t>& inBufIds);
|
||||
|
||||
// Get a vector of (frameNumber, streamId) pair of currently inflight
|
||||
// buffers
|
||||
void getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out);
|
||||
|
||||
status_t pushInflightBuffer(int32_t frameNumber, int32_t streamId,
|
||||
buffer_handle_t *buffer);
|
||||
|
||||
// Find a buffer_handle_t based on frame number and stream ID
|
||||
virtual status_t popInflightBuffer(int32_t frameNumber, int32_t streamId,
|
||||
/*out*/ buffer_handle_t **buffer) override;
|
||||
|
||||
// Pop inflight buffers based on pairs of (frameNumber,streamId)
|
||||
void popInflightBuffers(const std::vector<std::pair<int32_t, int32_t>>& buffers);
|
||||
|
||||
// Get a vector of bufferId of currently inflight buffers
|
||||
void getInflightRequestBufferKeys(std::vector<uint64_t>* out);
|
||||
|
||||
// Register a bufId (streamId, buffer_handle_t) to inflight request buffer
|
||||
virtual status_t pushInflightRequestBuffer(
|
||||
uint64_t bufferId, buffer_handle_t* buf, int32_t streamId) override;
|
||||
|
||||
// Find a buffer_handle_t based on bufferId
|
||||
virtual status_t popInflightRequestBuffer(uint64_t bufferId,
|
||||
/*out*/ buffer_handle_t** buffer,
|
||||
/*optional out*/ int32_t* streamId = nullptr) override;
|
||||
|
||||
private:
|
||||
std::mutex mBufferIdMapLock;
|
||||
BufferIdMaps mBufferIdMaps;
|
||||
uint64_t mNextBufferId = 1; // 0 means no buffer
|
||||
|
||||
std::mutex mInflightLock;
|
||||
InflightBufferMap mInflightBufferMap;
|
||||
|
||||
std::mutex mRequestedBuffersLock;
|
||||
RequestedBufferMap mRequestedBufferMap;
|
||||
}; // class BufferRecords
|
||||
|
||||
static const uint64_t BUFFER_ID_NO_BUFFER = 0;
|
||||
|
||||
camera3_buffer_status_t mapHidlBufferStatus(
|
||||
hardware::camera::device::V3_2::BufferStatus status);
|
||||
} // namespace camera3
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_SERVERS_CAMERA3_OUTPUT_INTERFACE_H
|
||||
#define ANDROID_SERVERS_CAMERA3_OUTPUT_INTERFACE_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <cutils/native_handle.h>
|
||||
|
||||
#include <utils/Timers.h>
|
||||
|
||||
#include "device3/Camera3StreamInterface.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
namespace camera3 {
|
||||
|
||||
/**
|
||||
* Interfaces used by result/notification path shared between Camera3Device and
|
||||
* Camera3OfflineSession
|
||||
*/
|
||||
class SetErrorInterface {
|
||||
public:
|
||||
// Switch device into error state and send a ERROR_DEVICE notification
|
||||
virtual void setErrorState(const char *fmt, ...) = 0;
|
||||
// Same as setErrorState except this method assumes callers holds the main object lock
|
||||
virtual void setErrorStateLocked(const char *fmt, ...) = 0;
|
||||
|
||||
virtual ~SetErrorInterface() {}
|
||||
};
|
||||
|
||||
// Interface used by callback path to update buffer records
|
||||
class BufferRecordsInterface {
|
||||
public:
|
||||
// method to extract buffer's unique ID
|
||||
// return pair of (newlySeenBuffer?, bufferId)
|
||||
virtual std::pair<bool, uint64_t> getBufferId(const buffer_handle_t& buf, int streamId) = 0;
|
||||
|
||||
// Find a buffer_handle_t based on frame number and stream ID
|
||||
virtual status_t popInflightBuffer(int32_t frameNumber, int32_t streamId,
|
||||
/*out*/ buffer_handle_t **buffer) = 0;
|
||||
|
||||
// Register a bufId (streamId, buffer_handle_t) to inflight request buffer
|
||||
virtual status_t pushInflightRequestBuffer(
|
||||
uint64_t bufferId, buffer_handle_t* buf, int32_t streamId) = 0;
|
||||
|
||||
// Find a buffer_handle_t based on bufferId
|
||||
virtual status_t popInflightRequestBuffer(uint64_t bufferId,
|
||||
/*out*/ buffer_handle_t** buffer,
|
||||
/*optional out*/ int32_t* streamId = nullptr) = 0;
|
||||
|
||||
virtual ~BufferRecordsInterface() {}
|
||||
};
|
||||
|
||||
class InflightRequestUpdateInterface {
|
||||
public:
|
||||
// Caller must hold the lock proctecting InflightRequestMap
|
||||
// duration: the maxExpectedDuration of the removed entry
|
||||
virtual void onInflightEntryRemovedLocked(nsecs_t duration) = 0;
|
||||
|
||||
virtual void checkInflightMapLengthLocked() = 0;
|
||||
|
||||
virtual void onInflightMapFlushedLocked() = 0;
|
||||
|
||||
virtual ~InflightRequestUpdateInterface() {}
|
||||
};
|
||||
|
||||
class RequestBufferInterface {
|
||||
public:
|
||||
// Return if the state machine currently allows for requestBuffers.
|
||||
// If this returns true, caller must call endRequestBuffer() later to signal end of a
|
||||
// request buffer transaction.
|
||||
virtual bool startRequestBuffer() = 0;
|
||||
|
||||
virtual void endRequestBuffer() = 0;
|
||||
|
||||
// Returns how long should implementation wait for a buffer returned
|
||||
virtual nsecs_t getWaitDuration() = 0;
|
||||
|
||||
virtual ~RequestBufferInterface() {}
|
||||
};
|
||||
|
||||
class FlushBufferInterface {
|
||||
public:
|
||||
virtual void getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out) = 0;
|
||||
|
||||
virtual void getInflightRequestBufferKeys(std::vector<uint64_t>* out) = 0;
|
||||
|
||||
virtual std::vector<sp<Camera3StreamInterface>> getAllStreams() = 0;
|
||||
|
||||
virtual ~FlushBufferInterface() {}
|
||||
};
|
||||
} // namespace camera3
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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-OutStrmIntf"
|
||||
#define ATRACE_TAG ATRACE_TAG_CAMERA
|
||||
//#define LOG_NDEBUG 0
|
||||
//#define LOG_NNDEBUG 0 // Per-frame verbose logging
|
||||
|
||||
|
||||
#include "Camera3OutputStreamInterface.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
namespace camera3 {
|
||||
|
||||
status_t StreamSet::add(
|
||||
int streamId, sp<camera3::Camera3OutputStreamInterface> stream) {
|
||||
if (stream == nullptr) {
|
||||
ALOGE("%s: cannot add null stream", __FUNCTION__);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
return mData.add(streamId, stream);
|
||||
}
|
||||
|
||||
ssize_t StreamSet::remove(int streamId) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
return mData.removeItem(streamId);
|
||||
}
|
||||
|
||||
sp<camera3::Camera3OutputStreamInterface> StreamSet::get(int streamId) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
ssize_t idx = mData.indexOfKey(streamId);
|
||||
if (idx == NAME_NOT_FOUND) {
|
||||
return nullptr;
|
||||
}
|
||||
return mData.editValueAt(idx);
|
||||
}
|
||||
|
||||
sp<camera3::Camera3OutputStreamInterface> StreamSet::operator[] (size_t index) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
return mData.editValueAt(index);
|
||||
}
|
||||
|
||||
size_t StreamSet::size() const {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
return mData.size();
|
||||
}
|
||||
|
||||
void StreamSet::clear() {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
return mData.clear();
|
||||
}
|
||||
|
||||
std::vector<int> StreamSet::getStreamIds() {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
std::vector<int> streamIds(mData.size());
|
||||
for (size_t i = 0; i < mData.size(); i++) {
|
||||
streamIds[i] = mData.keyAt(i);
|
||||
}
|
||||
return streamIds;
|
||||
}
|
||||
|
||||
StreamSet::StreamSet(const StreamSet& other) {
|
||||
std::lock_guard<std::mutex> lock(other.mLock);
|
||||
mData = other.mData;
|
||||
}
|
||||
|
||||
} // namespace camera3
|
||||
|
||||
} // namespace android
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_SERVERS_CAMERA3_OUTPUT_UTILS_H
|
||||
#define ANDROID_SERVERS_CAMERA3_OUTPUT_UTILS_H
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include <cutils/native_handle.h>
|
||||
|
||||
#include <fmq/MessageQueue.h>
|
||||
|
||||
#include <common/CameraDeviceBase.h>
|
||||
|
||||
#include "device3/BufferUtils.h"
|
||||
#include "device3/DistortionMapper.h"
|
||||
#include "device3/ZoomRatioMapper.h"
|
||||
#include "device3/InFlightRequest.h"
|
||||
#include "device3/Camera3Stream.h"
|
||||
#include "device3/Camera3OutputStreamInterface.h"
|
||||
#include "utils/TagMonitor.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
using ResultMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
|
||||
|
||||
namespace camera3 {
|
||||
|
||||
/**
|
||||
* Helper methods shared between Camera3Device/Camera3OfflineSession for HAL callbacks
|
||||
*/
|
||||
// helper function to return the output buffers to output streams.
|
||||
void returnOutputBuffers(
|
||||
bool useHalBufManager,
|
||||
sp<NotificationListener> listener, // Only needed when outputSurfaces is not empty
|
||||
const camera3_stream_buffer_t *outputBuffers,
|
||||
size_t numBuffers, nsecs_t timestamp, bool timestampIncreasing = true,
|
||||
// The following arguments are only meant for surface sharing use case
|
||||
const SurfaceMap& outputSurfaces = SurfaceMap{},
|
||||
// Used to send buffer error callback when failing to return buffer
|
||||
const CaptureResultExtras &resultExtras = CaptureResultExtras{});
|
||||
|
||||
// Camera3Device/Camera3OfflineSession internal states used in notify/processCaptureResult
|
||||
// callbacks
|
||||
struct CaptureOutputStates {
|
||||
const String8& cameraId;
|
||||
std::mutex& inflightLock;
|
||||
InFlightRequestMap& inflightMap; // end of inflightLock scope
|
||||
std::mutex& outputLock;
|
||||
List<CaptureResult>& resultQueue;
|
||||
std::condition_variable& resultSignal;
|
||||
uint32_t& nextShutterFrameNum;
|
||||
uint32_t& nextReprocShutterFrameNum;
|
||||
uint32_t& nextZslShutterFrameNum;
|
||||
uint32_t& nextResultFrameNum;
|
||||
uint32_t& nextReprocResultFrameNum;
|
||||
uint32_t& nextZslResultFrameNum; // end of outputLock scope
|
||||
const bool useHalBufManager;
|
||||
const bool usePartialResult;
|
||||
const bool needFixupMonoChrome;
|
||||
const uint32_t numPartialResults;
|
||||
const metadata_vendor_id_t vendorTagId;
|
||||
const CameraMetadata& deviceInfo;
|
||||
const std::unordered_map<std::string, CameraMetadata>& physicalDeviceInfoMap;
|
||||
std::unique_ptr<ResultMetadataQueue>& fmq;
|
||||
std::unordered_map<std::string, camera3::DistortionMapper>& distortionMappers;
|
||||
std::unordered_map<std::string, camera3::ZoomRatioMapper>& zoomRatioMappers;
|
||||
TagMonitor& tagMonitor;
|
||||
sp<Camera3Stream> inputStream;
|
||||
StreamSet& outputStreams;
|
||||
sp<NotificationListener> listener;
|
||||
SetErrorInterface& setErrIntf;
|
||||
InflightRequestUpdateInterface& inflightIntf;
|
||||
BufferRecordsInterface& bufferRecordsIntf;
|
||||
};
|
||||
|
||||
// Handle one capture result. Assume callers hold the lock to serialize all
|
||||
// processCaptureResult calls
|
||||
void processOneCaptureResultLocked(
|
||||
CaptureOutputStates& states,
|
||||
const hardware::camera::device::V3_2::CaptureResult& result,
|
||||
const hardware::hidl_vec<
|
||||
hardware::camera::device::V3_4::PhysicalCameraMetadata> physicalCameraMetadata);
|
||||
|
||||
// Handle one notify message
|
||||
void notify(CaptureOutputStates& states,
|
||||
const hardware::camera::device::V3_2::NotifyMsg& msg);
|
||||
|
||||
struct RequestBufferStates {
|
||||
const String8& cameraId;
|
||||
std::mutex& reqBufferLock; // lock to serialize request buffer calls
|
||||
const bool useHalBufManager;
|
||||
StreamSet& outputStreams;
|
||||
SetErrorInterface& setErrIntf;
|
||||
BufferRecordsInterface& bufferRecordsIntf;
|
||||
RequestBufferInterface& reqBufferIntf;
|
||||
};
|
||||
|
||||
void requestStreamBuffers(RequestBufferStates& states,
|
||||
const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
|
||||
hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb _hidl_cb);
|
||||
|
||||
struct ReturnBufferStates {
|
||||
const String8& cameraId;
|
||||
const bool useHalBufManager;
|
||||
StreamSet& outputStreams;
|
||||
BufferRecordsInterface& bufferRecordsIntf;
|
||||
};
|
||||
|
||||
void returnStreamBuffers(ReturnBufferStates& states,
|
||||
const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers);
|
||||
|
||||
struct FlushInflightReqStates {
|
||||
const String8& cameraId;
|
||||
std::mutex& inflightLock;
|
||||
InFlightRequestMap& inflightMap; // end of inflightLock scope
|
||||
const bool useHalBufManager;
|
||||
sp<NotificationListener> listener;
|
||||
InflightRequestUpdateInterface& inflightIntf;
|
||||
BufferRecordsInterface& bufferRecordsIntf;
|
||||
FlushBufferInterface& flushBufferIntf;
|
||||
};
|
||||
|
||||
void flushInflightRequests(FlushInflightReqStates& states);
|
||||
} // namespace camera3
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_SERVERS_CAMERA3_INFLIGHT_REQUEST_H
|
||||
#define ANDROID_SERVERS_CAMERA3_INFLIGHT_REQUEST_H
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <camera/CaptureResult.h>
|
||||
#include <camera/CameraMetadata.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/Timers.h>
|
||||
|
||||
#include "hardware/camera3.h"
|
||||
|
||||
#include "common/CameraDeviceBase.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
namespace camera3 {
|
||||
|
||||
struct InFlightRequest {
|
||||
// Set by notify() SHUTTER call.
|
||||
nsecs_t shutterTimestamp;
|
||||
// Set by process_capture_result().
|
||||
nsecs_t sensorTimestamp;
|
||||
int requestStatus;
|
||||
// Set by process_capture_result call with valid metadata
|
||||
bool haveResultMetadata;
|
||||
// Decremented by calls to process_capture_result with valid output
|
||||
// and input buffers
|
||||
int numBuffersLeft;
|
||||
CaptureResultExtras resultExtras;
|
||||
// If this request has any input buffer
|
||||
bool hasInputBuffer;
|
||||
|
||||
// The last metadata that framework receives from HAL and
|
||||
// not yet send out because the shutter event hasn't arrived.
|
||||
// It's added by process_capture_result and sent when framework
|
||||
// receives the shutter event.
|
||||
CameraMetadata pendingMetadata;
|
||||
|
||||
// The metadata of the partial results that framework receives from HAL so far
|
||||
// and has sent out.
|
||||
CameraMetadata collectedPartialResult;
|
||||
|
||||
// Buffers are added by process_capture_result when output buffers
|
||||
// return from HAL but framework has not yet received the shutter
|
||||
// event. They will be returned to the streams when framework receives
|
||||
// the shutter event.
|
||||
Vector<camera3_stream_buffer_t> pendingOutputBuffers;
|
||||
|
||||
// Whether this inflight request's shutter and result callback are to be
|
||||
// called. The policy is that if the request is the last one in the constrained
|
||||
// high speed recording request list, this flag will be true. If the request list
|
||||
// is not for constrained high speed recording, this flag will also be true.
|
||||
bool hasCallback;
|
||||
|
||||
// Maximum expected frame duration for this request.
|
||||
// For manual captures, equal to the max of requested exposure time and frame duration
|
||||
// For auto-exposure modes, equal to 1/(lower end of target FPS range)
|
||||
nsecs_t maxExpectedDuration;
|
||||
|
||||
// Whether the result metadata for this request is to be skipped. The
|
||||
// result metadata should be skipped in the case of
|
||||
// REQUEST/RESULT error.
|
||||
bool skipResultMetadata;
|
||||
|
||||
// The physical camera ids being requested.
|
||||
std::set<String8> physicalCameraIds;
|
||||
|
||||
// Map of physicalCameraId <-> Metadata
|
||||
std::vector<PhysicalCaptureResultInfo> physicalMetadatas;
|
||||
|
||||
// Indicates a still capture request.
|
||||
bool stillCapture;
|
||||
|
||||
// Indicates a ZSL capture request
|
||||
bool zslCapture;
|
||||
|
||||
// Requested camera ids (both logical and physical) with zoomRatio != 1.0f
|
||||
std::set<std::string> cameraIdsWithZoom;
|
||||
|
||||
// What shared surfaces an output should go to
|
||||
SurfaceMap outputSurfaces;
|
||||
|
||||
// TODO: dedupe
|
||||
static const nsecs_t kDefaultExpectedDuration = 100000000; // 100 ms
|
||||
|
||||
// Default constructor needed by KeyedVector
|
||||
InFlightRequest() :
|
||||
shutterTimestamp(0),
|
||||
sensorTimestamp(0),
|
||||
requestStatus(OK),
|
||||
haveResultMetadata(false),
|
||||
numBuffersLeft(0),
|
||||
hasInputBuffer(false),
|
||||
hasCallback(true),
|
||||
maxExpectedDuration(kDefaultExpectedDuration),
|
||||
skipResultMetadata(false),
|
||||
stillCapture(false),
|
||||
zslCapture(false) {
|
||||
}
|
||||
|
||||
InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput,
|
||||
bool hasAppCallback, nsecs_t maxDuration,
|
||||
const std::set<String8>& physicalCameraIdSet, bool isStillCapture,
|
||||
bool isZslCapture, const std::set<std::string>& idsWithZoom,
|
||||
const SurfaceMap& outSurfaces = SurfaceMap{}) :
|
||||
shutterTimestamp(0),
|
||||
sensorTimestamp(0),
|
||||
requestStatus(OK),
|
||||
haveResultMetadata(false),
|
||||
numBuffersLeft(numBuffers),
|
||||
resultExtras(extras),
|
||||
hasInputBuffer(hasInput),
|
||||
hasCallback(hasAppCallback),
|
||||
maxExpectedDuration(maxDuration),
|
||||
skipResultMetadata(false),
|
||||
physicalCameraIds(physicalCameraIdSet),
|
||||
stillCapture(isStillCapture),
|
||||
zslCapture(isZslCapture),
|
||||
cameraIdsWithZoom(idsWithZoom),
|
||||
outputSurfaces(outSurfaces) {
|
||||
}
|
||||
};
|
||||
|
||||
// Map from frame number to the in-flight request state
|
||||
typedef KeyedVector<uint32_t, InFlightRequest> InFlightRequestMap;
|
||||
|
||||
} // namespace camera3
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif
|
Loading…
Reference in new issue