[FFmpeg-devel] [PATCH 1/7] avcodec: move ffjni to avutil/jniutils

Matthieu Bouron matthieu.bouron at gmail.com
Wed Feb 14 00:50:09 EET 2024


This will allow to use the jni utils in libavformat. This will be mostly useful
to add Android content-uri support.

This deprecates avcodec/jni.h functions in favor of the ones from avutil/jni.h.
---
 doc/APIchanges                             |   6 +
 libavcodec/Makefile                        |   3 +-
 libavcodec/jni.c                           |  48 +----
 libavcodec/jni.h                           |   8 +
 libavcodec/mediacodec.c                    |   6 +-
 libavcodec/mediacodec_surface.c            |   6 +-
 libavcodec/mediacodec_wrapper.c            | 200 ++++++++++-----------
 libavcodec/mediacodecdec.c                 |   3 +-
 libavutil/Makefile                         |   4 +
 libavutil/jni.c                            |  78 ++++++++
 libavutil/jni.h                            |  46 +++++
 libavcodec/ffjni.c => libavutil/jniutils.c |  36 ++--
 libavcodec/ffjni.h => libavutil/jniutils.h |  26 ++-
 13 files changed, 283 insertions(+), 187 deletions(-)
 create mode 100644 libavutil/jni.c
 create mode 100644 libavutil/jni.h
 rename libavcodec/ffjni.c => libavutil/jniutils.c (88%)
 rename libavcodec/ffjni.h => libavutil/jniutils.h (84%)

diff --git a/doc/APIchanges b/doc/APIchanges
index 221fea30c2..45611ea7ea 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,12 @@ The last version increases of all libraries were on 2023-02-09
 
 API changes, most recent first:
 
+2024-02-xx - xxxxxxxxxx - lavu 58.39.100 - jni.h
+  Add av_jni_set_jvm() and av_jni_get_jvm().
+
+2024-02-xx - xxxxxxxxxx - lavc 60.40.100 - jni.h
+  Deprecate av_jni_set_java_vm() and av_jni_get_java_vm().
+
 2024-02-xx - xxxxxxxxxx - lavu 58.38.100 - channel_layout.h
   Add av_channel_layout_retype().
 
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 470d7cb9b1..f8584d8dfd 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -117,7 +117,7 @@ OBJS-$(CONFIG_IIRFILTER)               += iirfilter.o
 OBJS-$(CONFIG_INFLATE_WRAPPER)         += zlib_wrapper.o
 OBJS-$(CONFIG_INTRAX8)                 += intrax8.o intrax8dsp.o msmpeg4data.o
 OBJS-$(CONFIG_IVIDSP)                  += ivi_dsp.o
-OBJS-$(CONFIG_JNI)                     += ffjni.o jni.o
+OBJS-$(CONFIG_JNI)                     += jni.o
 OBJS-$(CONFIG_JPEGTABLES)              += jpegtables.o
 OBJS-$(CONFIG_LCMS2)                   += fflcms2.o
 OBJS-$(CONFIG_LLAUDDSP)                += lossless_audiodsp.o
@@ -1269,7 +1269,6 @@ SKIPHEADERS-$(CONFIG_AMF)              += amfenc.h
 SKIPHEADERS-$(CONFIG_D3D11VA)          += d3d11va.h dxva2_internal.h
 SKIPHEADERS-$(CONFIG_D3D12VA)          += d3d12va_decode.h
 SKIPHEADERS-$(CONFIG_DXVA2)            += dxva2.h dxva2_internal.h
-SKIPHEADERS-$(CONFIG_JNI)              += ffjni.h
 SKIPHEADERS-$(CONFIG_LCMS2)            += fflcms2.h
 SKIPHEADERS-$(CONFIG_LIBAOM)           += libaom.h
 SKIPHEADERS-$(CONFIG_LIBJXL)           += libjxl.h
diff --git a/libavcodec/jni.c b/libavcodec/jni.c
index ae6490de9d..a98c27d73a 100644
--- a/libavcodec/jni.c
+++ b/libavcodec/jni.c
@@ -20,60 +20,18 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include "config.h"
-
 #include <stdlib.h>
 
 #include "libavutil/error.h"
+#include "libavutil/jni.h"
 #include "jni.h"
 
-#if CONFIG_JNI
-#include <jni.h>
-#include <pthread.h>
-
-#include "libavutil/log.h"
-#include "ffjni.h"
-
-static void *java_vm;
-static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-
-int av_jni_set_java_vm(void *vm, void *log_ctx)
-{
-    int ret = 0;
-
-    pthread_mutex_lock(&lock);
-    if (java_vm == NULL) {
-        java_vm = vm;
-    } else if (java_vm != vm) {
-        ret = AVERROR(EINVAL);
-        av_log(log_ctx, AV_LOG_ERROR, "A Java virtual machine has already been set");
-    }
-    pthread_mutex_unlock(&lock);
-
-    return ret;
-}
-
-void *av_jni_get_java_vm(void *log_ctx)
-{
-    void *vm;
-
-    pthread_mutex_lock(&lock);
-    vm = java_vm;
-    pthread_mutex_unlock(&lock);
-
-    return vm;
-}
-
-#else
-
 int av_jni_set_java_vm(void *vm, void *log_ctx)
 {
-    return AVERROR(ENOSYS);
+    return av_jni_set_jvm(vm, log_ctx);
 }
 
 void *av_jni_get_java_vm(void *log_ctx)
 {
-    return NULL;
+    return av_jni_get_jvm(log_ctx);
 }
-
-#endif
diff --git a/libavcodec/jni.h b/libavcodec/jni.h
index dd99e92611..49ddab4120 100644
--- a/libavcodec/jni.h
+++ b/libavcodec/jni.h
@@ -23,6 +23,8 @@
 #ifndef AVCODEC_JNI_H
 #define AVCODEC_JNI_H
 
+#include <libavutil/attributes.h>
+
 /*
  * Manually set a Java virtual machine which will be used to retrieve the JNI
  * environment. Once a Java VM is set it cannot be changed afterwards, meaning
@@ -32,7 +34,10 @@
  * @param vm Java virtual machine
  * @param log_ctx context used for logging, can be NULL
  * @return 0 on success, < 0 otherwise
+ *
+ * @deprecated use av_jni_set_jvm from libavutil/jni.h
  */
+attribute_deprecated
 int av_jni_set_java_vm(void *vm, void *log_ctx);
 
 /*
@@ -40,7 +45,10 @@ int av_jni_set_java_vm(void *vm, void *log_ctx);
  *
  * @param vm Java virtual machine
  * @return a pointer to the Java virtual machine
+ *
+ * @deprecated use av_jni_get_jvm from libavutil/jni.h
  */
