blob: a64ce071686e2a4b2200e5fa3dca856201c58c37 [file]
/*
* Copyright (C) 2023 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.
*/
#include "VirtualCameraSessionContext.h"
#include <memory>
#include <mutex>
#include <unordered_set>
#include "VirtualCameraStream.h"
#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
namespace android {
namespace companion {
namespace virtualcamera {
using ::aidl::android::hardware::camera::device::BufferCache;
using ::aidl::android::hardware::camera::device::Stream;
using ::aidl::android::hardware::camera::device::StreamBuffer;
using ::aidl::android::hardware::camera::device::StreamConfiguration;
VirtualCameraSessionContext::VirtualCameraSessionContext(
const bool isMultiInputStreamEnabled,
std::function<void()> onFatalErrorCallback)
: mIsMultiInputStreamEnabled(isMultiInputStreamEnabled),
mOnFatalErrorCallback(onFatalErrorCallback) {
}
bool VirtualCameraSessionContext::initializeStream(
const ::aidl::android::hardware::camera::device::Stream& stream) {
std::lock_guard<std::mutex> lock(mLock);
auto s = std::make_unique<VirtualCameraStream>(stream);
const auto& [_, newlyInserted] = mStreams.emplace(
std::piecewise_construct, std::forward_as_tuple(stream.id),
std::forward_as_tuple(std::move(s)));
return newlyInserted;
}
void VirtualCameraSessionContext::clearStreams() {
ALOGV("%s", __func__);
std::lock_guard<std::mutex> lock(mLock);
mStreams.clear();
}
bool VirtualCameraSessionContext::importBuffersFromCaptureRequest(
const ::aidl::android::hardware::camera::device::CaptureRequest&
captureRequest) {
std::lock_guard<std::mutex> lock(mLock);
for (const StreamBuffer& buffer : captureRequest.outputBuffers) {
auto it = mStreams.find(buffer.streamId);
if (it == mStreams.end()) {
ALOGE("%s: Cannot import buffer for unknown stream with id %d", __func__,
buffer.streamId);
return false;
}
VirtualCameraStream& stream = *it->second;
if (stream.getHardwareBuffer(buffer.bufferId) != nullptr) {
// This buffer is already imported.
continue;
}
if (stream.importBuffer(buffer) == nullptr) {
ALOGE("%s: Failed to import buffer %" PRId64 " for streamId %d", __func__,
buffer.bufferId, buffer.streamId);
return false;
}
}
return true;
}
void VirtualCameraSessionContext::removeBufferCaches(
const std::vector<BufferCache>& cachesToRemove) {
std::lock_guard<std::mutex> lock(mLock);
for (const auto& bufferCache : cachesToRemove) {
auto it = mStreams.find(bufferCache.streamId);
if (it == mStreams.end()) {
ALOGE("%s: Ask to remove buffer %" PRId64 " from unknown stream %d",
__func__, bufferCache.bufferId, bufferCache.streamId);
continue;
}
if (it->second->removeBuffer(bufferCache.bufferId)) {
ALOGD("%s: Successfully removed buffer %" PRId64
" from cache of stream %d",
__func__, bufferCache.bufferId, bufferCache.streamId);
} else {
ALOGE("%s: Failed to remove buffer %" PRId64 " from cache of stream %d",
__func__, bufferCache.bufferId, bufferCache.streamId);
}
}
}
void VirtualCameraSessionContext::removeStreamsNotInStreamConfiguration(
const StreamConfiguration& streamConfiguration) {
std::unordered_set<int> newConfigurationStreamIds;
for (const Stream& stream : streamConfiguration.streams) {
newConfigurationStreamIds.insert(stream.id);
}
std::lock_guard<std::mutex> lock(mLock);
for (auto it = mStreams.begin(); it != mStreams.end();) {
if (newConfigurationStreamIds.find(it->first) ==
newConfigurationStreamIds.end()) {
ALOGV(
"Disposing of stream %d, since it is not referenced by new "
"configuration.",
it->first);
it = mStreams.erase(it);
} else {
++it;
}
}
}
std::optional<Stream> VirtualCameraSessionContext::getStreamConfig(
int streamId) const {
std::lock_guard<std::mutex> lock(mLock);
auto it = mStreams.find(streamId);
if (it == mStreams.end()) {
ALOGE("%s: StreamBuffer references buffer of unknown streamId %d", __func__,
streamId);
return std::optional<Stream>();
}
VirtualCameraStream& stream = *it->second;
return {stream.getStreamConfig()};
}
std::shared_ptr<AHardwareBuffer> VirtualCameraSessionContext::fetchHardwareBuffer(
const int streamId, const int bufferId) const {
std::lock_guard<std::mutex> lock(mLock);
auto it = mStreams.find(streamId);
if (it == mStreams.end()) {
ALOGE("%s: StreamBuffer references buffer of unknown streamId %d", __func__,
streamId);
return nullptr;
}
VirtualCameraStream& stream = *it->second;
return stream.getHardwareBuffer(bufferId);
}
std::shared_ptr<EglFrameBuffer>
VirtualCameraSessionContext::fetchOrCreateEglFramebuffer(
const EGLDisplay eglDisplay, const int streamId, const int bufferId) {
std::lock_guard<std::mutex> lock(mLock);
auto it = mStreams.find(streamId);
if (it == mStreams.end()) {
ALOGE("%s: StreamBuffer references buffer of unknown streamId %d", __func__,
streamId);
return nullptr;
}
VirtualCameraStream& stream = *it->second;
return stream.getEglFrameBuffer(eglDisplay, bufferId);
}
std::set<int> VirtualCameraSessionContext::getStreamIds() const {
std::set<int> result;
std::lock_guard<std::mutex> lock(mLock);
for (const auto& [streamId, _] : mStreams) {
result.insert(streamId);
}
return result;
}
std::shared_ptr<VirtualCameraCaptureResultConsumer>
VirtualCameraSessionContext::getCaptureResultConsumer() const {
std::lock_guard<std::mutex> lock(mLock);
return mCaptureResultConsumer;
}
void VirtualCameraSessionContext::setCaptureResultConsumer(
const std::shared_ptr<VirtualCameraCaptureResultConsumer> consumer) {
std::lock_guard<std::mutex> lock(mLock);
mCaptureResultConsumer = consumer;
}
const camera_metadata_t*
VirtualCameraSessionContext::getCaptureResultMetadataForTimestamp(
int64_t timestamp) {
std::shared_ptr<VirtualCameraCaptureResultConsumer> consumer =
getCaptureResultConsumer();
if (consumer == nullptr) {
return nullptr;
}
// don't lock when getting the capture result metadata for timestamp
return consumer->getCaptureResultMetadataForTimestamp(timestamp);
}
int VirtualCameraSessionContext::getInputStreamIdForOutputStreamId(
int streamId) const {
std::lock_guard<std::mutex> lock(mLock);
auto it = mOutputToInputStreamMap.find(streamId);
if (it == mOutputToInputStreamMap.end()) {
ALOGE("%s: output StreamId %d not found in map", __func__, streamId);
return kInvalidStreamId;
}
return it->second;
}
void VirtualCameraSessionContext::enqueueFrame(int frameId) {
std::lock_guard<std::mutex> lock(mLock);
mFrameQueue.insert(frameId);
}
bool VirtualCameraSessionContext::dequeueFrame(int frameId) {
std::lock_guard<std::mutex> lock(mLock);
auto it = mFrameQueue.find(frameId);
bool isQueued = it != mFrameQueue.end();
if (isQueued) {
mFrameQueue.erase(it);
}
return isQueued;
}
std::set<int> VirtualCameraSessionContext::updateOpenStreams(
const std::map<int, int> openStreams) {
std::lock_guard<std::mutex> lock(mLock);
std::set<int> staleStreams;
for (const auto& [outputStreamId, inputStreamId] : mOutputToInputStreamMap) {
if (openStreams.find(outputStreamId) == openStreams.end()) {
staleStreams.insert(inputStreamId);
}
}
mOutputToInputStreamMap = openStreams;
return staleStreams;
}
bool VirtualCameraSessionContext::isInputStreamUsed(int inputStreamId) const {
std::lock_guard<std::mutex> lock(mLock);
for (const auto& [outputId, inputId] : mOutputToInputStreamMap) {
if (inputStreamId == inputId) {
return true;
}
}
return false;
}
std::set<int> VirtualCameraSessionContext::getUsedInputStreamIds() const {
std::lock_guard<std::mutex> lock(mLock);
std::set<int> usedIds;
for (const auto& [_, inputStreamId] : mOutputToInputStreamMap) {
usedIds.insert(inputStreamId);
}
return usedIds;
}
bool VirtualCameraSessionContext::setFatalError() {
bool wasAlreadyFatal = mInFatalError.exchange(true);
if (wasAlreadyFatal) {
return false;
}
if (mOnFatalErrorCallback) {
mOnFatalErrorCallback();
}
return true;
}
} // namespace virtualcamera
} // namespace companion
} // namespace android