[FFmpeg-devel] [PATCH 3/5] lavu/jni: add helpers to manage android application contexts
Matthieu Bouron
matthieu.bouron at gmail.com
Fri Oct 9 18:26:51 CEST 2015
From: Matthieu Bouron <matthieu.bouron at stupeflix.com>
---
libavutil/jni.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++
libavutil/jni.h | 28 +++++++++++++
libavutil/jni_internal.c | 30 ++++++++++++++
libavutil/jni_internal.h | 11 +++++
4 files changed, 173 insertions(+)
diff --git a/libavutil/jni.c b/libavutil/jni.c
index c6ce3a5..0c4c8ca 100644
--- a/libavutil/jni.c
+++ b/libavutil/jni.c
@@ -20,12 +20,18 @@
#include "config.h"
#include "jni.h"
+#include "jni_internal.h"
#include "log.h"
#include <stdlib.h>
JavaVM *java_vm = NULL;
+jobject application_context = NULL;
+
+jobject application_class_loader = NULL;
+jmethodID find_class_id = NULL;
+
void av_jni_register_java_vm(JavaVM *vm)
{
java_vm = vm;
@@ -35,3 +41,101 @@ JavaVM *av_jni_get_java_vm(void)
{
return java_vm;
}
+
+#ifdef __ANDROID__
+int av_jni_register_application_context(JNIEnv *env, jobject context)
+{
+ int ret = 0;
+
+ jclass application_context_class;
+ jmethodID get_class_loader_id;
+
+ jclass application_class_loader_class;
+
+ if (application_context) {
+ (*env)->DeleteGlobalRef(env, application_context);
+ application_context = NULL;
+ }
+
+ if (application_class_loader) {
+ (*env)->DeleteGlobalRef(env, application_class_loader);
+ application_class_loader = NULL;
+ }
+
+ application_context_class = (*env)->GetObjectClass(env, context);
+ if ((ret = avpriv_jni_exception_check(env, 1, NULL)) < 0) {
+ goto done;
+ }
+
+ get_class_loader_id = (*env)->GetMethodID(env, application_context_class, "getClassLoader", "()Ljava/lang/ClassLoader;");
+ if ((ret = avpriv_jni_exception_check(env, 1, NULL)) < 0) {
+ goto done;
+ }
+
+ application_context = (*env)->NewGlobalRef(env, context);
+ application_class_loader = (*env)->CallObjectMethod(env, application_context, get_class_loader_id);
+ if ((ret = avpriv_jni_exception_check(env, 1, NULL)) < 0) {
+ goto done;
+ }
+
+ application_class_loader = (*env)->NewGlobalRef(env, application_class_loader);
+ if ((ret = avpriv_jni_exception_check(env, 1, NULL)) < 0) {
+ goto done;
+ }
+
+ application_class_loader_class = (*env)->GetObjectClass(env, application_class_loader);
+ if ((ret = avpriv_jni_exception_check(env, 1, NULL)) < 0) {
+ goto done;
+ }
+
+ find_class_id = (*env)->GetMethodID(env, application_class_loader_class, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+ if ((ret = avpriv_jni_exception_check(env, 1, NULL)) < 0) {
+ goto done;
+ }
+
+done:
+ if (application_context_class) {
+ (*env)->DeleteLocalRef(env, application_context_class);
+ }
+
+ if (application_class_loader_class) {
+ (*env)->DeleteLocalRef(env, application_class_loader_class);
+ }
+
+ if (ret != 0) {
+
+ if (application_context) {
+ (*env)->DeleteGlobalRef(env, application_context);
+ application_context = NULL;
+ }
+
+ if (application_class_loader) {
+ (*env)->DeleteGlobalRef(env, application_class_loader);
+ application_context = NULL;
+ }
+ }
+
+ return 0;
+}
+
+jobject av_jni_get_application_context(void)
+{
+ return application_context;
+}
+
+int av_jni_unregister_application_context(JNIEnv *env)
+{
+ if (application_context) {
+ (*env)->DeleteGlobalRef(env, application_context);
+ application_context = NULL;
+ }
+
+ if (application_class_loader) {
+ (*env)->DeleteGlobalRef(env, application_class_loader);
+ application_class_loader = NULL;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libavutil/jni.h b/libavutil/jni.h
index 3c36eaf..1bf783a 100644
--- a/libavutil/jni.h
+++ b/libavutil/jni.h
@@ -39,4 +39,32 @@ void av_jni_register_java_vm(JavaVM *vm);
*/
JavaVM *av_jni_get_java_vm(void);
+#ifdef __ANDROID__
+/*
+ * Register an Android application context that will be used later on
+ * to load application classes.
+ *
+ * @param env JNI environment
+ * @param context application context
+ * @return 0 on success, a negative number otherwise
+ */
+int av_jni_register_application_context(JNIEnv *env, jobject context);
+
+/*
+ * Get the registered android application context.
+ *
+ * @return the registered android application context
+ */
+jobject av_jni_get_application_context(void);
+
+/*
+ * Unregister the previously registered Android application context.
+ *
+ * @param env JNI environment
+ * @return 0 on success, a negative number otherwise
+ *
+ */
+int av_jni_unregister_application_context(JNIEnv *env);
+#endif
+
#endif /* AVUTIL_JNI_H */
diff --git a/libavutil/jni_internal.c b/libavutil/jni_internal.c
index 2c1dc70..58eb570 100644
--- a/libavutil/jni_internal.c
+++ b/libavutil/jni_internal.c
@@ -28,6 +28,11 @@
extern JavaVM *java_vm;
+extern jobject application_context;
+
+extern jobject application_class_loader;
+extern jmethodID find_class_id;
+
JNIEnv *avpriv_jni_attach_env(void *log_ctx)
{
int ret = 0;
@@ -357,3 +362,28 @@ int avpriv_jni_reset_jfields(JNIEnv *env, void *jfields, const struct FFJniField
return 0;
}
+
+jclass avpriv_jni_find_application_class(JNIEnv *env, const char *name, void *log_ctx)
+{
+ jobject ret;
+ jobject tmp;
+
+ if (!application_class_loader || !find_class_id) {
+ av_log(log_ctx, AV_LOG_ERROR, "No application class loader has been registered\n");
+ return NULL;
+ }
+
+ tmp = avpriv_jni_utf_chars_to_jstring(env, name, log_ctx);
+ if (!tmp) {
+ return NULL;
+ }
+
+ ret = (*env)->CallObjectMethod(env, application_class_loader, find_class_id, tmp);
+ if (avpriv_jni_exception_check(env, 1, log_ctx) < 0) {
+ ret = NULL;
+ }
+
+ (*env)->DeleteLocalRef(env, tmp);
+
+ return ret;
+}
diff --git a/libavutil/jni_internal.h b/libavutil/jni_internal.h
index 3411c78..24c4b4e 100644
--- a/libavutil/jni_internal.h
+++ b/libavutil/jni_internal.h
@@ -140,4 +140,15 @@ int avpriv_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField
*/
int avpriv_jni_reset_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx);
+/*
+ * Find an application class using the registered Android application context.
+ *
+ * @param env JNI environment
+ * @param name class name (for example: java/lang/String)
+ * @param log_ctx context used for logging, can be NULL
+ * @return a local reference to a class object corresponding the provided
+ * name, or NULL if the class cannot be found
+ */
+jclass avpriv_jni_find_application_class(JNIEnv *env, const char *name, void *log_ctx);
+
#endif /* AVUTIL_JNI_INTERNAL_H */
--
2.6.1
More information about the ffmpeg-devel
mailing list