* changes: Camera: Propagate all offline stream ids to clients Camera: Add initial offline client listener logic Camera: Initial support for composite streams in offline mode Camera: Initial offline session client Camera: fill in Camera3Device offline processing implgugelfrei
commit
f0b35a84d6
@ -0,0 +1,287 @@
|
|||||||
|
/*
|
||||||
|
* 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 "CameraOfflineClient"
|
||||||
|
#define ATRACE_TAG ATRACE_TAG_CAMERA
|
||||||
|
//#define LOG_NDEBUG 0
|
||||||
|
|
||||||
|
#include "CameraOfflineSessionClient.h"
|
||||||
|
#include "utils/CameraThreadState.h"
|
||||||
|
#include <utils/Trace.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
using binder::Status;
|
||||||
|
|
||||||
|
status_t CameraOfflineSessionClient::initialize(sp<CameraProviderManager>, const String8&) {
|
||||||
|
ATRACE_CALL();
|
||||||
|
|
||||||
|
// Verify ops permissions
|
||||||
|
auto res = startCameraOps();
|
||||||
|
if (res != OK) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mOfflineSession.get() == nullptr) {
|
||||||
|
ALOGE("%s: Camera %s: No valid offline session",
|
||||||
|
__FUNCTION__, mCameraIdStr.string());
|
||||||
|
return NO_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp<NotificationListener> weakThis(this);
|
||||||
|
res = mOfflineSession->initialize(weakThis);
|
||||||
|
if (res != OK) {
|
||||||
|
ALOGE("%s: Camera %s: unable to initialize device: %s (%d)",
|
||||||
|
__FUNCTION__, mCameraIdStr.string(), strerror(-res), res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t CameraOfflineSessionClient::dump(int fd, const Vector<String16>& args) {
|
||||||
|
return BasicClient::dump(fd, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t CameraOfflineSessionClient::dumpClient(int fd, const Vector<String16>& /*args*/) {
|
||||||
|
String8 result;
|
||||||
|
|
||||||
|
result = " Offline session dump:\n";
|
||||||
|
write(fd, result.string(), result.size());
|
||||||
|
|
||||||
|
if (mOfflineSession.get() == nullptr) {
|
||||||
|
result = " *** Offline session is detached\n";
|
||||||
|
write(fd, result.string(), result.size());
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto res = mOfflineSession->dump(fd);
|
||||||
|
if (res != OK) {
|
||||||
|
result = String8::format(" Error dumping offline session: %s (%d)",
|
||||||
|
strerror(-res), res);
|
||||||
|
write(fd, result.string(), result.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
binder::Status CameraOfflineSessionClient::disconnect() {
|
||||||
|
Mutex::Autolock icl(mBinderSerializationLock);
|
||||||
|
|
||||||
|
binder::Status res = Status::ok();
|
||||||
|
if (mDisconnected) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
// Allow both client and the media server to disconnect at all times
|
||||||
|
int callingPid = CameraThreadState::getCallingPid();
|
||||||
|
if (callingPid != mClientPid &&
|
||||||
|
callingPid != mServicePid) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDisconnected = true;
|
||||||
|
|
||||||
|
sCameraService->removeByClient(this);
|
||||||
|
sCameraService->logDisconnectedOffline(mCameraIdStr, mClientPid, String8(mClientPackageName));
|
||||||
|
|
||||||
|
sp<IBinder> remote = getRemote();
|
||||||
|
if (remote != nullptr) {
|
||||||
|
remote->unlinkToDeath(sCameraService);
|
||||||
|
}
|
||||||
|
|
||||||
|
finishCameraOps();
|
||||||
|
ALOGI("%s: Disconnected client for offline camera %s for PID %d", __FUNCTION__,
|
||||||
|
mCameraIdStr.string(), mClientPid);
|
||||||
|
|
||||||
|
// client shouldn't be able to call into us anymore
|
||||||
|
mClientPid = 0;
|
||||||
|
|
||||||
|
if (mOfflineSession.get() != nullptr) {
|
||||||
|
auto ret = mOfflineSession->disconnect();
|
||||||
|
if (ret != OK) {
|
||||||
|
ALOGE("%s: Failed disconnecting from offline session %s (%d)", __FUNCTION__,
|
||||||
|
strerror(-ret), ret);
|
||||||
|
}
|
||||||
|
mOfflineSession = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
|
||||||
|
auto ret = mCompositeStreamMap.valueAt(i)->deleteInternalStreams();
|
||||||
|
if (ret != OK) {
|
||||||
|
ALOGE("%s: Failed removing composite stream %s (%d)", __FUNCTION__,
|
||||||
|
strerror(-ret), ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mCompositeStreamMap.clear();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraOfflineSessionClient::notifyError(int32_t errorCode,
|
||||||
|
const CaptureResultExtras& resultExtras) {
|
||||||
|
// Thread safe. Don't bother locking.
|
||||||
|
// Composites can have multiple internal streams. Error notifications coming from such internal
|
||||||
|
// streams may need to remain within camera service.
|
||||||
|
bool skipClientNotification = false;
|
||||||
|
for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
|
||||||
|
skipClientNotification |= mCompositeStreamMap.valueAt(i)->onError(errorCode, resultExtras);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mRemoteCallback.get() != nullptr) && (!skipClientNotification)) {
|
||||||
|
mRemoteCallback->onDeviceError(errorCode, resultExtras);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t CameraOfflineSessionClient::startCameraOps() {
|
||||||
|
ATRACE_CALL();
|
||||||
|
{
|
||||||
|
ALOGV("%s: Start camera ops, package name = %s, client UID = %d",
|
||||||
|
__FUNCTION__, String8(mClientPackageName).string(), mClientUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mAppOpsManager != nullptr) {
|
||||||
|
// Notify app ops that the camera is not available
|
||||||
|
mOpsCallback = new OpsCallback(this);
|
||||||
|
int32_t res;
|
||||||
|
// TODO : possibly change this to OP_OFFLINE_CAMERA_SESSION
|
||||||
|
mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
|
||||||
|
mClientPackageName, mOpsCallback);
|
||||||
|
// TODO : possibly change this to OP_OFFLINE_CAMERA_SESSION
|
||||||
|
res = mAppOpsManager->startOpNoThrow(AppOpsManager::OP_CAMERA,
|
||||||
|
mClientUid, mClientPackageName, /*startIfModeDefault*/ false);
|
||||||
|
|
||||||
|
if (res == AppOpsManager::MODE_ERRORED) {
|
||||||
|
ALOGI("Offline Camera %s: Access for \"%s\" has been revoked",
|
||||||
|
mCameraIdStr.string(), String8(mClientPackageName).string());
|
||||||
|
return PERMISSION_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == AppOpsManager::MODE_IGNORED) {
|
||||||
|
ALOGI("Offline Camera %s: Access for \"%s\" has been restricted",
|
||||||
|
mCameraIdStr.string(), String8(mClientPackageName).string());
|
||||||
|
// Return the same error as for device policy manager rejection
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mOpsActive = true;
|
||||||
|
|
||||||
|
// Transition device state to OPEN
|
||||||
|
sCameraService->mUidPolicy->registerMonitorUid(mClientUid);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t CameraOfflineSessionClient::finishCameraOps() {
|
||||||
|
ATRACE_CALL();
|
||||||
|
|
||||||
|
// Check if startCameraOps succeeded, and if so, finish the camera op
|
||||||
|
if (mOpsActive) {
|
||||||
|
// Notify app ops that the camera is available again
|
||||||
|
if (mAppOpsManager != nullptr) {
|
||||||
|
// TODO : possibly change this to OP_OFFLINE_CAMERA_SESSION
|
||||||
|
mAppOpsManager->finishOp(AppOpsManager::OP_CAMERA, mClientUid,
|
||||||
|
mClientPackageName);
|
||||||
|
mOpsActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Always stop watching, even if no camera op is active
|
||||||
|
if (mOpsCallback != nullptr && mAppOpsManager != nullptr) {
|
||||||
|
mAppOpsManager->stopWatchingMode(mOpsCallback);
|
||||||
|
}
|
||||||
|
mOpsCallback.clear();
|
||||||
|
|
||||||
|
sCameraService->mUidPolicy->unregisterMonitorUid(mClientUid);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraOfflineSessionClient::onResultAvailable(const CaptureResult& result) {
|
||||||
|
ATRACE_CALL();
|
||||||
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
if (mRemoteCallback.get() != NULL) {
|
||||||
|
mRemoteCallback->onResultReceived(result.mMetadata, result.mResultExtras,
|
||||||
|
result.mPhysicalMetadatas);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
|
||||||
|
mCompositeStreamMap.valueAt(i)->onResultAvailable(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraOfflineSessionClient::notifyShutter(const CaptureResultExtras& resultExtras,
|
||||||
|
nsecs_t timestamp) {
|
||||||
|
|
||||||
|
if (mRemoteCallback.get() != nullptr) {
|
||||||
|
mRemoteCallback->onCaptureStarted(resultExtras, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
|
||||||
|
mCompositeStreamMap.valueAt(i)->onShutter(resultExtras, timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraOfflineSessionClient::notifyIdle() {
|
||||||
|
if (mRemoteCallback.get() != nullptr) {
|
||||||
|
mRemoteCallback->onDeviceIdle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraOfflineSessionClient::notifyAutoFocus(uint8_t newState, int triggerId) {
|
||||||
|
(void)newState;
|
||||||
|
(void)triggerId;
|
||||||
|
|
||||||
|
ALOGV("%s: Autofocus state now %d, last trigger %d",
|
||||||
|
__FUNCTION__, newState, triggerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraOfflineSessionClient::notifyAutoExposure(uint8_t newState, int triggerId) {
|
||||||
|
(void)newState;
|
||||||
|
(void)triggerId;
|
||||||
|
|
||||||
|
ALOGV("%s: Autoexposure state now %d, last trigger %d",
|
||||||
|
__FUNCTION__, newState, triggerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraOfflineSessionClient::notifyAutoWhitebalance(uint8_t newState, int triggerId) {
|
||||||
|
(void)newState;
|
||||||
|
(void)triggerId;
|
||||||
|
|
||||||
|
ALOGV("%s: Auto-whitebalance state now %d, last trigger %d", __FUNCTION__, newState,
|
||||||
|
triggerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraOfflineSessionClient::notifyPrepared(int /*streamId*/) {
|
||||||
|
ALOGE("%s: Unexpected stream prepare notification in offline mode!", __FUNCTION__);
|
||||||
|
notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
|
||||||
|
CaptureResultExtras());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraOfflineSessionClient::notifyRequestQueueEmpty() {
|
||||||
|
if (mRemoteCallback.get() != nullptr) {
|
||||||
|
mRemoteCallback->onRequestQueueEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraOfflineSessionClient::notifyRepeatingRequestError(long /*lastFrameNumber*/) {
|
||||||
|
ALOGE("%s: Unexpected repeating request error in offline mode!", __FUNCTION__);
|
||||||
|
notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
|
||||||
|
CaptureResultExtras());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
}; // namespace android
|
@ -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