+attribute_deprecated
 void *av_jni_get_java_vm(void *log_ctx);
 
 #endif /* AVCODEC_JNI_H */
diff --git a/libavcodec/mediacodec.c b/libavcodec/mediacodec.c
index 33bde8112e..2f1ccaa480 100644
--- a/libavcodec/mediacodec.c
+++ b/libavcodec/mediacodec.c
@@ -31,9 +31,9 @@
 #include <jni.h>
 
 #include "libavcodec/avcodec.h"
+#include "libavutil/jniutils.h"
 #include "libavutil/mem.h"
 
-#include "ffjni.h"
 #include "mediacodecdec_common.h"
 
 AVMediaCodecContext *av_mediacodec_alloc_context(void)
@@ -46,7 +46,7 @@ int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx,
     int ret = 0;
     JNIEnv *env = NULL;
 
-    env = ff_jni_get_env(avctx);
+    env = avpriv_jni_get_env(avctx);
     if (!env) {
         return AVERROR_EXTERNAL;
     }
@@ -72,7 +72,7 @@ void av_mediacodec_default_free(AVCodecContext *avctx)
         return;
     }
 
-    env = ff_jni_get_env(avctx);
+    env = avpriv_jni_get_env(avctx);
     if (!env) {
         return;
     }
diff --git a/libavcodec/mediacodec_surface.c b/libavcodec/mediacodec_surface.c
index ef41cdafa7..748f3e2804 100644
--- a/libavcodec/mediacodec_surface.c
+++ b/libavcodec/mediacodec_surface.c
@@ -24,7 +24,7 @@
 #include <jni.h>
 
 #include "libavutil/mem.h"
-#include "ffjni.h"
+#include "libavutil/jniutils.h"
 #include "mediacodec_surface.h"
 
 FFANativeWindow *ff_mediacodec_surface_ref(void *surface, void *native_window, void *log_ctx)
@@ -38,7 +38,7 @@ FFANativeWindow *ff_mediacodec_surface_ref(void *surface, void *native_window, v
     if (surface) {
         JNIEnv *env = NULL;
 
-        env = ff_jni_get_env(log_ctx);
+        env = avpriv_jni_get_env(log_ctx);
         if (env)
             ret->surface = (*env)->NewGlobalRef(env, surface);
     }
@@ -64,7 +64,7 @@ int ff_mediacodec_surface_unref(FFANativeWindow *window, void *log_ctx)
     if (window->surface) {
         JNIEnv *env = NULL;
 
-        env = ff_jni_get_env(log_ctx);
+        env = avpriv_jni_get_env(log_ctx);
         if (env)
             (*env)->DeleteGlobalRef(env, window->surface);
     }
diff --git a/libavcodec/mediacodec_wrapper.c b/libavcodec/mediacodec_wrapper.c
index 0880ddd3ef..bc3eb0a80d 100644
--- a/libavcodec/mediacodec_wrapper.c
+++ b/libavcodec/mediacodec_wrapper.c
@@ -30,9 +30,9 @@
 #include "libavutil/avassert.h"
 #include "libavutil/mem.h"
 #include "libavutil/avstring.h"
+#include "libavutil/jniutils.h"
 
 #include "avcodec.h"
-#include "ffjni.h"
 #include "mediacodec_wrapper.h"
 
 struct JNIAMediaCodecListFields {
@@ -287,14 +287,14 @@ typedef struct FFAMediaCodecJni {
 static const FFAMediaCodec media_codec_jni;
 
 #define JNI_GET_ENV_OR_RETURN(env, log_ctx, ret) do {              \
-    (env) = ff_jni_get_env(log_ctx);                               \
+    (env) = avpriv_jni_get_env(log_ctx);                           \
     if (!(env)) {                                                  \
         return ret;                                                \
     }                                                              \
 } while (0)
 
 #define JNI_GET_ENV_OR_RETURN_VOID(env, log_ctx) do {              \
-    (env) = ff_jni_get_env(log_ctx);                               \
+    (env) = avpriv_jni_get_env(log_ctx);                           \
     if (!(env)) {                                                  \
         return;                                                    \
     }                                                              \
@@ -485,16 +485,16 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e
 
     JNI_GET_ENV_OR_RETURN(env, log_ctx, NULL);
 
-    if ((ret = ff_jni_init_jfields(env, &jfields, jni_amediacodeclist_mapping, 0, log_ctx)) < 0) {
+    if ((ret = avpriv_jni_init_jfields(env, &jfields, jni_amediacodeclist_mapping, 0, log_ctx)) < 0) {
         goto done;
     }
 
-    if ((ret = ff_jni_init_jfields(env, &mediaformat_jfields, jni_amediaformat_mapping, 0, log_ctx)) < 0) {
+    if ((ret = avpriv_jni_init_jfields(env, &mediaformat_jfields, jni_amediaformat_mapping, 0, log_ctx)) < 0) {
         goto done;
     }
 
     codec_count = (*env)->CallStaticIntMethod(env, jfields.mediacodec_list_class, jfields.get_codec_count_id);
-    if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+    if (avpriv_jni_exception_check(env, 1, log_ctx) < 0) {
         goto done;
     }
 
@@ -504,17 +504,17 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e
         int is_encoder;
 
         info = (*env)->CallStaticObjectMethod(env, jfields.mediacodec_list_class, jfields.get_codec_info_at_id, i);
-        if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+        if (avpriv_jni_exception_check(env, 1, log_ctx) < 0) {
             goto done;
         }
 
         types = (*env)->CallObjectMethod(env, info, jfields.get_supported_types_id);
-        if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+        if (avpriv_jni_exception_check(env, 1, log_ctx) < 0) {
             goto done;
         }
 
         is_encoder = (*env)->CallBooleanMethod(env, info, jfields.is_encoder_id);
-        if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+        if (avpriv_jni_exception_check(env, 1, log_ctx) < 0) {
             goto done;
         }
 
@@ -524,7 +524,7 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e
 
         if (jfields.is_software_only_id) {
             int is_software_only = (*env)->CallBooleanMethod(env, info, jfields.is_software_only_id);
-            if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+            if (avpriv_jni_exception_check(env, 1, log_ctx) < 0) {
                 goto done;
             }
 
@@ -534,11 +534,11 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e
         }
 
         codec_name = (*env)->CallObjectMethod(env, info, jfields.get_name_id);
-        if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+        if (avpriv_jni_exception_check(env, 1, log_ctx) < 0) {
             goto done;
         }
 
-        name = ff_jni_jstring_to_utf_chars(env, codec_name, log_ctx);
+        name = avpriv_jni_jstring_to_utf_chars(env, codec_name, log_ctx);
         if (!name) {
             goto done;
         }
@@ -563,11 +563,11 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e
             int profile_count;
 
             type = (*env)->GetObjectArrayElement(env, types, j);
-            if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+            if (avpriv_jni_exception_check(env, 1, log_ctx) < 0) {
                 goto done;
             }
 
-            supported_type = ff_jni_jstring_to_utf_chars(env, type, log_ctx);
+            supported_type = avpriv_jni_jstring_to_utf_chars(env, type, log_ctx);
             if (!supported_type) {
                 goto done;
             }
@@ -577,12 +577,12 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e
             }
 
             capabilities = (*env)->CallObjectMethod(env, info, jfields.get_codec_capabilities_id, type);
-            if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+            if (avpriv_jni_exception_check(env, 1, log_ctx) < 0) {
                 goto done;
             }
 
             profile_levels = (*env)->GetObjectField(env, capabilities, jfields.profile_levels_id);
-            if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+            if (avpriv_jni_exception_check(env, 1, log_ctx) < 0) {
                 goto done;
             }
 
@@ -599,12 +599,12 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e
                 }
 
                 profile_level = (*env)->GetObjectArrayElement(env, profile_levels, k);
-                if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+                if (avpriv_jni_exception_check(env, 1, log_ctx) < 0) {
                     goto done;
                 }
 
                 supported_profile = (*env)->GetIntField(env, profile_level, jfields.profile_id);
-                if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+                if (avpriv_jni_exception_check(env, 1, log_ctx) < 0) {
                     goto done;
                 }
 
@@ -692,8 +692,8 @@ done:
 
     av_freep(&supported_type);
 
-    ff_jni_reset_jfields(env, &jfields, jni_amediacodeclist_mapping, 0, log_ctx);
-    ff_jni_reset_jfields(env, &mediaformat_jfields, jni_amediaformat_mapping, 0, log_ctx);
+    avpriv_jni_reset_jfields(env, &jfields, jni_amediacodeclist_mapping, 0, log_ctx);
+    avpriv_jni_reset_jfields(env, &mediaformat_jfields, jni_amediaformat_mapping, 0, log_ctx);
 
     if (!found_codec) {
         av_freep(&name);
@@ -714,13 +714,13 @@ static FFAMediaFormat *mediaformat_jni_new(void)
     }
     format->api = media_format_jni;
 
-    env = ff_jni_get_env(format);
+    env = avpriv_jni_get_env(format);
     if (!env) {
         av_freep(&format);
         return NULL;
     }
 
-    if (ff_jni_init_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format) < 0) {
+    if (avpriv_jni_init_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format) < 0) {
         goto fail;
     }
 
@@ -740,7 +740,7 @@ fail:
     }
 
     if (!format->object) {
-        ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
+        avpriv_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
         av_freep(&format);
     }
 
