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 @@
#include "jni.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;
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;
JNIEnv *env = NULL;
*attached = 0;
pthread_mutex_lock(&lock);
if (java_vm == NULL) {
java_vm = av_jni_get_java_vm(log_ctx);
}
pthread_mutex_unlock(&lock);
if (!java_vm) {
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);
......@@ -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");
env = NULL;
} else {
*attached = 1;
pthread_setspecific(current_env, env);
}
break;
case JNI_OK:
......@@ -72,19 +89,11 @@ JNIEnv *ff_jni_attach_env(int *attached, void *log_ctx)
break;
}
done:
pthread_mutex_unlock(&lock);
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 *ret = NULL;
......
......@@ -26,7 +26,10 @@
#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
* environment has been attached to the current thread or 0 if it is
......@@ -34,15 +37,7 @@
* @param log_ctx context used for logging, can be NULL
* @return the JNI environment on success, NULL otherwise
*/
JNIEnv *ff_jni_attach_env(int *attached, 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);
JNIEnv *ff_jni_get_env(void *log_ctx);
/*
* Convert a jstring to its utf characters equivalent.
......
......@@ -43,9 +43,8 @@ int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx,
{
int ret = 0;
JNIEnv *env = NULL;
int attached = 0;
env = ff_jni_attach_env(&attached, avctx);
env = ff_jni_get_env(avctx);
if (!env) {
return AVERROR_EXTERNAL;
}
......@@ -58,17 +57,12 @@ int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx,
ret = AVERROR_EXTERNAL;
}
if (attached) {
ff_jni_detach_env(avctx);
}
return ret;
}
void av_mediacodec_default_free(AVCodecContext *avctx)
{
JNIEnv *env = NULL;
int attached = 0;
AVMediaCodecContext *ctx = avctx->hwaccel_context;
......@@ -76,7 +70,7 @@ void av_mediacodec_default_free(AVCodecContext *avctx)
return;
}
env = ff_jni_attach_env(&attached, avctx);
env = ff_jni_get_env(avctx);
if (!env) {
return;
}
......@@ -86,10 +80,6 @@ void av_mediacodec_default_free(AVCodecContext *avctx)
ctx->surface = NULL;
}
if (attached) {
ff_jni_detach_env(avctx);
}
av_freep(&avctx->hwaccel_context);
}
......
......@@ -27,40 +27,30 @@
void *ff_mediacodec_surface_ref(void *surface, void *log_ctx)
{
int attached = 0;
JNIEnv *env = NULL;
void *reference = NULL;
env = ff_jni_attach_env(&attached, log_ctx);
env = ff_jni_get_env(log_ctx);
if (!env) {
return NULL;
}
reference = (*env)->NewGlobalRef(env, surface);
if (attached) {
ff_jni_detach_env(log_ctx);
}
return reference;
}
int ff_mediacodec_surface_unref(void *surface, void *log_ctx)
{
int attached = 0;
JNIEnv *env = NULL;
env = ff_jni_attach_env(&attached, log_ctx);
env = ff_jni_get_env(log_ctx);
if (!env) {
return AVERROR_EXTERNAL;
}
(*env)->DeleteGlobalRef(env, surface);
if (attached) {
ff_jni_detach_env(log_ctx);
}
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