Commit 376d8fb2 authored by Matthieu Bouron's avatar Matthieu Bouron

lavc/ffjni: replace ff_jni_{attach,detach} with ff_jni_get_env

If a JNI environment is not already attached to the thread where the
MediaCodec calls are made the current implementation will attach /
detach an environment for each MediaCodec call wasting some CPU time.

ff_jni_get_env replaces ff_jni_{attach,detach} by permanently attaching
an environment (if it is not already the case) to the current thread.
The environment will be automatically detached at the thread destruction
using a pthread_key callback.

Saves around 5% of CPU time (out of 20%) while decoding a stream with
MediaCodec.
parent 293676c4
...@@ -31,25 +31,42 @@ ...@@ -31,25 +31,42 @@
#include "jni.h" #include "jni.h"
#include "ffjni.h" #include "ffjni.h"
static JavaVM *java_vm = NULL; static JavaVM *java_vm;
static pthread_key_t current_env;
static pthread_once_t once = PTHREAD_ONCE_INIT;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
JNIEnv *ff_jni_attach_env(int *attached, void *log_ctx) static void jni_detach_env(void *data)
{
if (java_vm) {
(*java_vm)->DetachCurrentThread(java_vm);
}
}
static void jni_create_pthread_key(void)
{
pthread_key_create(&current_env, jni_detach_env);
}
JNIEnv *ff_jni_get_env(void *log_ctx)
{ {
int ret = 0; int ret = 0;
JNIEnv *env = NULL; JNIEnv *env = NULL;
*attached = 0;
pthread_mutex_lock(&lock); pthread_mutex_lock(&lock);
if (java_vm == NULL) { if (java_vm == NULL) {
java_vm = av_jni_get_java_vm(log_ctx); java_vm = av_jni_get_java_vm(log_ctx);
} }
pthread_mutex_unlock(&lock);
if (!java_vm) { if (!java_vm) {
av_log(log_ctx, AV_LOG_ERROR, "No Java virtual machine has been registered\n"); av_log(log_ctx, AV_LOG_ERROR, "No Java virtual machine has been registered\n");
return NULL; goto done;
}
pthread_once(&once, jni_create_pthread_key);
if ((env = pthread_getspecific(current_env)) != NULL) {
goto done;
} }
ret = (*java_vm)->GetEnv(java_vm, (void **)&env, JNI_VERSION_1_6); ret = (*java_vm)->GetEnv(java_vm, (void **)&env, JNI_VERSION_1_6);
...@@ -59,7 +76,7 @@ JNIEnv *ff_jni_attach_env(int *attached, void *log_ctx) ...@@ -59,7 +76,7 @@ JNIEnv *ff_jni_attach_env(int *attached, void *log_ctx)
av_log(log_ctx, AV_LOG_ERROR, "Failed to attach the JNI environment to the current thread\n"); av_log(log_ctx, AV_LOG_ERROR, "Failed to attach the JNI environment to the current thread\n");
env = NULL; env = NULL;
} else { } else {
*attached = 1; pthread_setspecific(current_env, env);
} }
break; break;
case JNI_OK: case JNI_OK:
...@@ -72,19 +89,11 @@ JNIEnv *ff_jni_attach_env(int *attached, void *log_ctx) ...@@ -72,19 +89,11 @@ JNIEnv *ff_jni_attach_env(int *attached, void *log_ctx)
break; break;
} }
done:
pthread_mutex_unlock(&lock);
return env; return env;
} }
int ff_jni_detach_env(void *log_ctx)
{
if (java_vm == NULL) {
av_log(log_ctx, AV_LOG_ERROR, "No Java virtual machine has been registered\n");
return AVERROR(EINVAL);
}
return (*java_vm)->DetachCurrentThread(java_vm);
}
char *ff_jni_jstring_to_utf_chars(JNIEnv *env, jstring string, void *log_ctx) char *ff_jni_jstring_to_utf_chars(JNIEnv *env, jstring string, void *log_ctx)
{ {
char *ret = NULL; char *ret = NULL;
......
...@@ -26,7 +26,10 @@ ...@@ -26,7 +26,10 @@
#include <jni.h> #include <jni.h>
/* /*
* Attach a JNI environment to the current thread. * Attach permanently a JNI environment to the current thread and retrieve it.
*
* If successfully attached, the JNI environment will automatically be detached
* at thread destruction.
* *
* @param attached pointer to an integer that will be set to 1 if the * @param attached pointer to an integer that will be set to 1 if the
* environment has been attached to the current thread or 0 if it is * environment has been attached to the current thread or 0 if it is
...@@ -34,15 +37,7 @@ ...@@ -34,15 +37,7 @@
* @param log_ctx context used for logging, can be NULL * @param log_ctx context used for logging, can be NULL
* @return the JNI environment on success, NULL otherwise * @return the JNI environment on success, NULL otherwise
*/ */
JNIEnv *ff_jni_attach_env(int *attached, void *log_ctx); JNIEnv *ff_jni_get_env(void *log_ctx);
/*
* Detach the JNI environment from the current thread.
*
* @param log_ctx context used for logging, can be NULL
* @return 0 on success, < 0 otherwise
*/
int ff_jni_detach_env(void *log_ctx);
/* /*
* Convert a jstring to its utf characters equivalent. * Convert a jstring to its utf characters equivalent.
......
...@@ -43,9 +43,8 @@ int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, ...@@ -43,9 +43,8 @@ int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx,
{ {
int ret = 0; int ret = 0;
JNIEnv *env = NULL; JNIEnv *env = NULL;
int attached = 0;
env = ff_jni_attach_env(&attached, avctx); env = ff_jni_get_env(avctx);
if (!env) { if (!env) {
return AVERROR_EXTERNAL; return AVERROR_EXTERNAL;
} }
...@@ -58,17 +57,12 @@ int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, ...@@ -58,17 +57,12 @@ int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx,
ret = AVERROR_EXTERNAL; ret = AVERROR_EXTERNAL;
} }
if (attached) {
ff_jni_detach_env(avctx);
}
return ret; return ret;
} }
void av_mediacodec_default_free(AVCodecContext *avctx) void av_mediacodec_default_free(AVCodecContext *avctx)
{ {
JNIEnv *env = NULL; JNIEnv *env = NULL;
int attached = 0;
AVMediaCodecContext *ctx = avctx->hwaccel_context; AVMediaCodecContext *ctx = avctx->hwaccel_context;
...@@ -76,7 +70,7 @@ void av_mediacodec_default_free(AVCodecContext *avctx) ...@@ -76,7 +70,7 @@ void av_mediacodec_default_free(AVCodecContext *avctx)
return; return;
} }
env = ff_jni_attach_env(&attached, avctx); env = ff_jni_get_env(avctx);
if (!env) { if (!env) {
return; return;
} }
...@@ -86,10 +80,6 @@ void av_mediacodec_default_free(AVCodecContext *avctx) ...@@ -86,10 +80,6 @@ void av_mediacodec_default_free(AVCodecContext *avctx)
ctx->surface = NULL; ctx->surface = NULL;
} }
if (attached) {
ff_jni_detach_env(avctx);
}
av_freep(&avctx->hwaccel_context); av_freep(&avctx->hwaccel_context);
} }
......
...@@ -27,40 +27,30 @@ ...@@ -27,40 +27,30 @@
void *ff_mediacodec_surface_ref(void *surface, void *log_ctx) void *ff_mediacodec_surface_ref(void *surface, void *log_ctx)
{ {
int attached = 0;
JNIEnv *env = NULL; JNIEnv *env = NULL;
void *reference = NULL; void *reference = NULL;
env = ff_jni_attach_env(&attached, log_ctx); env = ff_jni_get_env(log_ctx);
if (!env) { if (!env) {
return NULL; return NULL;
} }
reference = (*env)->NewGlobalRef(env, surface); reference = (*env)->NewGlobalRef(env, surface);
if (attached) {
ff_jni_detach_env(log_ctx);
}
return reference; return reference;
} }
int ff_mediacodec_surface_unref(void *surface, void *log_ctx) int ff_mediacodec_surface_unref(void *surface, void *log_ctx)
{ {
int attached = 0;
JNIEnv *env = NULL; JNIEnv *env = NULL;
env = ff_jni_attach_env(&attached, log_ctx); env = ff_jni_get_env(log_ctx);
if (!env) { if (!env) {
return AVERROR_EXTERNAL; return AVERROR_EXTERNAL;
} }
(*env)->DeleteGlobalRef(env, surface); (*env)->DeleteGlobalRef(env, surface);
if (attached) {
ff_jni_detach_env(log_ctx);
}
return 0; return 0;
} }
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment