Add support for dynamic shared output surfaces
The Camera API needs to support the dynamic attach/detach of extra
output surfaces to a given camera stream.
Bug: 63912484
Change-Id: I18809aea31f78fb9e125bd18b58951ade4fad3c5
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index 0771fc8..07d4e7e 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -140,5 +140,7 @@
void prepare2(int maxCount, int streamId);
+ void updateOutputConfiguration(int streamId, in OutputConfiguration outputConfiguration);
+
void finalizeOutputConfigurations(int streamId, in OutputConfiguration outputConfiguration);
}
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index 468a1eb..813d6c9 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -160,12 +160,12 @@
}
OutputConfiguration::OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
- int surfaceSetID) {
+ int surfaceSetID, bool isShared) {
mGbps.push_back(gbp);
mRotation = rotation;
mSurfaceSetID = surfaceSetID;
mIsDeferred = false;
- mIsShared = false;
+ mIsShared = isShared;
}
status_t OutputConfiguration::writeToParcel(android::Parcel* parcel) const {
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
index 8e641c7..3599604 100644
--- a/camera/include/camera/camera2/OutputConfiguration.h
+++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -64,7 +64,7 @@
OutputConfiguration(const android::Parcel& parcel);
OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
- int surfaceSetID = INVALID_SET_ID);
+ int surfaceSetID = INVALID_SET_ID, bool isShared = false);
bool operator == (const OutputConfiguration& other) const {
return ( mRotation == other.mRotation &&
@@ -110,6 +110,7 @@
bool gbpsEqual(const OutputConfiguration& other) const;
bool gbpsLessThan(const OutputConfiguration& other) const;
+ void addGraphicProducer(sp<IGraphicBufferProducer> gbp) {mGbps.push_back(gbp);}
private:
std::vector<sp<IGraphicBufferProducer>> mGbps;
int mRotation;
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
index 2a6b182..fd95296 100644
--- a/camera/ndk/NdkCameraCaptureSession.cpp
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -135,3 +135,19 @@
}
return session->abortCaptures();
}
+
+EXPORT
+camera_status_t ACameraCaptureSession_updateSharedOutput(ACameraCaptureSession* session,
+ ACaptureSessionOutput* output) {
+ ATRACE_CALL();
+ if (session == nullptr) {
+ ALOGE("%s: Error: session is null", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (session->isClosed()) {
+ ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+ return session->updateOutputConfiguration(output);
+}
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
index 9f6d1f7..ac4beea 100644
--- a/camera/ndk/NdkCameraDevice.cpp
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -103,11 +103,74 @@
__FUNCTION__, window, out);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- *out = new ACaptureSessionOutput(window);
+ *out = new ACaptureSessionOutput(window, false);
return ACAMERA_OK;
}
EXPORT
+camera_status_t ACaptureSessionSharedOutput_create(
+ ANativeWindow* window, /*out*/ACaptureSessionOutput** out) {
+ ATRACE_CALL();
+ if (window == nullptr || out == nullptr) {
+ ALOGE("%s: Error: bad argument. window %p, out %p",
+ __FUNCTION__, window, out);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ *out = new ACaptureSessionOutput(window, true);
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *out,
+ ANativeWindow* window) {
+ ATRACE_CALL();
+ if ((window == nullptr) || (out == nullptr)) {
+ ALOGE("%s: Error: bad argument. window %p, out %p",
+ __FUNCTION__, window, out);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if (!out->mIsShared) {
+ ALOGE("%s: Error trying to insert a new window in non-shared output configuration",
+ __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_OPERATION;
+ }
+ if (out->mWindow == window) {
+ ALOGE("%s: Error trying to add the same window associated with the output configuration",
+ __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ auto insert = out->mSharedWindows.insert(window);
+ camera_status_t ret = (insert.second) ? ACAMERA_OK : ACAMERA_ERROR_INVALID_PARAMETER;
+ return ret;
+}
+
+EXPORT
+camera_status_t ACaptureSessionSharedOutput_remove(ACaptureSessionOutput *out,
+ ANativeWindow* window) {
+ ATRACE_CALL();
+ if ((window == nullptr) || (out == nullptr)) {
+ ALOGE("%s: Error: bad argument. window %p, out %p",
+ __FUNCTION__, window, out);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if (!out->mIsShared) {
+ ALOGE("%s: Error trying to remove a window in non-shared output configuration",
+ __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_OPERATION;
+ }
+ if (out->mWindow == window) {
+ ALOGE("%s: Error trying to remove the same window associated with the output configuration",
+ __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ auto remove = out->mSharedWindows.erase(window);
+ camera_status_t ret = (remove) ? ACAMERA_OK : ACAMERA_ERROR_INVALID_PARAMETER;
+ return ret;
+}
+
+EXPORT
void ACaptureSessionOutput_free(ACaptureSessionOutput* output) {
ATRACE_CALL();
if (output != nullptr) {
diff --git a/camera/ndk/impl/ACameraCaptureSession.cpp b/camera/ndk/impl/ACameraCaptureSession.cpp
index b9c159d..6d1d5ce 100644
--- a/camera/ndk/impl/ACameraCaptureSession.cpp
+++ b/camera/ndk/impl/ACameraCaptureSession.cpp
@@ -148,6 +148,23 @@
return ret;
}
+camera_status_t ACameraCaptureSession::updateOutputConfiguration(ACaptureSessionOutput *output) {
+ sp<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->updateOutputConfiguration(output);
+ }
+ dev->unlockDevice();
+ return ret;
+}
+
ACameraDevice*
ACameraCaptureSession::getDevice() {
Mutex::Autolock _l(mSessionLock);
diff --git a/camera/ndk/impl/ACameraCaptureSession.h b/camera/ndk/impl/ACameraCaptureSession.h
index 339c665..a2068e7 100644
--- a/camera/ndk/impl/ACameraCaptureSession.h
+++ b/camera/ndk/impl/ACameraCaptureSession.h
@@ -24,7 +24,8 @@
using namespace android;
struct ACaptureSessionOutput {
- explicit ACaptureSessionOutput(ANativeWindow* window) : mWindow(window) {};
+ explicit ACaptureSessionOutput(ANativeWindow* window, bool isShared = false) :
+ mWindow(window), mIsShared(isShared) {};
bool operator == (const ACaptureSessionOutput& other) const {
return mWindow == other.mWindow;
@@ -40,6 +41,8 @@
}
ANativeWindow* mWindow;
+ std::set<ANativeWindow *> mSharedWindows;
+ bool mIsShared;
int mRotation = CAMERA3_STREAM_ROTATION_0;
};
@@ -89,6 +92,8 @@
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId);
+ camera_status_t updateOutputConfiguration(ACaptureSessionOutput *output);
+
ACameraDevice* getDevice();
private:
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 907802c..9ce0ac8 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -289,6 +289,82 @@
return ACAMERA_OK;
}
+camera_status_t CameraDevice::updateOutputConfiguration(ACaptureSessionOutput *output) {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+
+ if (output == nullptr) {
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (!output->mIsShared) {
+ ALOGE("Error output configuration is not shared");
+ return ACAMERA_ERROR_INVALID_OPERATION;
+ }
+
+ int32_t streamId = -1;
+ for (auto& kvPair : mConfiguredOutputs) {
+ if (kvPair.second.first == output->mWindow) {
+ streamId = kvPair.first;
+ break;
+ }
+ }
+ if (streamId < 0) {
+ ALOGE("Error: Invalid output configuration");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ sp<IGraphicBufferProducer> iGBP(nullptr);
+ ret = getIGBPfromAnw(output->mWindow, iGBP);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera device %s failed to extract graphic producer from native window",
+ getId());
+ return ret;
+ }
+
+ OutputConfiguration outConfig(iGBP, output->mRotation, OutputConfiguration::INVALID_SET_ID,
+ true);
+
+ for (auto& anw : output->mSharedWindows) {
+ ret = getIGBPfromAnw(anw, iGBP);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera device %s failed to extract graphic producer from native window",
+ getId());
+ return ret;
+ }
+ outConfig.addGraphicProducer(iGBP);
+ }
+
+ auto remoteRet = mRemote->updateOutputConfiguration(streamId, outConfig);
+ if (!remoteRet.isOk()) {
+ 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_ALREADY_EXISTS:
+ ALOGE("Camera device %s output surface already exists: %s", getId(),
+ remoteRet.toString8().string());
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ 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 add shared output: %s", getId(),
+ remoteRet.toString8().string());
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ }
+
+ return ACAMERA_OK;
+}
+
camera_status_t
CameraDevice::allocateCaptureRequest(
const ACaptureRequest* request, /*out*/sp<CaptureRequest>& outReq) {
@@ -540,7 +616,8 @@
return ret;
}
outputSet.insert(std::make_pair(
- anw, OutputConfiguration(iGBP, outConfig.mRotation)));
+ anw, OutputConfiguration(iGBP, outConfig.mRotation,
+ OutputConfiguration::INVALID_SET_ID, outConfig.mIsShared)));
}
auto addSet = outputSet;
std::vector<int> deleteList;
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 6ed3881..23cc1a1 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -36,7 +36,8 @@
#include <camera/camera2/OutputConfiguration.h>
#include <camera/camera2/CaptureRequest.h>
-#include <camera/NdkCameraDevice.h>
+#include <camera/NdkCameraManager.h>
+#include <camera/NdkCameraCaptureSession.h>
#include "ACameraMetadata.h"
namespace android {
@@ -122,6 +123,8 @@
/*out*/int* captureSequenceId,
bool isRepeating);
+ camera_status_t updateOutputConfiguration(ACaptureSessionOutput *output);
+
static camera_status_t allocateCaptureRequest(
const ACaptureRequest* request, sp<CaptureRequest>& outReq);
diff --git a/camera/ndk/include/camera/NdkCameraCaptureSession.h b/camera/ndk/include/camera/NdkCameraCaptureSession.h
index d96f538..67003c1 100644
--- a/camera/ndk/include/camera/NdkCameraCaptureSession.h
+++ b/camera/ndk/include/camera/NdkCameraCaptureSession.h
@@ -591,6 +591,54 @@
#endif /* __ANDROID_API__ >= 24 */
+#if __ANDROID_API__ >= 28
+
+typedef struct ACaptureSessionOutput ACaptureSessionOutput;
+
+/**
+ * Update shared ACaptureSessionOutput.
+ *
+ * <p>A shared ACaptureSessionOutput (see {@link ACaptureSessionSharedOutput_create}) that
+ * was modified via calls to {@link ACaptureSessionSharedOutput_add} or
+ * {@link ACaptureSessionSharedOutput_remove} must be updated by calling this method before its
+ * changes take effect. After the update call returns with {@link ACAMERA_OK}, any newly added
+ * native windows can be used as a target in subsequent capture requests.</p>
+ *
+ * <p>Native windows that get removed must not be part of any active repeating or single/burst
+ * request or have any pending results. Consider updating repeating requests via
+ * {@link ACaptureSessionOutput_setRepeatingRequest} and then wait for the last frame number
+ * when the sequence completes
+ * {@link ACameraCaptureSession_captureCallback#onCaptureSequenceCompleted}.</p>
+ *
+ * <p>Native windows that get added must not be part of any other registered ACaptureSessionOutput
+ * and must be compatible. Compatible windows must have matching format, rotation and
+ * consumer usage.</p>
+ *
+ * <p>A shared ACameraCaptureSession can support up to 4 additional native windows.</p>
+ *
+ * @param session the capture session of interest
+ * @param output the modified output configuration
+ *
+ * @return <ul><li>
+ * {@link ACAMERA_OK} if the method succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if session or output is NULL; or output
+ * contains invalid native windows; or if an attempt was made to add
+ * a native window to a different output configuration; or new native window is not
+ * compatible; or any removed native window still has pending requests;</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_OPERATION} if output configuration is not shared (see
+ * {@link ACaptureSessionSharedOutput_create}; or the number of additional
+ * native windows goes beyond the supported limit.</li>
+ * <li>{@link ACAMERA_ERROR_SESSION_CLOSED} if the capture session has been closed</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_DISCONNECTED} if the camera device is closed</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_DEVICE} if the camera device encounters fatal error</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_SERVICE} if the camera service encounters fatal
+ * error</li>
+ * <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons</li></ul>
+ */
+camera_status_t ACameraCaptureSession_updateSharedOutput(ACameraCaptureSession* session,
+ ACaptureSessionOutput* output);
+#endif /* __ANDROID_API__ >= 28 */
+
__END_DECLS
#endif /* _NDK_CAMERA_CAPTURE_SESSION_H */
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
index 6c9e85a..3a6f3ef 100644
--- a/camera/ndk/include/camera/NdkCameraDevice.h
+++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -661,6 +661,67 @@
#endif /* __ANDROID_API__ >= 24 */
+#if __ANDROID_API__ >= 28
+
+/**
+ * Create a shared ACaptureSessionOutput object.
+ *
+ * <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}. A shared ACaptureSessionOutput can be further modified
+ * via {@link ACaptureSessionSharedOutput_add} or {@link ACaptureSessionSharedOutput_remove} and
+ * must be updated via {@link ACameraCaptureSession_updateSharedOutput}.</p>
+ *
+ * @param anw the {@link ANativeWindow} to be associated with the {@link ACaptureSessionOutput}
+ * @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 or output is NULL.</li></ul>
+ *
+ * @see ACaptureSessionOutputContainer_add
+ */
+camera_status_t ACaptureSessionSharedOutput_create(
+ ANativeWindow* anw, /*out*/ACaptureSessionOutput** output);
+
+/**
+ * Add a native window to shared ACaptureSessionOutput.
+ *
+ * The ACaptureSessionOutput must be created via {@link ACaptureSessionSharedOutput_create}.
+ *
+ * @param output the shared ACaptureSessionOutput to be extended.
+ * @param anw The new native window.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if anw or output is NULL; or output is not
+ * shared see {@link ACaptureSessionSharedOutput_create}; or anw matches with the native
+ * window associated with ACaptureSessionOutput; or anw is already present inside
+ * ACaptureSessionOutput.</li></ul>
+ */
+camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *output, ANativeWindow *anw);
+
+/**
+ * Remove a native window from shared ACaptureSessionOutput.
+ *
+ * @param output the {@link ACaptureSessionOutput} to be modified.
+ * @param anw The native window to be removed.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if anw or output is NULL; or output is not
+ * shared see {@link ACaptureSessionSharedOutput_create}; or anw matches with the native
+ * window associated with ACaptureSessionOutput; or anw is not present inside
+ * ACaptureSessionOutput.</li></ul>
+ */
+camera_status_t ACaptureSessionSharedOutput_remove(ACaptureSessionOutput *output,
+ ANativeWindow* anw);
+
+#endif /* __ANDROID_API__ >= 28 */
+
__END_DECLS
#endif /* _NDK_CAMERA_DEVICE_H */
diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt
index 41bb22b..0a8a6e9 100644
--- a/camera/ndk/libcamera2ndk.map.txt
+++ b/camera/ndk/libcamera2ndk.map.txt
@@ -6,6 +6,7 @@
ACameraCaptureSession_getDevice;
ACameraCaptureSession_setRepeatingRequest;
ACameraCaptureSession_stopRepeating;
+ ACameraCaptureSession_updateSharedOutput;
ACameraDevice_close;
ACameraDevice_createCaptureRequest;
ACameraDevice_createCaptureSession;
@@ -40,6 +41,9 @@
ACaptureSessionOutputContainer_free;
ACaptureSessionOutputContainer_remove;
ACaptureSessionOutput_create;
+ ACaptureSessionSharedOutput_create;
+ ACaptureSessionSharedOutput_add;
+ ACaptureSessionSharedOutput_remove;
ACaptureSessionOutput_free;
local:
*;