#include <string.h>
#include <jni.h>
+#include <pthread.h>
+
GST_DEBUG_CATEGORY (gst_amc_debug);
#define GST_CAT_DEFAULT gst_amc_debug
jmethodID set_byte_buffer;
} media_format;
+static pthread_key_t current_jni_env;
+
static JNIEnv *
gst_amc_attach_current_thread (void)
{
}
static void
-gst_amc_detach_current_thread (void)
+gst_amc_detach_current_thread (void *env)
{
- /* FIXME: At some point we need to detach threads, otherwise
- * we leak memory
- */
- GST_DEBUG ("FIXME: Not detaching thread %p", g_thread_self ());
- /*(*java_vm)->DetachCurrentThread (java_vm); */
+ GST_DEBUG ("Detaching thread %p", g_thread_self ());
+ (*java_vm)->DetachCurrentThread (java_vm);
+}
+
+static JNIEnv *
+gst_amc_get_jni_env (void)
+{
+ JNIEnv *env;
+
+ if ((env = pthread_getspecific (current_jni_env)) == NULL) {
+ env = gst_amc_attach_current_thread ();
+ pthread_setspecific (current_jni_env, env);
+ }
+
+ return env;
}
static gboolean
g_return_val_if_fail (name != NULL, NULL);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
name_str = (*env)->NewStringUTF (env, name);
if (name_str == NULL)
if (name_str)
(*env)->DeleteLocalRef (env, name_str);
name_str = NULL;
- gst_amc_detach_current_thread ();
return codec;
g_return_if_fail (codec != NULL);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
(*env)->DeleteGlobalRef (env, codec->object);
g_slice_free (GstAmcCodec, codec);
- gst_amc_detach_current_thread ();
}
gboolean
g_return_val_if_fail (codec != NULL, FALSE);
g_return_val_if_fail (format != NULL, FALSE);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
(*env)->CallVoidMethod (env, codec->object, media_codec.configure,
format->object, NULL, NULL, flags);
}
done:
- gst_amc_detach_current_thread ();
return ret;
}
g_return_val_if_fail (codec != NULL, NULL);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
object =
(*env)->CallObjectMethod (env, codec->object,
(*env)->DeleteLocalRef (env, object);
done:
- gst_amc_detach_current_thread ();
return ret;
}
g_return_val_if_fail (codec != NULL, FALSE);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
(*env)->CallVoidMethod (env, codec->object, media_codec.start);
if ((*env)->ExceptionCheck (env)) {
}
done:
- gst_amc_detach_current_thread ();
return ret;
}
g_return_val_if_fail (codec != NULL, FALSE);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
(*env)->CallVoidMethod (env, codec->object, media_codec.stop);
if ((*env)->ExceptionCheck (env)) {
}
done:
- gst_amc_detach_current_thread ();
return ret;
}
g_return_val_if_fail (codec != NULL, FALSE);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
(*env)->CallVoidMethod (env, codec->object, media_codec.flush);
if ((*env)->ExceptionCheck (env)) {
}
done:
- gst_amc_detach_current_thread ();
return ret;
}
g_return_val_if_fail (codec != NULL, FALSE);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
(*env)->CallVoidMethod (env, codec->object, media_codec.release);
if ((*env)->ExceptionCheck (env)) {
}
done:
- gst_amc_detach_current_thread ();
return ret;
}
g_return_if_fail (buffers != NULL);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
for (i = 0; i < n_buffers; i++) {
if (buffers[i].object)
(*env)->DeleteGlobalRef (env, buffers[i].object);
}
g_free (buffers);
-
- gst_amc_detach_current_thread ();
}
GstAmcBuffer *
g_return_val_if_fail (n_buffers != NULL, NULL);
*n_buffers = 0;
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
output_buffers =
(*env)->CallObjectMethod (env, codec->object,
(*env)->DeleteLocalRef (env, output_buffers);
output_buffers = NULL;
- gst_amc_detach_current_thread ();
-
return ret;
error:
if (ret)
g_return_val_if_fail (n_buffers != NULL, NULL);
*n_buffers = 0;
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
input_buffers =
(*env)->CallObjectMethod (env, codec->object,
(*env)->DeleteLocalRef (env, input_buffers);
input_buffers = NULL;
- gst_amc_detach_current_thread ();
-
return ret;
error:
if (ret)
g_return_val_if_fail (codec != NULL, G_MININT);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
ret =
(*env)->CallIntMethod (env, codec->object,
}
done:
- gst_amc_detach_current_thread ();
return ret;
}
g_return_val_if_fail (codec != NULL, G_MININT);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
info_o =
(*env)->NewObject (env, media_codec_buffer_info.klass,
(*env)->DeleteLocalRef (env, info_o);
info_o = NULL;
- gst_amc_detach_current_thread ();
-
return ret;
}
g_return_val_if_fail (codec != NULL, FALSE);
g_return_val_if_fail (info != NULL, FALSE);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
(*env)->CallVoidMethod (env, codec->object, media_codec.queue_input_buffer,
index, info->offset, info->size, info->presentation_time_us, info->flags);
}
done:
- gst_amc_detach_current_thread ();
return ret;
}
g_return_val_if_fail (codec != NULL, FALSE);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
(*env)->CallVoidMethod (env, codec->object, media_codec.release_output_buffer,
index, JNI_FALSE);
}
done:
- gst_amc_detach_current_thread ();
return ret;
}
g_return_val_if_fail (mime != NULL, NULL);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
mime_str = (*env)->NewStringUTF (env, mime);
if (mime_str == NULL)
if (mime_str)
(*env)->DeleteLocalRef (env, mime_str);
mime_str = NULL;
- gst_amc_detach_current_thread ();
return format;
g_return_val_if_fail (mime != NULL, NULL);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
mime_str = (*env)->NewStringUTF (env, mime);
if (mime_str == NULL)
if (mime_str)
(*env)->DeleteLocalRef (env, mime_str);
mime_str = NULL;
- gst_amc_detach_current_thread ();
return format;
g_return_if_fail (format != NULL);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
(*env)->DeleteGlobalRef (env, format->object);
g_slice_free (GstAmcFormat, format);
- gst_amc_detach_current_thread ();
}
gboolean
g_return_val_if_fail (format != NULL, FALSE);
g_return_val_if_fail (key != NULL, FALSE);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
key_str = (*env)->NewStringUTF (env, key);
if (!key_str)
done:
if (key_str)
(*env)->DeleteLocalRef (env, key_str);
- gst_amc_detach_current_thread ();
return ret;
}
g_return_val_if_fail (value != NULL, FALSE);
*value = 0;
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
key_str = (*env)->NewStringUTF (env, key);
if (!key_str)
done:
if (key_str)
(*env)->DeleteLocalRef (env, key_str);
- gst_amc_detach_current_thread ();
return ret;
}
g_return_if_fail (format != NULL);
g_return_if_fail (key != NULL);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
key_str = (*env)->NewStringUTF (env, key);
if (!key_str)
done:
if (key_str)
(*env)->DeleteLocalRef (env, key_str);
- gst_amc_detach_current_thread ();
}
gboolean
g_return_val_if_fail (value != NULL, FALSE);
*value = 0;
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
key_str = (*env)->NewStringUTF (env, key);
if (!key_str)
done:
if (key_str)
(*env)->DeleteLocalRef (env, key_str);
- gst_amc_detach_current_thread ();
return ret;
g_return_if_fail (format != NULL);
g_return_if_fail (key != NULL);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
key_str = (*env)->NewStringUTF (env, key);
if (!key_str)
done:
if (key_str)
(*env)->DeleteLocalRef (env, key_str);
- gst_amc_detach_current_thread ();
}
gboolean
g_return_val_if_fail (value != NULL, FALSE);
*value = 0;
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
key_str = (*env)->NewStringUTF (env, key);
if (!key_str)
(*env)->ReleaseStringUTFChars (env, v_str, v);
if (v_str)
(*env)->DeleteLocalRef (env, v_str);
- gst_amc_detach_current_thread ();
return ret;
}
g_return_if_fail (key != NULL);
g_return_if_fail (value != NULL);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
key_str = (*env)->NewStringUTF (env, key);
if (!key_str)
(*env)->DeleteLocalRef (env, key_str);
if (v_str)
(*env)->DeleteLocalRef (env, v_str);
- gst_amc_detach_current_thread ();
}
gboolean
g_return_val_if_fail (value != NULL, FALSE);
*value = 0;
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
key_str = (*env)->NewStringUTF (env, key);
if (!key_str)
(*env)->DeleteLocalRef (env, key_str);
if (v)
(*env)->DeleteLocalRef (env, v);
- gst_amc_detach_current_thread ();
return ret;
}
g_return_if_fail (key != NULL);
g_return_if_fail (value != NULL);
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
key_str = (*env)->NewStringUTF (env, key);
if (!key_str)
(*env)->DeleteLocalRef (env, key_str);
if (v)
(*env)->DeleteLocalRef (env, v);
- gst_amc_detach_current_thread ();
}
static gboolean
GST_DEBUG ("Retrieving Java classes");
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
tmp = (*env)->FindClass (env, "java/lang/String");
if (!tmp) {
if (tmp)
(*env)->DeleteLocalRef (env, tmp);
tmp = NULL;
- gst_amc_detach_current_thread ();
return ret;
}
/* TODO: Cache this in the plugin and also cache
* classes and method ids
*/
- env = gst_amc_attach_current_thread ();
+ env = gst_amc_get_jni_env ();
codec_list_class = (*env)->FindClass (env, "android/media/MediaCodecList");
if (!codec_list_class) {
if (codec_list_class)
(*env)->DeleteLocalRef (env, codec_list_class);
- gst_amc_detach_current_thread ();
-
return ret;
}
{
GST_DEBUG_CATEGORY_INIT (gst_amc_debug, "amc", 0, "android-media-codec");
+ pthread_key_create (¤t_jni_env, gst_amc_detach_current_thread);
+
if (!initialize_java_vm ())
return FALSE;