@@ -758,13 +758,13 @@ static FFAMediaFormat *mediaformat_jni_newFromObject(void *object)
     }
     format->api = media_format_jni;
 
-    env = ff_jni_get_env(format);
+    env = avpriv_jni_get_env(format);
     if (!env) {
         av_freep(&format);
         return NULL;
     }
 
-    if (ff_jni_init_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format) < 0) {
+    if (avpriv_jni_init_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format) < 0) {
         goto fail;
     }
 
@@ -775,7 +775,7 @@ static FFAMediaFormat *mediaformat_jni_newFromObject(void *object)
 
     return (FFAMediaFormat *)format;
 fail:
-    ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
+    avpriv_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
 
     av_freep(&format);
 
@@ -797,7 +797,7 @@ static int mediaformat_jni_delete(FFAMediaFormat* ctx)
     (*env)->DeleteGlobalRef(env, format->object);
     format->object = NULL;
 
-    ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
+    avpriv_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
 
     av_freep(&format);
 
@@ -816,11 +816,11 @@ static char* mediaformat_jni_toString(FFAMediaFormat* ctx)
     JNI_GET_ENV_OR_RETURN(env, format, NULL);
 
     description = (*env)->CallObjectMethod(env, format->object, format->jfields.to_string_id);
-    if (ff_jni_exception_check(env, 1, NULL) < 0) {
+    if (avpriv_jni_exception_check(env, 1, NULL) < 0) {
         goto fail;
     }
 
-    ret = ff_jni_jstring_to_utf_chars(env, description, format);
+    ret = avpriv_jni_jstring_to_utf_chars(env, description, format);
 fail:
     if (description) {
         (*env)->DeleteLocalRef(env, description);
@@ -841,20 +841,20 @@ static int mediaformat_jni_getInt32(FFAMediaFormat* ctx, const char *name, int32
 
     JNI_GET_ENV_OR_RETURN(env, format, 0);
 
-    key = ff_jni_utf_chars_to_jstring(env, name, format);
+    key = avpriv_jni_utf_chars_to_jstring(env, name, format);
     if (!key) {
         ret = 0;
         goto fail;
     }
 
     contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
-    if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+    if (!contains_key || (ret = avpriv_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
         goto fail;
     }
 
     *out = (*env)->CallIntMethod(env, format->object, format->jfields.get_integer_id, key);
-    if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
+    if ((ret = avpriv_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
         goto fail;
     }
@@ -880,20 +880,20 @@ static int mediaformat_jni_getInt64(FFAMediaFormat* ctx, const char *name, int64
 
     JNI_GET_ENV_OR_RETURN(env, format, 0);
 
-    key = ff_jni_utf_chars_to_jstring(env, name, format);
+    key = avpriv_jni_utf_chars_to_jstring(env, name, format);
     if (!key) {
         ret = 0;
         goto fail;
     }
 
     contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
-    if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+    if (!contains_key || (ret = avpriv_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
         goto fail;
     }
 
     *out = (*env)->CallLongMethod(env, format->object, format->jfields.get_long_id, key);
-    if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
+    if ((ret = avpriv_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
         goto fail;
     }
@@ -919,20 +919,20 @@ static int mediaformat_jni_getFloat(FFAMediaFormat* ctx, const char *name, float
 
     JNI_GET_ENV_OR_RETURN(env, format, 0);
 
-    key = ff_jni_utf_chars_to_jstring(env, name, format);
+    key = avpriv_jni_utf_chars_to_jstring(env, name, format);
     if (!key) {
         ret = 0;
         goto fail;
     }
 
     contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
-    if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+    if (!contains_key || (ret = avpriv_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
         goto fail;
     }
 
     *out = (*env)->CallFloatMethod(env, format->object, format->jfields.get_float_id, key);
-    if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
+    if ((ret = avpriv_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
         goto fail;
     }
@@ -959,20 +959,20 @@ static int mediaformat_jni_getBuffer(FFAMediaFormat* ctx, const char *name, void
 
     JNI_GET_ENV_OR_RETURN(env, format, 0);
 
-    key = ff_jni_utf_chars_to_jstring(env, name, format);
+    key = avpriv_jni_utf_chars_to_jstring(env, name, format);
     if (!key) {
         ret = 0;
         goto fail;
     }
 
     contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
-    if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+    if (!contains_key || (ret = avpriv_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
         goto fail;
     }
 
     result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_bytebuffer_id, key);
-    if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
+    if ((ret = avpriv_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
         goto fail;
     }
@@ -1017,25 +1017,25 @@ static int mediaformat_jni_getString(FFAMediaFormat* ctx, const char *name, cons
 
     JNI_GET_ENV_OR_RETURN(env, format, 0);
 
-    key = ff_jni_utf_chars_to_jstring(env, name, format);
+    key = avpriv_jni_utf_chars_to_jstring(env, name, format);
     if (!key) {
         ret = 0;
         goto fail;
     }
 
     contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
-    if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+    if (!contains_key || (ret = avpriv_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
         goto fail;
     }
 
     result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_string_id, key);
-    if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
+    if ((ret = avpriv_jni_exception_check(env, 1, format)) < 0) {
         ret = 0;
         goto fail;
     }
 
-    *out = ff_jni_jstring_to_utf_chars(env, result, format);
+    *out = avpriv_jni_jstring_to_utf_chars(env, result, format);
     if (!*out) {
         ret = 0;
         goto fail;
@@ -1064,13 +1064,13 @@ static void mediaformat_jni_setInt32(FFAMediaFormat* ctx, const char* name, int3
 
     JNI_GET_ENV_OR_RETURN_VOID(env, format);
 
-    key = ff_jni_utf_chars_to_jstring(env, name, format);
+    key = avpriv_jni_utf_chars_to_jstring(env, name, format);
     if (!key) {
         goto fail;
     }
 
     (*env)->CallVoidMethod(env, format->object, format->jfields.set_integer_id, key, value);
-    if (ff_jni_exception_check(env, 1, format) < 0) {
+    if (avpriv_jni_exception_check(env, 1, format) < 0) {
         goto fail;
     }
 
@@ -1090,13 +1090,13 @@ static void mediaformat_jni_setInt64(FFAMediaFormat* ctx, const char* name, int6
 
     JNI_GET_ENV_OR_RETURN_VOID(env, format);
 
-    key = ff_jni_utf_chars_to_jstring(env, name, format);
+    key = avpriv_jni_utf_chars_to_jstring(env, name, format);
     if (!key) {
         goto fail;
     }
 
     (*env)->CallVoidMethod(env, format->object, format->jfields.set_long_id, key, value);
-    if (ff_jni_exception_check(env, 1, format) < 0) {
+    if (avpriv_jni_exception_check(env, 1, format) < 0) {
         goto fail;
     }
 
@@ -1116,13 +1116,13 @@ static void mediaformat_jni_setFloat(FFAMediaFormat* ctx, const char* name, floa
 
     JNI_GET_ENV_OR_RETURN_VOID(env, format);
 
-    key = ff_jni_utf_chars_to_jstring(env, name, format);
+    key = avpriv_jni_utf_chars_to_jstring(env, name, format);
     if (!key) {
         goto fail;
     }
 
     (*env)->CallVoidMethod(env, format->object, format->jfields.set_float_id, key, value);
-    if (ff_jni_exception_check(env, 1, format) < 0) {
+    if (avpriv_jni_exception_check(env, 1, format) < 0) {
         goto fail;
     }
 
@@ -1143,18 +1143,18 @@ static void mediaformat_jni_setString(FFAMediaFormat* ctx, const char* name, con
 
     JNI_GET_ENV_OR_RETURN_VOID(env, format);
 
-    key = ff_jni_utf_chars_to_jstring(env, name, format);
+    key = avpriv_jni_utf_chars_to_jstring(env, name, format);
     if (!key) {
         goto fail;
     }
 
-    string = ff_jni_utf_chars_to_jstring(env, value, format);
+    string = avpriv_jni_utf_chars_to_jstring(env, value, format);
     if (!string) {
         goto fail;
     }
 
     (*env)->CallVoidMethod(env, format->object, format->jfields.set_string_id, key, string);
-    if (ff_jni_exception_check(env, 1, format) < 0) {
+    if (avpriv_jni_exception_check(env, 1, format) < 0) {
         goto fail;
     }
 
@@ -1180,7 +1180,7 @@ static void mediaformat_jni_setBuffer(FFAMediaFormat* ctx, const char* name, voi
 
     JNI_GET_ENV_OR_RETURN_VOID(env, format);
 
-    key = ff_jni_utf_chars_to_jstring(env, name, format);
+    key = avpriv_jni_utf_chars_to_jstring(env, name, format);
     if (!key) {
         goto fail;
     }
@@ -1202,7 +1202,7 @@ static void mediaformat_jni_setBuffer(FFAMediaFormat* ctx, const char* name, voi
     }
 
     (*env)->CallVoidMethod(env, format->object, format->jfields.set_bytebuffer_id, key, buffer);
-    if (ff_jni_exception_check(env, 1, format) < 0) {
+    if (avpriv_jni_exception_check(env, 1, format) < 0) {
         goto fail;
     }
 
@@ -1224,44 +1224,44 @@ static int codec_init_static_fields(FFAMediaCodecJni *codec)
     JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
 
     codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
-    if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
+    if ((ret = avpriv_jni_exception_check(env, 1, codec)) < 0) {
         goto fail;
     }
 
     codec->BUFFER_FLAG_CODEC_CONFIG = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_codec_config_id);
-    if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
+    if ((ret = avpriv_jni_exception_check(env, 1, codec)) < 0) {
         goto fail;
     }
 
     codec->BUFFER_FLAG_END_OF_STREAM = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_end_of_stream_id);
-    if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
+    if ((ret = avpriv_jni_exception_check(env, 1, codec)) < 0) {
         goto fail;
     }
 
     if (codec->jfields.buffer_flag_key_frame_id) {
         codec->BUFFER_FLAG_KEY_FRAME = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_key_frame_id);
-        if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
+        if ((ret = avpriv_jni_exception_check(env, 1, codec)) < 0) {
             goto fail;
         }
     }
 
     codec->CONFIGURE_FLAG_ENCODE = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.configure_flag_encode_id);
-    if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
+    if ((ret = avpriv_jni_exception_check(env, 1, codec)) < 0) {
         goto fail;
     }
 
     codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
-    if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
+    if ((ret = avpriv_jni_exception_check(env, 1, codec)) < 0) {
         goto fail;
     }
 
     codec->INFO_OUTPUT_BUFFERS_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_buffers_changed_id);
-    if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
+    if ((ret = avpriv_jni_exception_check(env, 1, codec)) < 0) {
         goto fail;
     }
 
     codec->INFO_OUTPUT_FORMAT_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_format_changed_id);
-    if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
+    if ((ret = avpriv_jni_exception_check(env, 1, codec)) < 0) {
         goto fail;
     }
 
@@ -1290,17 +1290,17 @@ static inline FFAMediaCodec *codec_create(int method, const char *arg)
     }
     codec->api = media_codec_jni;
 
-    env = ff_jni_get_env(codec);
+    env = avpriv_jni_get_env(codec);
     if (!env) {
         av_freep(&codec);
         return NULL;
     }
 
-    if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
+    if (avpriv_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
         goto fail;
     }
 
-    jarg = ff_jni_utf_chars_to_jstring(env, arg, codec);
+    jarg = avpriv_jni_utf_chars_to_jstring(env, arg, codec);
     if (!jarg) {
         goto fail;
     }
@@ -1317,7 +1317,7 @@ static inline FFAMediaCodec *codec_create(int method, const char *arg)
                                             codec->jfields.mediacodec_class,
                                             create_id,
                                             jarg);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         goto fail;
     }
 
@@ -1335,7 +1335,7 @@ static inline FFAMediaCodec *codec_create(int method, const char *arg)
     }
 
     buffer_info = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         goto fail;
     }
 
@@ -1367,7 +1367,7 @@ fail:
             (*env)->DeleteGlobalRef(env, codec->buffer_info);
         }
 
-        ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
+        avpriv_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
         av_freep(&codec);
     }
 
@@ -1397,7 +1397,7 @@ static int mediacodec_jni_delete(FFAMediaCodec* ctx)
     JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
 
     (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_id);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         ret = AVERROR_EXTERNAL;
     }
 
@@ -1413,7 +1413,7 @@ static int mediacodec_jni_delete(FFAMediaCodec* ctx)
     (*env)->DeleteGlobalRef(env, codec->buffer_info);
     codec->buffer_info = NULL;
 
-    ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
+    avpriv_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
 
     av_freep(&codec);
 
@@ -1430,11 +1430,11 @@ static char *mediacodec_jni_getName(FFAMediaCodec *ctx)
     JNI_GET_ENV_OR_RETURN(env, codec, NULL);
 
     name = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_name_id);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         goto fail;
     }
 
-    ret = ff_jni_jstring_to_utf_chars(env, name, codec);
+    ret = avpriv_jni_jstring_to_utf_chars(env, name, codec);
 
 fail:
     if (name) {
@@ -1465,20 +1465,20 @@ static int mediacodec_jni_configure(FFAMediaCodec *ctx,
         }
 
         (*env)->CallVoidMethod(env, codec->object, codec->jfields.configure_id, format->object, NULL, NULL, flags);
-        if (ff_jni_exception_check(env, 1, codec) < 0)
+        if (avpriv_jni_exception_check(env, 1, codec) < 0)
             return AVERROR_EXTERNAL;
 
         if (!surface)
             return 0;
 
         (*env)->CallVoidMethod(env, codec->object, codec->jfields.set_input_surface_id, surface);
-        if (ff_jni_exception_check(env, 1, codec) < 0)
+        if (avpriv_jni_exception_check(env, 1, codec) < 0)
             return AVERROR_EXTERNAL;
         return 0;
     } else {
         (*env)->CallVoidMethod(env, codec->object, codec->jfields.configure_id, format->object, surface, NULL, flags);
     }
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         ret = AVERROR_EXTERNAL;
         goto fail;
     }
@@ -1496,7 +1496,7 @@ static int mediacodec_jni_start(FFAMediaCodec* ctx)
     JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
 
     (*env)->CallVoidMethod(env, codec->object, codec->jfields.start_id);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         ret = AVERROR_EXTERNAL;
         goto fail;
     }
@@ -1514,7 +1514,7 @@ static int mediacodec_jni_stop(FFAMediaCodec* ctx)
     JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
 
     (*env)->CallVoidMethod(env, codec->object, codec->jfields.stop_id);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         ret = AVERROR_EXTERNAL;
         goto fail;
     }
@@ -1532,7 +1532,7 @@ static int mediacodec_jni_flush(FFAMediaCodec* ctx)
     JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
 
     (*env)->CallVoidMethod(env, codec->object, codec->jfields.flush_id);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         ret = AVERROR_EXTERNAL;
         goto fail;
     }
@@ -1550,7 +1550,7 @@ static int mediacodec_jni_releaseOutputBuffer(FFAMediaCodec* ctx, size_t idx, in
     JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
 
     (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_id, (jint)idx, (jboolean)render);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         ret = AVERROR_EXTERNAL;
         goto fail;
     }
@@ -1568,7 +1568,7 @@ static int mediacodec_jni_releaseOutputBufferAtTime(FFAMediaCodec *ctx, size_t i
     JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
 
     (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_at_time_id, (jint)idx, (jlong)timestampNs);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         ret = AVERROR_EXTERNAL;
         goto fail;
     }
@@ -1586,7 +1586,7 @@ static ssize_t mediacodec_jni_dequeueInputBuffer(FFAMediaCodec* ctx, int64_t tim
     JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
 
     ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_input_buffer_id, timeoutUs);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         ret = AVERROR_EXTERNAL;
         goto fail;
     }
@@ -1604,7 +1604,7 @@ static int mediacodec_jni_queueInputBuffer(FFAMediaCodec* ctx, size_t idx, off_t
     JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
 
     (*env)->CallVoidMethod(env, codec->object, codec->jfields.queue_input_buffer_id, (jint)idx, (jint)offset, (jint)size, time, flags);
-    if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
+    if ((ret = avpriv_jni_exception_check(env, 1, codec)) < 0) {
         ret = AVERROR_EXTERNAL;
         goto fail;
     }
@@ -1622,27 +1622,27 @@ static ssize_t mediacodec_jni_dequeueOutputBuffer(FFAMediaCodec* ctx, FFAMediaCo
     JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
 
     ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_output_buffer_id, codec->buffer_info, timeoutUs);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         return AVERROR_EXTERNAL;
     }
 
     info->flags = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.flags_id);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         return AVERROR_EXTERNAL;
     }
 
     info->offset = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.offset_id);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         return AVERROR_EXTERNAL;
     }
 
     info->presentationTimeUs = (*env)->GetLongField(env, codec->buffer_info, codec->jfields.presentation_time_us_id);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         return AVERROR_EXTERNAL;
     }
 
     info->size = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.size_id);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         return AVERROR_EXTERNAL;
     }
 
