diff --git a/sys/androidcamera/Makefile.am b/sys/androidcamera/Makefile.am index b10a327601..daf9ca29f4 100644 --- a/sys/androidcamera/Makefile.am +++ b/sys/androidcamera/Makefile.am @@ -19,7 +19,8 @@ libgstandroidmedia_la_SOURCES = \ video/video.c \ video/gstvideodecoder.c \ video/gstvideoencoder.c \ - video/gstvideoutils.c + video/gstvideoutils.c \ + gst-dvm.c noinst_HEADERS = \ gstamc.h \ @@ -29,7 +30,8 @@ noinst_HEADERS = \ video/video.h \ video/gstvideodecoder.h \ video/gstvideoencoder.h \ - video/gstvideoutils.h + video/gstvideoutils.h \ + gst-dvm.h if !HAVE_GST_0_10_37 libgstandroidmedia_la_SOURCES += $(VIDEO_BASE_CLASSES_C) diff --git a/sys/androidcamera/gst-dvm.c b/sys/androidcamera/gst-dvm.c new file mode 100644 index 0000000000..df2209ba52 --- /dev/null +++ b/sys/androidcamera/gst-dvm.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2012, Collabora Ltd. + * Author: Sebastian Dröge + * Copyright (C) 2012, Cisco Systems, Inc. + * Author: Youness Alaoui + * + * This library 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 + * version 2.1 of the License. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gst-dvm.h" + +#include + +GST_DEBUG_CATEGORY (gst_dvm_debug); +#define GST_CAT_DEFAULT gst_dvm_debug + +static GModule *java_module; +static jint (*get_created_java_vms) (JavaVM ** vmBuf, jsize bufLen, + jsize * nVMs); +static jint (*create_java_vm) (JavaVM ** p_vm, JNIEnv ** p_env, void *vm_args); +static JavaVM *java_vm = NULL; +static gboolean started_java_vm = FALSE; + +static pthread_key_t current_jni_env; + +static JNIEnv * +gst_dvm_attach_current_thread (void) +{ + JNIEnv *env; + JavaVMAttachArgs args; + + GST_DEBUG ("Attaching thread %p", g_thread_self ()); + args.version = JNI_VERSION_1_6; + args.name = NULL; + args.group = NULL; + + if ((*java_vm)->AttachCurrentThread (java_vm, &env, &args) < 0) { + GST_ERROR ("Failed to attach current thread"); + return NULL; + } + + return env; +} + +static void +gst_dvm_detach_current_thread (void *env) +{ + GST_DEBUG ("Detaching thread %p", g_thread_self ()); + (*java_vm)->DetachCurrentThread (java_vm); +} + +JNIEnv * +gst_dvm_get_env (void) +{ + JNIEnv *env; + + if ((env = pthread_getspecific (current_jni_env)) == NULL) { + env = gst_dvm_attach_current_thread (); + pthread_setspecific (current_jni_env, env); + } + + return env; +} + +gboolean +gst_dvm_init (void) +{ + jsize n_vms; + + GST_DEBUG_CATEGORY_INIT (gst_dvm_debug, "dvm", 0, "DVM"); + + pthread_key_create (¤t_jni_env, gst_dvm_detach_current_thread); + + java_module = g_module_open ("libdvm", G_MODULE_BIND_LOCAL); + if (!java_module) + goto load_failed; + + if (!g_module_symbol (java_module, "JNI_CreateJavaVM", + (gpointer *) & create_java_vm)) + goto symbol_error; + + if (!g_module_symbol (java_module, "JNI_GetCreatedJavaVMs", + (gpointer *) & get_created_java_vms)) + goto symbol_error; + + n_vms = 0; + if (get_created_java_vms (&java_vm, 1, &n_vms) < 0) + goto get_created_failed; + + if (n_vms > 0) { + GST_DEBUG ("Successfully got existing Java VM %p", java_vm); + } else { + JNIEnv *env; + JavaVMInitArgs vm_args; + JavaVMOption options[4]; + + options[0].optionString = "-verbose:jni"; + options[1].optionString = "-verbose:gc"; + options[2].optionString = "-Xcheck:jni"; + options[3].optionString = "-Xdebug"; + + vm_args.version = JNI_VERSION_1_4; + vm_args.options = options; + vm_args.nOptions = 4; + vm_args.ignoreUnrecognized = JNI_TRUE; + if (create_java_vm (&java_vm, &env, &vm_args) < 0) + goto create_failed; + GST_DEBUG ("Successfully created Java VM %p", java_vm); + + started_java_vm = TRUE; + } + + return java_vm != NULL; + +load_failed: + { + GST_ERROR ("Failed to load libdvm: %s", g_module_error ()); + return FALSE; + } +symbol_error: + { + GST_ERROR ("Failed to locate required JNI symbols in libdvm: %s", + g_module_error ()); + g_module_close (java_module); + java_module = NULL; + return FALSE; + } +get_created_failed: + { + GST_ERROR ("Failed to get already created VMs"); + g_module_close (java_module); + java_module = NULL; + return FALSE; + } +create_failed: + { + GST_ERROR ("Failed to create a Java VM"); + g_module_close (java_module); + java_module = NULL; + return FALSE; + } +} diff --git a/sys/androidcamera/gst-dvm.h b/sys/androidcamera/gst-dvm.h new file mode 100644 index 0000000000..4cef357a9e --- /dev/null +++ b/sys/androidcamera/gst-dvm.h @@ -0,0 +1,103 @@ +/* Dalvik Virtual Machine helper functions + * + * Copyright (C) 2012, Collabora Ltd. + * Author: Sebastian Dröge + * Copyright (C) 2012, Cisco Systems, Inc. + * Author: Youness Alaoui + * + * This library 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 + * version 2.1 of the License. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __GST_DVM_H__ +#define __GST_DVM_H__ + +#include +#include + +#define GST_DVM_GET_CLASS(k, name) { \ + jclass tmp; \ + \ + tmp = (*env)->FindClass (env, name); \ + if (!tmp) { \ + (*env)->ExceptionClear (env); \ + GST_ERROR ("Failed to get class %s", name); \ + return FALSE; \ + } \ + \ + k.klass = (*env)->NewGlobalRef (env, tmp); \ + if (!k.klass) { \ + (*env)->ExceptionClear (env); \ + (*env)->DeleteLocalRef (env, tmp); \ + GST_ERROR ("Failed to get %s class global reference", name); \ + return FALSE; \ + } \ + (*env)->DeleteLocalRef (env, tmp); \ + } +#define GST_DVM_GET_STATIC_METHOD(k, method, signature) \ + k.method = (*env)->GetStaticMethodID (env, k.klass, #method, \ + signature); \ + if (!k.method) { \ + (*env)->ExceptionClear (env); \ + GST_ERROR ("Failed to get static method %s for %s", #method, #k); \ + return FALSE; \ + } + +#define GST_DVM_GET_METHOD(k, method, signature) \ + k.method = (*env)->GetMethodID (env, k.klass, #method, signature); \ + if (!k.method) { \ + (*env)->ExceptionClear (env); \ + GST_ERROR ("Failed to get method %s for %s", #method, #k); \ + return FALSE; \ + } + +#define GST_DVM_GET_CONSTRUCTOR(k, field, signature) \ + k.field = (*env)->GetMethodID (env, k.klass, "", signature); \ + if (!k.field) { \ + (*env)->ExceptionClear (env); \ + GST_ERROR ("Failed to get constructor %s for %s", #field, #k); \ + return FALSE; \ + } + +#define GST_DVM_GET_FIELD(k, field, signature) \ + k.field = (*env)->GetFieldID (env, k.klass, #field, signature); \ + if (!k.field) { \ + (*env)->ExceptionClear (env); \ + GST_ERROR ("Failed to get field %s for %s", #field, #k); \ + return FALSE; \ + } + +#define GST_DVM_GET_CONSTANT(k, field, type, signature) { \ + jfieldID id; \ + \ + id = (*env)->GetStaticFieldID (env, k.klass, #field, signature); \ + if (!id) { \ + (*env)->ExceptionClear (env); \ + GST_ERROR ("Failed to get static field %s for %s", #field, #k); \ + return FALSE; \ + } \ + k.field = (*env)->GetStatic##type##Field (env, k.klass, id); \ + if ((*env)->ExceptionCheck (env)) { \ + (*env)->ExceptionClear (env); \ + GST_ERROR ("Failed to get " #type " constant %s", #field); \ + return FALSE; \ + } \ + } + + +JNIEnv *gst_dvm_get_env (void); +gboolean gst_dvm_init (void); + +#endif /* __GST_DVM_H__ */