Merge changes from topic "OfflineReproc-impl"

* 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 impl
gugelfrei
TreeHugger Robot 5 years ago committed by Android (Google) Code Review
commit f0b35a84d6

@ -83,8 +83,9 @@ interface ICameraDeviceUser
* @param operatingMode The kind of session to create; either NORMAL_MODE or
* CONSTRAINED_HIGH_SPEED_MODE. Must be a non-negative value.
* @param sessionParams Session wide camera parameters
* @return a list of stream ids that can be used in offline mode via "switchToOffline"
*/
void endConfigure(int operatingMode, in CameraMetadataNative sessionParams);
int[] endConfigure(int operatingMode, in CameraMetadataNative sessionParams);
/**
* Check whether a particular session configuration has camera device
@ -189,5 +190,5 @@ interface ICameraDeviceUser
* @return Offline session object.
*/
ICameraOfflineSession switchToOffline(in ICameraDeviceCallbacks callbacks,
in Surface[] offlineOutputs);
in int[] offlineOutputIds);
}

@ -710,7 +710,8 @@ CameraDevice::configureStreamsLocked(const ACaptureSessionOutputContainer* outpu
if ((sessionParameters != nullptr) && (sessionParameters->settings != nullptr)) {
params.append(sessionParameters->settings->getInternalData());
}
remoteRet = mRemote->endConfigure(/*isConstrainedHighSpeed*/ false, params);
std::vector<int> offlineStreamIds;
remoteRet = mRemote->endConfigure(/*isConstrainedHighSpeed*/ false, params, &offlineStreamIds);
if (remoteRet.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_ILLEGAL_ARGUMENT) {
ALOGE("Camera device %s cannnot support app output configuration: %s", getId(),
remoteRet.toString8().string());

@ -498,7 +498,9 @@ TEST_F(CameraClientBinderTest, CheckBinderCameraDeviceUser) {
EXPECT_TRUE(res.isOk()) << res;
EXPECT_LE(0, streamId);
CameraMetadata sessionParams;
res = device->endConfigure(/*isConstrainedHighSpeed*/ false, sessionParams);
std::vector<int> offlineStreamIds;
res = device->endConfigure(/*isConstrainedHighSpeed*/ false, sessionParams,
&offlineStreamIds);
EXPECT_TRUE(res.isOk()) << res;
EXPECT_FALSE(callbacks->hadError());
@ -609,7 +611,8 @@ TEST_F(CameraClientBinderTest, CheckBinderCameraDeviceUser) {
EXPECT_TRUE(res.isOk()) << res;
res = device->deleteStream(streamId);
EXPECT_TRUE(res.isOk()) << res;
res = device->endConfigure(/*isConstrainedHighSpeed*/ false, sessionParams);
res = device->endConfigure(/*isConstrainedHighSpeed*/ false, sessionParams,
&offlineStreamIds);
EXPECT_TRUE(res.isOk()) << res;
sleep(/*second*/1); // allow some time for errors to show up, if any

@ -41,11 +41,13 @@ cc_library_shared {
"api1/client2/CaptureSequencer.cpp",
"api1/client2/ZslProcessor.cpp",
"api2/CameraDeviceClient.cpp",
"api2/CameraOfflineSessionClient.cpp",
"api2/CompositeStream.cpp",
"api2/DepthCompositeStream.cpp",
"api2/HeicEncoderInfoManager.cpp",
"api2/HeicCompositeStream.cpp",
"device1/CameraHardwareInterface.cpp",
"device3/BufferUtils.cpp",
"device3/Camera3Device.cpp",
"device3/Camera3OfflineSession.cpp",
"device3/Camera3Stream.cpp",
@ -60,6 +62,8 @@ cc_library_shared {
"device3/CoordinateMapper.cpp",
"device3/DistortionMapper.cpp",
"device3/ZoomRatioMapper.cpp",
"device3/Camera3OutputStreamInterface.cpp",
"device3/Camera3OutputUtils.cpp",
"gui/RingBufferConsumer.cpp",
"utils/CameraThreadState.cpp",
"hidl/AidlCameraDeviceCallbacks.cpp",

@ -128,6 +128,7 @@ static const String16
static constexpr int32_t kVendorClientScore = 200;
// Matches with PROCESS_STATE_PERSISTENT_UI in ActivityManager.java
static constexpr int32_t kVendorClientState = 1;
const String8 CameraService::kOfflineDevice("offline-");
Mutex CameraService::sProxyMutex;
sp<hardware::ICameraServiceProxy> CameraService::sCameraServiceProxy;
@ -394,7 +395,7 @@ void CameraService::onDeviceStatusChanged(const String8& id,
// to this device until the status changes
updateStatus(StatusInternal::NOT_PRESENT, id);
sp<BasicClient> clientToDisconnect;
sp<BasicClient> clientToDisconnectOnline, clientToDisconnectOffline;
{
// Don't do this in updateStatus to avoid deadlock over mServiceLock
Mutex::Autolock lock(mServiceLock);
@ -402,23 +403,14 @@ void CameraService::onDeviceStatusChanged(const String8& id,
// Remove cached shim parameters
state->setShimParams(CameraParameters());
// Remove the client from the list of active clients, if there is one
clientToDisconnect = removeClientLocked(id);
// Remove online as well as offline client from the list of active clients,
// if they are present
clientToDisconnectOnline = removeClientLocked(id);
clientToDisconnectOffline = removeClientLocked(kOfflineDevice + id);
}
// Disconnect client
if (clientToDisconnect.get() != nullptr) {
ALOGI("%s: Client for camera ID %s evicted due to device status change from HAL",
__FUNCTION__, id.string());
// Notify the client of disconnection
clientToDisconnect->notifyError(
hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
CaptureResultExtras{});
// Ensure not in binder RPC so client disconnect PID checks work correctly
LOG_ALWAYS_FATAL_IF(CameraThreadState::getCallingPid() != getpid(),
"onDeviceStatusChanged must be called from the camera service process!");
clientToDisconnect->disconnect();
}
disconnectClient(id, clientToDisconnectOnline);
disconnectClient(kOfflineDevice + id, clientToDisconnectOffline);
removeStates(id);
} else {
@ -431,6 +423,21 @@ void CameraService::onDeviceStatusChanged(const String8& id,
}
void CameraService::disconnectClient(const String8& id, sp<BasicClient> clientToDisconnect) {
if (clientToDisconnect.get() != nullptr) {
ALOGI("%s: Client for camera ID %s evicted due to device status change from HAL",
__FUNCTION__, id.string());
// Notify the client of disconnection
clientToDisconnect->notifyError(
hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
CaptureResultExtras{});
// Ensure not in binder RPC so client disconnect PID checks work correctly
LOG_ALWAYS_FATAL_IF(CameraThreadState::getCallingPid() != getpid(),
"onDeviceStatusChanged must be called from the camera service process!");
clientToDisconnect->disconnect();
}
}
void CameraService::onTorchStatusChanged(const String8& cameraId,
TorchModeStatus newStatus) {
Mutex::Autolock al(mTorchStatusMutex);
@ -1696,6 +1703,77 @@ Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8&
return ret;
}
status_t CameraService::addOfflineClient(String8 cameraId, sp<BasicClient> offlineClient) {
if (offlineClient.get() == nullptr) {
return BAD_VALUE;
}
{
// Acquire mServiceLock and prevent other clients from connecting
std::unique_ptr<AutoConditionLock> lock =
AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);
if (lock == nullptr) {
ALOGE("%s: (PID %d) rejected (too many other clients connecting)."
, __FUNCTION__, offlineClient->getClientPid());
return TIMED_OUT;
}
auto onlineClientDesc = mActiveClientManager.get(cameraId);
if (onlineClientDesc.get() == nullptr) {
ALOGE("%s: No active online client using camera id: %s", __FUNCTION__,
cameraId.c_str());
return BAD_VALUE;
}
// Offline clients do not evict or conflict with other online devices. Resource sharing
// conflicts are handled by the camera provider which will either succeed or fail before
// reaching this method.
const auto& onlinePriority = onlineClientDesc->getPriority();
auto offlineClientDesc = CameraClientManager::makeClientDescriptor(
kOfflineDevice + onlineClientDesc->getKey(), offlineClient, /*cost*/ 0,
/*conflictingKeys*/ std::set<String8>(), onlinePriority.getScore(),
onlineClientDesc->getOwnerId(), onlinePriority.getState());
// Allow only one offline device per camera
auto incompatibleClients = mActiveClientManager.getIncompatibleClients(offlineClientDesc);
if (!incompatibleClients.empty()) {
ALOGE("%s: Incompatible offline clients present!", __FUNCTION__);
return BAD_VALUE;
}
auto err = offlineClient->initialize(mCameraProviderManager, mMonitorTags);
if (err != OK) {
ALOGE("%s: Could not initialize offline client.", __FUNCTION__);
return err;
}
auto evicted = mActiveClientManager.addAndEvict(offlineClientDesc);
if (evicted.size() > 0) {
for (auto& i : evicted) {
ALOGE("%s: Invalid state: Offline client for camera %s was not removed ",
__FUNCTION__, i->getKey().string());
}
LOG_ALWAYS_FATAL("%s: Invalid state for CameraService, offline clients not evicted "
"properly", __FUNCTION__);
return BAD_VALUE;
}
logConnectedOffline(offlineClientDesc->getKey(),
static_cast<int>(offlineClientDesc->getOwnerId()),
String8(offlineClient->getPackageName()));
sp<IBinder> remoteCallback = offlineClient->getRemote();
if (remoteCallback != nullptr) {
remoteCallback->linkToDeath(this);
}
} // lock is destroyed, allow further connect calls
return OK;
}
Status CameraService::setTorchMode(const String16& cameraId, bool enabled,
const sp<IBinder>& clientBinder) {
Mutex::Autolock lock(mServiceLock);
@ -2300,6 +2378,13 @@ void CameraService::logDisconnected(const char* cameraId, int clientPid,
clientPackage, clientPid));
}
void CameraService::logDisconnectedOffline(const char* cameraId, int clientPid,
const char* clientPackage) {
// Log the clients evicted
logEvent(String8::format("DISCONNECT offline device %s client for package %s (PID %d)",
cameraId, clientPackage, clientPid));
}
void CameraService::logConnected(const char* cameraId, int clientPid,
const char* clientPackage) {
// Log the clients evicted
@ -2307,6 +2392,13 @@ void CameraService::logConnected(const char* cameraId, int clientPid,
clientPackage, clientPid));
}
void CameraService::logConnectedOffline(const char* cameraId, int clientPid,
const char* clientPackage) {
// Log the clients evicted
logEvent(String8::format("CONNECT offline device %s client for package %s (PID %d)", cameraId,
clientPackage, clientPid));
}
void CameraService::logRejected(const char* cameraId, int clientPid,
const char* clientPackage, const char* reason) {
// Log the client rejected
@ -2744,6 +2836,7 @@ void CameraService::BasicClient::opChanged(int32_t op, const String16&) {
if (mAppOpsManager == nullptr) {
return;
}
// TODO : add offline camera session case
if (op != AppOpsManager::OP_CAMERA) {
ALOGW("Unexpected app ops notification received: %d", op);
return;
@ -2778,20 +2871,6 @@ void CameraService::BasicClient::block() {
// ----------------------------------------------------------------------------
sp<CameraService> CameraService::OfflineClient::sCameraService;
status_t CameraService::OfflineClient::startCameraOps() {
// TODO
return OK;
}
status_t CameraService::OfflineClient::finishCameraOps() {
// TODO
return OK;
}
// ----------------------------------------------------------------------------
void CameraService::Client::notifyError(int32_t errorCode,
const CaptureResultExtras& resultExtras) {
(void) resultExtras;

@ -68,6 +68,7 @@ class CameraService :
{
friend class BinderService<CameraService>;
friend class CameraClient;
friend class CameraOfflineSessionClient;
public:
class Client;
class BasicClient;
@ -185,6 +186,9 @@ public:
// Monitored UIDs availability notification
void notifyMonitoredUids();
// Register an offline client for a given active camera id
status_t addOfflineClient(String8 cameraId, sp<BasicClient> offlineClient);
/////////////////////////////////////////////////////////////////////
// Client functionality
@ -310,10 +314,9 @@ public:
sp<IBinder> mRemoteBinder; // immutable after constructor
// permissions management
status_t startCameraOps();
status_t finishCameraOps();
virtual status_t startCameraOps();
virtual status_t finishCameraOps();
private:
std::unique_ptr<AppOpsManager> mAppOpsManager = nullptr;
class OpsCallback : public BnAppOpsCallback {
@ -402,87 +405,6 @@ public:
int mCameraId; // All API1 clients use integer camera IDs
}; // class Client
// Client for offline session. Note that offline session client does not affect camera service's
// client arbitration logic. It is camera HAL's decision to decide whether a normal camera
// client is conflicting with existing offline client(s).
// The other distinctive difference between offline clients and normal clients is that normal
// clients are created through ICameraService binder calls, while the offline session client
// is created through ICameraDeviceUser::switchToOffline call.
class OfflineClient : public virtual RefBase {
virtual status_t dump(int fd, const Vector<String16>& args) = 0;
// Block the client form using the camera
virtual void block() = 0;
// Return the package name for this client
virtual String16 getPackageName() const = 0;
// Notify client about a fatal error
// TODO: maybe let impl notify within block?
virtual void notifyError(int32_t errorCode,
const CaptureResultExtras& resultExtras) = 0;
// Get the UID of the application client using this
virtual uid_t getClientUid() const = 0;
// Get the PID of the application client using this
virtual int getClientPid() const = 0;
protected:
OfflineClient(const sp<CameraService>& cameraService,
const String16& clientPackageName,
const String8& cameraIdStr,
int clientPid,
uid_t clientUid,
int servicePid): mCameraIdStr(cameraIdStr),
mClientPackageName(clientPackageName), mClientPid(clientPid),
mClientUid(clientUid), mServicePid(servicePid) {
if (sCameraService == nullptr) {
sCameraService = cameraService;
}
}
virtual ~OfflineClient() { /*TODO*/ }
// these are initialized in the constructor.
static sp<CameraService> sCameraService;
const String8 mCameraIdStr;
String16 mClientPackageName;
pid_t mClientPid;
const uid_t mClientUid;
const pid_t mServicePid;
bool mDisconnected;
// - The app-side Binder interface to receive callbacks from us
sp<IBinder> mRemoteBinder; // immutable after constructor
// permissions management
status_t startCameraOps();
status_t finishCameraOps();
private:
std::unique_ptr<AppOpsManager> mAppOpsManager = nullptr;
class OpsCallback : public BnAppOpsCallback {
public:
explicit OpsCallback(wp<OfflineClient> client) : mClient(client) {}
virtual void opChanged(int32_t /*op*/, const String16& /*packageName*/) {
//TODO
}
private:
wp<OfflineClient> mClient;
}; // class OpsCallback
sp<OpsCallback> mOpsCallback;
// IAppOpsCallback interface, indirected through opListener
// virtual void opChanged(int32_t op, const String16& packageName);
}; // class OfflineClient
/**
* A listener class that implements the LISTENER interface for use with a ClientManager, and
* implements the following methods:
@ -871,6 +793,17 @@ private:
*/
void logDisconnected(const char* cameraId, int clientPid, const char* clientPackage);
/**
* Add an event log message that a client has been disconnected from offline device.
*/
void logDisconnectedOffline(const char* cameraId, int clientPid, const char* clientPackage);
/**
* Add an event log message that an offline client has been connected.
*/
void logConnectedOffline(const char* cameraId, int clientPid,
const char* clientPackage);
/**
* Add an event log message that a client has been connected.
*/
@ -1095,6 +1028,12 @@ private:
void broadcastTorchModeStatus(const String8& cameraId,
hardware::camera::common::V1_0::TorchModeStatus status);
void disconnectClient(const String8& id, sp<BasicClient> clientToDisconnect);
// Regular online and offline devices must not be in conflict at camera service layer.
// Use separate keys for offline devices.
static const String8 kOfflineDevice;
// TODO: right now each BasicClient holds one AppOpsManager instance.
// We can refactor the code so all of clients share this instance
AppOpsManager mAppOps;

@ -470,7 +470,8 @@ binder::Status CameraDeviceClient::beginConfigure() {
}
binder::Status CameraDeviceClient::endConfigure(int operatingMode,
const hardware::camera2::impl::CameraMetadataNative& sessionParams) {
const hardware::camera2::impl::CameraMetadataNative& sessionParams,
std::vector<int>* offlineStreamIds /*out*/) {
ATRACE_CALL();
ALOGV("%s: ending configure (%d input stream, %zu output surfaces)",
__FUNCTION__, mInputStream.configured ? 1 : 0,
@ -479,6 +480,12 @@ binder::Status CameraDeviceClient::endConfigure(int operatingMode,
binder::Status res;
if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
if (offlineStreamIds == nullptr) {
String8 msg = String8::format("Invalid offline stream ids");
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
Mutex::Autolock icl(mBinderSerializationLock);
if (!mDevice.get()) {
@ -502,15 +509,41 @@ binder::Status CameraDeviceClient::endConfigure(int operatingMode,
ALOGE("%s: %s", __FUNCTION__, msg.string());
res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
} else {
offlineStreamIds->clear();
mDevice->getOfflineStreamIds(offlineStreamIds);
for (size_t i = 0; i < mCompositeStreamMap.size(); ++i) {
err = mCompositeStreamMap.valueAt(i)->configureStream();
if (err != OK ) {
if (err != OK) {
String8 msg = String8::format("Camera %s: Error configuring composite "
"streams: %s (%d)", mCameraIdStr.string(), strerror(-err), err);
ALOGE("%s: %s", __FUNCTION__, msg.string());
res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
break;
}
// Composite streams can only support offline mode in case all individual internal
// streams are also supported.
std::vector<int> internalStreams;
mCompositeStreamMap.valueAt(i)->insertCompositeStreamIds(&internalStreams);
std::remove_if(offlineStreamIds->begin(), offlineStreamIds->end(),
[&internalStreams] (int streamId) {
auto it = std::find(internalStreams.begin(), internalStreams.end(),
streamId);
if (it != internalStreams.end()) {
internalStreams.erase(it);
return true;
}
return false;
});
if (internalStreams.empty()) {
offlineStreamIds->push_back(mCompositeStreamMap.valueAt(i)->getStreamId());
}
}
for (const auto& offlineStreamId : *offlineStreamIds) {
mStreamInfoMap[offlineStreamId].supportsOffline = true;
}
}
@ -1903,7 +1936,7 @@ binder::Status CameraDeviceClient::getGlobalAudioRestriction(/*out*/ int32_t* ou
binder::Status CameraDeviceClient::switchToOffline(
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
const std::vector<view::Surface>& offlineOutputs,
const std::vector<int>& offlineOutputIds,
/*out*/
sp<hardware::camera2::ICameraOfflineSession>* session) {
ATRACE_CALL();
@ -1917,8 +1950,8 @@ binder::Status CameraDeviceClient::switchToOffline(
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
if (offlineOutputs.empty()) {
String8 msg = String8::format("Offline outputs must not be empty");
if (offlineOutputIds.empty()) {
String8 msg = String8::format("Offline surfaces must not be empty");
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
@ -1929,24 +1962,47 @@ binder::Status CameraDeviceClient::switchToOffline(
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
std::vector<int32_t> offlineStreamIds(offlineOutputs.size());
for (auto& surface : offlineOutputs) {
sp<IBinder> binder = IInterface::asBinder(surface.graphicBufferProducer);
ssize_t index = mStreamMap.indexOfKey(binder);
std::vector<int32_t> offlineStreamIds(offlineOutputIds.size());
KeyedVector<sp<IBinder>, sp<CompositeStream>> offlineCompositeStreamMap;
for (const auto& streamId : offlineOutputIds) {
ssize_t index = mConfiguredOutputs.indexOfKey(streamId);
if (index == NAME_NOT_FOUND) {
String8 msg = String8::format("Offline output is invalid");
String8 msg = String8::format("Offline surface with id: %d is not registered",
streamId);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
// TODO: Also check whether the offline output is supported by Hal for offline mode.
sp<Surface> s = new Surface(surface.graphicBufferProducer);
bool isCompositeStream = camera3::DepthCompositeStream::isDepthCompositeStream(s);
isCompositeStream |= camera3::HeicCompositeStream::isHeicCompositeStream(s);
if (isCompositeStream) {
// TODO: Add composite specific handling
} else {
offlineStreamIds.push_back(mStreamMap.valueAt(index).streamId());
if (!mStreamInfoMap[streamId].supportsOffline) {
String8 msg = String8::format("Offline surface with id: %d doesn't support "
"offline mode", streamId);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
bool isCompositeStream = false;
for (const auto& gbp : mConfiguredOutputs[streamId].getGraphicBufferProducers()) {
sp<Surface> s = new Surface(gbp, false /*controlledByApp*/);
isCompositeStream = camera3::DepthCompositeStream::isDepthCompositeStream(s) |
camera3::HeicCompositeStream::isHeicCompositeStream(s);
if (isCompositeStream) {
auto compositeIdx = mCompositeStreamMap.indexOfKey(IInterface::asBinder(gbp));
if (compositeIdx == NAME_NOT_FOUND) {
ALOGE("%s: Unknown composite stream", __FUNCTION__);
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
"Unknown composite stream");
}
mCompositeStreamMap.valueAt(compositeIdx)->insertCompositeStreamIds(
&offlineStreamIds);
offlineCompositeStreamMap.add(mCompositeStreamMap.keyAt(compositeIdx),
mCompositeStreamMap.valueAt(compositeIdx));
break;
}
}
if (!isCompositeStream) {
offlineStreamIds.push_back(streamId);
}
}
@ -1958,16 +2014,36 @@ binder::Status CameraDeviceClient::switchToOffline(
mCameraIdStr.string(), strerror(ret), ret);
}
sp<CameraOfflineSessionClient> offlineClient = new CameraOfflineSessionClient(sCameraService,
offlineSession, cameraCb, mClientPackageName, mCameraIdStr, mClientPid, mClientUid,
mServicePid);
ret = offlineClient->initialize();
sp<CameraOfflineSessionClient> offlineClient;
if (offlineSession.get() != nullptr) {
offlineClient = new CameraOfflineSessionClient(sCameraService,
offlineSession, offlineCompositeStreamMap, cameraCb, mClientPackageName,
mClientFeatureId, mCameraIdStr, mCameraFacing, mClientPid, mClientUid, mServicePid);
ret = sCameraService->addOfflineClient(mCameraIdStr, offlineClient);
}
if (ret == OK) {
// TODO: We need to update mStreamMap, mConfiguredOutputs
// A successful offline session switch must reset the current camera client
// and release any resources occupied by previously configured streams.
mStreamMap.clear();
mConfiguredOutputs.clear();
mDeferredStreams.clear();
mStreamInfoMap.clear();
mCompositeStreamMap.clear();
mInputStream = {false, 0, 0, 0, 0};
} else {
return STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
"Camera %s: Failed to initilize offline session: %s (%d)",
mCameraIdStr.string(), strerror(ret), ret);
switch(ret) {
case BAD_VALUE:
return STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
"Illegal argument to HAL module for camera \"%s\"", mCameraIdStr.c_str());
case TIMED_OUT:
return STATUS_ERROR_FMT(CameraService::ERROR_CAMERA_IN_USE,
"Camera \"%s\" is already open", mCameraIdStr.c_str());
default:
return STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
"Failed to initialize camera \"%s\": %s (%d)", mCameraIdStr.c_str(),
strerror(-ret), ret);
}
}
*session = offlineClient;

@ -92,7 +92,9 @@ public:
virtual binder::Status beginConfigure() override;
virtual binder::Status endConfigure(int operatingMode,
const hardware::camera2::impl::CameraMetadataNative& sessionParams) override;
const hardware::camera2::impl::CameraMetadataNative& sessionParams,
/*out*/
std::vector<int>* offlineStreamIds) override;
// Verify specific session configuration.
virtual binder::Status isSessionConfigurationSupported(
@ -160,7 +162,7 @@ public:
virtual binder::Status switchToOffline(
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
const std::vector<view::Surface>& offlineOutputs,
const std::vector<int>& offlineOutputIds,
/*out*/
sp<hardware::camera2::ICameraOfflineSession>* session) override;

@ -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

@ -19,65 +19,88 @@
#include <android/hardware/camera2/BnCameraOfflineSession.h>
#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
#include "common/FrameProcessorBase.h"
#include "common/CameraDeviceBase.h"
#include "CameraService.h"
#include "CompositeStream.h"
namespace android {
using android::hardware::camera2::ICameraDeviceCallbacks;
using camera3::CompositeStream;
// Client for offline session. Note that offline session client does not affect camera service's
// client arbitration logic. It is camera HAL's decision to decide whether a normal camera
// client is conflicting with existing offline client(s).
// The other distinctive difference between offline clients and normal clients is that normal
// clients are created through ICameraService binder calls, while the offline session client
// is created through ICameraDeviceUser::switchToOffline call.
class CameraOfflineSessionClient :
public CameraService::OfflineClient,
public hardware::camera2::BnCameraOfflineSession
// public camera2::FrameProcessorBase::FilteredListener?
public CameraService::BasicClient,
public hardware::camera2::BnCameraOfflineSession,
public camera2::FrameProcessorBase::FilteredListener,
public NotificationListener
{
public:
CameraOfflineSessionClient(
const sp<CameraService>& cameraService,
sp<CameraOfflineSessionBase> session,
const KeyedVector<sp<IBinder>, sp<CompositeStream>>& offlineCompositeStreamMap,
const sp<ICameraDeviceCallbacks>& remoteCallback,
const String16& clientPackageName,
const String8& cameraIdStr,
const std::unique_ptr<String16>& clientFeatureId,
const String8& cameraIdStr, int cameraFacing,
int clientPid, uid_t clientUid, int servicePid) :
CameraService::OfflineClient(cameraService, clientPackageName,
cameraIdStr, clientPid, clientUid, servicePid),
mRemoteCallback(remoteCallback), mOfflineSession(session) {}
~CameraOfflineSessionClient() {}
CameraService::BasicClient(
cameraService,
IInterface::asBinder(remoteCallback),
clientPackageName, clientFeatureId,
cameraIdStr, cameraFacing, clientPid, clientUid, servicePid),
mRemoteCallback(remoteCallback), mOfflineSession(session),
mCompositeStreamMap(offlineCompositeStreamMap) {}
virtual ~CameraOfflineSessionClient() {}
sp<IBinder> asBinderWrapper() override {
return IInterface::asBinder(this);
}
virtual binder::Status disconnect() override { return binder::Status::ok(); }
binder::Status disconnect() override;
virtual status_t dump(int /*fd*/, const Vector<String16>& /*args*/) override {
return OK;
}
status_t dump(int /*fd*/, const Vector<String16>& /*args*/) override;
// Block the client form using the camera
virtual void block() override {};
status_t dumpClient(int /*fd*/, const Vector<String16>& /*args*/) override;
// Return the package name for this client
virtual String16 getPackageName() const override { String16 ret; return ret; };
status_t initialize(sp<CameraProviderManager> /*manager*/,
const String8& /*monitorTags*/) override;
// Notify client about a fatal error
// TODO: maybe let impl notify within block?
virtual void notifyError(int32_t /*errorCode*/,
const CaptureResultExtras& /*resultExtras*/) override {}
// permissions management
status_t startCameraOps() override;
status_t finishCameraOps() override;
// Get the UID of the application client using this
virtual uid_t getClientUid() const override { return 0; }
// FilteredResultListener API
void onResultAvailable(const CaptureResult& result) override;
// Get the PID of the application client using this
virtual int getClientPid() const override { return 0; }
// NotificationListener API
void notifyError(int32_t errorCode, const CaptureResultExtras& resultExtras) override;
void notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) override;
void notifyIdle() override;
void notifyAutoFocus(uint8_t newState, int triggerId) override;
void notifyAutoExposure(uint8_t newState, int triggerId) override;
void notifyAutoWhitebalance(uint8_t newState, int triggerId) override;
void notifyPrepared(int streamId) override;
void notifyRequestQueueEmpty() override;
void notifyRepeatingRequestError(long lastFrameNumber) override;
status_t initialize() {
// TODO: Talk to camera service to add the offline session client book keeping
return OK;
}
private:
sp<CameraOfflineSessionBase> mSession;
mutable Mutex mBinderSerializationLock;
sp<hardware::camera2::ICameraDeviceCallbacks> mRemoteCallback;
// This class is responsible to convert HAL callbacks to AIDL callbacks
sp<CameraOfflineSessionBase> mOfflineSession;
// Offline composite stream map, output surface -> composite stream
KeyedVector<sp<IBinder>, sp<CompositeStream>> mCompositeStreamMap;
};
} // namespace android

@ -64,6 +64,10 @@ public:
virtual status_t insertGbp(SurfaceMap* /*out*/outSurfaceMap,
Vector<int32_t>* /*out*/outputStreamIds, int32_t* /*out*/currentStreamId) = 0;
// Attach the internal composite stream ids.
virtual status_t insertCompositeStreamIds(
std::vector<int32_t>* compositeStreamIds /*out*/) = 0;
// Return composite stream id.
virtual int getStreamId() = 0;

@ -683,6 +683,18 @@ status_t DepthCompositeStream::insertGbp(SurfaceMap* /*out*/outSurfaceMap,
return NO_ERROR;
}
status_t DepthCompositeStream::insertCompositeStreamIds(
std::vector<int32_t>* compositeStreamIds /*out*/) {
if (compositeStreamIds == nullptr) {
return BAD_VALUE;
}
compositeStreamIds->push_back(mDepthStreamId);
compositeStreamIds->push_back(mBlobStreamId);
return OK;
}
void DepthCompositeStream::onResultError(const CaptureResultExtras& resultExtras) {
// Processing can continue even in case of result errors.
// At the moment depth composite stream processing relies mainly on static camera

@ -56,6 +56,7 @@ public:
status_t configureStream() override;
status_t insertGbp(SurfaceMap* /*out*/outSurfaceMap, Vector<int32_t>* /*out*/outputStreamIds,
int32_t* /*out*/currentStreamId) override;
status_t insertCompositeStreamIds(std::vector<int32_t>* compositeStreamIds /*out*/) override;
int getStreamId() override { return mBlobStreamId; }
// CpuConsumer listener implementation

@ -504,6 +504,18 @@ status_t HeicCompositeStream::insertGbp(SurfaceMap* /*out*/outSurfaceMap,
return NO_ERROR;
}
status_t HeicCompositeStream::insertCompositeStreamIds(
std::vector<int32_t>* compositeStreamIds /*out*/) {
if (compositeStreamIds == nullptr) {
return BAD_VALUE;
}
compositeStreamIds->push_back(mAppSegmentStreamId);
compositeStreamIds->push_back(mMainImageStreamId);
return OK;
}
void HeicCompositeStream::onShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) {
Mutex::Autolock l(mMutex);
if (mErrorState) {

@ -55,6 +55,8 @@ public:
status_t insertGbp(SurfaceMap* /*out*/outSurfaceMap, Vector<int32_t>* /*out*/outputStreamIds,
int32_t* /*out*/currentStreamId) override;
status_t insertCompositeStreamIds(std::vector<int32_t>* compositeStreamIds /*out*/) override;
void onShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) override;
int getStreamId() override { return mMainImageStreamId; }

@ -111,7 +111,7 @@ status_t Camera2ClientBase<TClientBase>::initializeImpl(TProviderPtr providerPtr
return res;
}
wp<CameraDeviceBase::NotificationListener> weakThis(this);
wp<NotificationListener> weakThis(this);
res = mDevice->setNotifyCallback(weakThis);
return OK;

@ -29,7 +29,7 @@ class CameraService;
template <typename TClientBase>
class Camera2ClientBase :
public TClientBase,
public CameraDeviceBase::NotificationListener
public NotificationListener
{
public:
typedef typename TClientBase::TCamCallbacks TCamCallbacks;
@ -61,7 +61,7 @@ public:
virtual status_t dumpClient(int fd, const Vector<String16>& args);
/**
* CameraDeviceBase::NotificationListener implementation
* NotificationListener implementation
*/
virtual void notifyError(int32_t errorCode,

@ -24,7 +24,4 @@ namespace android {
CameraDeviceBase::~CameraDeviceBase() {
}
CameraDeviceBase::NotificationListener::~NotificationListener() {
}
} // namespace android

@ -234,6 +234,12 @@ class CameraDeviceBase : public virtual RefBase {
virtual status_t configureStreams(const CameraMetadata& sessionParams,
int operatingMode = 0) = 0;
/**
* Retrieve a list of all stream ids that were advertised as capable of
* supporting offline processing mode by Hal after the last stream configuration.
*/
virtual void getOfflineStreamIds(std::vector<int> *offlineStreamIds) = 0;
// get the buffer producer of the input stream
virtual status_t getInputBufferProducer(
sp<IGraphicBufferProducer> *producer) = 0;
@ -258,35 +264,6 @@ class CameraDeviceBase : public virtual RefBase {
*/
virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const = 0;
/**
* Abstract class for HAL notification listeners
*/
class NotificationListener : public virtual RefBase {
public:
// The set of notifications is a merge of the notifications required for
// API1 and API2.
// Required for API 1 and 2
virtual void notifyError(int32_t errorCode,
const CaptureResultExtras &resultExtras) = 0;
// Required only for API2
virtual void notifyIdle() = 0;
virtual void notifyShutter(const CaptureResultExtras &resultExtras,
nsecs_t timestamp) = 0;
virtual void notifyPrepared(int streamId) = 0;
virtual void notifyRequestQueueEmpty() = 0;
// Required only for API1
virtual void notifyAutoFocus(uint8_t newState, int triggerId) = 0;
virtual void notifyAutoExposure(uint8_t newState, int triggerId) = 0;
virtual void notifyAutoWhitebalance(uint8_t newState,
int triggerId) = 0;
virtual void notifyRepeatingRequestError(long lastFrameNumber) = 0;
protected:
virtual ~NotificationListener();
};
/**
* Connect HAL notifications to a listener. Overwrites previous
* listener. Set to NULL to stop receiving notifications.

@ -25,10 +25,42 @@
namespace android {
/**
* Abstract class for HAL notification listeners
*/
class NotificationListener : public virtual RefBase {
public:
// The set of notifications is a merge of the notifications required for
// API1 and API2.
// Required for API 1 and 2
virtual void notifyError(int32_t errorCode,
const CaptureResultExtras &resultExtras) = 0;
// Required only for API2
virtual void notifyIdle() = 0;
virtual void notifyShutter(const CaptureResultExtras &resultExtras,
nsecs_t timestamp) = 0;
virtual void notifyPrepared(int streamId) = 0;
virtual void notifyRequestQueueEmpty() = 0;
// Required only for API1
virtual void notifyAutoFocus(uint8_t newState, int triggerId) = 0;
virtual void notifyAutoExposure(uint8_t newState, int triggerId) = 0;
virtual void notifyAutoWhitebalance(uint8_t newState,
int triggerId) = 0;
virtual void notifyRepeatingRequestError(long lastFrameNumber) = 0;
protected:
virtual ~NotificationListener() {}
};
class CameraOfflineSessionBase : public virtual RefBase {
public:
virtual ~CameraOfflineSessionBase();
virtual status_t initialize(
wp<NotificationListener> listener) = 0;
// The session's original camera ID
virtual const String8& getId() const = 0;
@ -36,8 +68,6 @@ class CameraOfflineSessionBase : public virtual RefBase {
virtual status_t dump(int fd) = 0;
virtual status_t abort() = 0;
/**
* Capture result passing
*/

@ -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

@ -43,10 +43,14 @@
#include <camera/CaptureResult.h>
#include "common/CameraDeviceBase.h"
#include "device3/BufferUtils.h"
#include "device3/StatusTracker.h"
#include "device3/Camera3BufferManager.h"
#include "device3/DistortionMapper.h"
#include "device3/ZoomRatioMapper.h"
#include "device3/InFlightRequest.h"
#include "device3/Camera3OutputInterface.h"
#include "device3/Camera3OfflineSession.h"
#include "utils/TagMonitor.h"
#include "utils/LatencyHistogram.h"
#include <camera_metadata_hidden.h>
@ -69,7 +73,11 @@ class Camera3StreamInterface;
*/
class Camera3Device :
public CameraDeviceBase,
virtual public hardware::camera::device::V3_5::ICameraDeviceCallback {
virtual public hardware::camera::device::V3_5::ICameraDeviceCallback,
public camera3::SetErrorInterface,
public camera3::InflightRequestUpdateInterface,
public camera3::RequestBufferInterface,
public camera3::FlushBufferInterface {
public:
explicit Camera3Device(const String8& id);
@ -142,6 +150,8 @@ class Camera3Device :
status_t getInputBufferProducer(
sp<IGraphicBufferProducer> *producer) override;
void getOfflineStreamIds(std::vector<int> *offlineStreamIds) override;
status_t createDefaultRequest(int templateId, CameraMetadata *request) override;
// Transitions to the idle state on success
@ -201,6 +211,16 @@ class Camera3Device :
status_t switchToOffline(const std::vector<int32_t>& streamsToKeep,
/*out*/ sp<CameraOfflineSessionBase>* session) override;
// RequestBufferInterface
bool startRequestBuffer() override;
void endRequestBuffer() override;
nsecs_t getWaitDuration() override;
// FlushBufferInterface
void getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out) override;
void getInflightRequestBufferKeys(std::vector<uint64_t>* out) override;
std::vector<sp<camera3::Camera3StreamInterface>> getAllStreams() override;
/**
* Helper functions to map between framework and HIDL values
*/
@ -213,8 +233,6 @@ class Camera3Device :
// Returns a negative error code if the passed-in operation mode is not valid.
static status_t mapToStreamConfigurationMode(camera3_stream_configuration_mode_t operationMode,
/*out*/ hardware::camera::device::V3_2::StreamConfigurationMode *mode);
static camera3_buffer_status_t mapHidlBufferStatus(
hardware::camera::device::V3_2::BufferStatus status);
static int mapToFrameworkFormat(hardware::graphics::common::V1_0::PixelFormat pixelFormat);
static android_dataspace mapToFrameworkDataspace(
hardware::camera::device::V3_2::DataspaceFlags);
@ -229,7 +247,6 @@ class Camera3Device :
// internal typedefs
using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
using ResultMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
static const size_t kDumpLockAttempts = 10;
static const size_t kDumpSleepDuration = 100000; // 0.10 sec
@ -283,7 +300,8 @@ class Camera3Device :
* Adapter for legacy HAL / HIDL HAL interface calls; calls either into legacy HALv3 or the
* HIDL HALv3 interfaces.
*/
class HalInterface : public camera3::Camera3StreamBufferFreedListener {
class HalInterface : public camera3::Camera3StreamBufferFreedListener,
public camera3::BufferRecordsInterface {
public:
HalInterface(sp<hardware::camera::device::V3_2::ICameraDeviceSession> &session,
std::shared_ptr<RequestMetadataQueue> queue,
@ -321,27 +339,31 @@ class Camera3Device :
bool isReconfigurationRequired(CameraMetadata& oldSessionParams,
CameraMetadata& newSessionParams);
// Upon successful return, HalInterface will return buffer maps needed for offline
// processing, and clear all its internal buffer maps.
status_t switchToOffline(
const std::vector<int32_t>& streamsToKeep,
/*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
/*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession);
/*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
/*out*/camera3::BufferRecords* bufferRecords);
// method to extract buffer's unique ID
// return pair of (newlySeenBuffer?, bufferId)
std::pair<bool, uint64_t> getBufferId(const buffer_handle_t& buf, int streamId);
/////////////////////////////////////////////////////////////////////
// Implements BufferRecordsInterface
std::pair<bool, uint64_t> getBufferId(
const buffer_handle_t& buf, int streamId) override;
// Find a buffer_handle_t based on frame number and stream ID
status_t popInflightBuffer(int32_t frameNumber, int32_t streamId,
/*out*/ buffer_handle_t **buffer);
/*out*/ buffer_handle_t **buffer) override;
// Register a bufId (streamId, buffer_handle_t) to inflight request buffer
status_t pushInflightRequestBuffer(
uint64_t bufferId, buffer_handle_t* buf, int32_t streamId);
uint64_t bufferId, buffer_handle_t* buf, int32_t streamId) override;
// Find a buffer_handle_t based on bufferId
status_t popInflightRequestBuffer(uint64_t bufferId,
/*out*/ buffer_handle_t** buffer,
/*optional out*/ int32_t* streamId = nullptr);
/*optional out*/ int32_t* streamId = nullptr) override;
/////////////////////////////////////////////////////////////////////
// Get a vector of (frameNumber, streamId) pair of currently inflight
// buffers
@ -352,7 +374,6 @@ class Camera3Device :
void onStreamReConfigured(int streamId);
static const uint64_t BUFFER_ID_NO_BUFFER = 0;
private:
// Always valid
sp<hardware::camera::device::V3_2::ICameraDeviceSession> mHidlSession;
@ -367,8 +388,6 @@ class Camera3Device :
std::shared_ptr<RequestMetadataQueue> mRequestMetadataQueue;
std::mutex mInflightLock;
// The output HIDL request still depends on input camera3_capture_request_t
// Do not free input camera3_capture_request_t before output HIDL request
status_t wrapAsHidlRequest(camera3_capture_request_t* in,
@ -382,55 +401,20 @@ class Camera3Device :
// Pop inflight buffers based on pairs of (frameNumber,streamId)
void popInflightBuffers(const std::vector<std::pair<int32_t, int32_t>>& buffers);
// Cache of buffer handles keyed off (frameNumber << 32 | streamId)
std::unordered_map<uint64_t, buffer_handle_t*> mInflightBufferMap;
// Return true if the input caches match what we have; otherwise false
bool verifyBufferIds(int32_t streamId, std::vector<uint64_t>& inBufIds);
// Delete and optionally close native handles and clear the input vector afterward
static void cleanupNativeHandles(
std::vector<native_handle_t*> *handles, bool closeFd = false);
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;
}
};
std::mutex mBufferIdMapLock; // protecting mBufferIdMaps and mNextBufferId
typedef std::unordered_map<const buffer_handle_t, uint64_t,
BufferHasher, BufferComparator> BufferIdMap;
// stream ID -> per stream buffer ID map
std::unordered_map<int, BufferIdMap> mBufferIdMaps;
uint64_t mNextBufferId = 1; // 0 means no buffer
virtual void onBufferFreed(int streamId, const native_handle_t* handle) override;
std::mutex mFreedBuffersLock;
std::vector<std::pair<int, uint64_t>> mFreedBuffers;
// Buffers given to HAL through requestStreamBuffer API
std::mutex mRequestedBuffersLock;
std::unordered_map<uint64_t, std::pair<int32_t, buffer_handle_t*>> mRequestedBuffers;
// Keep track of buffer cache and inflight buffer records
camera3::BufferRecords mBufferRecords;
uint32_t mNextStreamConfigCounter = 1;
@ -473,24 +457,7 @@ class Camera3Device :
// Tracking cause of fatal errors when in STATUS_ERROR
String8 mErrorCause;
// Synchronized mapping of stream IDs to stream instances
class StreamSet {
public:
status_t add(int streamId, sp<camera3::Camera3OutputStreamInterface>);
ssize_t remove(int streamId);
sp<camera3::Camera3OutputStreamInterface> get(int streamId);
// get by (underlying) vector index
sp<camera3::Camera3OutputStreamInterface> operator[] (size_t index);
size_t size() const;
std::vector<int> getStreamIds();
void clear();
private:
mutable std::mutex mLock;
KeyedVector<int, sp<camera3::Camera3OutputStreamInterface>> mData;
};
StreamSet mOutputStreams;
camera3::StreamSet mOutputStreams;
sp<camera3::Camera3Stream> mInputStream;
int mNextStreamId;
bool mNeedConfig;
@ -579,15 +546,6 @@ class Camera3Device :
const hardware::hidl_vec<
hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
// Handle one capture result. Assume that mProcessCaptureResultLock is held.
void processOneCaptureResultLocked(
const hardware::camera::device::V3_2::CaptureResult& result,
const hardware::hidl_vec<
hardware::camera::device::V3_4::PhysicalCameraMetadata> physicalCameraMetadata);
status_t readOneCameraMetadataLocked(uint64_t fmqResultSize,
hardware::camera::device::V3_2::CameraMetadata& resultMetadata,
const hardware::camera::device::V3_2::CameraMetadata& result);
// Handle one notify message
void notify(const hardware::camera::device::V3_2::NotifyMsg& msg);
@ -710,23 +668,26 @@ class Camera3Device :
* error message to indicate why. Only the first call's message will be
* used. The message is also sent to the log.
*/
void setErrorState(const char *fmt, ...);
void setErrorState(const char *fmt, ...) override;
void setErrorStateLocked(const char *fmt, ...) override;
void setErrorStateV(const char *fmt, va_list args);
void setErrorStateLocked(const char *fmt, ...);
void setErrorStateLockedV(const char *fmt, va_list args);
/////////////////////////////////////////////////////////////////////
// Implements InflightRequestUpdateInterface
void onInflightEntryRemovedLocked(nsecs_t duration) override;
void checkInflightMapLengthLocked() override;
void onInflightMapFlushedLocked() override;
/////////////////////////////////////////////////////////////////////
/**
* Debugging trylock/spin method
* Try to acquire a lock a few times with sleeps between before giving up.
*/
bool tryLockSpinRightRound(Mutex& lock);
/**
* Helper function to determine if an input size for implementation defined
* format is supported.
*/
bool isOpaqueInputSizeSupported(uint32_t width, uint32_t height);
/**
* Helper function to get the largest Jpeg resolution (in area)
* Return Size(0, 0) if static metatdata is invalid
@ -860,7 +821,8 @@ class Camera3Device :
status_t switchToOffline(
const std::vector<int32_t>& streamsToKeep,
/*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
/*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession);
/*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
/*out*/camera3::BufferRecords* bufferRecords);
protected:
@ -1021,119 +983,12 @@ class Camera3Device :
/**
* In-flight queue for tracking completion of capture requests.
*/
std::mutex mInFlightLock;
camera3::InFlightRequestMap mInFlightMap;
nsecs_t mExpectedInflightDuration = 0;
// End of mInFlightLock protection scope
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;
// 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> InFlightMap;
Mutex mInFlightLock; // Protects mInFlightMap and
// mExpectedInflightDuration
InFlightMap mInFlightMap;
nsecs_t mExpectedInflightDuration = 0;
int mInFlightStatusId;
int mInFlightStatusId; // const after initialize
status_t registerInFlight(uint32_t frameNumber,
int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
@ -1211,7 +1066,7 @@ class Camera3Device :
*/
// Lock for output side of device
Mutex mOutputLock;
std::mutex mOutputLock;
/**** Scope for mOutputLock ****/
// the minimal frame number of the next non-reprocess result
@ -1226,61 +1081,18 @@ class Camera3Device :
uint32_t mNextReprocessShutterFrameNumber;
// the minimal frame number of the next ZSL still capture shutter
uint32_t mNextZslStillShutterFrameNumber;
List<CaptureResult> mResultQueue;
Condition mResultSignal;
wp<NotificationListener> mListener;
List<CaptureResult> mResultQueue;
std::condition_variable mResultSignal;
wp<NotificationListener> mListener;
/**** End scope for mOutputLock ****/
/**
* Callback functions from HAL device
*/
void processCaptureResult(const camera3_capture_result *result);
void notify(const camera3_notify_msg *msg);
// Specific notify handlers
void notifyError(const camera3_error_msg_t &msg,
sp<NotificationListener> listener);
void notifyShutter(const camera3_shutter_msg_t &msg,
sp<NotificationListener> listener);
// helper function to return the output buffers to the streams.
void returnOutputBuffers(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{});
// Send a partial capture result.
void sendPartialCaptureResult(const camera_metadata_t * partialResult,
const CaptureResultExtras &resultExtras, uint32_t frameNumber);
// Send a total capture result given the pending metadata and result extras,
// partial results, and the frame number to the result queue.
void sendCaptureResult(CameraMetadata &pendingMetadata,
CaptureResultExtras &resultExtras,
CameraMetadata &collectedPartialResult, uint32_t frameNumber,
bool reprocess, bool zslStillCapture,
const std::set<std::string>& cameraIdsWithZoom,
const std::vector<PhysicalCaptureResultInfo>& physicalMetadatas);
bool isLastFullResult(const InFlightRequest& inFlightRequest);
// Insert the result to the result queue after updating frame number and overriding AE
// trigger cancel.
// mOutputLock must be held when calling this function.
void insertResultLocked(CaptureResult *result, uint32_t frameNumber);
/**** Scope for mInFlightLock ****/
// Remove the in-flight map entry of the given index from mInFlightMap.
// It must only be called with mInFlightLock held.
void removeInFlightMapEntryLocked(int idx);
// Remove the in-flight request of the given index from mInFlightMap
// if it's no longer needed. It must only be called with mInFlightLock held.
void removeInFlightRequestIfReadyLocked(int idx);
// Remove all in-flight requests and return all buffers.
// This is used after HAL interface is closed to cleanup any request/buffers
// not returned by HAL.
@ -1378,6 +1190,10 @@ class Camera3Device :
void onSubmittingRequest();
void onRequestThreadPaused();
// Events triggered by successful switchToOffline call
// Return true is there is no ongoing requestBuffer call.
bool onSwitchToOfflineSuccess();
private:
void notifyTrackerLocked(bool active);
@ -1391,6 +1207,7 @@ class Camera3Device :
bool mRequestThreadPaused = true;
bool mInflightMapEmpty = true;
bool mRequestBufferOngoing = false;
bool mSwitchedToOffline = false;
wp<camera3::StatusTracker> mStatusTracker;
int mRequestBufferStatusId;
@ -1398,7 +1215,6 @@ class Camera3Device :
// Fix up result metadata for monochrome camera.
bool mNeedFixupMonochromeTags;
status_t fixupMonochromeTags(const CameraMetadata& deviceInfo, CameraMetadata& resultMetadata);
// Whether HAL supports offline processing capability.
bool mSupportOfflineProcessing = false;

@ -29,90 +29,435 @@
#include <utils/Trace.h>
#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
#include "device3/Camera3OfflineSession.h"
#include "device3/Camera3OutputStream.h"
#include "device3/Camera3InputStream.h"
#include "device3/Camera3SharedOutputStream.h"
#include "utils/CameraTraces.h"
using namespace android::camera3;
using namespace android::hardware::camera;
namespace android {
Camera3OfflineSession::Camera3OfflineSession(const String8 &id):
mId(id)
{
Camera3OfflineSession::Camera3OfflineSession(const String8 &id,
const sp<camera3::Camera3Stream>& inputStream,
const camera3::StreamSet& offlineStreamSet,
camera3::BufferRecords&& bufferRecords,
const camera3::InFlightRequestMap& offlineReqs,
const Camera3OfflineStates& offlineStates,
sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession) :
mId(id),
mInputStream(inputStream),
mOutputStreams(offlineStreamSet),
mBufferRecords(std::move(bufferRecords)),
mOfflineReqs(offlineReqs),
mSession(offlineSession),
mTagMonitor(offlineStates.mTagMonitor),
mVendorTagId(offlineStates.mVendorTagId),
mUseHalBufManager(offlineStates.mUseHalBufManager),
mNeedFixupMonochromeTags(offlineStates.mNeedFixupMonochromeTags),
mUsePartialResult(offlineStates.mUsePartialResult),
mNumPartialResults(offlineStates.mNumPartialResults),
mNextResultFrameNumber(offlineStates.mNextResultFrameNumber),
mNextReprocessResultFrameNumber(offlineStates.mNextReprocessResultFrameNumber),
mNextZslStillResultFrameNumber(offlineStates.mNextZslStillResultFrameNumber),
mNextShutterFrameNumber(offlineStates.mNextShutterFrameNumber),
mNextReprocessShutterFrameNumber(offlineStates.mNextReprocessShutterFrameNumber),
mNextZslStillShutterFrameNumber(offlineStates.mNextZslStillShutterFrameNumber),
mDeviceInfo(offlineStates.mDeviceInfo),
mPhysicalDeviceInfoMap(offlineStates.mPhysicalDeviceInfoMap),
mDistortionMappers(offlineStates.mDistortionMappers),
mZoomRatioMappers(offlineStates.mZoomRatioMappers),
mStatus(STATUS_UNINITIALIZED) {
ATRACE_CALL();
ALOGV("%s: Created offline session for camera %s", __FUNCTION__, mId.string());
}
Camera3OfflineSession::~Camera3OfflineSession()
{
Camera3OfflineSession::~Camera3OfflineSession() {
ATRACE_CALL();
ALOGV("%s: Tearing down offline session for camera id %s", __FUNCTION__, mId.string());
disconnectImpl();
}
const String8& Camera3OfflineSession::getId() const {
return mId;
}
status_t Camera3OfflineSession::initialize(
sp<hardware::camera::device::V3_6::ICameraOfflineSession> /*hidlSession*/) {
status_t Camera3OfflineSession::initialize(wp<NotificationListener> listener) {
ATRACE_CALL();
if (mSession == nullptr) {
ALOGE("%s: HIDL session is null!", __FUNCTION__);
return DEAD_OBJECT;
}
{
std::lock_guard<std::mutex> lock(mLock);
mListener = listener;
// setup result FMQ
std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
auto resultQueueRet = mSession->getCaptureResultMetadataQueue(
[&resQueue](const auto& descriptor) {
resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
ALOGE("HAL returns empty result metadata fmq, not use it");
resQueue = nullptr;
// Don't use resQueue onwards.
}
});
if (!resultQueueRet.isOk()) {
ALOGE("Transaction error when getting result metadata queue from camera session: %s",
resultQueueRet.description().c_str());
return DEAD_OBJECT;
}
mStatus = STATUS_ACTIVE;
}
mSession->setCallback(this);
return OK;
}
status_t Camera3OfflineSession::dump(int /*fd*/) {
ATRACE_CALL();
std::lock_guard<std::mutex> il(mInterfaceLock);
return OK;
}
status_t Camera3OfflineSession::abort() {
status_t Camera3OfflineSession::disconnect() {
ATRACE_CALL();
return OK;
return disconnectImpl();
}
status_t Camera3OfflineSession::disconnect() {
status_t Camera3OfflineSession::disconnectImpl() {
ATRACE_CALL();
std::lock_guard<std::mutex> il(mInterfaceLock);
sp<NotificationListener> listener;
{
std::lock_guard<std::mutex> lock(mLock);
if (mStatus == STATUS_CLOSED) {
return OK; // don't close twice
} else if (mStatus == STATUS_ERROR) {
ALOGE("%s: offline session %s shutting down in error state",
__FUNCTION__, mId.string());
}
listener = mListener.promote();
}
ALOGV("%s: E", __FUNCTION__);
{
std::lock_guard<std::mutex> lock(mRequestBufferInterfaceLock);
mAllowRequestBuffer = false;
}
std::vector<wp<Camera3StreamInterface>> streams;
streams.reserve(mOutputStreams.size() + (mInputStream != nullptr ? 1 : 0));
for (size_t i = 0; i < mOutputStreams.size(); i++) {
streams.push_back(mOutputStreams[i]);
}
if (mInputStream != nullptr) {
streams.push_back(mInputStream);
}
mSession->close();
FlushInflightReqStates states {
mId, mOfflineReqsLock, mOfflineReqs, mUseHalBufManager,
listener, *this, mBufferRecords, *this};
camera3::flushInflightRequests(states);
{
std::lock_guard<std::mutex> lock(mLock);
mSession.clear();
mOutputStreams.clear();
mInputStream.clear();
mStatus = STATUS_CLOSED;
}
for (auto& weakStream : streams) {
sp<Camera3StreamInterface> stream = weakStream.promote();
if (stream != nullptr) {
ALOGE("%s: Stream %d leaked! strong reference (%d)!",
__FUNCTION__, stream->getId(), stream->getStrongCount() - 1);
}
}
ALOGV("%s: X", __FUNCTION__);
return OK;
}
status_t Camera3OfflineSession::waitForNextFrame(nsecs_t /*timeout*/) {
status_t Camera3OfflineSession::waitForNextFrame(nsecs_t timeout) {
ATRACE_CALL();
std::unique_lock<std::mutex> lk(mOutputLock);
while (mResultQueue.empty()) {
auto st = mResultSignal.wait_for(lk, std::chrono::nanoseconds(timeout));
if (st == std::cv_status::timeout) {
return TIMED_OUT;
}
}
return OK;
}
status_t Camera3OfflineSession::getNextResult(CaptureResult* /*frame*/) {
status_t Camera3OfflineSession::getNextResult(CaptureResult* frame) {
ATRACE_CALL();
std::lock_guard<std::mutex> l(mOutputLock);
if (mResultQueue.empty()) {
return NOT_ENOUGH_DATA;
}
if (frame == nullptr) {
ALOGE("%s: argument cannot be NULL", __FUNCTION__);
return BAD_VALUE;
}
CaptureResult &result = *(mResultQueue.begin());
frame->mResultExtras = result.mResultExtras;
frame->mMetadata.acquire(result.mMetadata);
frame->mPhysicalMetadatas = std::move(result.mPhysicalMetadatas);
mResultQueue.erase(mResultQueue.begin());
return OK;
}
hardware::Return<void> Camera3OfflineSession::processCaptureResult_3_4(
const hardware::hidl_vec<
hardware::camera::device::V3_4::CaptureResult>& /*results*/) {
hardware::camera::device::V3_4::CaptureResult>& results) {
sp<NotificationListener> listener;
{
std::lock_guard<std::mutex> lock(mLock);
if (mStatus != STATUS_ACTIVE) {
ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
return hardware::Void();
}
listener = mListener.promote();
}
CaptureOutputStates states {
mId,
mOfflineReqsLock, mOfflineReqs,
mOutputLock, mResultQueue, mResultSignal,
mNextShutterFrameNumber,
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mTagMonitor,
mInputStream, mOutputStreams, listener, *this, *this, mBufferRecords
};
std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
for (const auto& result : results) {
processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
}
return hardware::Void();
}
hardware::Return<void> Camera3OfflineSession::processCaptureResult(
const hardware::hidl_vec<
hardware::camera::device::V3_2::CaptureResult>& /*results*/) {
hardware::camera::device::V3_2::CaptureResult>& results) {
// TODO: changed impl to call into processCaptureResult_3_4 instead?
// might need to figure how to reduce copy though.
sp<NotificationListener> listener;
{
std::lock_guard<std::mutex> lock(mLock);
if (mStatus != STATUS_ACTIVE) {
ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
return hardware::Void();
}
listener = mListener.promote();
}
hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
CaptureOutputStates states {
mId,
mOfflineReqsLock, mOfflineReqs,
mOutputLock, mResultQueue, mResultSignal,
mNextShutterFrameNumber,
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mTagMonitor,
mInputStream, mOutputStreams, listener, *this, *this, mBufferRecords
};
std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
for (const auto& result : results) {
processOneCaptureResultLocked(states, result, noPhysMetadata);
}
return hardware::Void();
}
hardware::Return<void> Camera3OfflineSession::notify(
const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& /*msgs*/) {
const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
sp<NotificationListener> listener;
{
std::lock_guard<std::mutex> lock(mLock);
if (mStatus != STATUS_ACTIVE) {
ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
return hardware::Void();
}
listener = mListener.promote();
}
CaptureOutputStates states {
mId,
mOfflineReqsLock, mOfflineReqs,
mOutputLock, mResultQueue, mResultSignal,
mNextShutterFrameNumber,
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mTagMonitor,
mInputStream, mOutputStreams, listener, *this, *this, mBufferRecords
};
for (const auto& msg : msgs) {
camera3::notify(states, msg);
}
return hardware::Void();
}
hardware::Return<void> Camera3OfflineSession::requestStreamBuffers(
const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& /*bufReqs*/,
requestStreamBuffers_cb /*_hidl_cb*/) {
const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
requestStreamBuffers_cb _hidl_cb) {
{
std::lock_guard<std::mutex> lock(mLock);
if (mStatus != STATUS_ACTIVE) {
ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
return hardware::Void();
}
}
RequestBufferStates states {
mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams,
*this, mBufferRecords, *this};
camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
return hardware::Void();
}
hardware::Return<void> Camera3OfflineSession::returnStreamBuffers(
const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& /*buffers*/) {
const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
{
std::lock_guard<std::mutex> lock(mLock);
if (mStatus != STATUS_ACTIVE) {
ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
return hardware::Void();
}
}
ReturnBufferStates states {
mId, mUseHalBufManager, mOutputStreams, mBufferRecords};
camera3::returnStreamBuffers(states, buffers);
return hardware::Void();
}
void Camera3OfflineSession::setErrorState(const char *fmt, ...) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mLock);
va_list args;
va_start(args, fmt);
setErrorStateLockedV(fmt, args);
va_end(args);
//FIXME: automatically disconnect here?
}
void Camera3OfflineSession::setErrorStateLocked(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
setErrorStateLockedV(fmt, args);
va_end(args);
}
void Camera3OfflineSession::setErrorStateLockedV(const char *fmt, va_list args) {
// Print out all error messages to log
String8 errorCause = String8::formatV(fmt, args);
ALOGE("Camera %s: %s", mId.string(), errorCause.string());
// But only do error state transition steps for the first error
if (mStatus == STATUS_ERROR || mStatus == STATUS_UNINITIALIZED) return;
mErrorCause = errorCause;
mStatus = STATUS_ERROR;
// Notify upstream about a device error
sp<NotificationListener> listener = mListener.promote();
if (listener != NULL) {
listener->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
CaptureResultExtras());
}
// Save stack trace. View by dumping it later.
CameraTraces::saveTrace();
}
void Camera3OfflineSession::onInflightEntryRemovedLocked(nsecs_t /*duration*/) {
if (mOfflineReqs.size() == 0) {
std::lock_guard<std::mutex> lock(mRequestBufferInterfaceLock);
mAllowRequestBuffer = false;
}
}
void Camera3OfflineSession::checkInflightMapLengthLocked() {
// Intentional empty impl.
}
void Camera3OfflineSession::onInflightMapFlushedLocked() {
// Intentional empty impl.
}
bool Camera3OfflineSession::startRequestBuffer() {
return mAllowRequestBuffer;
}
void Camera3OfflineSession::endRequestBuffer() {
// Intentional empty impl.
}
nsecs_t Camera3OfflineSession::getWaitDuration() {
const nsecs_t kBaseGetBufferWait = 3000000000; // 3 sec.
return kBaseGetBufferWait;
}
void Camera3OfflineSession::getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out) {
mBufferRecords.getInflightBufferKeys(out);
}
void Camera3OfflineSession::getInflightRequestBufferKeys(std::vector<uint64_t>* out) {
mBufferRecords.getInflightRequestBufferKeys(out);
}
std::vector<sp<Camera3StreamInterface>> Camera3OfflineSession::getAllStreams() {
std::vector<sp<Camera3StreamInterface>> ret;
bool hasInputStream = mInputStream != nullptr;
ret.reserve(mOutputStreams.size() + ((hasInputStream) ? 1 : 0));
if (hasInputStream) {
ret.push_back(mInputStream);
}
for (size_t i = 0; i < mOutputStreams.size(); i++) {
ret.push_back(mOutputStreams[i]);
}
return ret;
}
}; // namespace android

@ -17,16 +17,23 @@
#ifndef ANDROID_SERVERS_CAMERA3OFFLINESESSION_H
#define ANDROID_SERVERS_CAMERA3OFFLINESESSION_H
#include <memory>
#include <mutex>
#include <utils/String8.h>
#include <utils/String16.h>
#include <android/hardware/camera/device/3.6/ICameraOfflineSession.h>
#include <fmq/MessageQueue.h>
#include "common/CameraOfflineSessionBase.h"
#include "device3/Camera3BufferManager.h"
#include "device3/DistortionMapper.h"
#include "device3/InFlightRequest.h"
#include "device3/Camera3OutputUtils.h"
#include "device3/ZoomRatioMapper.h"
#include "utils/TagMonitor.h"
#include "utils/LatencyHistogram.h"
#include <camera_metadata_hidden.h>
@ -41,26 +48,90 @@ class Camera3StreamInterface;
} // namespace camera3
// An immutable struct containing general states that will be copied from Camera3Device to
// Camera3OfflineSession
struct Camera3OfflineStates {
Camera3OfflineStates(
const TagMonitor& tagMonitor, const metadata_vendor_id_t vendorTagId,
const bool useHalBufManager, const bool needFixupMonochromeTags,
const bool usePartialResult, const uint32_t numPartialResults,
const uint32_t nextResultFN, const uint32_t nextReprocResultFN,
const uint32_t nextZslResultFN, const uint32_t nextShutterFN,
const uint32_t nextReprocShutterFN, const uint32_t nextZslShutterFN,
const CameraMetadata& deviceInfo,
const std::unordered_map<std::string, CameraMetadata>& physicalDeviceInfoMap,
const std::unordered_map<std::string, camera3::DistortionMapper>& distortionMappers,
const std::unordered_map<std::string, camera3::ZoomRatioMapper>& zoomRatioMappers) :
mTagMonitor(tagMonitor), mVendorTagId(vendorTagId),
mUseHalBufManager(useHalBufManager), mNeedFixupMonochromeTags(needFixupMonochromeTags),
mUsePartialResult(usePartialResult), mNumPartialResults(numPartialResults),
mNextResultFrameNumber(nextResultFN),
mNextReprocessResultFrameNumber(nextReprocResultFN),
mNextZslStillResultFrameNumber(nextZslResultFN),
mNextShutterFrameNumber(nextShutterFN),
mNextReprocessShutterFrameNumber(nextReprocShutterFN),
mNextZslStillShutterFrameNumber(nextZslShutterFN),
mDeviceInfo(deviceInfo),
mPhysicalDeviceInfoMap(physicalDeviceInfoMap),
mDistortionMappers(distortionMappers),
mZoomRatioMappers(zoomRatioMappers) {}
const TagMonitor& mTagMonitor;
const metadata_vendor_id_t mVendorTagId;
const bool mUseHalBufManager;
const bool mNeedFixupMonochromeTags;
const bool mUsePartialResult;
const uint32_t mNumPartialResults;
// the minimal frame number of the next non-reprocess result
const uint32_t mNextResultFrameNumber;
// the minimal frame number of the next reprocess result
const uint32_t mNextReprocessResultFrameNumber;
// the minimal frame number of the next ZSL still capture result
const uint32_t mNextZslStillResultFrameNumber;
// the minimal frame number of the next non-reprocess shutter
const uint32_t mNextShutterFrameNumber;
// the minimal frame number of the next reprocess shutter
const uint32_t mNextReprocessShutterFrameNumber;
// the minimal frame number of the next ZSL still capture shutter
const uint32_t mNextZslStillShutterFrameNumber;
const CameraMetadata& mDeviceInfo;
const std::unordered_map<std::string, CameraMetadata>& mPhysicalDeviceInfoMap;
const std::unordered_map<std::string, camera3::DistortionMapper>& mDistortionMappers;
const std::unordered_map<std::string, camera3::ZoomRatioMapper>& mZoomRatioMappers;
};
/**
* Camera3OfflineSession for offline session defined in HIDL ICameraOfflineSession@3.6 or higher
*/
class Camera3OfflineSession :
public CameraOfflineSessionBase,
virtual public hardware::camera::device::V3_5::ICameraDeviceCallback {
virtual public hardware::camera::device::V3_5::ICameraDeviceCallback,
public camera3::SetErrorInterface,
public camera3::InflightRequestUpdateInterface,
public camera3::RequestBufferInterface,
public camera3::FlushBufferInterface {
public:
// initialize by Camera3Device. Camera3Device must send all info in separate argument.
// monitored tags
// mUseHalBufManager
// mUsePartialResult
// mNumPartialResults
explicit Camera3OfflineSession(const String8& id);
// initialize by Camera3Device.
explicit Camera3OfflineSession(const String8& id,
const sp<camera3::Camera3Stream>& inputStream,
const camera3::StreamSet& offlineStreamSet,
camera3::BufferRecords&& bufferRecords,
const camera3::InFlightRequestMap& offlineReqs,
const Camera3OfflineStates& offlineStates,
sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession);
virtual ~Camera3OfflineSession();
status_t initialize(
sp<hardware::camera::device::V3_6::ICameraOfflineSession> hidlSession);
virtual status_t initialize(wp<NotificationListener> listener) override;
/**
* CameraOfflineSessionBase interface
@ -71,8 +142,6 @@ class Camera3OfflineSession :
status_t dump(int fd) override;
status_t abort() override;
// methods for capture result passing
status_t waitForNextFrame(nsecs_t timeout) override;
status_t getNextResult(CaptureResult *frame) override;
@ -115,10 +184,99 @@ class Camera3OfflineSession :
*/
private:
// Camera device ID
const String8 mId;
sp<camera3::Camera3Stream> mInputStream;
camera3::StreamSet mOutputStreams;
camera3::BufferRecords mBufferRecords;
std::mutex mOfflineReqsLock;
camera3::InFlightRequestMap mOfflineReqs;
sp<hardware::camera::device::V3_6::ICameraOfflineSession> mSession;
TagMonitor mTagMonitor;
const metadata_vendor_id_t mVendorTagId;
const bool mUseHalBufManager;
const bool mNeedFixupMonochromeTags;
const bool mUsePartialResult;
const uint32_t mNumPartialResults;
std::mutex mOutputLock;
List<CaptureResult> mResultQueue;
std::condition_variable mResultSignal;
// the minimal frame number of the next non-reprocess result
uint32_t mNextResultFrameNumber;
// the minimal frame number of the next reprocess result
uint32_t mNextReprocessResultFrameNumber;
// the minimal frame number of the next ZSL still capture result
uint32_t mNextZslStillResultFrameNumber;
// the minimal frame number of the next non-reprocess shutter
uint32_t mNextShutterFrameNumber;
// the minimal frame number of the next reprocess shutter
uint32_t mNextReprocessShutterFrameNumber;
// the minimal frame number of the next ZSL still capture shutter
uint32_t mNextZslStillShutterFrameNumber;
// End of mOutputLock scope
const CameraMetadata mDeviceInfo;
std::unordered_map<std::string, CameraMetadata> mPhysicalDeviceInfoMap;
std::unordered_map<std::string, camera3::DistortionMapper> mDistortionMappers;
std::unordered_map<std::string, camera3::ZoomRatioMapper> mZoomRatioMappers;
mutable std::mutex mLock;
enum Status {
STATUS_UNINITIALIZED = 0,
STATUS_ACTIVE,
STATUS_ERROR,
STATUS_CLOSED
} mStatus;
wp<NotificationListener> mListener;
// End of mLock protect scope
std::mutex mProcessCaptureResultLock;
// FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
std::unique_ptr<ResultMetadataQueue> mResultMetadataQueue;
// Tracking cause of fatal errors when in STATUS_ERROR
String8 mErrorCause;
// Lock to ensure requestStreamBuffers() callbacks are serialized
std::mutex mRequestBufferInterfaceLock;
// allow request buffer until all requests are processed or disconnectImpl is called
bool mAllowRequestBuffer = true;
// For client methods such as disconnect/dump
std::mutex mInterfaceLock;
// SetErrorInterface
void setErrorState(const char *fmt, ...) override;
void setErrorStateLocked(const char *fmt, ...) override;
// InflightRequestUpdateInterface
void onInflightEntryRemovedLocked(nsecs_t duration) override;
void checkInflightMapLengthLocked() override;
void onInflightMapFlushedLocked() override;
// RequestBufferInterface
bool startRequestBuffer() override;
void endRequestBuffer() override;
nsecs_t getWaitDuration() override;
// FlushBufferInterface
void getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out) override;
void getInflightRequestBufferKeys(std::vector<uint64_t>* out) override;
std::vector<sp<camera3::Camera3StreamInterface>> getAllStreams() override;
void setErrorStateLockedV(const char *fmt, va_list args);
status_t disconnectImpl();
}; // class Camera3OfflineSession
}; // namespace android

@ -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

@ -97,6 +97,26 @@ class Camera3OutputStreamInterface : public virtual Camera3StreamInterface {
virtual const String8& getPhysicalCameraId() const = 0;
};
// Helper class to organize a synchronized mapping of stream IDs to stream instances
class StreamSet {
public:
status_t add(int streamId, sp<camera3::Camera3OutputStreamInterface>);
ssize_t remove(int streamId);
sp<camera3::Camera3OutputStreamInterface> get(int streamId);
// get by (underlying) vector index
sp<camera3::Camera3OutputStreamInterface> operator[] (size_t index);
size_t size() const;
std::vector<int> getStreamIds();
void clear();
StreamSet() {};
StreamSet(const StreamSet& other);
private:
mutable std::mutex mLock;
KeyedVector<int, sp<camera3::Camera3OutputStreamInterface>> mData;
};
} // namespace camera3
} // namespace android

@ -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

@ -65,6 +65,12 @@ public:
const std::vector<size_t> &removedSurfaceIds,
KeyedVector<sp<Surface>, size_t> *outputMap/*out*/);
virtual bool getOfflineProcessingSupport() const {
// As per Camera spec. shared streams currently do not support
// offline mode.
return false;
}
private:
static const size_t kMaxOutputs = 4;

@ -151,6 +151,14 @@ const String8& Camera3Stream::physicalCameraId() const {
return mPhysicalCameraId;
}
void Camera3Stream::setOfflineProcessingSupport(bool support) {
mSupportOfflineProcessing = support;
}
bool Camera3Stream::getOfflineProcessingSupport() const {
return mSupportOfflineProcessing;
}
status_t Camera3Stream::forceToIdle() {
ATRACE_CALL();
Mutex::Autolock l(mLock);

@ -167,6 +167,9 @@ class Camera3Stream :
android_dataspace getOriginalDataSpace() const;
const String8& physicalCameraId() const;
void setOfflineProcessingSupport(bool) override;
bool getOfflineProcessingSupport() const override;
camera3_stream* asHalStream() override {
return this;
}
@ -592,6 +595,8 @@ class Camera3Stream :
String8 mPhysicalCameraId;
nsecs_t mLastTimestamp;
bool mSupportOfflineProcessing = false;
}; // class Camera3Stream
}; // namespace camera3

@ -23,6 +23,7 @@
#include "Camera3StreamBufferListener.h"
#include "Camera3StreamBufferFreedListener.h"
struct camera3_stream;
struct camera3_stream_buffer;
namespace android {
@ -54,6 +55,7 @@ class OutputStreamInfo {
android_dataspace dataSpace;
uint64_t consumerUsage;
bool finalized = false;
bool supportsOffline = false;
OutputStreamInfo() :
width(-1), height(-1), format(-1), dataSpace(HAL_DATASPACE_UNKNOWN),
consumerUsage(0) {}
@ -98,6 +100,12 @@ class Camera3StreamInterface : public virtual RefBase {
virtual bool isDataSpaceOverridden() const = 0;
virtual android_dataspace getOriginalDataSpace() const = 0;
/**
* Offline processing
*/
virtual void setOfflineProcessingSupport(bool support) = 0;
virtual bool getOfflineProcessingSupport() const = 0;
/**
* Get a HAL3 handle for the stream, without starting stream configuration.
*/

@ -36,6 +36,15 @@ class DistortionMapper : private CoordinateMapper {
public:
DistortionMapper();
DistortionMapper(const DistortionMapper& other) :
mValidMapping(other.mValidMapping), mValidGrids(other.mValidGrids),
mFx(other.mFx), mFy(other.mFy), mCx(other.mCx), mCy(other.mCy), mS(other.mS),
mInvFx(other.mInvFx), mInvFy(other.mInvFy), mK(other.mK),
mArrayWidth(other.mArrayWidth), mArrayHeight(other.mArrayHeight),
mActiveWidth(other.mActiveWidth), mActiveHeight(other.mActiveHeight),
mArrayDiffX(other.mArrayDiffX), mArrayDiffY(other.mArrayDiffY),
mCorrectedGrid(other.mCorrectedGrid), mDistortedGrid(other.mDistortedGrid) {}
/**
* Check whether distortion correction is supported by the camera HAL
*/
@ -173,7 +182,7 @@ class DistortionMapper : private CoordinateMapper {
// pre-calculated inverses for speed
float mInvFx, mInvFy;
// radial/tangential distortion parameters
float mK[5];
std::array<float, 5> mK;
// pre-correction active array dimensions
float mArrayWidth, mArrayHeight;

@ -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

@ -201,8 +201,9 @@ Return<HStatus> HidlCameraDeviceUser::endConfigure(StreamConfigurationMode opera
return HStatus::ILLEGAL_ARGUMENT;
}
std::vector<int> offlineStreamIds;
binder::Status ret = mDeviceRemote->endConfigure(convertFromHidl(operatingMode),
cameraMetadata);
cameraMetadata, &offlineStreamIds);
return B2HStatus(ret);
}

@ -33,6 +33,16 @@ TagMonitor::TagMonitor():
mVendorTagId(CAMERA_METADATA_INVALID_VENDOR_ID)
{}
TagMonitor::TagMonitor(const TagMonitor& other):
mMonitoringEnabled(other.mMonitoringEnabled.load()),
mMonitoredTagList(other.mMonitoredTagList),
mLastMonitoredRequestValues(other.mLastMonitoredRequestValues),
mLastMonitoredResultValues(other.mLastMonitoredResultValues),
mLastMonitoredPhysicalRequestKeys(other.mLastMonitoredPhysicalRequestKeys),
mLastMonitoredPhysicalResultKeys(other.mLastMonitoredPhysicalResultKeys),
mMonitoringEvents(other.mMonitoringEvents),
mVendorTagId(other.mVendorTagId) {}
const String16 TagMonitor::kMonitorOption = String16("-m");
const char* TagMonitor::k3aTags =

@ -50,6 +50,8 @@ class TagMonitor {
TagMonitor();
TagMonitor(const TagMonitor& other);
void initialize(metadata_vendor_id_t id) { mVendorTagId = id; }
// Parse tag name list (comma-separated) and if valid, enable monitoring

Loading…
Cancel
Save