@@ -1661,24 +1661,24 @@ static uint8_t* mediacodec_jni_getInputBuffer(FFAMediaCodec* ctx, size_t idx, si
 
     if (codec->has_get_i_o_buffer) {
         buffer = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_input_buffer_id, (jint)idx);
-        if (ff_jni_exception_check(env, 1, codec) < 0) {
+        if (avpriv_jni_exception_check(env, 1, codec) < 0) {
             goto fail;
         }
     } else {
         if (!codec->input_buffers) {
             input_buffers = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_input_buffers_id);
-            if (ff_jni_exception_check(env, 1, codec) < 0) {
+            if (avpriv_jni_exception_check(env, 1, codec) < 0) {
                 goto fail;
             }
 
             codec->input_buffers = (*env)->NewGlobalRef(env, input_buffers);
-            if (ff_jni_exception_check(env, 1, codec) < 0) {
+            if (avpriv_jni_exception_check(env, 1, codec) < 0) {
                 goto fail;
             }
         }
 
         buffer = (*env)->GetObjectArrayElement(env, codec->input_buffers, idx);
-        if (ff_jni_exception_check(env, 1, codec) < 0) {
+        if (avpriv_jni_exception_check(env, 1, codec) < 0) {
             goto fail;
         }
     }
@@ -1709,24 +1709,24 @@ static uint8_t* mediacodec_jni_getOutputBuffer(FFAMediaCodec* ctx, size_t idx, s
 
     if (codec->has_get_i_o_buffer) {
         buffer = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_buffer_id, (jint)idx);
-        if (ff_jni_exception_check(env, 1, codec) < 0) {
+        if (avpriv_jni_exception_check(env, 1, codec) < 0) {
             goto fail;
         }
     } else {
         if (!codec->output_buffers) {
             output_buffers = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_buffers_id);
-            if (ff_jni_exception_check(env, 1, codec) < 0) {
+            if (avpriv_jni_exception_check(env, 1, codec) < 0) {
                 goto fail;
             }
 
             codec->output_buffers = (*env)->NewGlobalRef(env, output_buffers);
-            if (ff_jni_exception_check(env, 1, codec) < 0) {
+            if (avpriv_jni_exception_check(env, 1, codec) < 0) {
                 goto fail;
             }
         }
 
         buffer = (*env)->GetObjectArrayElement(env, codec->output_buffers, idx);
-        if (ff_jni_exception_check(env, 1, codec) < 0) {
+        if (avpriv_jni_exception_check(env, 1, codec) < 0) {
             goto fail;
         }
     }
@@ -1756,7 +1756,7 @@ static FFAMediaFormat* mediacodec_jni_getOutputFormat(FFAMediaCodec* ctx)
     JNI_GET_ENV_OR_RETURN(env, codec, NULL);
 
     mediaformat = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_format_id);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         goto fail;
     }
 
@@ -1820,7 +1820,7 @@ static int mediacodec_jni_cleanOutputBuffers(FFAMediaCodec *ctx)
         if (codec->output_buffers) {
             JNIEnv *env = NULL;
 
-            env = ff_jni_get_env(codec);
+            env = avpriv_jni_get_env(codec);
             if (!env) {
                 ret = AVERROR_EXTERNAL;
                 goto fail;
@@ -1843,7 +1843,7 @@ static int mediacodec_jni_signalEndOfInputStream(FFAMediaCodec *ctx)
     JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
 
     (*env)->CallVoidMethod(env, codec->object, codec->jfields.signal_end_of_input_stream_id);
-    if (ff_jni_exception_check(env, 1, codec) < 0) {
+    if (avpriv_jni_exception_check(env, 1, codec) < 0) {
         return AVERROR_EXTERNAL;
     }
 
diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c
index b8587289a2..128a5bfef1 100644
--- a/libavcodec/mediacodecdec.c
+++ b/libavcodec/mediacodecdec.c
@@ -29,6 +29,7 @@
 #include "libavutil/common.h"
 #include "libavutil/opt.h"
 #include "libavutil/intreadwrite.h"
+#include "libavutil/jni.h"
 #include "libavutil/pixfmt.h"
 #include "libavutil/internal.h"
 
@@ -314,7 +315,7 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx)
     MediaCodecH264DecContext *s = avctx->priv_data;
 
     if (s->use_ndk_codec < 0)
-        s->use_ndk_codec = !av_jni_get_java_vm(avctx);
+        s->use_ndk_codec = !av_jni_get_jvm(avctx);
 
     format = ff_AMediaFormat_new(s->use_ndk_codec);
     if (!format) {
diff --git a/libavutil/Makefile b/libavutil/Makefile
index e7709b97d0..e28944b1b6 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -56,6 +56,7 @@ HEADERS = adler32.h                                                     \
           imgutils.h                                                    \
           intfloat.h                                                    \
           intreadwrite.h                                                \
+          jni.h                                                         \
           lfg.h                                                         \
           log.h                                                         \
           lzo.h                                                         \
@@ -146,6 +147,7 @@ OBJS = adler32.o                                                        \
        imgutils.o                                                       \
        integer.o                                                        \
        intmath.o                                                        \
+       jni.o                                                            \
        lfg.o                                                            \
        lls.o                                                            \
        log.o                                                            \
@@ -195,6 +197,7 @@ OBJS-$(CONFIG_CUDA)                     += hwcontext_cuda.o
 OBJS-$(CONFIG_D3D11VA)                  += hwcontext_d3d11va.o
 OBJS-$(CONFIG_D3D12VA)                  += hwcontext_d3d12va.o
 OBJS-$(CONFIG_DXVA2)                    += hwcontext_dxva2.o
+OBJS-$(CONFIG_JNI)                      += jniutils.o
 OBJS-$(CONFIG_LIBDRM)                   += hwcontext_drm.o
 OBJS-$(CONFIG_MACOS_KPERF)              += macos_kperf.o
 OBJS-$(CONFIG_MEDIACODEC)               += hwcontext_mediacodec.o
@@ -219,6 +222,7 @@ SKIPHEADERS-$(CONFIG_CUDA)             += hwcontext_cuda_internal.h     \
 SKIPHEADERS-$(CONFIG_D3D11VA)          += hwcontext_d3d11va.h
 SKIPHEADERS-$(CONFIG_D3D12VA)          += hwcontext_d3d12va.h
 SKIPHEADERS-$(CONFIG_DXVA2)            += hwcontext_dxva2.h
+SKIPHEADERS-$(CONFIG_JNI)              += jniutils.h
 SKIPHEADERS-$(CONFIG_QSV)              += hwcontext_qsv.h
 SKIPHEADERS-$(CONFIG_OPENCL)           += hwcontext_opencl.h
 SKIPHEADERS-$(CONFIG_VAAPI)            += hwcontext_vaapi.h
diff --git a/libavutil/jni.c b/libavutil/jni.c
new file mode 100644
index 0000000000..541747cb20
--- /dev/null
+++ b/libavutil/jni.c
@@ -0,0 +1,78 @@
+/*
+ * JNI public API functions
+ *
+ * Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include "libavutil/error.h"
+
+#if CONFIG_JNI
+#include <jni.h>
+#include <pthread.h>
+
+#include "libavutil/log.h"
+#include "libavutil/jni.h"
+
+static void *java_vm;
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+int av_jni_set_jvm(void *vm, void *log_ctx)
+{
+    int ret = 0;
+
+    pthread_mutex_lock(&lock);
+    if (java_vm == NULL) {
+        java_vm = vm;
+    } else if (java_vm != vm) {
+        ret = AVERROR(EINVAL);
+        av_log(log_ctx, AV_LOG_ERROR, "A Java virtual machine has already been set");
+    }
+    pthread_mutex_unlock(&lock);
+
+    return ret;
+}
+
+void *av_jni_get_jvm(void *log_ctx)
+{
+    void *vm;
+
+    pthread_mutex_lock(&lock);
+    vm = java_vm;
+    pthread_mutex_unlock(&lock);
+
+    return vm;
+}
+
+#else
+
+int av_jni_set_java_vm(void *vm, void *log_ctx)
+{
+    return AVERROR(ENOSYS);
+}
+
+void *av_jni_get_java_vm(void *log_ctx)
+{
+    return NULL;
+}
+
+#endif
diff --git a/libavutil/jni.h b/libavutil/jni.h
new file mode 100644
index 0000000000..700960dbb8
--- /dev/null
+++ b/libavutil/jni.h
@@ -0,0 +1,46 @@
+/*
+ * JNI public API functions
+ *
+ * Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_JNI_H
+#define AVUTIL_JNI_H
+
+/*
+ * Manually set a Java virtual machine which will be used to retrieve the JNI
+ * environment. Once a Java VM is set it cannot be changed afterwards, meaning
+ * you can call multiple times av_jni_set_java_vm with the same Java VM pointer
+ * however it will error out if you try to set a different Java VM.
+ *
+ * @param vm Java virtual machine
+ * @param log_ctx context used for logging, can be NULL
+ * @return 0 on success, < 0 otherwise
+ */
+int av_jni_set_jvm(void *vm, void *log_ctx);
+
+/*
+ * Get the Java virtual machine which has been set with av_jni_set_java_vm.
+ *
+ * @param vm Java virtual machine
+ * @return a pointer to the Java virtual machine
+ */
+void *av_jni_get_jvm(void *log_ctx);
+
+#endif /* AVUTIL_JNI_H */
diff --git a/libavcodec/ffjni.c b/libavutil/jniutils.c
similarity index 88%
rename from libavcodec/ffjni.c
rename to libavutil/jniutils.c
index e3cf24d3e2..89623af3f8 100644
--- a/libavcodec/ffjni.c
+++ b/libavutil/jniutils.c
@@ -31,7 +31,7 @@
 
 #include "config.h"
 #include "jni.h"
-#include "ffjni.h"
+#include "jniutils.h"
 
 static JavaVM *java_vm;
 static pthread_key_t current_env;
@@ -50,14 +50,14 @@ static void jni_create_pthread_key(void)
     pthread_key_create(&current_env, jni_detach_env);
 }
 
-JNIEnv *ff_jni_get_env(void *log_ctx)
+JNIEnv *avpriv_jni_get_env(void *log_ctx)
 {
     int ret = 0;
     JNIEnv *env = NULL;
 
     pthread_mutex_lock(&lock);
     if (java_vm == NULL) {
-        java_vm = av_jni_get_java_vm(log_ctx);
+        java_vm = av_jni_get_jvm(log_ctx);
     }
 
     if (!java_vm) {
@@ -96,7 +96,7 @@ done:
     return env;
 }
 
-char *ff_jni_jstring_to_utf_chars(JNIEnv *env, jstring string, void *log_ctx)
+char *avpriv_jni_jstring_to_utf_chars(JNIEnv *env, jstring string, void *log_ctx)
 {
     char *ret = NULL;
     const char *utf_chars = NULL;
@@ -126,7 +126,7 @@ char *ff_jni_jstring_to_utf_chars(JNIEnv *env, jstring string, void *log_ctx)
     return ret;
 }
 
-jstring ff_jni_utf_chars_to_jstring(JNIEnv *env, const char *utf_chars, void *log_ctx)
+jstring avpriv_jni_utf_chars_to_jstring(JNIEnv *env, const char *utf_chars, void *log_ctx)
 {
     jstring ret;
 
@@ -140,7 +140,7 @@ jstring ff_jni_utf_chars_to_jstring(JNIEnv *env, const char *utf_chars, void *lo
     return ret;
 }
 
-int ff_jni_exception_get_summary(JNIEnv *env, jthrowable exception, char **error, void *log_ctx)
+int avpriv_jni_exception_get_summary(JNIEnv *env, jthrowable exception, char **error, void *log_ctx)
 {
     int ret = 0;
 
@@ -192,7 +192,7 @@ int ff_jni_exception_get_summary(JNIEnv *env, jthrowable exception, char **error
     }
 
     if (string) {
-        name = ff_jni_jstring_to_utf_chars(env, string, log_ctx);
+        name = avpriv_jni_jstring_to_utf_chars(env, string, log_ctx);
         (*env)->DeleteLocalRef(env, string);
         string = NULL;
     }
@@ -214,7 +214,7 @@ int ff_jni_exception_get_summary(JNIEnv *env, jthrowable exception, char **error
     }
 
     if (string) {
-        message = ff_jni_jstring_to_utf_chars(env, string, log_ctx);
+        message = avpriv_jni_jstring_to_utf_chars(env, string, log_ctx);
         (*env)->DeleteLocalRef(env, string);
         string = NULL;
     }
@@ -251,7 +251,7 @@ done:
     return ret;
 }
 
-int ff_jni_exception_check(JNIEnv *env, int log, void *log_ctx)
+int avpriv_jni_exception_check(JNIEnv *env, int log, void *log_ctx)
 {
     int ret;
 
@@ -271,7 +271,7 @@ int ff_jni_exception_check(JNIEnv *env, int log, void *log_ctx)
     exception = (*env)->ExceptionOccurred(env);
     (*(env))->ExceptionClear((env));
 
-    if ((ret = ff_jni_exception_get_summary(env, exception, &message, log_ctx)) < 0) {
+    if ((ret = avpriv_jni_exception_get_summary(env, exception, &message, log_ctx)) < 0) {
         (*env)->DeleteLocalRef(env, exception);
         return ret;
     }
@@ -284,7 +284,7 @@ int ff_jni_exception_check(JNIEnv *env, int log, void *log_ctx)
     return -1;
 }
 
-int ff_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx)
+int avpriv_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx)
 {
     int i, ret = 0;
     jclass last_clazz = NULL;
@@ -299,7 +299,7 @@ int ff_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfi
             last_clazz = NULL;
 
             clazz = (*env)->FindClass(env, jfields_mapping[i].name);
-            if ((ret = ff_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
+            if ((ret = avpriv_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
                 goto done;
             }
 
@@ -320,7 +320,7 @@ int ff_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfi
             switch(type) {
             case FF_JNI_FIELD: {
                 jfieldID field_id = (*env)->GetFieldID(env, last_clazz, jfields_mapping[i].method, jfields_mapping[i].signature);
-                if ((ret = ff_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
+                if ((ret = avpriv_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
                     goto done;
                 }
 
@@ -329,7 +329,7 @@ int ff_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfi
             }
             case FF_JNI_STATIC_FIELD: {
                 jfieldID field_id = (*env)->GetStaticFieldID(env, last_clazz, jfields_mapping[i].method, jfields_mapping[i].signature);
-                if ((ret = ff_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
+                if ((ret = avpriv_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
                     goto done;
                 }
 
@@ -338,7 +338,7 @@ int ff_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfi
             }
             case FF_JNI_METHOD: {
                 jmethodID method_id = (*env)->GetMethodID(env, last_clazz, jfields_mapping[i].method, jfields_mapping[i].signature);
-                if ((ret = ff_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
+                if ((ret = avpriv_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
                     goto done;
                 }
 
@@ -347,7 +347,7 @@ int ff_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfi
             }
             case FF_JNI_STATIC_METHOD: {
                 jmethodID method_id = (*env)->GetStaticMethodID(env, last_clazz, jfields_mapping[i].method, jfields_mapping[i].signature);
-                if ((ret = ff_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
+                if ((ret = avpriv_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
                     goto done;
                 }
 
@@ -367,13 +367,13 @@ int ff_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfi
 done:
     if (ret < 0) {
         /* reset jfields in case of failure so it does not leak references */
-        ff_jni_reset_jfields(env, jfields, jfields_mapping, global, log_ctx);
+        avpriv_jni_reset_jfields(env, jfields, jfields_mapping, global, log_ctx);
     }
 
     return ret;
 }
 
-int ff_jni_reset_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx)
+int avpriv_jni_reset_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx)
 {
     int i;
 
diff --git a/libavcodec/ffjni.h b/libavutil/jniutils.h
similarity index 84%
rename from libavcodec/ffjni.h
rename to libavutil/jniutils.h
index 6027bac0ab..2be401c974 100644
--- a/libavcodec/ffjni.h
+++ b/libavutil/jniutils.h
@@ -20,8 +20,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#ifndef AVCODEC_FFJNI_H
-#define AVCODEC_FFJNI_H
+#ifndef AVUTIL_JNIUTILS_H
+#define AVUTIL_JNIUTILS_H
 
 #include <jni.h>
 
@@ -37,7 +37,7 @@
  * @param log_ctx context used for logging, can be NULL
  * @return the JNI environment on success, NULL otherwise
  */
-JNIEnv *ff_jni_get_env(void *log_ctx);
+JNIEnv *avpriv_jni_get_env(void *log_ctx);
 
 /*
  * Convert a jstring to its utf characters equivalent.
@@ -48,7 +48,7 @@ JNIEnv *ff_jni_get_env(void *log_ctx);
  * @return a pointer to an array of unicode characters on success, NULL
  * otherwise
  */
-char *ff_jni_jstring_to_utf_chars(JNIEnv *env, jstring string, void *log_ctx);
+char *avpriv_jni_jstring_to_utf_chars(JNIEnv *env, jstring string, void *log_ctx);
 
 /*
  * Convert utf chars to its jstring equivalent.
@@ -58,7 +58,7 @@ char *ff_jni_jstring_to_utf_chars(JNIEnv *env, jstring string, void *log_ctx);
  * @param log_ctx context used for logging, can be NULL
  * @return a Java string object on success, NULL otherwise
  */
-jstring ff_jni_utf_chars_to_jstring(JNIEnv *env, const char *utf_chars, void *log_ctx);
+jstring avpriv_jni_utf_chars_to_jstring(JNIEnv *env, const char *utf_chars, void *log_ctx);
 
 /*
  * Extract the error summary from a jthrowable in the form of "className: errorMessage"
@@ -70,7 +70,7 @@ jstring ff_jni_utf_chars_to_jstring(JNIEnv *env, const char *utf_chars, void *lo
  * @param log_ctx context used for logging, can be NULL
  * @return 0 on success, < 0 otherwise
  */
-int ff_jni_exception_get_summary(JNIEnv *env, jthrowable exception, char **error, void *log_ctx);
+int avpriv_jni_exception_get_summary(JNIEnv *env, jthrowable exception, char **error, void *log_ctx);
 
 /*
  * Check if an exception has occurred,log it using av_log and clear it.
@@ -80,34 +80,30 @@ int ff_jni_exception_get_summary(JNIEnv *env, jthrowable exception, char **error
  * 0 disables logging, != 0 enables logging
  * @param log_ctx context used for logging, can be NULL
  */
-int ff_jni_exception_check(JNIEnv *env, int log, void *log_ctx);
+int avpriv_jni_exception_check(JNIEnv *env, int log, void *log_ctx);
 
 /*
  * Jni field type.
  */
 enum FFJniFieldType {
-
     FF_JNI_CLASS,
     FF_JNI_FIELD,
     FF_JNI_STATIC_FIELD,
     FF_JNI_METHOD,
     FF_JNI_STATIC_METHOD
-
 };
 
 /*
  * Jni field describing a class, a field or a method to be retrieved using
- * the ff_jni_init_jfields method.
+ * the avpriv_jni_init_jfields method.
  */
 struct FFJniField {
-
     const char *name;
     const char *method;
     const char *signature;
     enum FFJniFieldType type;
     int offset;
     int mandatory;
-
 };
 
 /*
@@ -124,7 +120,7 @@ struct FFJniField {
  * @param log_ctx context used for logging, can be NULL
  * @return 0 on success, < 0 otherwise
  */
-int ff_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx);
+int avpriv_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx);
 
 /*
  * Delete class references, field ids and method ids of an arbitrary structure.
@@ -140,6 +136,6 @@ int ff_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfi
  * @param log_ctx context used for logging, can be NULL
  * @return 0 on success, < 0 otherwise
  */
-int ff_jni_reset_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx);
+int avpriv_jni_reset_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx);
 
-#endif /* AVCODEC_FFJNI_H */
+#endif /* AVCODEC_JNIUTILS_H */
-- 
2.43.1



More information about the ffmpeg-devel mailing list