camera2 (v)ndk: Add APIs for pre-allocation of surface buffers.
Clients may need to pre-allocate stream buffers in order to reduce
affects of buffer-allocation time such as frame jank till steady state
capture is reached (eg: for a repeating request).
The SDK already has an api which does this :
CameraCaptureSession.prepare(Surface). We're exposing a similar API to
the ndk/ vndk here.
Bug: 259735869
Test: NdkCameraDeviceTest.java
Change-Id: Iee8559fcebd61a6886f23779a05351b52633f851
Signed-off-by: Jayant Chowdhary <jchowdhary@google.com>
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 536055b..b90f276 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -342,6 +342,58 @@
return ACAMERA_OK;
}
+camera_status_t CameraDevice::prepareLocked(ACameraWindowType *window) {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+
+ if (window == nullptr) {
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ int32_t streamId = -1;
+ for (auto& kvPair : mConfiguredOutputs) {
+ if (window == kvPair.second.first) {
+ streamId = kvPair.first;
+ break;
+ }
+ }
+ if (streamId < 0) {
+ ALOGE("Error: Invalid output configuration");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ auto remoteRet = mRemote->prepare(streamId);
+ if (!remoteRet.isOk()) {
+ // TODO:(b/259735869) Do this check for all other binder calls in the
+ // ndk as well.
+ if (remoteRet.exceptionCode() != EX_SERVICE_SPECIFIC) {
+ ALOGE("Camera device %s failed to prepare output window %p: %s", getId(), window,
+ remoteRet.toString8().string());
+ return ACAMERA_ERROR_UNKNOWN;
+
+ }
+ switch (remoteRet.serviceSpecificErrorCode()) {
+ case hardware::ICameraService::ERROR_INVALID_OPERATION:
+ ALOGE("Camera device %s invalid operation: %s", getId(),
+ remoteRet.toString8().string());
+ return ACAMERA_ERROR_INVALID_OPERATION;
+ break;
+ case hardware::ICameraService::ERROR_ILLEGAL_ARGUMENT:
+ ALOGE("Camera device %s invalid input argument: %s", getId(),
+ remoteRet.toString8().string());
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ break;
+ default:
+ ALOGE("Camera device %s failed to prepare output window %p: %s", getId(), window,
+ remoteRet.toString8().string());
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ }
+
+ return ACAMERA_OK;
+}
+
camera_status_t
CameraDevice::allocateCaptureRequest(
const ACaptureRequest* request, /*out*/sp<CaptureRequest>& outReq) {
@@ -919,6 +971,7 @@
case kWhatCaptureSeqEnd:
case kWhatCaptureSeqAbort:
case kWhatCaptureBufferLost:
+ case kWhatPreparedCb:
ALOGV("%s: Received msg %d", __FUNCTION__, msg->what());
break;
case kWhatCleanUpSessions:
@@ -992,6 +1045,7 @@
case kWhatCaptureSeqEnd:
case kWhatCaptureSeqAbort:
case kWhatCaptureBufferLost:
+ case kWhatPreparedCb:
{
sp<RefBase> obj;
found = msg->findObject(kSessionSpKey, &obj);
@@ -1034,6 +1088,26 @@
(*onState)(context, session.get());
break;
}
+ case kWhatPreparedCb:
+ {
+ ACameraCaptureSession_prepareCallback onWindowPrepared;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onWindowPrepared);
+ if (!found) {
+ ALOGE("%s: Cannot find state callback!", __FUNCTION__);
+ return;
+ }
+ if (onWindowPrepared == nullptr) {
+ return;
+ }
+ ACameraWindowType* anw;
+ found = msg->findPointer(kAnwKey, (void**) &anw);
+ if (!found) {
+ ALOGE("%s: Cannot find ANativeWindow: %d!", __FUNCTION__, __LINE__);
+ return;
+ }
+ (*onWindowPrepared)(context, anw, session.get());
+ break;
+ }
case kWhatCaptureStart:
{
ACameraCaptureSession_captureCallback_start onStart;
@@ -1729,8 +1803,36 @@
}
binder::Status
-CameraDevice::ServiceCallback::onPrepared(int) {
- // Prepare not yet implemented in NDK
+CameraDevice::ServiceCallback::onPrepared(int streamId) {
+ ALOGV("%s: callback for stream id %d", __FUNCTION__, streamId);
+ binder::Status ret = binder::Status::ok();
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return ret; // device has been closed
+ }
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->isClosed() || dev->mRemote == nullptr) {
+ return ret;
+ }
+ auto it = dev->mConfiguredOutputs.find(streamId);
+ if (it == dev->mConfiguredOutputs.end()) {
+ ALOGE("%s: stream id %d does not exist", __FUNCTION__ , streamId);
+ return ret;
+ }
+ sp<ACameraCaptureSession> session = dev->mCurrentSession.promote();
+ if (session == nullptr) {
+ ALOGE("%s: Session is dead already", __FUNCTION__ );
+ return ret;
+ }
+ // We've found the window corresponding to the surface id.
+ ACameraWindowType *window = it->second.first;
+ sp<AMessage> msg = new AMessage(kWhatPreparedCb, dev->mHandler);
+ msg->setPointer(kContextKey, session->mPreparedCb.context);
+ msg->setPointer(kAnwKey, window);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void *)session->mPreparedCb.onWindowPrepared);
+ dev->postSessionMsgAndCleanup(msg);
+
return binder::Status::ok();
}