Camera: Enable logical multi-camera API in NDK

The support inclues:
- Physical camera specific stream support,
- Physical camera result metadata, and

Test: Newly added NDK CTS test pass
Test: Newly added VNDK test pass
Bug: 120566141
Bug: 115532726
Change-Id: I939b81522ca6c518c0e54ded5d3615f9973a6a65
gugelfrei
Shuzhen Wang 6 years ago
parent 3c3c97ae53
commit 0ff9ae3ecb

@ -167,19 +167,23 @@ status_t OutputConfiguration::readFromParcel(const android::Parcel* parcel) {
}
OutputConfiguration::OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
const String16& physicalId,
int surfaceSetID, bool isShared) {
mGbps.push_back(gbp);
mRotation = rotation;
mSurfaceSetID = surfaceSetID;
mIsDeferred = false;
mIsShared = isShared;
mPhysicalCameraId = physicalId;
}
OutputConfiguration::OutputConfiguration(
const std::vector<sp<IGraphicBufferProducer>>& gbps,
int rotation, int surfaceSetID, int surfaceType, int width, int height, bool isShared)
int rotation, const String16& physicalCameraId, int surfaceSetID, int surfaceType,
int width, int height, bool isShared)
: mGbps(gbps), mRotation(rotation), mSurfaceSetID(surfaceSetID), mSurfaceType(surfaceType),
mWidth(width), mHeight(height), mIsDeferred(false), mIsShared(isShared) { }
mWidth(width), mHeight(height), mIsDeferred(false), mIsShared(isShared),
mPhysicalCameraId(physicalCameraId) { }
status_t OutputConfiguration::writeToParcel(android::Parcel* parcel) const {

@ -65,10 +65,12 @@ public:
OutputConfiguration(const android::Parcel& parcel);
OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
const String16& physicalCameraId,
int surfaceSetID = INVALID_SET_ID, bool isShared = false);
OutputConfiguration(const std::vector<sp<IGraphicBufferProducer>>& gbps,
int rotation, int surfaceSetID = INVALID_SET_ID,
int rotation, const String16& physicalCameraId,
int surfaceSetID = INVALID_SET_ID,
int surfaceType = OutputConfiguration::SURFACE_TYPE_UNKNOWN, int width = 0,
int height = 0, bool isShared = false);

