diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp index d8220eb181..56f209c5a9 100644 --- a/camera/ndk/Android.bp +++ b/camera/ndk/Android.bp @@ -57,6 +57,9 @@ cc_library_shared { "libmediandk", "libnativewindow", ], + header_libs: [ + "jni_headers", + ], cflags: [ "-fvisibility=hidden", "-DEXPORT=__attribute__ ((visibility (\"default\")))", @@ -121,7 +124,6 @@ cc_library_shared { "android.frameworks.cameraservice.common@2.0", "android.frameworks.cameraservice.service@2.0", ], - static_libs: [ "android.hardware.camera.common@1.0-helper", "libarect", diff --git a/camera/ndk/NdkCameraMetadata.cpp b/camera/ndk/NdkCameraMetadata.cpp index 9a39ed872f..99691ed613 100644 --- a/camera/ndk/NdkCameraMetadata.cpp +++ b/camera/ndk/NdkCameraMetadata.cpp @@ -26,6 +26,68 @@ using namespace android; +#ifndef __ANDROID_VNDK__ +namespace { + +constexpr const char* android_hardware_camera2_CameraMetadata_jniClassName = + "android/hardware/camera2/CameraMetadata"; +constexpr const char* android_hardware_camera2_CameraCharacteristics_jniClassName = + "android/hardware/camera2/CameraCharacteristics"; +constexpr const char* android_hardware_camera2_CaptureResult_jniClassName = + "android/hardware/camera2/CaptureResult"; + +jclass android_hardware_camera2_CameraCharacteristics_clazz = nullptr; +jclass android_hardware_camera2_CaptureResult_clazz = nullptr; +jmethodID android_hardware_camera2_CameraMetadata_getNativeMetadataPtr = nullptr; + +// Called at most once to initializes global variables used by JNI. +bool InitJni(JNIEnv* env) { + // From C++11 onward, static initializers are guaranteed to be executed at most once, + // even if called from multiple threads. + static bool ok = [env]() -> bool { + const jclass cameraMetadataClazz = env->FindClass( + android_hardware_camera2_CameraMetadata_jniClassName); + if (cameraMetadataClazz == nullptr) { + return false; + } + android_hardware_camera2_CameraMetadata_getNativeMetadataPtr = + env->GetMethodID(cameraMetadataClazz, "getNativeMetadataPtr", "()J"); + if (android_hardware_camera2_CameraMetadata_getNativeMetadataPtr == nullptr) { + return false; + } + + android_hardware_camera2_CameraCharacteristics_clazz = env->FindClass( + android_hardware_camera2_CameraCharacteristics_jniClassName); + if (android_hardware_camera2_CameraCharacteristics_clazz == nullptr) { + return false; + } + + android_hardware_camera2_CaptureResult_clazz = env->FindClass( + android_hardware_camera2_CaptureResult_jniClassName); + if (android_hardware_camera2_CaptureResult_clazz == nullptr) { + return false; + } + + return true; + }(); + return ok; +} + +// Given cameraMetadata, an instance of android.hardware.camera2.CameraMetadata, invokes +// cameraMetadata.getNativeMetadataPtr() and returns it as a CameraMetadata*. +CameraMetadata* CameraMetadata_getNativeMetadataPtr(JNIEnv* env, jobject cameraMetadata) { + if (cameraMetadata == nullptr) { + ALOGE("%s: Invalid Java CameraMetadata object.", __FUNCTION__); + return nullptr; + } + jlong ret = env->CallLongMethod(cameraMetadata, + android_hardware_camera2_CameraMetadata_getNativeMetadataPtr); + return reinterpret_cast(ret); +} + +} // namespace +#endif /* __ANDROID_VNDK__ */ + EXPORT camera_status_t ACameraMetadata_getConstEntry( const ACameraMetadata* acm, uint32_t tag, ACameraMetadata_const_entry* entry) { @@ -58,7 +120,7 @@ ACameraMetadata* ACameraMetadata_copy(const ACameraMetadata* src) { return nullptr; } ACameraMetadata* copy = new ACameraMetadata(*src); - copy->incStrong((void*) ACameraMetadata_copy); + copy->incStrong(/*id=*/(void*) ACameraMetadata_copy); return copy; } @@ -86,3 +148,34 @@ bool ACameraMetadata_isLogicalMultiCamera(const ACameraMetadata* staticMetadata, return staticMetadata->isLogicalMultiCamera(numPhysicalCameras, physicalCameraIds); } + +#ifndef __ANDROID_VNDK__ +EXPORT +ACameraMetadata* ACameraMetadata_fromCameraMetadata(JNIEnv* env, jobject cameraMetadata) { + ATRACE_CALL(); + + const bool ok = InitJni(env); + LOG_ALWAYS_FATAL_IF(!ok, "Failed to find CameraMetadata Java classes."); + + if (cameraMetadata == nullptr) { + return nullptr; + } + + ACameraMetadata::ACAMERA_METADATA_TYPE type; + if (env->IsInstanceOf(cameraMetadata, + android_hardware_camera2_CameraCharacteristics_clazz)) { + type = ACameraMetadata::ACM_CHARACTERISTICS; + } else if (env->IsInstanceOf(cameraMetadata, + android_hardware_camera2_CaptureResult_clazz)) { + type = ACameraMetadata::ACM_RESULT; + } else { + return nullptr; + } + + CameraMetadata* src = CameraMetadata_getNativeMetadataPtr(env, + cameraMetadata); + ACameraMetadata* output = new ACameraMetadata(src, type); + output->incStrong(/*id=*/(void*) ACameraMetadata_fromCameraMetadata); + return output; +} +#endif /* __ANDROID_VNDK__ */ \ No newline at end of file diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp index e15e1a020c..0ff78abe01 100644 --- a/camera/ndk/impl/ACameraMetadata.cpp +++ b/camera/ndk/impl/ACameraMetadata.cpp @@ -28,7 +28,37 @@ using namespace android; * ACameraMetadata Implementation */ ACameraMetadata::ACameraMetadata(camera_metadata_t* buffer, ACAMERA_METADATA_TYPE type) : - mData(buffer), mType(type) { + mData(new CameraMetadata(buffer)), + mOwnsData(true), + mType(type) { + init(); +} + +ACameraMetadata::ACameraMetadata(CameraMetadata* cameraMetadata, ACAMERA_METADATA_TYPE type) : + mData(cameraMetadata), + mOwnsData(false), + mType(type) { + init(); +} + +ACameraMetadata::ACameraMetadata(const ACameraMetadata& other) : + mOwnsData(other.mOwnsData), + mType(other.mType) { + if (other.mOwnsData) { + mData = new CameraMetadata(*(other.mData)); + } else { + mData = other.mData; + } +} + +ACameraMetadata::~ACameraMetadata() { + if (mOwnsData) { + delete mData; + } +} + +void +ACameraMetadata::init() { if (mType == ACM_CHARACTERISTICS) { filterUnsupportedFeatures(); filterStreamConfigurations(); @@ -61,7 +91,7 @@ ACameraMetadata::isNdkSupportedCapability(int32_t capability) { void ACameraMetadata::filterUnsupportedFeatures() { // Hide unsupported capabilities (reprocessing) - camera_metadata_entry entry = mData.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES); + camera_metadata_entry entry = mData->find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES); if (entry.count == 0 || entry.type != TYPE_BYTE) { ALOGE("%s: malformed available capability key! count %zu, type %d", __FUNCTION__, entry.count, entry.type); @@ -80,7 +110,7 @@ ACameraMetadata::filterUnsupportedFeatures() { } } } - mData.update(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, capabilities); + mData->update(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, capabilities); } void @@ -118,7 +148,7 @@ ACameraMetadata::filterDurations(uint32_t tag) { const int STREAM_WIDTH_OFFSET = 1; const int STREAM_HEIGHT_OFFSET = 2; const int STREAM_DURATION_OFFSET = 3; - camera_metadata_entry entry = mData.find(tag); + camera_metadata_entry entry = mData->find(tag); if (entry.count == 0 || entry.count % 4 || entry.type != TYPE_INT64) { ALOGE("%s: malformed duration key %d! count %zu, type %d", __FUNCTION__, tag, entry.count, entry.type); @@ -194,7 +224,7 @@ ACameraMetadata::filterDurations(uint32_t tag) { } } - mData.update(tag, filteredDurations); + mData->update(tag, filteredDurations); } void @@ -204,7 +234,7 @@ ACameraMetadata::filterStreamConfigurations() { const int STREAM_WIDTH_OFFSET = 1; const int STREAM_HEIGHT_OFFSET = 2; const int STREAM_IS_INPUT_OFFSET = 3; - camera_metadata_entry entry = mData.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS); + camera_metadata_entry entry = mData->find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS); if (entry.count > 0 && (entry.count % 4 || entry.type != TYPE_INT32)) { ALOGE("%s: malformed available stream configuration key! count %zu, type %d", __FUNCTION__, entry.count, entry.type); @@ -234,10 +264,10 @@ ACameraMetadata::filterStreamConfigurations() { } if (filteredStreamConfigs.size() > 0) { - mData.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, filteredStreamConfigs); + mData->update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, filteredStreamConfigs); } - entry = mData.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS); + entry = mData->find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS); if (entry.count > 0 && (entry.count % 4 || entry.type != TYPE_INT32)) { ALOGE("%s: malformed available depth stream configuration key! count %zu, type %d", __FUNCTION__, entry.count, entry.type); @@ -270,11 +300,11 @@ ACameraMetadata::filterStreamConfigurations() { } if (filteredDepthStreamConfigs.size() > 0) { - mData.update(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, + mData->update(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, filteredDepthStreamConfigs); } - entry = mData.find(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS); + entry = mData->find(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS); Vector filteredHeicStreamConfigs; filteredHeicStreamConfigs.setCapacity(entry.count); @@ -297,9 +327,9 @@ ACameraMetadata::filterStreamConfigurations() { filteredHeicStreamConfigs.push_back(height); filteredHeicStreamConfigs.push_back(isInput); } - mData.update(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS, filteredHeicStreamConfigs); + mData->update(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS, filteredHeicStreamConfigs); - entry = mData.find(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS); + entry = mData->find(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS); Vector filteredDynamicDepthStreamConfigs; filteredDynamicDepthStreamConfigs.setCapacity(entry.count); @@ -322,7 +352,7 @@ ACameraMetadata::filterStreamConfigurations() { filteredDynamicDepthStreamConfigs.push_back(height); filteredDynamicDepthStreamConfigs.push_back(isInput); } - mData.update(ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS, + mData->update(ACAMERA_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS, filteredDynamicDepthStreamConfigs); } @@ -343,7 +373,7 @@ ACameraMetadata::getConstEntry(uint32_t tag, ACameraMetadata_const_entry* entry) Mutex::Autolock _l(mLock); - camera_metadata_ro_entry rawEntry = mData.find(tag); + camera_metadata_ro_entry rawEntry = static_cast(mData)->find(tag); if (rawEntry.count == 0) { ALOGE("%s: cannot find metadata tag %d", __FUNCTION__, tag); return ACAMERA_ERROR_METADATA_NOT_FOUND; @@ -390,9 +420,9 @@ ACameraMetadata::getTags(/*out*/int32_t* numTags, /*out*/const uint32_t** tags) const { Mutex::Autolock _l(mLock); if (mTags.size() == 0) { - size_t entry_count = mData.entryCount(); + size_t entry_count = mData->entryCount(); mTags.setCapacity(entry_count); - const camera_metadata_t* rawMetadata = mData.getAndLock(); + const camera_metadata_t* rawMetadata = mData->getAndLock(); for (size_t i = 0; i < entry_count; i++) { camera_metadata_ro_entry_t entry; int ret = get_camera_metadata_ro_entry(rawMetadata, i, &entry); @@ -405,7 +435,7 @@ ACameraMetadata::getTags(/*out*/int32_t* numTags, mTags.push_back(entry.tag); } } - mData.unlock(rawMetadata); + mData->unlock(rawMetadata); } *numTags = mTags.size(); @@ -415,7 +445,7 @@ ACameraMetadata::getTags(/*out*/int32_t* numTags, const CameraMetadata& ACameraMetadata::getInternalData() const { - return mData; + return (*mData); } bool diff --git a/camera/ndk/impl/ACameraMetadata.h b/camera/ndk/impl/ACameraMetadata.h index 97f7f48c1c..a57b2ffa49 100644 --- a/camera/ndk/impl/ACameraMetadata.h +++ b/camera/ndk/impl/ACameraMetadata.h @@ -36,8 +36,8 @@ using CameraMetadata = android::hardware::camera::common::V1_0::helper::CameraMe using namespace android; /** - * ACameraMetadata opaque struct definition - * Leave outside of android namespace because it's NDK struct + * ACameraMetadata is an opaque struct definition. + * It is intentionally left outside of the android namespace because it's NDK struct. */ struct ACameraMetadata : public RefBase { public: @@ -47,11 +47,20 @@ struct ACameraMetadata : public RefBase { ACM_RESULT, // Read only } ACAMERA_METADATA_TYPE; - // Takes ownership of pass-in buffer - ACameraMetadata(camera_metadata_t *buffer, ACAMERA_METADATA_TYPE type); - // Clone - ACameraMetadata(const ACameraMetadata& other) : - mData(other.mData), mType(other.mType) {}; + // Constructs a ACameraMetadata that takes ownership of `buffer`. + ACameraMetadata(camera_metadata_t* buffer, ACAMERA_METADATA_TYPE type); + + // Constructs a ACameraMetadata that is a view of `cameraMetadata`. + // `cameraMetadata` will not be deleted by ~ACameraMetadata(). + ACameraMetadata(CameraMetadata* cameraMetadata, ACAMERA_METADATA_TYPE type); + + // Copy constructor. + // + // If `other` owns its CameraMetadata, then makes a deep copy. + // Otherwise, the new instance is also a view of the same data. + ACameraMetadata(const ACameraMetadata& other); + + ~ACameraMetadata(); camera_status_t getConstEntry(uint32_t tag, ACameraMetadata_const_entry* entry) const; @@ -70,6 +79,9 @@ struct ACameraMetadata : public RefBase { private: + // Common code called by constructors. + void init(); + // This function does not check whether the capability passed to it is valid. // The caller must make sure that it is. bool isNdkSupportedCapability(const int32_t capability); @@ -95,11 +107,11 @@ struct ACameraMetadata : public RefBase { status_t ret = OK; if (count == 0 && data == nullptr) { - ret = mData.erase(tag); + ret = mData->erase(tag); } else { // Here we have to use reinterpret_cast because the NDK data type is // exact copy of internal data type but they do not inherit from each other - ret = mData.update(tag, reinterpret_cast(data), count); + ret = mData->update(tag, reinterpret_cast(data), count); } if (ret == OK) { @@ -110,10 +122,14 @@ struct ACameraMetadata : public RefBase { } } - // guard access of public APIs: get/update/getTags - mutable Mutex mLock; - CameraMetadata mData; - mutable Vector mTags; // updated in getTags, cleared by update + // Guard access of public APIs: get/update/getTags. + mutable Mutex mLock; + + CameraMetadata* mData; + // If true, has ownership of mData. Otherwise, mData is a view of an external instance. + bool mOwnsData; + + mutable Vector mTags; // Updated by `getTags()`, cleared by `update()`. const ACAMERA_METADATA_TYPE mType; static std::unordered_set sSystemTags; diff --git a/camera/ndk/include/camera/NdkCameraMetadata.h b/camera/ndk/include/camera/NdkCameraMetadata.h index 9bbfb83fc8..ee75610543 100644 --- a/camera/ndk/include/camera/NdkCameraMetadata.h +++ b/camera/ndk/include/camera/NdkCameraMetadata.h @@ -39,6 +39,12 @@ #include #include +#ifndef __ANDROID_VNDK__ +#if __ANDROID_API__ >= 30 +#include "jni.h" +#endif /* __ANDROID_API__ >= 30 */ +#endif /* __ANDROID_VNDK__ */ + #include "NdkCameraError.h" #include "NdkCameraMetadataTags.h" @@ -255,8 +261,40 @@ bool ACameraMetadata_isLogicalMultiCamera(const ACameraMetadata* staticMetadata, #endif /* __ANDROID_API__ >= 29 */ +#ifndef __ANDROID_VNDK__ +#if __ANDROID_API__ >= 30 + +/** + * Return a {@link ACameraMetadata} that references the same data as + * {@link cameraMetadata}, which is an instance of + * {@link android.hardware.camera2.CameraMetadata} (e.g., a + * {@link android.hardware.camera2.CameraCharacteristics} or + * {@link android.hardware.camera2.CaptureResult}). + * + *

The returned ACameraMetadata must be freed by the application by {@link ACameraMetadata_free} + * after application is done using it.

+ * + *

This function does not affect the lifetime of {@link cameraMetadata}. Attempting to use the + * returned ACameraMetadata object after {@link cameraMetadata} has been garbage collected is + * unsafe. To manage the lifetime beyond the current JNI function call, use + * {@code env->NewGlobalRef()} and {@code env->DeleteGlobalRef()}. + * + * @param env the JNI environment. + * @param cameraMetadata the source {@link android.hardware.camera2.CameraMetadata} from which the + * returned {@link ACameraMetadata} is a view. + * + * @return a valid ACameraMetadata pointer or NULL if {@link cameraMetadata} is null or not a valid + * instance of {@link android.hardware.camera2.CameraMetadata}. + * + */ +ACameraMetadata* ACameraMetadata_fromCameraMetadata(JNIEnv* env, jobject cameraMetadata) + __INTRODUCED_IN(30); + +#endif /* __ANDROID_API__ >= 30 */ +#endif /* __ANDROID_VNDK__ */ + __END_DECLS #endif /* _NDK_CAMERA_METADATA_H */ -/** @} */ +/** @} */ \ No newline at end of file diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt index b6f1553ee3..2b630db3ed 100644 --- a/camera/ndk/libcamera2ndk.map.txt +++ b/camera/ndk/libcamera2ndk.map.txt @@ -31,6 +31,7 @@ LIBCAMERA2NDK { ACameraMetadata_getAllTags; ACameraMetadata_getConstEntry; ACameraMetadata_isLogicalMultiCamera; # introduced=29 + ACameraMetadata_fromCameraMetadata; # introduced=30 ACameraOutputTarget_create; ACameraOutputTarget_free; ACaptureRequest_addTarget;