@ -28,6 +28,8 @@
#include <camera/NdkCameraCaptureSession.h>
#include "impl/ACameraCaptureSession.h"
#include "impl/ACameraCaptureSession.inc"
using namespace android;
EXPORT
@ -82,7 +84,31 @@ camera_status_t ACameraCaptureSession_capture(
return ACAMERA_ERROR_SESSION_CLOSED;
}
return session->capture(cbs, numRequests, requests, captureSequenceId);
return session->capture(
cbs, numRequests, requests, captureSequenceId);
}
EXPORT
camera_status_t ACameraCaptureSession_logicalCamera_capture(
ACameraCaptureSession* session,
/*optional*/ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
ATRACE_CALL();
if (session == nullptr || requests == nullptr || numRequests < 1) {
ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
__FUNCTION__, session, numRequests, requests);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
if (session->isClosed()) {
ALOGE("%s: session %p is already closed", __FUNCTION__, session);
*captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
return ACAMERA_ERROR_SESSION_CLOSED;
}
return session->capture(
lcbs, numRequests, requests, captureSequenceId);
}
EXPORT
@ -106,6 +132,28 @@ camera_status_t ACameraCaptureSession_setRepeatingRequest(
return session->setRepeatingRequest(cbs, numRequests, requests, captureSequenceId);
}
EXPORT
camera_status_t ACameraCaptureSession_logicalCamera_setRepeatingRequest(
ACameraCaptureSession* session,
/*optional*/ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
ATRACE_CALL();
if (session == nullptr || requests == nullptr || numRequests < 1) {
ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
__FUNCTION__, session, numRequests, requests);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
if (session->isClosed()) {
ALOGE("%s: session %p is already closed", __FUNCTION__, session);
*captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
return ACAMERA_ERROR_SESSION_CLOSED;
}
return session->setRepeatingRequest(lcbs, numRequests, requests, captureSequenceId);
}
EXPORT
camera_status_t ACameraCaptureSession_stopRepeating(ACameraCaptureSession* session) {
ATRACE_CALL();

@ -128,6 +128,20 @@ camera_status_t ACaptureSessionSharedOutput_create(
return ACAMERA_OK;
}
EXPORT
camera_status_t ACaptureSessionPhysicalOutput_create(
ACameraWindowType* window, const char* physicalId,
/*out*/ACaptureSessionOutput** out) {
ATRACE_CALL();
if (window == nullptr || physicalId == nullptr || out == nullptr) {
ALOGE("%s: Error: bad argument. window %p, physicalId %p, out %p",
__FUNCTION__, window, physicalId, out);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
*out = new ACaptureSessionOutput(window, false, physicalId);
return ACAMERA_OK;
}
EXPORT
camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *out,
ACameraWindowType* window) {

@ -69,3 +69,20 @@ void ACameraMetadata_free(ACameraMetadata* metadata) {
metadata->decStrong((void*) ACameraMetadata_free);
}
}
EXPORT
bool ACameraMetadata_isLogicalMultiCamera(const ACameraMetadata* staticMetadata,
/*out*/size_t* numPhysicalCameras, /*out*/const char*const** physicalCameraIds) {
ATRACE_CALL();
if (numPhysicalCameras == nullptr || physicalCameraIds == nullptr) {
ALOGE("%s: Invalid input: numPhysicalCameras %p, physicalCameraIds %p",
__FUNCTION__, numPhysicalCameras, physicalCameraIds);
return false;
}
if (staticMetadata == nullptr) {
ALOGE("%s: Invalid input: staticMetadata is null.", __FUNCTION__);
return false;
}
return staticMetadata->isLogicalMultiCamera(numPhysicalCameras, physicalCameraIds);
}

@ -107,47 +107,6 @@ ACameraCaptureSession::abortCaptures() {
return ret;
}
camera_status_t
ACameraCaptureSession::setRepeatingRequest(
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
}
camera_status_t ret;
dev->lockDeviceForSessionOps();
{
Mutex::Autolock _l(mSessionLock);
ret = dev->setRepeatingRequestsLocked(
this, cbs, numRequests, requests, captureSequenceId);
}
dev->unlockDevice();
return ret;
}
camera_status_t ACameraCaptureSession::capture(
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
}
camera_status_t ret;
dev->lockDeviceForSessionOps();
{
Mutex::Autolock _l(mSessionLock);
ret = dev->captureLocked(this, cbs, numRequests, requests, captureSequenceId);
}
dev->unlockDevice();
return ret;
}
camera_status_t ACameraCaptureSession::updateOutputConfiguration(ACaptureSessionOutput *output) {
sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {

@ -17,6 +17,7 @@
#define _ACAMERA_CAPTURE_SESSION_H
#include <set>
#include <string>
#include <hardware/camera3.h>
#include <camera/NdkCameraDevice.h>
@ -29,8 +30,9 @@
using namespace android;
struct ACaptureSessionOutput {
explicit ACaptureSessionOutput(ACameraWindowType* window, bool isShared = false) :
mWindow(window), mIsShared(isShared) {};
explicit ACaptureSessionOutput(ACameraWindowType* window, bool isShared = false,
const char* physicalCameraId = "") :
mWindow(window), mIsShared(isShared), mPhysicalCameraId(physicalCameraId) {};
bool operator == (const ACaptureSessionOutput& other) const {
return mWindow == other.mWindow;
@ -49,6 +51,7 @@ struct ACaptureSessionOutput {
std::set<ACameraWindowType *> mSharedWindows;
bool mIsShared;
int mRotation = CAMERA3_STREAM_ROTATION_0;
std::string mPhysicalCameraId;
};
#endif
@ -88,13 +91,15 @@ struct ACameraCaptureSession : public RefBase {
camera_status_t abortCaptures();
template<class T>
camera_status_t setRepeatingRequest(
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId);
template<class T>
camera_status_t capture(
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId);

@ -0,0 +1,68 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ACameraCaptureSession.h"
#ifdef __ANDROID_VNDK__
#include "ndk_vendor/impl/ACameraDeviceVendor.inc"
#else
#include "ACameraDevice.inc"
#endif
using namespace android;
template <class T>
camera_status_t
ACameraCaptureSession::setRepeatingRequest(
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
}
camera_status_t ret;
dev->lockDeviceForSessionOps();
{
Mutex::Autolock _l(mSessionLock);
ret = dev->setRepeatingRequestsLocked(
this, cbs, numRequests, requests, captureSequenceId);
}
dev->unlockDevice();
return ret;
}
template <class T>
camera_status_t ACameraCaptureSession::capture(
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
}
camera_status_t ret;
dev->lockDeviceForSessionOps();
{
Mutex::Autolock _l(mSessionLock);
ret = dev->captureLocked(this, cbs, numRequests, requests, captureSequenceId);
}
dev->unlockDevice();
return ret;
}

@ -20,13 +20,14 @@
#include <vector>
#include <inttypes.h>
#include <android/hardware/ICameraService.h>
#include <camera2/SubmitInfo.h>
#include <gui/Surface.h>
#include "ACameraDevice.h"
#include "ACameraMetadata.h"
#include "ACaptureRequest.h"
#include "ACameraCaptureSession.h"
#include "ACameraCaptureSession.inc"
namespace android {
namespace acam {
@ -39,6 +40,7 @@ const char* CameraDevice::kSessionSpKey = "SessionSp";
const char* CameraDevice::kCaptureRequestKey = "CaptureRequest";
const char* CameraDevice::kTimeStampKey = "TimeStamp";
const char* CameraDevice::kCaptureResultKey = "CaptureResult";
const char* CameraDevice::kPhysicalCaptureResultKey = "PhysicalCaptureResult";
const char* CameraDevice::kCaptureFailureKey = "CaptureFailure";
const char* CameraDevice::kSequenceIdKey = "SequenceId";
const char* CameraDevice::kFrameNumberKey = "FrameNumber";
@ -190,106 +192,6 @@ CameraDevice::createCaptureSession(
return ACAMERA_OK;
}
camera_status_t
CameraDevice::captureLocked(
sp<ACameraCaptureSession> session,
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
return submitRequestsLocked(
session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/false);
}
camera_status_t
CameraDevice::setRepeatingRequestsLocked(
sp<ACameraCaptureSession> session,
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
return submitRequestsLocked(
session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/true);
}
camera_status_t
CameraDevice::submitRequestsLocked(
sp<ACameraCaptureSession> session,
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId,
bool isRepeating) {
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
ALOGE("Camera %s submit capture request failed! ret %d", getId(), ret);
return ret;
}
// Form two vectors of capture request, one for internal tracking
std::vector<hardware::camera2::CaptureRequest> requestList;
Vector<sp<CaptureRequest> > requestsV;
requestsV.setCapacity(numRequests);
for (int i = 0; i < numRequests; i++) {
sp<CaptureRequest> req;
ret = allocateCaptureRequest(requests[i], req);
if (ret != ACAMERA_OK) {
ALOGE("Convert capture request to internal format failure! ret %d", ret);
return ret;
}
if (req->mSurfaceList.empty()) {
ALOGE("Capture request without output target cannot be submitted!");
return ACAMERA_ERROR_INVALID_PARAMETER;
}
requestList.push_back(*(req.get()));
requestsV.push_back(req);
}
if (isRepeating) {
ret = stopRepeatingLocked();
if (ret != ACAMERA_OK) {
ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
return ret;
}
}
binder::Status remoteRet;
hardware::camera2::utils::SubmitInfo info;
remoteRet = mRemote->submitRequestList(requestList, isRepeating, &info);
int sequenceId = info.mRequestId;
int64_t lastFrameNumber = info.mLastFrameNumber;
if (sequenceId < 0) {
ALOGE("Camera %s submit request remote failure: ret %d", getId(), sequenceId);
return ACAMERA_ERROR_UNKNOWN;
}
CallbackHolder cbHolder(session, requestsV, isRepeating, cbs);
mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder));
if (isRepeating) {
// stopRepeating above should have cleanup repeating sequence id
if (mRepeatingSequenceId != REQUEST_ID_NONE) {
setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
return ACAMERA_ERROR_CAMERA_DEVICE;
}
mRepeatingSequenceId = sequenceId;
} else {
mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
}
if (mIdle) {
sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
msg->setPointer(kContextKey, session->mUserSessionCallback.context);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
postSessionMsgAndCleanup(msg);
}
mIdle = false;
mBusySession = session;
if (captureSequenceId) {
*captureSequenceId = sequenceId;
}
return ACAMERA_OK;
}
camera_status_t CameraDevice::updateOutputConfigurationLocked(ACaptureSessionOutput *output) {
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
@ -325,8 +227,9 @@ camera_status_t CameraDevice::updateOutputConfigurationLocked(ACaptureSessionOut
return ret;
}
OutputConfiguration outConfig(iGBP, output->mRotation, OutputConfiguration::INVALID_SET_ID,
true);
String16 physicalId16(output->mPhysicalCameraId.c_str());
OutputConfiguration outConfig(iGBP, output->mRotation, physicalId16,
OutputConfiguration::INVALID_SET_ID, true);
for (auto& anw : output->mSharedWindows) {
ret = getIGBPfromAnw(anw, iGBP);
@ -640,8 +543,9 @@ CameraDevice::configureStreamsLocked(const ACaptureSessionOutputContainer* outpu
if (ret != ACAMERA_OK) {
return ret;
}
String16 physicalId16(outConfig.mPhysicalCameraId.c_str());
outputSet.insert(std::make_pair(
anw, OutputConfiguration(iGBP, outConfig.mRotation,
anw, OutputConfiguration(iGBP, outConfig.mRotation, physicalId16,
OutputConfiguration::INVALID_SET_ID, outConfig.mIsShared)));
}
auto addSet = outputSet;
@ -829,7 +733,7 @@ CameraDevice::onCaptureErrorLocked(
if (errorCode == hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER) {
int32_t streamId = resultExtras.errorStreamId;
ACameraCaptureSession_captureCallback_bufferLost onBufferLost =
cbh.mCallbacks.onCaptureBufferLost;
cbh.mOnCaptureBufferLost;
auto outputPairIt = mConfiguredOutputs.find(streamId);
if (outputPairIt == mConfiguredOutputs.end()) {
ALOGE("%s: Error: stream id %d does not exist", __FUNCTION__, streamId);
@ -846,7 +750,7 @@ CameraDevice::onCaptureErrorLocked(
getId(), anw, frameNumber);
sp<AMessage> msg = new AMessage(kWhatCaptureBufferLost, mHandler);
msg->setPointer(kContextKey, cbh.mCallbacks.context);
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) onBufferLost);
msg->setObject(kCaptureRequestKey, request);
@ -858,7 +762,7 @@ CameraDevice::onCaptureErrorLocked(
}
} else { // Handle other capture failures
// Fire capture failure callback if there is one registered
ACameraCaptureSession_captureCallback_failed onError = cbh.mCallbacks.onCaptureFailed;
ACameraCaptureSession_captureCallback_failed onError = cbh.mOnCaptureFailed;
sp<CameraCaptureFailure> failure(new CameraCaptureFailure());
failure->frameNumber = frameNumber;
// TODO: refine this when implementing flush
@ -868,7 +772,7 @@ CameraDevice::onCaptureErrorLocked(
hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT);
sp<AMessage> msg = new AMessage(kWhatCaptureFail, mHandler);
msg->setPointer(kContextKey, cbh.mCallbacks.context);
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) onError);
msg->setObject(kCaptureRequestKey, request);
@ -890,6 +794,7 @@ void CameraDevice::CallbackHandler::onMessageReceived(
case kWhatSessionStateCb:
case kWhatCaptureStart:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
case kWhatCaptureSeqEnd:
case kWhatCaptureSeqAbort:
@ -960,6 +865,7 @@ void CameraDevice::CallbackHandler::onMessageReceived(
case kWhatSessionStateCb:
case kWhatCaptureStart:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
case kWhatCaptureSeqEnd:
case kWhatCaptureSeqAbort:
@ -977,6 +883,7 @@ void CameraDevice::CallbackHandler::onMessageReceived(
switch (msg->what()) {
case kWhatCaptureStart:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
case kWhatCaptureBufferLost:
found = msg->findObject(kCaptureRequestKey, &obj);
@ -1048,6 +955,64 @@ void CameraDevice::CallbackHandler::onMessageReceived(
freeACaptureRequest(request);
break;
}
case kWhatLogicalCaptureResult:
{
ACameraCaptureSession_logicalCamera_captureCallback_result onResult;
found = msg->findPointer(kCallbackFpKey, (void**) &onResult);
if (!found) {
ALOGE("%s: Cannot find logicalCamera capture result callback!",
__FUNCTION__);
return;
}
if (onResult == nullptr) {
return;
}
found = msg->findObject(kCaptureResultKey, &obj);
if (!found) {
ALOGE("%s: Cannot find capture result!", __FUNCTION__);
return;
}
sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
found = msg->findObject(kPhysicalCaptureResultKey, &obj);
if (!found) {
ALOGE("%s: Cannot find physical capture result!", __FUNCTION__);
return;
}
sp<ACameraPhysicalCaptureResultInfo> physicalResult(
static_cast<ACameraPhysicalCaptureResultInfo*>(obj.get()));
std::vector<PhysicalCaptureResultInfo>& physicalResultInfo =
physicalResult->mPhysicalResultInfo;
std::vector<std::string> physicalCameraIds;
std::vector<sp<ACameraMetadata>> physicalMetadataCopy;
for (size_t i = 0; i < physicalResultInfo.size(); i++) {
String8 physicalId8(physicalResultInfo[i].mPhysicalCameraId);
physicalCameraIds.push_back(physicalId8.c_str());
CameraMetadata clone = physicalResultInfo[i].mPhysicalCameraMetadata;
clone.update(ANDROID_SYNC_FRAME_NUMBER,
&physicalResult->mFrameNumber, /*data_count*/1);
sp<ACameraMetadata> metadata =
new ACameraMetadata(clone.release(), ACameraMetadata::ACM_RESULT);
physicalMetadataCopy.push_back(metadata);
}
std::vector<const char*> physicalCameraIdPtrs;
std::vector<const ACameraMetadata*> physicalMetadataCopyPtrs;
for (size_t i = 0; i < physicalResultInfo.size(); i++) {
physicalCameraIdPtrs.push_back(physicalCameraIds[i].c_str());
physicalMetadataCopyPtrs.push_back(physicalMetadataCopy[i].get());
}
ACaptureRequest* request = allocateACaptureRequest(requestSp);
(*onResult)(context, session.get(), request, result.get(),
physicalResultInfo.size(), physicalCameraIdPtrs.data(),
physicalMetadataCopyPtrs.data());
freeACaptureRequest(request);
break;
}
case kWhatCaptureFail:
{
ACameraCaptureSession_captureCallback_failed onFail;
@ -1158,12 +1123,34 @@ void CameraDevice::CallbackHandler::onMessageReceived(
}
CameraDevice::CallbackHolder::CallbackHolder(
sp<ACameraCaptureSession> session,
const Vector<sp<CaptureRequest> >& requests,
bool isRepeating,
ACameraCaptureSession_captureCallbacks* cbs) :
mSession(session), mRequests(requests),
mIsRepeating(isRepeating), mCallbacks(fillCb(cbs)) {}
sp<ACameraCaptureSession> session,
const Vector<sp<CaptureRequest> >& requests,
bool isRepeating,
ACameraCaptureSession_captureCallbacks* cbs) :
mSession(session), mRequests(requests),
mIsRepeating(isRepeating),
mIsLogicalCameraCallback(false) {
initCaptureCallbacks(cbs);
if (cbs != nullptr) {
mOnCaptureCompleted = cbs->onCaptureCompleted;
}
}
CameraDevice::CallbackHolder::CallbackHolder(
sp<ACameraCaptureSession> session,
const Vector<sp<CaptureRequest> >& requests,
bool isRepeating,
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs) :
mSession(session), mRequests(requests),
mIsRepeating(isRepeating),
mIsLogicalCameraCallback(true) {
initCaptureCallbacks(lcbs);
if (lcbs != nullptr) {
mOnLogicalCameraCaptureCompleted = lcbs->onLogicalCameraCaptureCompleted;
}
}
void
CameraDevice::checkRepeatingSequenceCompleteLocked(
@ -1180,9 +1167,9 @@ CameraDevice::checkRepeatingSequenceCompleteLocked(
mSequenceCallbackMap.erase(cbIt);
// send seq aborted callback
sp<AMessage> msg = new AMessage(kWhatCaptureSeqAbort, mHandler);
msg->setPointer(kContextKey, cbh.mCallbacks.context);
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, cbh.mSession);
msg->setPointer(kCallbackFpKey, (void*) cbh.mCallbacks.onCaptureSequenceAborted);
msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceAborted);
msg->setInt32(kSequenceIdKey, sequenceId);
postSessionMsgAndCleanup(msg);
} else {
@ -1230,9 +1217,9 @@ CameraDevice::checkAndFireSequenceCompleteLocked() {
mSequenceCallbackMap.erase(cbIt);
// send seq complete callback
sp<AMessage> msg = new AMessage(kWhatCaptureSeqEnd, mHandler);
msg->setPointer(kContextKey, cbh.mCallbacks.context);
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, cbh.mSession);
msg->setPointer(kCallbackFpKey, (void*) cbh.mCallbacks.onCaptureSequenceCompleted);
msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceCompleted);
msg->setInt32(kSequenceIdKey, sequenceId);
msg->setInt64(kFrameNumberKey, lastFrameNumber);
@ -1389,7 +1376,7 @@ CameraDevice::ServiceCallback::onCaptureStarted(
auto it = dev->mSequenceCallbackMap.find(sequenceId);
if (it != dev->mSequenceCallbackMap.end()) {
CallbackHolder cbh = (*it).second;
ACameraCaptureSession_captureCallback_start onStart = cbh.mCallbacks.onCaptureStarted;
ACameraCaptureSession_captureCallback_start onStart = cbh.mOnCaptureStarted;
sp<ACameraCaptureSession> session = cbh.mSession;
if ((size_t) burstId >= cbh.mRequests.size()) {
ALOGE("%s: Error: request index %d out of bound (size %zu)",
@ -1398,7 +1385,7 @@ CameraDevice::ServiceCallback::onCaptureStarted(
}
sp<CaptureRequest> request = cbh.mRequests[burstId];
sp<AMessage> msg = new AMessage(kWhatCaptureStart, dev->mHandler);
msg->setPointer(kContextKey, cbh.mCallbacks.context);
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) onStart);
msg->setObject(kCaptureRequestKey, request);
@ -1413,7 +1400,6 @@ CameraDevice::ServiceCallback::onResultReceived(
const CameraMetadata& metadata,
const CaptureResultExtras& resultExtras,
const std::vector<PhysicalCaptureResultInfo>& physicalResultInfos) {
(void) physicalResultInfos;
binder::Status ret = binder::Status::ok();
sp<CameraDevice> dev = mDevice.promote();
@ -1449,9 +1435,6 @@ CameraDevice::ServiceCallback::onResultReceived(
auto it = dev->mSequenceCallbackMap.find(sequenceId);
if (it != dev->mSequenceCallbackMap.end()) {
CallbackHolder cbh = (*it).second;
ACameraCaptureSession_captureCallback_result onResult = isPartialResult ?
cbh.mCallbacks.onCaptureProgressed :
cbh.mCallbacks.onCaptureCompleted;
sp<ACameraCaptureSession> session = cbh.mSession;
if ((size_t) burstId >= cbh.mRequests.size()) {
ALOGE("%s: Error: request index %d out of bound (size %zu)",
@ -1461,13 +1444,27 @@ CameraDevice::ServiceCallback::onResultReceived(
sp<CaptureRequest> request = cbh.mRequests[burstId];
sp<ACameraMetadata> result(new ACameraMetadata(
metadataCopy.release(), ACameraMetadata::ACM_RESULT));
sp<ACameraPhysicalCaptureResultInfo> physicalResult(
new ACameraPhysicalCaptureResultInfo(physicalResultInfos, frameNumber));
sp<AMessage> msg = new AMessage(kWhatCaptureResult, dev->mHandler);
msg->setPointer(kContextKey, cbh.mCallbacks.context);
sp<AMessage> msg = new AMessage(
cbh.mIsLogicalCameraCallback ? kWhatLogicalCaptureResult : kWhatCaptureResult,
dev->mHandler);
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) onResult);
msg->setObject(kCaptureRequestKey, request);
msg->setObject(kCaptureResultKey, result);
if (isPartialResult) {
msg->setPointer(kCallbackFpKey,
(void *)cbh.mOnCaptureProgressed);
} else if (cbh.mIsLogicalCameraCallback) {
msg->setPointer(kCallbackFpKey,
(void *)cbh.mOnLogicalCameraCaptureCompleted);
msg->setObject(kPhysicalCaptureResultKey, physicalResult);
} else {
msg->setPointer(kCallbackFpKey,
(void *)cbh.mOnCaptureCompleted);
}
dev->postSessionMsgAndCleanup(msg);
}

@ -21,6 +21,7 @@
#include <set>
#include <atomic>
#include <utility>
#include <vector>
#include <utils/StrongPointer.h>
#include <utils/Mutex.h>
#include <utils/String8.h>
@ -46,6 +47,16 @@ namespace acam {
// Wrap ACameraCaptureFailure so it can be ref-counted
struct CameraCaptureFailure : public RefBase, public ACameraCaptureFailure {};
// Wrap PhysicalCaptureResultInfo so that it can be ref-counted
struct ACameraPhysicalCaptureResultInfo: public RefBase {
ACameraPhysicalCaptureResultInfo(const std::vector<PhysicalCaptureResultInfo>& info,
int64_t frameNumber) :
mPhysicalResultInfo(info), mFrameNumber(frameNumber) {}
std::vector<PhysicalCaptureResultInfo> mPhysicalResultInfo;
int64_t mFrameNumber;
};
class CameraDevice final : public RefBase {
public:
CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
@ -109,19 +120,22 @@ class CameraDevice final : public RefBase {
camera_status_t waitUntilIdleLocked();
template<class T>
camera_status_t captureLocked(sp<ACameraCaptureSession> session,
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId);
template<class T>
camera_status_t setRepeatingRequestsLocked(sp<ACameraCaptureSession> session,
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId);
template<class T>
camera_status_t submitRequestsLocked(
sp<ACameraCaptureSession> session,
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*out*/int* captureSequenceId,
bool isRepeating);
@ -192,6 +206,7 @@ class CameraDevice final : public RefBase {
// Capture callbacks
kWhatCaptureStart, // onCaptureStarted
kWhatCaptureResult, // onCaptureProgressed, onCaptureCompleted
kWhatLogicalCaptureResult, // onLogicalCameraCaptureCompleted
kWhatCaptureFail, // onCaptureFailed
kWhatCaptureSeqEnd, // onCaptureSequenceCompleted
kWhatCaptureSeqAbort, // onCaptureSequenceAborted
@ -207,6 +222,7 @@ class CameraDevice final : public RefBase {
static const char* kCaptureRequestKey;
static const char* kTimeStampKey;
static const char* kCaptureResultKey;
static const char* kPhysicalCaptureResultKey;
static const char* kCaptureFailureKey;
static const char* kSequenceIdKey;
static const char* kFrameNumberKey;
@ -245,19 +261,46 @@ class CameraDevice final : public RefBase {
const Vector<sp<CaptureRequest> >& requests,
bool isRepeating,
ACameraCaptureSession_captureCallbacks* cbs);
static ACameraCaptureSession_captureCallbacks fillCb(
ACameraCaptureSession_captureCallbacks* cbs) {
CallbackHolder(sp<ACameraCaptureSession> session,
const Vector<sp<CaptureRequest> >& requests,
bool isRepeating,
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs);
template <class T>
void initCaptureCallbacks(T* cbs) {
mContext = nullptr;
mOnCaptureStarted = nullptr;
mOnCaptureProgressed = nullptr;
mOnCaptureCompleted = nullptr;
mOnLogicalCameraCaptureCompleted = nullptr;
mOnCaptureFailed = nullptr;
mOnCaptureSequenceCompleted = nullptr;
mOnCaptureSequenceAborted = nullptr;
mOnCaptureBufferLost = nullptr;
if (cbs != nullptr) {
return *cbs;
mContext = cbs->context;
mOnCaptureStarted = cbs->onCaptureStarted;
mOnCaptureProgressed = cbs->onCaptureProgressed;
mOnCaptureFailed = cbs->onCaptureFailed;
mOnCaptureSequenceCompleted = cbs->onCaptureSequenceCompleted;
mOnCaptureSequenceAborted = cbs->onCaptureSequenceAborted;
mOnCaptureBufferLost = cbs->onCaptureBufferLost;
}
return { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
}
sp<ACameraCaptureSession> mSession;
Vector<sp<CaptureRequest> > mRequests;
const bool mIsRepeating;
ACameraCaptureSession_captureCallbacks mCallbacks;
const bool mIsLogicalCameraCallback;
void* mContext;
ACameraCaptureSession_captureCallback_start mOnCaptureStarted;
ACameraCaptureSession_captureCallback_result mOnCaptureProgressed;
ACameraCaptureSession_captureCallback_result mOnCaptureCompleted;
ACameraCaptureSession_logicalCamera_captureCallback_result mOnLogicalCameraCaptureCompleted;
ACameraCaptureSession_captureCallback_failed mOnCaptureFailed;
ACameraCaptureSession_captureCallback_sequenceEnd mOnCaptureSequenceCompleted;
ACameraCaptureSession_captureCallback_sequenceAbort mOnCaptureSequenceAborted;
ACameraCaptureSession_captureCallback_bufferLost mOnCaptureBufferLost;
};
// sequence id -> callbacks map
std::map<int, CallbackHolder> mSequenceCallbackMap;

@ -0,0 +1,130 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vector>
#include <inttypes.h>
#include "ACameraDevice.h"
#include "ACameraMetadata.h"
#include "ACaptureRequest.h"
#include "ACameraCaptureSession.h"
namespace android {
namespace acam {
template<class T>
camera_status_t
CameraDevice::captureLocked(
sp<ACameraCaptureSession> session,
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
return submitRequestsLocked(
session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/false);
}
template<class T>
camera_status_t
CameraDevice::setRepeatingRequestsLocked(
sp<ACameraCaptureSession> session,
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
return submitRequestsLocked(
session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/true);
}
template<class T>
camera_status_t CameraDevice::submitRequestsLocked(
sp<ACameraCaptureSession> session,
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId,
bool isRepeating) {
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
ALOGE("Camera %s submit capture request failed! ret %d", getId(), ret);
return ret;
}
// Form two vectors of capture request, one for internal tracking
std::vector<hardware::camera2::CaptureRequest> requestList;
Vector<sp<CaptureRequest> > requestsV;
requestsV.setCapacity(numRequests);
for (int i = 0; i < numRequests; i++) {
sp<CaptureRequest> req;
ret = allocateCaptureRequest(requests[i], req);
if (ret != ACAMERA_OK) {
ALOGE("Convert capture request to internal format failure! ret %d", ret);
return ret;
}
if (req->mSurfaceList.empty()) {
ALOGE("Capture request without output target cannot be submitted!");
return ACAMERA_ERROR_INVALID_PARAMETER;
}
requestList.push_back(*(req.get()));
requestsV.push_back(req);
}
if (isRepeating) {
ret = stopRepeatingLocked();
if (ret != ACAMERA_OK) {
ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
return ret;
}
}
binder::Status remoteRet;
hardware::camera2::utils::SubmitInfo info;
remoteRet = mRemote->submitRequestList(requestList, isRepeating, &info);
int sequenceId = info.mRequestId;
int64_t lastFrameNumber = info.mLastFrameNumber;
if (sequenceId < 0) {
ALOGE("Camera %s submit request remote failure: ret %d", getId(), sequenceId);
return ACAMERA_ERROR_UNKNOWN;
}
CallbackHolder cbHolder(session, requestsV, isRepeating, cbs);
mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder));
if (isRepeating) {
// stopRepeating above should have cleanup repeating sequence id
if (mRepeatingSequenceId != REQUEST_ID_NONE) {
setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
return ACAMERA_ERROR_CAMERA_DEVICE;
}
mRepeatingSequenceId = sequenceId;
} else {
mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
}
if (mIdle) {
sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
msg->setPointer(kContextKey, session->mUserSessionCallback.context);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
postSessionMsgAndCleanup(msg);
}
mIdle = false;
mBusySession = session;
if (captureSequenceId) {
*captureSequenceId = sequenceId;
}
return ACAMERA_OK;
}
} // namespace acam
} // namespace android

@ -50,6 +50,7 @@ ACameraMetadata::isNdkSupportedCapability(int32_t capability) {
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS:
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE:
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT:
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA:
return true;
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING:
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING:
@ -79,11 +80,41 @@ ACameraMetadata::filterUnsupportedFeatures() {
uint8_t capability = entry.data.u8[i];
if (isNdkSupportedCapability(capability)) {
capabilities.push(capability);
if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
derivePhysicalCameraIds();
}
}
}
mData.update(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, capabilities);
}
void
ACameraMetadata::derivePhysicalCameraIds() {
ACameraMetadata_const_entry entry;
auto ret = getConstEntry(ACAMERA_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS, &entry);
if (ret != ACAMERA_OK) {
ALOGE("%s: Get ACAMERA_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS key failed. ret %d",
__FUNCTION__, ret);
return;
}
const uint8_t* ids = entry.data.u8;
size_t start = 0;
for (size_t i = 0; i < entry.count; ++i) {
if (ids[i] == '\0') {
if (start != i) {
mStaticPhysicalCameraIds.push_back((const char*)ids+start);
}
start = i+1;
}
}
if (mStaticPhysicalCameraIds.size() < 2) {
ALOGW("%s: Logical multi-camera device only has %zu physical cameras",
__FUNCTION__, mStaticPhysicalCameraIds.size());
}
}
void
ACameraMetadata::filterDurations(uint32_t tag) {
@ -309,6 +340,27 @@ ACameraMetadata::getInternalData() const {
return mData;
}
bool
ACameraMetadata::isLogicalMultiCamera(size_t* count, const char*const** physicalCameraIds) const {
if (mType != ACM_CHARACTERISTICS) {
ALOGE("%s must be called for a static metadata!", __FUNCTION__);
return false;
}
if (count == nullptr || physicalCameraIds == nullptr) {
ALOGE("%s: Invalid input count: %p, physicalCameraIds: %p", __FUNCTION__,
count, physicalCameraIds);
return false;
}
if (mStaticPhysicalCameraIds.size() >= 2) {
*count = mStaticPhysicalCameraIds.size();
*physicalCameraIds = mStaticPhysicalCameraIds.data();
return true;
}
return false;
}
// TODO: some of key below should be hidden from user
// ex: ACAMERA_REQUEST_ID and ACAMERA_REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~

@ -17,6 +17,7 @@
#define _ACAMERA_METADATA_H
#include <unordered_set>
#include <vector>
#include <sys/types.h>
#include <utils/Mutex.h>
@ -65,6 +66,7 @@ struct ACameraMetadata : public RefBase {
/*out*/const uint32_t** tags) const;
const CameraMetadata& getInternalData() const;
bool isLogicalMultiCamera(size_t* count, const char* const** physicalCameraIds) const;
private:
@ -74,6 +76,7 @@ struct ACameraMetadata : public RefBase {
void filterUnsupportedFeatures(); // Hide features not yet supported by NDK
void filterStreamConfigurations(); // Hide input streams, translate hal format to NDK formats
void filterDurations(uint32_t tag); // translate hal format to NDK formats
void derivePhysicalCameraIds(); // Derive array of physical ids.
template<typename INTERNAL_T, typename NDK_T>
camera_status_t updateImpl(uint32_t tag, uint32_t count, const NDK_T* data) {
@ -112,6 +115,8 @@ struct ACameraMetadata : public RefBase {
const ACAMERA_METADATA_TYPE mType;
static std::unordered_set<uint32_t> sSystemTags;
std::vector<const char*> mStaticPhysicalCameraIds;
};
#endif // _ACAMERA_METADATA_H

@ -643,6 +643,103 @@ camera_status_t ACameraCaptureSession_updateSharedOutput(ACameraCaptureSession*
ACaptureSessionOutput* output) __INTRODUCED_IN(28);
#endif /* __ANDROID_API__ >= 28 */
#if __ANDROID_API__ >= 29
/**
* The definition of final capture result callback with logical multi-camera support.
*
* This has the same functionality as final ACameraCaptureSession_captureCallback_result, with
* added ability to return physical camera result metadata within a logical multi-camera.
*
* For a logical multi-camera, this function will be called with the Id and result metadata
* of the underlying physical cameras, which the corresponding capture request contains targets for.
* If the capture request doesn't contain targets specific to any physical camera, or the current
* camera device isn't a logical multi-camera, physicalResultCount will be 0.
*
* @param context The optional application context provided by user in
* {@link ACameraCaptureSession_captureCallbacks}.
* @param session The camera capture session of interest.
* @param request The capture request of interest. Note that this pointer points to a copy of
* capture request sent by application, so the address is different to what
* application sent but the content will match. This request will be freed by
* framework immediately after this callback returns.
* @param result The capture result metadata reported by camera device. The memory is managed by
* camera framework. Do not access this pointer after this callback returns.
* @param physicalResultCount The number of physical camera result metadata
* @param physicalCameraIds The array of physical camera IDs on which the
* physical result metadata are reported.
* @param physicalResults The array of capture result metadata reported by the
* physical camera devices.
*/
typedef void (*ACameraCaptureSession_logicalCamera_captureCallback_result)(
void* context, ACameraCaptureSession* session,
ACaptureRequest* request, const ACameraMetadata* result,
size_t physicalResultCount, const char** physicalCameraIds,
const ACameraMetadata** physicalResults);
/**
* This has the same functionality as ACameraCaptureSession_captureCallbacks,
* with the exception that an onLogicalCameraCaptureCompleted callback is
* used, instead of onCaptureCompleted, to support logical multi-camera.
*/
typedef struct ACameraCaptureSession_logicalCamera_captureCallbacks {
/**
* Same as ACameraCaptureSession_captureCallbacks
*/
void* context;
ACameraCaptureSession_captureCallback_start onCaptureStarted;
ACameraCaptureSession_captureCallback_result onCaptureProgressed;
/**
* This callback is called when an image capture has fully completed and all the
* result metadata is available. For a logical multi-camera, this callback
* also returns the result metadata for all physical cameras being
* explicitly requested on.
*
* <p>This callback will always fire after the last {@link onCaptureProgressed};
* in other words, no more partial results will be delivered once the completed result
* is available.</p>
*
* <p>For performance-intensive use-cases where latency is a factor, consider
* using {@link onCaptureProgressed} instead.</p>
*
* <p>Note that the ACaptureRequest pointer in the callback will not match what application has
* submitted, but the contents the ACaptureRequest will match what application submitted.</p>
*/
ACameraCaptureSession_logicalCamera_captureCallback_result onLogicalCameraCaptureCompleted;
/**
* Same as ACameraCaptureSession_captureCallbacks
*/
ACameraCaptureSession_captureCallback_failed onCaptureFailed;
ACameraCaptureSession_captureCallback_sequenceEnd onCaptureSequenceCompleted;
ACameraCaptureSession_captureCallback_sequenceAbort onCaptureSequenceAborted;
ACameraCaptureSession_captureCallback_bufferLost onCaptureBufferLost;
} ACameraCaptureSession_logicalCamera_captureCallbacks;
/**
* This has the same functionality as ACameraCaptureSession_capture, with added
* support for logical multi-camera where the capture callbacks supports result metadata for
* physical cameras.
*/
camera_status_t ACameraCaptureSession_logicalCamera_capture(
ACameraCaptureSession* session,
/*optional*/ACameraCaptureSession_logicalCamera_captureCallbacks* callbacks,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) __INTRODUCED_IN(29);
/**
* This has the same functionality as ACameraCaptureSession_setRepeatingRequest, with added
* support for logical multi-camera where the capture callbacks supports result metadata for
* physical cameras.
*/
camera_status_t ACameraCaptureSession_logicalCamera_setRepeatingRequest(
ACameraCaptureSession* session,
/*optional*/ACameraCaptureSession_logicalCamera_captureCallbacks* callbacks,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) __INTRODUCED_IN(29);
#endif /* __ANDROID_API__ >= 29 */
__END_DECLS
#endif /* _NDK_CAMERA_CAPTURE_SESSION_H */

@ -765,6 +765,36 @@ camera_status_t ACameraDevice_createCaptureSessionWithSessionParameters(
#endif /* __ANDROID_API__ >= 28 */
#if __ANDROID_API__ >= 29
/**
* Create a ACaptureSessionOutput object used for streaming from a physical
* camera as part of a logical camera device.
*
* <p>The ACaptureSessionOutput is used in {@link ACaptureSessionOutputContainer_add} method to add
* an output {@link ANativeWindow} to ACaptureSessionOutputContainer. Use
* {@link ACaptureSessionOutput_free} to free the object and its memory after application no longer
* needs the {@link ACaptureSessionOutput}.</p>
*
* @param anw the {@link ANativeWindow} to be associated with the {@link ACaptureSessionOutput}
* @param physicalId the Id of the physical camera this output is associated
* with.
* @param output the output {@link ACaptureSessionOutput} will be stored here if the
* method call succeeds.
*
* @return <ul>
* <li>{@link ACAMERA_OK} if the method call succeeds. The created container will be
* filled in the output argument.</li>
* <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if anw, physicalId or output is NULL.</li></ul>
*
* @see ACaptureSessionOutputContainer_add
*/
camera_status_t ACaptureSessionPhysicalOutput_create(
ACameraWindowType* anw, const char* physicalId,
/*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(29);
#endif /* __ANDROID_API__ >= 29 */
__END_DECLS
#endif /* _NDK_CAMERA_DEVICE_H */

@ -233,6 +233,28 @@ void ACameraMetadata_free(ACameraMetadata* metadata) __INTRODUCED_IN(24);
#endif /* __ANDROID_API__ >= 24 */
#if __ANDROID_API__ >= 29
/**
* Helper function to check if a camera is logical multi-camera.
*
* <p> Check whether a camera device is a logical multi-camera based on its
* static metadata. If it is, also returns its physical sub camera Ids.</p>
*
* @param staticMetadata the static metadata of the camera being checked.
* @param numPhysicalCameras returns the number of physical cameras.
* @param physicalCameraIds returns the array of physical camera Ids backing this logical
* camera device. Note that this pointer is only valid
* during the lifetime of the staticMetadata object.
*
* @return true if this is a logical multi-camera, false otherwise.
*/
bool ACameraMetadata_isLogicalMultiCamera(const ACameraMetadata* staticMetadata,
/*out*/size_t* numPhysicalCameras, /*out*/const char* const** physicalCameraIds)
__INTRODUCED_IN(29);
#endif /* __ANDROID_API__ >= 29 */
__END_DECLS
#endif /* _NDK_CAMERA_METADATA_H */

@ -5551,6 +5551,25 @@ typedef enum acamera_metadata_tag {
ACAMERA_DEPTH_START + 5,
ACAMERA_DEPTH_END,
/**
* <p>String containing the ids of the underlying physical cameras.</p>
*
* <p>Type: byte[n]</p>
*
* <p>This tag may appear in:
* <ul>
* <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
* </ul></p>
*
* <p>For a logical camera, this is concatenation of all underlying physical camera ids.
* The null terminator for physical camera id must be preserved so that the whole string
* can be tokenized using '\0' to generate list of physical camera ids.</p>
* <p>For example, if the physical camera ids of the logical camera are "2" and "3", the
* value of this tag will be ['2', '\0', '3', '\0'].</p>
* <p>The number of physical camera ids must be no less than 2.</p>
*/
ACAMERA_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS = // byte[n]
ACAMERA_LOGICAL_MULTI_CAMERA_START,
/**
* <p>The accuracy of frame timestamp synchronization between physical cameras</p>
*

@ -2,9 +2,11 @@ LIBCAMERA2NDK {
global:
ACameraCaptureSession_abortCaptures;
ACameraCaptureSession_capture;
ACameraCaptureSession_logicalCamera_capture; # introduced=29
ACameraCaptureSession_close;
ACameraCaptureSession_getDevice;
ACameraCaptureSession_setRepeatingRequest;
ACameraCaptureSession_logicalCamera_setRepeatingRequest; # introduced=29
ACameraCaptureSession_stopRepeating;
ACameraCaptureSession_updateSharedOutput; # introduced=28
ACameraDevice_close;
@ -24,6 +26,7 @@ LIBCAMERA2NDK {
ACameraMetadata_free;
ACameraMetadata_getAllTags;
ACameraMetadata_getConstEntry;
ACameraMetadata_isLogicalMultiCamera; # introduced=29
ACameraOutputTarget_create;
ACameraOutputTarget_free;
ACaptureRequest_addTarget;
@ -48,6 +51,7 @@ LIBCAMERA2NDK {
ACaptureSessionSharedOutput_create; # introduced=28
ACaptureSessionSharedOutput_add; # introduced=28
ACaptureSessionSharedOutput_remove; # introduced=28
ACaptureSessionPhysicalOutput_create; # introduced=29
ACaptureSessionOutput_free;
local:
*;

@ -14,11 +14,13 @@
* limitations under the License.
*/
#include <string>
#include "utils.h"
struct ACaptureSessionOutput {
explicit ACaptureSessionOutput(native_handle_t* window, bool isShared = false) :
mWindow(window), mIsShared(isShared) {};
explicit ACaptureSessionOutput(native_handle_t* window, bool isShared = false,
const char* physicalCameraId = "") :
mWindow(window), mIsShared(isShared), mPhysicalCameraId(physicalCameraId) {};
bool operator == (const ACaptureSessionOutput& other) const {
return (mWindow == other.mWindow);
@ -40,6 +42,7 @@ struct ACaptureSessionOutput {
std::set<android::acam::utils::native_handle_ptr_wrapper> mSharedWindows;
bool mIsShared;
int mRotation = CAMERA3_STREAM_ROTATION_0;
std::string mPhysicalCameraId;
};

@ -29,6 +29,8 @@
#include "ACaptureRequest.h"
#include "utils.h"
#include "ACameraCaptureSession.inc"
using namespace android;
namespace android {
@ -47,6 +49,7 @@ const char* CameraDevice::kSessionSpKey = "SessionSp";
const char* CameraDevice::kCaptureRequestKey = "CaptureRequest";
const char* CameraDevice::kTimeStampKey = "TimeStamp";
const char* CameraDevice::kCaptureResultKey = "CaptureResult";
const char* CameraDevice::kPhysicalCaptureResultKey = "PhysicalCaptureResult";
const char* CameraDevice::kCaptureFailureKey = "CaptureFailure";
const char* CameraDevice::kSequenceIdKey = "SequenceId";
const char* CameraDevice::kFrameNumberKey = "FrameNumber";
@ -206,28 +209,8 @@ CameraDevice::createCaptureSession(
return ACAMERA_OK;
}
camera_status_t
CameraDevice::captureLocked(
sp<ACameraCaptureSession> session,
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
return submitRequestsLocked(
session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/false);
}
camera_status_t
CameraDevice::setRepeatingRequestsLocked(
sp<ACameraCaptureSession> session,
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
return submitRequestsLocked(
session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/true);
}
void addRequestSettingsMetadata(ACaptureRequest *aCaptureRequest,
sp<CaptureRequest> &req) {
void CameraDevice::addRequestSettingsMetadata(ACaptureRequest *aCaptureRequest,
sp<CaptureRequest> &req) {
CameraMetadata metadataCopy = aCaptureRequest->settings->getInternalData();
const camera_metadata_t *camera_metadata = metadataCopy.getAndLock();
HCameraMetadata hCameraMetadata;
@ -237,101 +220,6 @@ void addRequestSettingsMetadata(ACaptureRequest *aCaptureRequest,
req->mPhysicalCameraSettings[0].settings.metadata(std::move(hCameraMetadata));
}
camera_status_t
CameraDevice::submitRequestsLocked(
sp<ACameraCaptureSession> session,
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId,
bool isRepeating) {
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
ALOGE("Camera %s submit capture request failed! ret %d", getId(), ret);
return ret;
}
// Form two vectors of capture request, one for internal tracking
std::vector<frameworks::cameraservice::device::V2_0::CaptureRequest> requestList;
Vector<sp<CaptureRequest>> requestsV;
requestsV.setCapacity(numRequests);
for (int i = 0; i < numRequests; i++) {
sp<CaptureRequest> req;
ret = allocateCaptureRequest(requests[i], req);
// We need to call this method since after submitRequestList is called,
// the request metadata queue might have removed the capture request
// metadata. Therefore we simply add the metadata to its wrapper class,
// so that it can be retrived later.
addRequestSettingsMetadata(requests[i], req);
if (ret != ACAMERA_OK) {
ALOGE("Convert capture request to internal format failure! ret %d", ret);
return ret;
}
if (req->mCaptureRequest.streamAndWindowIds.size() == 0) {
ALOGE("Capture request without output target cannot be submitted!");
return ACAMERA_ERROR_INVALID_PARAMETER;
}
requestList.push_back(utils::convertToHidl(req.get()));
requestsV.push_back(req);
}
if (isRepeating) {
ret = stopRepeatingLocked();
if (ret != ACAMERA_OK) {
ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
return ret;
}
}
SubmitInfo info;
Status status;
auto remoteRet = mRemote->submitRequestList(requestList, isRepeating,
[&status, &info](auto s, auto &submitInfo) {
status = s;
info = submitInfo;
});
if (!remoteRet.isOk()) {
ALOGE("%s: Transaction error for submitRequestList call: %s", __FUNCTION__,
remoteRet.description().c_str());
}
if (status != Status::NO_ERROR) {
return utils::convertFromHidl(status);
}
int32_t sequenceId = info.requestId;
int64_t lastFrameNumber = info.lastFrameNumber;
if (sequenceId < 0) {
ALOGE("Camera %s submit request remote failure: ret %d", getId(), sequenceId);
return ACAMERA_ERROR_UNKNOWN;
}
CallbackHolder cbHolder(session, requestsV, isRepeating, cbs);
mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder));
if (isRepeating) {
// stopRepeating above should have cleanup repeating sequence id
if (mRepeatingSequenceId != REQUEST_ID_NONE) {
setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
return ACAMERA_ERROR_CAMERA_DEVICE;
}
mRepeatingSequenceId = sequenceId;
} else {
mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
}
if (mIdle) {
sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
msg->setPointer(kContextKey, session->mUserSessionCallback.context);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
postSessionMsgAndCleanup(msg);
}
mIdle = false;
mBusySession = session;
if (captureSequenceId) {
*captureSequenceId = sequenceId;
}
return ACAMERA_OK;
}
camera_status_t CameraDevice::updateOutputConfigurationLocked(ACaptureSessionOutput *output) {
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
@ -365,6 +253,7 @@ camera_status_t CameraDevice::updateOutputConfigurationLocked(ACaptureSessionOut
outConfig.windowGroupId = -1; // ndk doesn't support inter OutputConfiguration buffer sharing.
outConfig.windowHandles.resize(output->mSharedWindows.size() + 1);
outConfig.windowHandles[0] = output->mWindow;
outConfig.physicalCameraId = output->mPhysicalCameraId;
int i = 1;
for (auto& anw : output->mSharedWindows) {
outConfig.windowHandles[i++] = anw;
@ -668,6 +557,7 @@ CameraDevice::configureStreamsLocked(const ACaptureSessionOutputContainer* outpu
outConfigInsert.windowGroupId = -1;
outConfigInsert.windowHandles.resize(outConfig.mSharedWindows.size() + 1);
outConfigInsert.windowHandles[0] = anw;
outConfigInsert.physicalCameraId = outConfig.mPhysicalCameraId;
native_handle_ptr_wrapper wrap(anw);
outputSet.insert(std::make_pair(anw, outConfigInsertW));
}
@ -894,7 +784,7 @@ CameraDevice::onCaptureErrorLocked(
if (errorCode == ErrorCode::CAMERA_BUFFER) {
int32_t streamId = resultExtras.errorStreamId;
ACameraCaptureSession_captureCallback_bufferLost onBufferLost =
cbh.mCallbacks.onCaptureBufferLost;
cbh.mOnCaptureBufferLost;
auto outputPairIt = mConfiguredOutputs.find(streamId);
if (outputPairIt == mConfiguredOutputs.end()) {
ALOGE("%s: Error: stream id %d does not exist", __FUNCTION__, streamId);
@ -913,7 +803,7 @@ CameraDevice::onCaptureErrorLocked(
getId(), anw, frameNumber);
sp<AMessage> msg = new AMessage(kWhatCaptureBufferLost, mHandler);
msg->setPointer(kContextKey, cbh.mCallbacks.context);
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) onBufferLost);
msg->setObject(kCaptureRequestKey, request);
@ -925,7 +815,7 @@ CameraDevice::onCaptureErrorLocked(
}
} else { // Handle other capture failures
// Fire capture failure callback if there is one registered
ACameraCaptureSession_captureCallback_failed onError = cbh.mCallbacks.onCaptureFailed;
ACameraCaptureSession_captureCallback_failed onError = cbh.mOnCaptureFailed;
sp<CameraCaptureFailure> failure(new CameraCaptureFailure());
failure->frameNumber = frameNumber;
// TODO: refine this when implementing flush
@ -934,7 +824,7 @@ CameraDevice::onCaptureErrorLocked(
failure->wasImageCaptured = (errorCode == ErrorCode::CAMERA_RESULT);
sp<AMessage> msg = new AMessage(kWhatCaptureFail, mHandler);
msg->setPointer(kContextKey, cbh.mCallbacks.context);
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) onError);
msg->setObject(kCaptureRequestKey, request);
@ -956,6 +846,7 @@ void CameraDevice::CallbackHandler::onMessageReceived(
case kWhatSessionStateCb:
case kWhatCaptureStart:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
case kWhatCaptureSeqEnd:
case kWhatCaptureSeqAbort:
@ -1026,6 +917,7 @@ void CameraDevice::CallbackHandler::onMessageReceived(
case kWhatSessionStateCb:
case kWhatCaptureStart:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
case kWhatCaptureSeqEnd:
case kWhatCaptureSeqAbort:
@ -1043,6 +935,7 @@ void CameraDevice::CallbackHandler::onMessageReceived(
switch (msg->what()) {
case kWhatCaptureStart:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
case kWhatCaptureBufferLost:
found = msg->findObject(kCaptureRequestKey, &obj);
@ -1114,6 +1007,62 @@ void CameraDevice::CallbackHandler::onMessageReceived(
freeACaptureRequest(request);
break;
}
case kWhatLogicalCaptureResult:
{
ACameraCaptureSession_logicalCamera_captureCallback_result onResult;
found = msg->findPointer(kCallbackFpKey, (void**) &onResult);
if (!found) {
ALOGE("%s: Cannot find capture result callback!", __FUNCTION__);
return;
}
if (onResult == nullptr) {
return;
}
found = msg->findObject(kCaptureResultKey, &obj);
if (!found) {
ALOGE("%s: Cannot find capture result!", __FUNCTION__);
return;
}
sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
found = msg->findObject(kPhysicalCaptureResultKey, &obj);
if (!found) {
ALOGE("%s: Cannot find physical capture result!", __FUNCTION__);
return;
}
sp<ACameraPhysicalCaptureResultInfo> physicalResult(
static_cast<ACameraPhysicalCaptureResultInfo*>(obj.get()));
std::vector<PhysicalCaptureResultInfoLocal>& physicalResultInfo =
physicalResult->mPhysicalResultInfo;
std::vector<std::string> physicalCameraIds;
std::vector<sp<ACameraMetadata>> physicalMetadataCopy;
for (size_t i = 0; i < physicalResultInfo.size(); i++) {
physicalCameraIds.push_back(physicalResultInfo[i].physicalCameraId);
CameraMetadata clone = physicalResultInfo[i].physicalMetadata;
clone.update(ANDROID_SYNC_FRAME_NUMBER,
&physicalResult->mFrameNumber, /*data_count*/1);
sp<ACameraMetadata> metadata =
new ACameraMetadata(clone.release(), ACameraMetadata::ACM_RESULT);
physicalMetadataCopy.push_back(metadata);
}
std::vector<const char*> physicalCameraIdPtrs;
std::vector<const ACameraMetadata*> physicalMetadataCopyPtrs;
for (size_t i = 0; i < physicalResultInfo.size(); i++) {
physicalCameraIdPtrs.push_back(physicalCameraIds[i].c_str());
physicalMetadataCopyPtrs.push_back(physicalMetadataCopy[i].get());
}
ACaptureRequest* request = allocateACaptureRequest(requestSp);
(*onResult)(context, session.get(), request, result.get(),
physicalResultInfo.size(), physicalCameraIdPtrs.data(),
physicalMetadataCopyPtrs.data());
freeACaptureRequest(request);
break;
}
case kWhatCaptureFail:
{
ACameraCaptureSession_captureCallback_failed onFail;
@ -1224,12 +1173,34 @@ void CameraDevice::CallbackHandler::onMessageReceived(
}
CameraDevice::CallbackHolder::CallbackHolder(
sp<ACameraCaptureSession> session,
const Vector<sp<CaptureRequest> >& requests,
bool isRepeating,
ACameraCaptureSession_captureCallbacks* cbs) :
mSession(session), mRequests(requests),
mIsRepeating(isRepeating), mCallbacks(fillCb(cbs)) {}
sp<ACameraCaptureSession> session,
const Vector<sp<CaptureRequest> >& requests,
bool isRepeating,
ACameraCaptureSession_captureCallbacks* cbs) :
mSession(session), mRequests(requests),
mIsRepeating(isRepeating),
mIsLogicalCameraCallback(false) {
initCaptureCallbacks(cbs);
if (cbs != nullptr) {
mOnCaptureCompleted = cbs->onCaptureCompleted;
}
}
CameraDevice::CallbackHolder::CallbackHolder(
sp<ACameraCaptureSession> session,
const Vector<sp<CaptureRequest> >& requests,
bool isRepeating,
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs) :
mSession(session), mRequests(requests),
mIsRepeating(isRepeating),
mIsLogicalCameraCallback(true) {
initCaptureCallbacks(lcbs);
if (lcbs != nullptr) {
mOnLogicalCameraCaptureCompleted = lcbs->onLogicalCameraCaptureCompleted;
}
}
void
CameraDevice::checkRepeatingSequenceCompleteLocked(
@ -1246,9 +1217,9 @@ CameraDevice::checkRepeatingSequenceCompleteLocked(
mSequenceCallbackMap.erase(cbIt);
// send seq aborted callback
sp<AMessage> msg = new AMessage(kWhatCaptureSeqAbort, mHandler);
msg->setPointer(kContextKey, cbh.mCallbacks.context);
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, cbh.mSession);
msg->setPointer(kCallbackFpKey, (void*) cbh.mCallbacks.onCaptureSequenceAborted);
msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceAborted);
msg->setInt32(kSequenceIdKey, sequenceId);
postSessionMsgAndCleanup(msg);
} else {
@ -1295,9 +1266,9 @@ CameraDevice::checkAndFireSequenceCompleteLocked() {
mSequenceCallbackMap.erase(cbIt);
// send seq complete callback
sp<AMessage> msg = new AMessage(kWhatCaptureSeqEnd, mHandler);
msg->setPointer(kContextKey, cbh.mCallbacks.context);
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, cbh.mSession);
msg->setPointer(kCallbackFpKey, (void*) cbh.mCallbacks.onCaptureSequenceCompleted);
msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceCompleted);
msg->setInt32(kSequenceIdKey, sequenceId);
msg->setInt64(kFrameNumberKey, lastFrameNumber);
@ -1454,7 +1425,7 @@ CameraDevice::ServiceCallback::onCaptureStarted(
auto it = dev->mSequenceCallbackMap.find(sequenceId);
if (it != dev->mSequenceCallbackMap.end()) {
CallbackHolder cbh = (*it).second;
ACameraCaptureSession_captureCallback_start onStart = cbh.mCallbacks.onCaptureStarted;
ACameraCaptureSession_captureCallback_start onStart = cbh.mOnCaptureStarted;
sp<ACameraCaptureSession> session = cbh.mSession;
if ((size_t) burstId >= cbh.mRequests.size()) {
ALOGE("%s: Error: request index %d out of bound (size %zu)",
@ -1463,7 +1434,7 @@ CameraDevice::ServiceCallback::onCaptureStarted(
}
sp<CaptureRequest> request = cbh.mRequests[burstId];
sp<AMessage> msg = new AMessage(kWhatCaptureStart, dev->mHandler);
msg->setPointer(kContextKey, cbh.mCallbacks.context);
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) onStart);
msg->setObject(kCaptureRequestKey, request);
@ -1478,7 +1449,6 @@ CameraDevice::ServiceCallback::onResultReceived(
const FmqSizeOrMetadata& resultMetadata,
const CaptureResultExtras& resultExtras,
const hidl_vec<PhysicalCaptureResultInfo>& physicalResultInfos) {
(void) physicalResultInfos;
auto ret = Void();
sp<CameraDevice> dev = mDevice.promote();
@ -1508,27 +1478,10 @@ CameraDevice::ServiceCallback::onResultReceived(
}
CameraMetadata metadataCopy;
HCameraMetadata hCameraMetadata;
bool converted = false;
if (resultMetadata.getDiscriminator() ==
FmqSizeOrMetadata::hidl_discriminator::fmqMetadataSize) {
hCameraMetadata.resize(resultMetadata.fmqMetadataSize());
bool read = dev->mCaptureResultMetadataQueue->read(hCameraMetadata.data(),
resultMetadata.fmqMetadataSize());
if (!read) {
ALOGE("%s capture request settings could't be read from fmq",
__FUNCTION__);
return ret;
}
// TODO: Do we actually need to clone here ?
converted = utils::convertFromHidlCloned(hCameraMetadata, &metadataCopy);
} else {
converted = utils::convertFromHidlCloned(resultMetadata.metadata(), &metadataCopy);
}
if (!converted) {
ALOGE("%s result metadata couldn't be converted", __FUNCTION__);
camera_status_t status = readOneResultMetadata(resultMetadata,
dev->mCaptureResultMetadataQueue.get(), &metadataCopy);
if (status != ACAMERA_OK) {
ALOGE("%s: result metadata couldn't be converted", __FUNCTION__);
return ret;
}
@ -1538,9 +1491,6 @@ CameraDevice::ServiceCallback::onResultReceived(
auto it = dev->mSequenceCallbackMap.find(sequenceId);
if (it != dev->mSequenceCallbackMap.end()) {
CallbackHolder cbh = (*it).second;
ACameraCaptureSession_captureCallback_result onResult = isPartialResult ?
cbh.mCallbacks.onCaptureProgressed :
cbh.mCallbacks.onCaptureCompleted;
sp<ACameraCaptureSession> session = cbh.mSession;
if ((size_t) burstId >= cbh.mRequests.size()) {
ALOGE("%s: Error: request index %d out of bound (size %zu)",
@ -1551,12 +1501,39 @@ CameraDevice::ServiceCallback::onResultReceived(
sp<ACameraMetadata> result(new ACameraMetadata(
metadataCopy.release(), ACameraMetadata::ACM_RESULT));
sp<AMessage> msg = new AMessage(kWhatCaptureResult, dev->mHandler);
msg->setPointer(kContextKey, cbh.mCallbacks.context);
std::vector<PhysicalCaptureResultInfoLocal> localPhysicalResult;
localPhysicalResult.resize(physicalResultInfos.size());
for (size_t i = 0; i < physicalResultInfos.size(); i++) {
localPhysicalResult[i].physicalCameraId = physicalResultInfos[i].physicalCameraId;
status = readOneResultMetadata(physicalResultInfos[i].physicalCameraMetadata,
dev->mCaptureResultMetadataQueue.get(),
&localPhysicalResult[i].physicalMetadata);
if (status != ACAMERA_OK) {
ALOGE("%s: physical camera result metadata couldn't be converted", __FUNCTION__);
return ret;
}
}
sp<ACameraPhysicalCaptureResultInfo> physicalResult(
new ACameraPhysicalCaptureResultInfo(localPhysicalResult, frameNumber));
sp<AMessage> msg = new AMessage(
cbh.mIsLogicalCameraCallback ? kWhatLogicalCaptureResult : kWhatCaptureResult,
dev->mHandler);
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) onResult);
msg->setObject(kCaptureRequestKey, request);
msg->setObject(kCaptureResultKey, result);
if (isPartialResult) {
msg->setPointer(kCallbackFpKey,
(void *)cbh.mOnCaptureProgressed);
} else if (cbh.mIsLogicalCameraCallback) {
msg->setPointer(kCallbackFpKey,
(void *)cbh.mOnLogicalCameraCaptureCompleted);
msg->setObject(kPhysicalCaptureResultKey, physicalResult);
} else {
msg->setPointer(kCallbackFpKey,
(void *)cbh.mOnCaptureCompleted);
}
dev->postSessionMsgAndCleanup(msg);
}
@ -1590,5 +1567,31 @@ CameraDevice::ServiceCallback::onRepeatingRequestError(
return ret;
}
camera_status_t CameraDevice::ServiceCallback::readOneResultMetadata(
const FmqSizeOrMetadata& fmqSizeOrMetadata, ResultMetadataQueue* metadataQueue,
CameraMetadata* metadata) {
if (metadataQueue == nullptr || metadata == nullptr) {
return ACAMERA_ERROR_INVALID_PARAMETER;
}
bool converted;
HCameraMetadata hCameraMetadata;
if (fmqSizeOrMetadata.getDiscriminator() ==
FmqSizeOrMetadata::hidl_discriminator::fmqMetadataSize) {
hCameraMetadata.resize(fmqSizeOrMetadata.fmqMetadataSize());
bool read = metadataQueue->read(
hCameraMetadata.data(), fmqSizeOrMetadata.fmqMetadataSize());
if (!read) {
ALOGE("%s capture request settings could't be read from fmq", __FUNCTION__);
return ACAMERA_ERROR_UNKNOWN;
}
// TODO: Do we actually need to clone here ?
converted = utils::convertFromHidlCloned(hCameraMetadata, metadata);
} else {
converted = utils::convertFromHidlCloned(fmqSizeOrMetadata.metadata(), metadata);
}
return converted ? ACAMERA_OK : ACAMERA_ERROR_UNKNOWN;
}
} // namespace acam
} // namespace android

@ -21,6 +21,7 @@
#include <set>
#include <atomic>
#include <utility>
#include <vector>
#include <utils/StrongPointer.h>
#include <utils/Mutex.h>
#include <utils/List.h>
@ -65,6 +66,21 @@ using utils::OutputConfigurationWrapper;
// Wrap ACameraCaptureFailure so it can be ref-counted
struct CameraCaptureFailure : public RefBase, public ACameraCaptureFailure { };
// Wrap PhysicalCaptureResultInfo so that it can be ref-counted
struct PhysicalCaptureResultInfoLocal {
std::string physicalCameraId;
CameraMetadata physicalMetadata;
};
struct ACameraPhysicalCaptureResultInfo: public RefBase {
ACameraPhysicalCaptureResultInfo(const std::vector<PhysicalCaptureResultInfoLocal>& info,
int64_t frameNumber) :
mPhysicalResultInfo(info), mFrameNumber(frameNumber) {}
std::vector<PhysicalCaptureResultInfoLocal> mPhysicalResultInfo;
int64_t mFrameNumber;
};
class CameraDevice final : public RefBase {
public:
CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
@ -99,6 +115,8 @@ class CameraDevice final : public RefBase {
android::hardware::Return<void> onRepeatingRequestError(uint64_t lastFrameNumber,
int32_t stoppedSequenceId) override;
private:
camera_status_t readOneResultMetadata(const FmqSizeOrMetadata& fmqSizeOrMetadata,
ResultMetadataQueue* metadataQueue, CameraMetadata* metadata);
const wp<CameraDevice> mDevice;
};
inline sp<ICameraDeviceCallback> getServiceCallback() {
@ -127,24 +145,28 @@ class CameraDevice final : public RefBase {
camera_status_t waitUntilIdleLocked();
template<class T>
camera_status_t captureLocked(sp<ACameraCaptureSession> session,
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId);
template<class T>
camera_status_t setRepeatingRequestsLocked(sp<ACameraCaptureSession> session,
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId);
template<class T>
camera_status_t submitRequestsLocked(
sp<ACameraCaptureSession> session,
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*out*/int* captureSequenceId,
bool isRepeating);
void addRequestSettingsMetadata(ACaptureRequest *aCaptureRequest, sp<CaptureRequest> &req);
camera_status_t updateOutputConfigurationLocked(ACaptureSessionOutput *output);
camera_status_t allocateCaptureRequest(
@ -206,6 +228,7 @@ class CameraDevice final : public RefBase {
// Capture callbacks
kWhatCaptureStart, // onCaptureStarted
kWhatCaptureResult, // onCaptureProgressed, onCaptureCompleted
kWhatLogicalCaptureResult, // onLogicalCameraCaptureCompleted
kWhatCaptureFail, // onCaptureFailed
kWhatCaptureSeqEnd, // onCaptureSequenceCompleted
kWhatCaptureSeqAbort, // onCaptureSequenceAborted
@ -221,6 +244,7 @@ class CameraDevice final : public RefBase {
static const char* kCaptureRequestKey;
static const char* kTimeStampKey;
static const char* kCaptureResultKey;
static const char* kPhysicalCaptureResultKey;
static const char* kCaptureFailureKey;
static const char* kSequenceIdKey;
static const char* kFrameNumberKey;
@ -259,19 +283,47 @@ class CameraDevice final : public RefBase {
const Vector<sp<CaptureRequest>>& requests,
bool isRepeating,
ACameraCaptureSession_captureCallbacks* cbs);
static ACameraCaptureSession_captureCallbacks fillCb(
ACameraCaptureSession_captureCallbacks* cbs) {
CallbackHolder(sp<ACameraCaptureSession> session,
const Vector<sp<CaptureRequest>>& requests,
bool isRepeating,
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs);
template <class T>
void initCaptureCallbacks(T* cbs) {
mContext = nullptr;
mOnCaptureStarted = nullptr;
mOnCaptureProgressed = nullptr;
mOnCaptureCompleted = nullptr;
mOnLogicalCameraCaptureCompleted = nullptr;
mOnCaptureFailed = nullptr;
mOnCaptureSequenceCompleted = nullptr;
mOnCaptureSequenceAborted = nullptr;
mOnCaptureBufferLost = nullptr;
if (cbs != nullptr) {
return *cbs;
mContext = cbs->context;
mOnCaptureStarted = cbs->onCaptureStarted;
mOnCaptureProgressed = cbs->onCaptureProgressed;
mOnCaptureFailed = cbs->onCaptureFailed;
mOnCaptureSequenceCompleted = cbs->onCaptureSequenceCompleted;
mOnCaptureSequenceAborted = cbs->onCaptureSequenceAborted;
mOnCaptureBufferLost = cbs->onCaptureBufferLost;
}
return { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
}
sp<ACameraCaptureSession> mSession;
Vector<sp<CaptureRequest>> mRequests;
Vector<sp<CaptureRequest>> mRequests;
const bool mIsRepeating;
ACameraCaptureSession_captureCallbacks mCallbacks;
const bool mIsLogicalCameraCallback;
void* mContext;
ACameraCaptureSession_captureCallback_start mOnCaptureStarted;
ACameraCaptureSession_captureCallback_result mOnCaptureProgressed;
ACameraCaptureSession_captureCallback_result mOnCaptureCompleted;
ACameraCaptureSession_logicalCamera_captureCallback_result mOnLogicalCameraCaptureCompleted;
ACameraCaptureSession_captureCallback_failed mOnCaptureFailed;
ACameraCaptureSession_captureCallback_sequenceEnd mOnCaptureSequenceCompleted;
ACameraCaptureSession_captureCallback_sequenceAbort mOnCaptureSequenceAborted;
ACameraCaptureSession_captureCallback_bufferLost mOnCaptureBufferLost;
};
// sequence id -> callbacks map
std::map<int, CallbackHolder> mSequenceCallbackMap;

@ -0,0 +1,152 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vector>
#include <inttypes.h>
#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
#include <android/frameworks/cameraservice/device/2.0/types.h>
#include <CameraMetadata.h>
#include "ndk_vendor/impl/ACameraDevice.h"
#include "ACameraCaptureSession.h"
#include "ACameraMetadata.h"
#include "ACaptureRequest.h"
#include "utils.h"
using namespace android;
namespace android {
namespace acam {
template<class T>
camera_status_t
CameraDevice::captureLocked(
sp<ACameraCaptureSession> session,
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
return submitRequestsLocked(
session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/false);
}
template<class T>
camera_status_t
CameraDevice::setRepeatingRequestsLocked(
sp<ACameraCaptureSession> session,
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
return submitRequestsLocked(
session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/true);
}
template<class T>
camera_status_t CameraDevice::submitRequestsLocked(
sp<ACameraCaptureSession> session,
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*out*/int* captureSequenceId,
bool isRepeating)
{
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
ALOGE("Camera %s submit capture request failed! ret %d", getId(), ret);
return ret;
}
// Form two vectors of capture request, one for internal tracking
std::vector<frameworks::cameraservice::device::V2_0::CaptureRequest> requestList;
Vector<sp<CaptureRequest>> requestsV;
requestsV.setCapacity(numRequests);
for (int i = 0; i < numRequests; i++) {
sp<CaptureRequest> req;
ret = allocateCaptureRequest(requests[i], req);
// We need to call this method since after submitRequestList is called,
// the request metadata queue might have removed the capture request
// metadata. Therefore we simply add the metadata to its wrapper class,
// so that it can be retrieved later.
addRequestSettingsMetadata(requests[i], req);
if (ret != ACAMERA_OK) {
ALOGE("Convert capture request to internal format failure! ret %d", ret);
return ret;
}
if (req->mCaptureRequest.streamAndWindowIds.size() == 0) {
ALOGE("Capture request without output target cannot be submitted!");
return ACAMERA_ERROR_INVALID_PARAMETER;
}
requestList.push_back(utils::convertToHidl(req.get()));
requestsV.push_back(req);
}
if (isRepeating) {
ret = stopRepeatingLocked();
if (ret != ACAMERA_OK) {
ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
return ret;
}
}
SubmitInfo info;
Status status;
auto remoteRet = mRemote->submitRequestList(requestList, isRepeating,
[&status, &info](auto s, auto &submitInfo) {
status = s;
info = submitInfo;
});
if (!remoteRet.isOk()) {
ALOGE("%s: Transaction error for submitRequestList call: %s", __FUNCTION__,
remoteRet.description().c_str());
}
if (status != Status::NO_ERROR) {
return utils::convertFromHidl(status);
}
int32_t sequenceId = info.requestId;
int64_t lastFrameNumber = info.lastFrameNumber;
if (sequenceId < 0) {
ALOGE("Camera %s submit request remote failure: ret %d", getId(), sequenceId);
return ACAMERA_ERROR_UNKNOWN;
}
CallbackHolder cbHolder(session, requestsV, isRepeating, cbs);
mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder));
if (isRepeating) {
// stopRepeating above should have cleanup repeating sequence id
if (mRepeatingSequenceId != REQUEST_ID_NONE) {
setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
return ACAMERA_ERROR_CAMERA_DEVICE;
}
mRepeatingSequenceId = sequenceId;
} else {
mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
}
if (mIdle) {
sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
msg->setPointer(kContextKey, session->mUserSessionCallback.context);
msg->setObject(kSessionSpKey, session);
msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
postSessionMsgAndCleanup(msg);
}
mIdle = false;
mBusySession = session;
if (captureSequenceId) {
*captureSequenceId = sequenceId;
}
return ACAMERA_OK;
}
} // namespace acam
} // namespace android

@ -480,7 +480,8 @@ TEST_F(CameraClientBinderTest, CheckBinderCameraDeviceUser) {
sp<Surface> surface(new Surface(gbProducer, /*controlledByApp*/false));
OutputConfiguration output(gbProducer, /*rotation*/0);
String16 noPhysicalId;
OutputConfiguration output(gbProducer, /*rotation*/0, noPhysicalId);
// Can we configure?
res = device->beginConfigure();

@ -139,18 +139,18 @@ void H2BCameraDeviceCallbacks::CallbackHandler::processResultMessage(
}
CameraMetadataNative &result = resultWrapper->mResult;
auto resultExtras = resultWrapper->mResultExtras;
auto &physicalCaptureResultInfos = resultWrapper->mPhysicalCaptureResultInfos;
HCaptureResultExtras hResultExtras =
hardware::cameraservice::utils::conversion::convertToHidl(resultExtras);
hidl_vec<HPhysicalCaptureResultInfo> hPhysicalCaptureResultInfos =
hardware::cameraservice::utils::conversion::convertToHidl(
physicalCaptureResultInfos, converter->mCaptureResultMetadataQueue);
// Convert Metadata into HCameraMetadata;
FmqSizeOrMetadata hResult;
const camera_metadata_t *rawMetadata = result.getAndLock();
converter->convertResultMetadataToHidl(rawMetadata, &hResult);
result.unlock(rawMetadata);
auto &physicalCaptureResultInfos = resultWrapper->mPhysicalCaptureResultInfos;
hidl_vec<HPhysicalCaptureResultInfo> hPhysicalCaptureResultInfos =
hardware::cameraservice::utils::conversion::convertToHidl(
physicalCaptureResultInfos, converter->mCaptureResultMetadataQueue);
auto ret = converter->mBase->onResultReceived(hResult, hResultExtras,
hPhysicalCaptureResultInfos);
if (!ret.isOk()) {

@ -89,8 +89,9 @@ hardware::camera2::params::OutputConfiguration convertFromHidl(
for (auto &handle : windowHandles) {
iGBPs.push_back(new H2BGraphicBufferProducer(AImageReader_getHGBPFromHandle(handle)));
}
String16 physicalCameraId16(hOutputConfiguration.physicalCameraId.c_str());
hardware::camera2::params::OutputConfiguration outputConfiguration(
iGBPs, convertFromHidl(hOutputConfiguration.rotation),
iGBPs, convertFromHidl(hOutputConfiguration.rotation), physicalCameraId16,
hOutputConfiguration.windowGroupId, OutputConfiguration::SURFACE_TYPE_UNKNOWN, 0, 0,
(windowHandles.size() > 1));
return outputConfiguration;

Loading…
Cancel
Save