[Android] [PATCH] Add support for multiple video instances.

Paulo Vitor Magacho da Silva pvmagacho at gmail.com
Fri Dec 5 02:12:35 CET 2014


---
 libvlc/jni/libvlcjni-equalizer.c                   |   4 +-
 libvlc/jni/libvlcjni-util.c                        |  17 --
 libvlc/jni/libvlcjni.c                             | 179 +++++++++++---------
 libvlc/jni/native_crash_handler.c                  |  25 +--
 libvlc/jni/native_crash_handler.h                  |   5 +-
 libvlc/jni/utils.h                                 |   2 -
 libvlc/jni/vout.c                                  | 186 ++++++++++++---------
 libvlc/jni/vout.h                                  |  24 ++-
 libvlc/src/org/videolan/libvlc/EventHandler.java   |   8 -
 libvlc/src/org/videolan/libvlc/LibVLC.java         |  98 +++--------
 libvlc/src/org/videolan/libvlc/LibVlcUtil.java     |  56 ++++++-
 .../org/videolan/libvlc/NativeCrashHandler.java    |  64 +++++++
 .../src/org/videolan/vlc/VLCApplication.java       |  15 +-
 .../src/org/videolan/vlc/audio/AudioService.java   |  14 +-
 .../org/videolan/vlc/gui/PreferencesActivity.java  |   2 +-
 .../vlc/gui/video/VideoPlayerActivity.java         |   9 +-
 .../src/org/videolan/vlc/util/VLCInstance.java     |  14 +-
 17 files changed, 399 insertions(+), 323 deletions(-)
 create mode 100644 libvlc/src/org/videolan/libvlc/NativeCrashHandler.java

diff --git a/libvlc/jni/libvlcjni-equalizer.c b/libvlc/jni/libvlcjni-equalizer.c
index 2dad0e4..d11f24d 100644
--- a/libvlc/jni/libvlcjni-equalizer.c
+++ b/libvlc/jni/libvlcjni-equalizer.c
@@ -89,10 +89,10 @@ jfloatArray Java_org_videolan_libvlc_LibVLC_getPreset(JNIEnv *env, jobject thiz,
  * apply equalizer settings (param bands is float[] (first element is preamp, then bands))
  */
 //"--audio-filter=equalizer", "--equalizer-bands=-3.5 -4.5 -1 0 0 5 8 8 8 8",
-jint Java_org_videolan_libvlc_LibVLC_setNativeEqualizer(JNIEnv *env, jobject thiz, jlong media_player, jfloatArray bands)
+jint Java_org_videolan_libvlc_LibVLC_setNativeEqualizer(JNIEnv *env, jobject thiz, jfloatArray bands)
 {
     jint res = -1;
-    libvlc_media_player_t *mp = (libvlc_media_player_t*)(intptr_t)media_player;
+    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
     if (!mp)
         return res;
 
diff --git a/libvlc/jni/libvlcjni-util.c b/libvlc/jni/libvlcjni-util.c
index 205d59d..67c2554 100644
--- a/libvlc/jni/libvlcjni-util.c
+++ b/libvlc/jni/libvlcjni-util.c
@@ -131,23 +131,6 @@ void arrayListStringAdd(JNIEnv *env, jclass class, jmethodID methodID, jobject a
     (*env)->DeleteLocalRef(env, jstr);
 }
 
-jobject getEventHandlerReference(JNIEnv *env, jobject thiz, jobject eventHandler)
-{
-    jclass cls = (*env)->GetObjectClass(env, eventHandler);
-    if (!cls) {
-        LOGE("setEventHandler: failed to get class reference");
-        return NULL;
-    }
-
-    jmethodID methodID = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;)V");
-    if (!methodID) {
-        LOGE("setEventHandler: failed to get the callback method");
-        return NULL;
-    }
-
-    return (*env)->NewGlobalRef(env, eventHandler);
-}
-
 static void debug_buffer_log(void *data, int level, const char *fmt, va_list ap)
 {
     bool isAttached = false;
diff --git a/libvlc/jni/libvlcjni.c b/libvlc/jni/libvlcjni.c
index ecfb02e..6f35182 100644
--- a/libvlc/jni/libvlcjni.c
+++ b/libvlc/jni/libvlcjni.c
@@ -38,7 +38,6 @@
 #include "aout.h"
 #include "vout.h"
 #include "utils.h"
-#include "native_crash_handler.h"
 
 #define VOUT_ANDROID_SURFACE 0
 #define VOUT_OPENGLES2       1
@@ -60,6 +59,26 @@ int jni_attach_thread(JNIEnv **env, const char *thread_name);
 void jni_detach_thread();
 int jni_get_env(JNIEnv **env);
 
+static void setLibVlcSysInstance(JNIEnv *env, jobject thiz, libvlc_instance_sys_t *p_sys)
+{
+    setLong(env, thiz, "mLibVlcInstance", (jlong)(intptr_t) p_sys);
+}
+
+static libvlc_instance_sys_t *getLibVlcSysInstance(JNIEnv *env, jobject thiz)
+{
+    return (libvlc_instance_sys_t *)(intptr_t)getLong(env, thiz, "mLibVlcInstance");
+}
+
+static void releaseMediaPlayer(JNIEnv *env, jobject thiz)
+{
+    libvlc_media_player_t *p_mp = getMediaPlayer(env, thiz);
+    if (p_mp)
+    {
+        libvlc_media_player_stop(p_mp);
+        libvlc_media_player_release(p_mp);
+    }
+}
+
 static void add_media_options(libvlc_media_t *p_md, JNIEnv *env, jobjectArray mediaOptions)
 {
     int stringCount = (*env)->GetArrayLength(env, mediaOptions);
@@ -98,24 +117,20 @@ libvlc_media_t *new_media(JNIEnv *env, jobject thiz, jstring fileLocation, bool
 
 libvlc_instance_t *getLibVlcInstance(JNIEnv *env, jobject thiz)
 {
-    return (libvlc_instance_t*)(intptr_t)getLong(env, thiz, "mLibVlcInstance");
+    libvlc_instance_sys_t *p_sys = getLibVlcSysInstance(env, thiz);
+    return p_sys ? p_sys->p_libvlc : NULL;
 }
 
-libvlc_media_player_t *getMediaPlayer(JNIEnv *env, jobject thiz)
+android_surf_value_t *getAndroidSurfaceInstance(JNIEnv *env, jobject thiz)
 {
-    return (libvlc_media_player_t*)(intptr_t)getLong(env, thiz, "mInternalMediaPlayerInstance");
+    libvlc_instance_sys_t *p_sys = getLibVlcSysInstance(env, thiz);
+    return p_sys ? p_sys->p_surf : NULL;
 }
 
-
-static void releaseMediaPlayer(JNIEnv *env, jobject thiz)
+libvlc_media_player_t *getMediaPlayer(JNIEnv *env, jobject thiz)
 {
-    libvlc_media_player_t* p_mp = getMediaPlayer(env, thiz);
-    if (p_mp)
-    {
-        libvlc_media_player_stop(p_mp);
-        libvlc_media_player_release(p_mp);
-        setLong(env, thiz, "mInternalMediaPlayerInstance", 0);
-    }
+    libvlc_instance_sys_t *p_sys = getLibVlcSysInstance(env, thiz);
+    return p_sys ? p_sys->p_mp : NULL;
 }
 
 /* Pointer to the Java virtual machine
@@ -124,17 +139,12 @@ static void releaseMediaPlayer(JNIEnv *env, jobject thiz)
  */
 static JavaVM *myVm;
 
-static jobject eventHandlerInstance = NULL;
-
 static void vlc_event_callback(const libvlc_event_t *ev, void *data)
 {
     JNIEnv *env;
 
     bool isAttached = false;
 
-    if (eventHandlerInstance == NULL)
-        return;
-
     if (jni_get_env(&env) < 0) {
         if (jni_attach_thread(&env, THREAD_NAME) < 0)
             return;
@@ -193,20 +203,31 @@ static void vlc_event_callback(const libvlc_event_t *ev, void *data)
         free(mrl);
     }
 
+    /* The LibVLC object */
+    jobject vlcObject = (jobject) data;
+
+    /* Get the event handler object */
+    jclass cls = (*env)->GetObjectClass(env, vlcObject);
+    jmethodID methodId = (*env)->GetMethodID(env, cls, "getEventHandler", "()Lorg/videolan/libvlc/EventHandler;");
+    jobject eventHandlerInstance = (*env)->CallObjectMethod(env, vlcObject, methodId);
+
+    (*env)->DeleteLocalRef(env, cls);
+
     /* Get the object class */
-    jclass cls = (*env)->GetObjectClass(env, eventHandlerInstance);
+    cls = (*env)->GetObjectClass(env, eventHandlerInstance);
     if (!cls) {
         LOGE("EventHandler: failed to get class reference");
         goto end;
     }
 
     /* Find the callback ID */
-    jmethodID methodID = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;)V");
-    if (methodID) {
-        (*env)->CallVoidMethod(env, eventHandlerInstance, methodID, ev->type, bundle);
+    methodId = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;)V");
+    if (methodId) {
+        (*env)->CallVoidMethod(env, eventHandlerInstance, methodId, ev->type, bundle);
     } else {
         LOGE("EventHandler: failed to get the callback method");
     }
+    (*env)->DeleteLocalRef(env, cls);
 
 end:
     (*env)->DeleteLocalRef(env, bundle);
@@ -219,16 +240,12 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved)
     // Keep a reference on the Java VM.
     myVm = vm;
 
-    pthread_mutex_init(&vout_android_lock, NULL);
-    pthread_cond_init(&vout_android_surf_attached, NULL);
-
     LOGD("JNI interface loaded.");
     return VLC_JNI_VERSION;
 }
 
 void JNI_OnUnload(JavaVM* vm, void* reserved) {
-    pthread_mutex_destroy(&vout_android_lock);
-    pthread_cond_destroy(&vout_android_surf_attached);
+    LOGD("JNI interface un-loaded.");
 }
 
 int jni_attach_thread(JNIEnv **env, const char *thread_name)
@@ -353,8 +370,6 @@ void Java_org_videolan_libvlc_LibVLC_nativeInit(JNIEnv *env, jobject thiz)
     };
     libvlc_instance_t *instance = libvlc_new(sizeof(argv) / sizeof(*argv), argv);
 
-    setLong(env, thiz, "mLibVlcInstance", (jlong)(intptr_t) instance);
-
     (*env)->ReleaseStringUTFChars(env, chroma, chromastr);
     (*env)->ReleaseStringUTFChars(env, subsencoding, subsencodingstr);
 
@@ -364,45 +379,45 @@ void Java_org_videolan_libvlc_LibVLC_nativeInit(JNIEnv *env, jobject thiz)
         (*env)->ThrowNew(env, exc, "Unable to instantiate LibVLC");
     }
 
+    /* Set values to libvlc sys instance */
+    libvlc_instance_sys_t  *p_sys = (libvlc_instance_sys_t *) calloc(1, sizeof(libvlc_instance_sys_t));
+    p_sys->p_libvlc = instance;
+    p_sys->p_surf = (android_surf_value_t *) calloc(1, sizeof(android_surf_value_t));
+    p_sys->p_this = (*env)->NewGlobalRef(env, thiz);
+
+    pthread_mutex_init(&p_sys->p_surf->vout_android_lock, NULL);
+    pthread_cond_init(&p_sys->p_surf->vout_android_surf_attached, NULL);
+
+    setLibVlcSysInstance(env, thiz, p_sys);
+
     LOGI("LibVLC initialized: %p", instance);
 
     libvlc_log_set(instance, debug_log, &verbosity);
-
-    init_native_crash_handler(env, thiz);
 }
 
 void Java_org_videolan_libvlc_LibVLC_nativeDestroy(JNIEnv *env, jobject thiz)
 {
-    destroy_native_crash_handler(env);
+    libvlc_instance_sys_t *p_sys = getLibVlcSysInstance(env, thiz);
+    if (p_sys == NULL)
+        return; // Already destroyed
 
     releaseMediaPlayer(env, thiz);
-    jlong libVlcInstance = getLong(env, thiz, "mLibVlcInstance");
-    if (!libVlcInstance)
-        return; // Already destroyed
 
-    libvlc_instance_t *instance = (libvlc_instance_t*)(intptr_t) libVlcInstance;
+    libvlc_instance_t *instance = p_sys->p_libvlc;
+    LOGI("LibVLC destroyed: %p", instance);
+
     libvlc_log_unset(instance);
     libvlc_release(instance);
 
-    setLong(env, thiz, "mLibVlcInstance", 0);
-}
+    (*env)->DeleteGlobalRef(env, p_sys->p_this);
 
-void Java_org_videolan_libvlc_LibVLC_detachEventHandler(JNIEnv *env, jobject thiz)
-{
-    if (eventHandlerInstance != NULL) {
-        (*env)->DeleteGlobalRef(env, eventHandlerInstance);
-        eventHandlerInstance = NULL;
-    }
-}
+    pthread_mutex_destroy(&p_sys->p_surf->vout_android_lock);
+    pthread_cond_destroy(&p_sys->p_surf->vout_android_surf_attached);
 
-void Java_org_videolan_libvlc_LibVLC_setEventHandler(JNIEnv *env, jobject thiz, jobject eventHandler)
-{
-    if (eventHandlerInstance != NULL) {
-        (*env)->DeleteGlobalRef(env, eventHandlerInstance);
-        eventHandlerInstance = NULL;
-    }
+    free(p_sys->p_surf);
+    free(p_sys);
 
-    eventHandlerInstance = getEventHandlerReference(env, thiz, eventHandler);
+    setLibVlcSysInstance(env, thiz, NULL);
 }
 
 void Java_org_videolan_libvlc_LibVLC_playMRL(JNIEnv *env, jobject thiz,
@@ -411,25 +426,24 @@ void Java_org_videolan_libvlc_LibVLC_playMRL(JNIEnv *env, jobject thiz,
     /* Release previous media player, if any */
     releaseMediaPlayer(env, thiz);
 
-    libvlc_instance_t *p_instance = getLibVlcInstance(env, thiz);
+    libvlc_instance_sys_t *p_sys = getLibVlcSysInstance(env, thiz);
 
     /* Create a media player playing environment */
-    libvlc_media_player_t *mp = libvlc_media_player_new(p_instance);
-    libvlc_media_player_set_video_title_display(mp, libvlc_position_disable, 0);
-    jobject myJavaLibVLC = (*env)->NewGlobalRef(env, thiz);
+    p_sys->p_mp = libvlc_media_player_new(p_sys->p_libvlc);
+
+    libvlc_media_player_set_video_title_display(p_sys->p_mp, libvlc_position_disable, 0);
 
     //if AOUT_AUDIOTRACK_JAVA, we use amem
     jclass cls = (*env)->GetObjectClass(env, thiz);
     jmethodID methodId = (*env)->GetMethodID(env, cls, "getAout", "()I");
     if ( (*env)->CallIntMethod(env, thiz, methodId) == AOUT_AUDIOTRACK_JAVA )
     {
-        libvlc_audio_set_callbacks(mp, aout_play, aout_pause, NULL, NULL, NULL,
-                                   (void*) myJavaLibVLC);
-        libvlc_audio_set_format_callbacks(mp, aout_open, aout_close);
+        libvlc_audio_set_callbacks(p_sys->p_mp, aout_play, aout_pause, NULL, NULL, NULL, p_sys->p_this);
+        libvlc_audio_set_format_callbacks(p_sys->p_mp, aout_open, aout_close);
     }
 
     /* Connect the event manager */
-    libvlc_event_manager_t *ev = libvlc_media_player_event_manager(mp);
+    libvlc_event_manager_t *ev = libvlc_media_player_event_manager(p_sys->p_mp);
     static const libvlc_event_type_t mp_events[] = {
         libvlc_MediaPlayerPlaying,
         libvlc_MediaPlayerPaused,
@@ -441,10 +455,7 @@ void Java_org_videolan_libvlc_LibVLC_playMRL(JNIEnv *env, jobject thiz,
         libvlc_MediaPlayerEncounteredError
     };
     for(int i = 0; i < (sizeof(mp_events) / sizeof(*mp_events)); i++)
-        libvlc_event_attach(ev, mp_events[i], vlc_event_callback, myVm);
-
-    /* Keep a pointer to this media player */
-    setLong(env, thiz, "mInternalMediaPlayerInstance", (jlong)(intptr_t)mp);
+        libvlc_event_attach(ev, mp_events[i], vlc_event_callback, p_sys->p_this);
 
     cls = (*env)->GetObjectClass(env, thiz);
     jmethodID methodID = (*env)->GetMethodID(env, cls, "applyEqualizer", "()V");
@@ -452,13 +463,16 @@ void Java_org_videolan_libvlc_LibVLC_playMRL(JNIEnv *env, jobject thiz,
 
     const char* p_mrl = (*env)->GetStringUTFChars(env, mrl, 0);
 
-    libvlc_media_t* p_md = libvlc_media_new_location(p_instance, p_mrl);
+    libvlc_media_t* p_md = libvlc_media_new_location(p_sys->p_libvlc, p_mrl);
     /* media options */
     if (mediaOptions != NULL)
         add_media_options(p_md, env, mediaOptions);
 
     (*env)->ReleaseStringUTFChars(env, mrl, p_mrl);
 
+    /* set the Android surface value structure before playing */
+    libvlc_media_player_set_androidobject(p_sys->p_mp, p_sys->p_surf);
+
     /* Connect the media event manager. */
     libvlc_event_manager_t *ev_media = libvlc_media_event_manager(p_md);
     static const libvlc_event_type_t mp_media_events[] = {
@@ -466,10 +480,10 @@ void Java_org_videolan_libvlc_LibVLC_playMRL(JNIEnv *env, jobject thiz,
         libvlc_MediaMetaChanged,
     };
     for(int i = 0; i < (sizeof(mp_media_events) / sizeof(*mp_media_events)); i++)
-        libvlc_event_attach(ev_media, mp_media_events[i], vlc_event_callback, myVm);
+        libvlc_event_attach(ev_media, mp_media_events[i], vlc_event_callback, p_sys->p_this);
 
-    libvlc_media_player_set_media(mp, p_md);
-    libvlc_media_player_play(mp);
+    libvlc_media_player_set_media(p_sys->p_mp, p_md);
+    libvlc_media_player_play(p_sys->p_mp);
 }
 
 jfloat Java_org_videolan_libvlc_LibVLC_getRate(JNIEnv *env, jobject thiz) {
@@ -654,23 +668,26 @@ void Java_org_videolan_libvlc_LibVLC_playerNavigate(JNIEnv *env, jobject thiz, j
         libvlc_media_player_navigate(mp, (unsigned) nav);
 }
 
-// TODO: remove static variables
-static int i_window_width = 0;
-static int i_window_height = 0;
-
 void Java_org_videolan_libvlc_LibVLC_setWindowSize(JNIEnv *env, jobject thiz, jint width, jint height)
 {
-    pthread_mutex_lock(&vout_android_lock);
-    i_window_width = width;
-    i_window_height = height;
-    pthread_mutex_unlock(&vout_android_lock);
+    android_surf_value_t *android_surface = getAndroidSurfaceInstance(env, thiz);
+    if (android_surface == NULL)
+        return;
+
+    pthread_mutex_lock(&android_surface->vout_android_lock);
+    android_surface->i_window_width = width;
+    android_surface->i_window_height = height;
+    pthread_mutex_unlock(&android_surface->vout_android_lock);
 }
 
-int jni_GetWindowSize(int *width, int *height)
+int jni_GetWindowSize(android_surf_value_t *android_surface, int *width, int *height)
 {
-    pthread_mutex_lock(&vout_android_lock);
-    *width = i_window_width;
-    *height = i_window_height;
-    pthread_mutex_unlock(&vout_android_lock);
+    if (android_surface == NULL)
+        return;
+
+    pthread_mutex_lock(&android_surface->vout_android_lock);
+    *width = android_surface->i_window_width;
+    *height = android_surface->i_window_height;
+    pthread_mutex_unlock(&android_surface->vout_android_lock);
     return 0;
 }
diff --git a/libvlc/jni/native_crash_handler.c b/libvlc/jni/native_crash_handler.c
index 2cb1590..73b1e1e 100644
--- a/libvlc/jni/native_crash_handler.c
+++ b/libvlc/jni/native_crash_handler.c
@@ -23,7 +23,7 @@
 #include "native_crash_handler.h"
 
 static struct sigaction old_actions[NSIG];
-static jobject j_libVLC;
+static jobject j_NativeCrashHandler = NULL;
 
 #define THREAD_NAME "native_crash_handler"
 extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
@@ -54,9 +54,9 @@ void sigaction_callback(int signal, siginfo_t *info, void *reserved)
     JNIEnv *env;
     jni_attach_thread(&env, THREAD_NAME);
 
-    jclass cls = (*env)->GetObjectClass(env, j_libVLC);
+    jclass cls = (*env)->GetObjectClass(env, j_NativeCrashHandler);
     jmethodID methodId = (*env)->GetMethodID(env, cls, "onNativeCrash", "()V");
-    (*env)->CallVoidMethod(env, j_libVLC, methodId);
+    (*env)->CallVoidMethod(env, j_NativeCrashHandler, methodId);
 
     (*env)->DeleteLocalRef(env, cls);
     jni_detach_thread();
@@ -65,10 +65,8 @@ void sigaction_callback(int signal, siginfo_t *info, void *reserved)
     old_actions[signal].sa_handler(signal);
 }
 
-
-void init_native_crash_handler(JNIEnv *env, jobject j_libVLC_local)
+void Java_org_videolan_libvlc_NativeCrashHandler_nativeInit(JNIEnv *env, jobject thiz)
 {
-    j_libVLC = (*env)->NewGlobalRef(env, j_libVLC_local);
     struct sigaction handler;
     memset(&handler, 0, sizeof(struct sigaction));
 
@@ -81,17 +79,6 @@ void init_native_crash_handler(JNIEnv *env, jobject j_libVLC_local)
         const int s = monitored_signals[i];
         sigaction(s, &handler, &old_actions[s]);
     }
-}
-
-
-void destroy_native_crash_handler(JNIEnv *env)
-{
-    // Uninstall the signal handlers and restore their old actions.
-    for (unsigned i = 0; i < sizeof(monitored_signals) / sizeof(int); ++i)
-    {
-        const int s = monitored_signals[i];
-        sigaction(s, &old_actions[s], NULL);
-    }
 
-    (*env)->DeleteGlobalRef(env, j_libVLC);
-}
+    j_NativeCrashHandler = (*env)->NewGlobalRef(env, thiz);;
+}
\ No newline at end of file
diff --git a/libvlc/jni/native_crash_handler.h b/libvlc/jni/native_crash_handler.h
index a57e61e..d220af5 100644
--- a/libvlc/jni/native_crash_handler.h
+++ b/libvlc/jni/native_crash_handler.h
@@ -23,7 +23,4 @@
 
 #include <jni.h>
 
-void init_native_crash_handler(JNIEnv *env, jobject j_libVLC_local);
-void destroy_native_crash_handler(JNIEnv *env);
-
-#endif // LIBVLCJNI_NATIVE_CRASH_HANDLER_H
+#endif // LIBVLCJNI_NATIVE_CRASH_HANDLER_H
\ No newline at end of file
diff --git a/libvlc/jni/utils.h b/libvlc/jni/utils.h
index f5b9f8d..e136bcb 100644
--- a/libvlc/jni/utils.h
+++ b/libvlc/jni/utils.h
@@ -43,8 +43,6 @@ void arrayListGetIDs(JNIEnv *env, jclass* p_class, jmethodID* p_add, jmethodID*
 
 void arrayListStringAdd(JNIEnv *env, jclass class, jmethodID methodID, jobject arrayList, const char* str);
 
-jobject getEventHandlerReference(JNIEnv *env, jobject thiz, jobject eventHandler);
-
 void debug_log(void *data, int level, const libvlc_log_t *ctx, const char *fmt, va_list ap);
 
 #endif // LIBVLCJNI_UTILS_H
diff --git a/libvlc/jni/vout.c b/libvlc/jni/vout.c
index 04c933c..7cdc234 100644
--- a/libvlc/jni/vout.c
+++ b/libvlc/jni/vout.c
@@ -22,100 +22,104 @@
 #include <vlc_common.h>
 
 #include <jni.h>
+#include "vout.h"
+
+#define LOG_TAG "VLC/JNI/vout"
+#include "log.h"
 
 #define THREAD_NAME "jni_vout"
 extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
 extern void jni_detach_thread();
 extern int jni_get_env(JNIEnv **env);
 
-pthread_mutex_t vout_android_lock;
-pthread_cond_t vout_android_surf_attached;
-static void *vout_android_gui = NULL;
-static jobject vout_android_java_surf = NULL;
-static jobject vout_android_subtitles_surf = NULL;
-static bool vout_video_player_activity_created = false;
-
-void *jni_LockAndGetSubtitlesSurface() {
-    pthread_mutex_lock(&vout_android_lock);
-    while (vout_android_subtitles_surf == NULL)
-        pthread_cond_wait(&vout_android_surf_attached, &vout_android_lock);
-    return vout_android_subtitles_surf;
+void *jni_LockAndGetSubtitlesSurface(android_surf_value_t *android_surface) {
+    pthread_mutex_lock(&android_surface->vout_android_lock);
+    while (android_surface->vout_android_subtitles_surf == NULL)
+        pthread_cond_wait(&android_surface->vout_android_surf_attached, &android_surface->vout_android_lock);
+    return android_surface->vout_android_subtitles_surf;
+}
+
+jobject jni_LockAndGetAndroidJavaSurface(android_surf_value_t *android_surface) {
+    pthread_mutex_lock(&android_surface->vout_android_lock);
+    while (android_surface->vout_android_java_surf == NULL)
+        pthread_cond_wait(&android_surface->vout_android_surf_attached, &android_surface->vout_android_lock);
+    return android_surface->vout_android_java_surf;
 }
 
-jobject jni_LockAndGetAndroidJavaSurface() {
-    pthread_mutex_lock(&vout_android_lock);
-    while (vout_android_java_surf == NULL)
-        pthread_cond_wait(&vout_android_surf_attached, &vout_android_lock);
-    return vout_android_java_surf;
+void jni_LockAndroidSurface(android_surf_value_t *android_surface) {
+    pthread_mutex_lock(&android_surface->vout_android_lock);
 }
 
-void jni_UnlockAndroidSurface() {
-    pthread_mutex_unlock(&vout_android_lock);
+void jni_UnlockAndroidSurface(android_surf_value_t *android_surface) {
+    pthread_mutex_unlock(&android_surface->vout_android_lock);
 }
 
-void jni_EventHardwareAccelerationError()
+void jni_EventHardwareAccelerationError(android_surf_value_t *android_surface)
 {
     JNIEnv *env;
     bool isAttached = false;
 
-    pthread_mutex_lock(&vout_android_lock);
-    if (vout_android_gui == NULL) {
-        pthread_mutex_unlock(&vout_android_lock);
+    pthread_mutex_lock(&android_surface->vout_android_lock);
+    if (android_surface->vout_android_gui == NULL) {
+        pthread_mutex_unlock(&android_surface->vout_android_lock);
         return;
     }
 
     if (jni_get_env(&env) < 0) {
         if (jni_attach_thread(&env, THREAD_NAME) < 0) {
-            pthread_mutex_unlock(&vout_android_lock);
+            pthread_mutex_unlock(&android_surface->vout_android_lock);
             return;
         }
         isAttached = true;
     }
 
-    jclass cls = (*env)->GetObjectClass(env, vout_android_gui);
+    jclass cls = (*env)->GetObjectClass(env, android_surface->vout_android_gui);
     jmethodID methodId = (*env)->GetMethodID(env, cls, "eventHardwareAccelerationError", "()V");
-    (*env)->CallVoidMethod(env, vout_android_gui, methodId);
+    (*env)->CallVoidMethod(env, android_surface->vout_android_gui, methodId);
 
     (*env)->DeleteLocalRef(env, cls);
     if (isAttached)
         jni_detach_thread();
-    pthread_mutex_unlock(&vout_android_lock);
+    pthread_mutex_unlock(&android_surface->vout_android_lock);
 }
 
-static void jni_SetSurfaceLayoutEnv(JNIEnv *p_env, int width, int height, int visible_width, int visible_height, int sar_num, int sar_den)
+void jni_SetSurfaceLayoutEnv(JNIEnv *p_env, android_surf_value_t *android_surface, int width, int height, int visible_width, int visible_height, int sar_num, int sar_den)
 {
-    pthread_mutex_lock(&vout_android_lock);
-    if (vout_android_gui == NULL) {
-        pthread_mutex_unlock(&vout_android_lock);
+    pthread_mutex_lock(&android_surface->vout_android_lock);
+    if (android_surface->vout_android_gui == NULL) {
+        pthread_mutex_unlock(&android_surface->vout_android_lock);
         return;
     }
 
-    jclass cls = (*p_env)->GetObjectClass (p_env, vout_android_gui);
+    jclass cls = (*p_env)->GetObjectClass (p_env, android_surface->vout_android_gui);
     jmethodID methodId = (*p_env)->GetMethodID (p_env, cls, "setSurfaceLayout", "(IIIIII)V");
 
-    (*p_env)->CallVoidMethod (p_env, vout_android_gui, methodId, width, height, visible_width, visible_height, sar_num, sar_den);
+    (*p_env)->CallVoidMethod (p_env, android_surface->vout_android_gui, methodId, width, height, visible_width, visible_height, sar_num, sar_den);
 
     (*p_env)->DeleteLocalRef(p_env, cls);
-    pthread_mutex_unlock(&vout_android_lock);
+    pthread_mutex_unlock(&android_surface->vout_android_lock);
 }
 
-void jni_SetSurfaceLayout(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den)
+void jni_SetSurfaceLayout(android_surf_value_t *android_surface, int width, int height, int visible_width, int visible_height, int sar_num, int sar_den)
 {
     JNIEnv *p_env;
     bool isAttached = false;
 
+    if (android_surface == NULL)
+        return;
+
     if (jni_get_env(&p_env) < 0) {
         if (jni_attach_thread(&p_env, THREAD_NAME) < 0)
             return;
         isAttached = true;
     }
-    jni_SetSurfaceLayoutEnv(p_env, width, height, visible_width, visible_height, sar_num, sar_den);
+    jni_SetSurfaceLayoutEnv(p_env, android_surface, width, height, visible_width, visible_height, sar_num, sar_den);
 
     if (isAttached)
         jni_detach_thread();
 }
 
-void *jni_AndroidJavaSurfaceToNativeSurface(jobject *surf)
+void *jni_AndroidJavaSurfaceToNativeSurface(jobject surf)
 {
     JNIEnv *p_env;
     jclass clz;
@@ -154,28 +158,29 @@ void *jni_AndroidJavaSurfaceToNativeSurface(jobject *surf)
     return native_surface;
 }
 
-int jni_ConfigureSurface(jobject jsurf, int width, int height, int hal, bool *configured)
+int jni_ConfigureSurface(android_surf_value_t *android_surface, int width, int height, int hal, bool *configured)
 {
     JNIEnv *p_env;
     bool isAttached = false;
     int ret;
 
-    pthread_mutex_lock(&vout_android_lock);
-    if (vout_android_gui == NULL) {
-        pthread_mutex_unlock(&vout_android_lock);
+    pthread_mutex_lock(&android_surface->vout_android_lock);
+    if (android_surface->vout_android_gui == NULL) {
+        pthread_mutex_unlock(&android_surface->vout_android_lock);
         return -1;
     }
 
     if (jni_get_env(&p_env) < 0) {
         if (jni_attach_thread(&p_env, THREAD_NAME) < 0) {
-            pthread_mutex_unlock(&vout_android_lock);
+            pthread_mutex_unlock(&android_surface->vout_android_lock);
             return -1;
         }
         isAttached = true;
     }
-    jclass clz = (*p_env)->GetObjectClass (p_env, vout_android_gui);
+    jclass clz = (*p_env)->GetObjectClass (p_env, android_surface->vout_android_gui);
     jmethodID methodId = (*p_env)->GetMethodID (p_env, clz, "configureSurface", "(Landroid/view/Surface;III)I");
-    ret = (*p_env)->CallIntMethod (p_env, vout_android_gui, methodId, jsurf, width, height, hal);
+    ret = (*p_env)->CallIntMethod (p_env, android_surface->vout_android_gui, methodId,
+                                   android_surface->vout_android_java_surf, width, height, hal);
     if (ret >= 0 && configured)
         *configured = ret == 1;
 
@@ -183,62 +188,81 @@ int jni_ConfigureSurface(jobject jsurf, int width, int height, int hal, bool *co
 
     if (isAttached)
         jni_detach_thread();
-    pthread_mutex_unlock(&vout_android_lock);
+    pthread_mutex_unlock(&android_surface->vout_android_lock);
     return ret == -1 ? -1 : 0;
 }
 
-bool jni_IsVideoPlayerActivityCreated() {
-    pthread_mutex_lock(&vout_android_lock);
-    bool result = vout_video_player_activity_created;
-    pthread_mutex_unlock(&vout_android_lock);
+bool jni_IsVideoPlayerActivityCreated(android_surf_value_t *android_surface) {
+    pthread_mutex_lock(&android_surface->vout_android_lock);
+    bool result = android_surface->vout_video_player_activity_created;
+    pthread_mutex_unlock(&android_surface->vout_android_lock);
     return result;
 }
 
 void Java_org_videolan_libvlc_LibVLC_eventVideoPlayerActivityCreated(JNIEnv *env, jobject thiz, jboolean created) {
-    pthread_mutex_lock(&vout_android_lock);
-    vout_video_player_activity_created = created;
-    pthread_mutex_unlock(&vout_android_lock);
+    android_surf_value_t * android_surface = getAndroidSurfaceInstance(env, thiz);
+    if (android_surface == NULL)
+        return;
+
+    pthread_mutex_lock(&android_surface->vout_android_lock);
+    android_surface->vout_video_player_activity_created = created;
+    pthread_mutex_unlock(&android_surface->vout_android_lock);
 }
 
 void Java_org_videolan_libvlc_LibVLC_attachSurface(JNIEnv *env, jobject thiz, jobject surf, jobject gui) {
-    pthread_mutex_lock(&vout_android_lock);
-
-    if (vout_android_gui != NULL)
-        (*env)->DeleteGlobalRef(env, vout_android_gui);
-    if (vout_android_java_surf != NULL)
-        (*env)->DeleteGlobalRef(env, vout_android_java_surf);
-    vout_android_gui = (*env)->NewGlobalRef(env, gui);
-    vout_android_java_surf = (*env)->NewGlobalRef(env, surf);
-    pthread_cond_signal(&vout_android_surf_attached);
-    pthread_mutex_unlock(&vout_android_lock);
+    android_surf_value_t * android_surface = getAndroidSurfaceInstance(env, thiz);
+    if (android_surface == NULL)
+        return;
+
+    pthread_mutex_lock(&android_surface->vout_android_lock);
+    if (android_surface->vout_android_gui != NULL)
+        (*env)->DeleteGlobalRef(env, android_surface->vout_android_gui);
+    if (android_surface->vout_android_java_surf != NULL)
+        (*env)->DeleteGlobalRef(env, android_surface->vout_android_java_surf);
+    android_surface->vout_android_gui = (*env)->NewGlobalRef(env, gui);
+    android_surface->vout_android_java_surf = (*env)->NewGlobalRef(env, surf);
+    pthread_cond_signal(&android_surface->vout_android_surf_attached);
+    pthread_mutex_unlock(&android_surface->vout_android_lock);
 }
 
 void Java_org_videolan_libvlc_LibVLC_detachSurface(JNIEnv *env, jobject thiz) {
-    pthread_mutex_lock(&vout_android_lock);
-    if (vout_android_gui != NULL)
-        (*env)->DeleteGlobalRef(env, vout_android_gui);
-    if (vout_android_java_surf != NULL)
-        (*env)->DeleteGlobalRef(env, vout_android_java_surf);
-    vout_android_gui = NULL;
-    vout_android_java_surf = NULL;
-    pthread_mutex_unlock(&vout_android_lock);
+    android_surf_value_t * android_surface = getAndroidSurfaceInstance(env, thiz);
+    if (android_surface == NULL)
+        return;
+
+    pthread_mutex_lock(&android_surface->vout_android_lock);
+    if (android_surface->vout_android_gui != NULL)
+        (*env)->DeleteGlobalRef(env, android_surface->vout_android_gui);
+    if (android_surface->vout_android_java_surf != NULL)
+        (*env)->DeleteGlobalRef(env, android_surface->vout_android_java_surf);
+    android_surface->vout_android_gui = NULL;
+    android_surface->vout_android_java_surf = NULL;
+    pthread_mutex_unlock(&android_surface->vout_android_lock);
 }
 
 void Java_org_videolan_libvlc_LibVLC_attachSubtitlesSurface(JNIEnv *env, jobject thiz, jobject surf) {
-    pthread_mutex_lock(&vout_android_lock);
-    if (vout_android_subtitles_surf != NULL)
-        (*env)->DeleteGlobalRef(env, vout_android_subtitles_surf);
-    vout_android_subtitles_surf = (*env)->NewGlobalRef(env, surf);
-    pthread_cond_signal(&vout_android_surf_attached);
-    pthread_mutex_unlock(&vout_android_lock);
+    android_surf_value_t * android_surface = getAndroidSurfaceInstance(env, thiz);
+    if (android_surface == NULL)
+        return;
+
+    pthread_mutex_lock(&android_surface->vout_android_lock);
+    if (android_surface->vout_android_subtitles_surf != NULL)
+        (*env)->DeleteGlobalRef(env, android_surface->vout_android_subtitles_surf);
+    android_surface->vout_android_subtitles_surf = (*env)->NewGlobalRef(env, surf);
+    pthread_cond_signal(&android_surface->vout_android_surf_attached);
+    pthread_mutex_unlock(&android_surface->vout_android_lock);
 }
 
 void Java_org_videolan_libvlc_LibVLC_detachSubtitlesSurface(JNIEnv *env, jobject thiz) {
-    pthread_mutex_lock(&vout_android_lock);
-    if (vout_android_subtitles_surf != NULL)
-        (*env)->DeleteGlobalRef(env, vout_android_subtitles_surf);
-    vout_android_subtitles_surf = NULL;
-    pthread_mutex_unlock(&vout_android_lock);
+    android_surf_value_t * android_surface = getAndroidSurfaceInstance(env, thiz);
+    if (android_surface == NULL)
+        return;
+
+    pthread_mutex_lock(&android_surface->vout_android_lock);
+    if (android_surface->vout_android_subtitles_surf != NULL)
+        (*env)->DeleteGlobalRef(env, android_surface->vout_android_subtitles_surf);
+    android_surface->vout_android_subtitles_surf = NULL;
+    pthread_mutex_unlock(&android_surface->vout_android_lock);
 }
 
 static int mouse_x = -1;
diff --git a/libvlc/jni/vout.h b/libvlc/jni/vout.h
index c3d4fd7..ac13413 100644
--- a/libvlc/jni/vout.h
+++ b/libvlc/jni/vout.h
@@ -21,8 +21,26 @@
 #ifndef LIBVLCJNI_VOUT_H
 #define LIBVLCJNI_VOUT_H
 
-/* vout lock initialized in vout.c */
-pthread_mutex_t vout_android_lock;
-pthread_cond_t vout_android_surf_attached;
+#include <pthread.h>
+
+typedef struct android_surf_value_t {
+    pthread_mutex_t   vout_android_lock;
+    pthread_cond_t    vout_android_surf_attached;
+    void             *vout_android_gui;
+    jobject           vout_android_java_surf;
+    jobject           vout_android_subtitles_surf;
+    bool              vout_video_player_activity_created;
+    int               i_window_width;
+    int               i_window_height;
+} android_surf_value_t;
+
+typedef struct libvlc_instance_sys_t {
+    void                    *p_this;
+    libvlc_instance_t       *p_libvlc;
+    libvlc_media_player_t   *p_mp;
+    android_surf_value_t    *p_surf;
+} libvlc_instance_sys_t;
+
+android_surf_value_t *getAndroidSurfaceInstance(JNIEnv *env, jobject thiz);
 
 #endif // LIBVLCJNI_VOUT_H
diff --git a/libvlc/src/org/videolan/libvlc/EventHandler.java b/libvlc/src/org/videolan/libvlc/EventHandler.java
index 4ec0861..2d13d30 100644
--- a/libvlc/src/org/videolan/libvlc/EventHandler.java
+++ b/libvlc/src/org/videolan/libvlc/EventHandler.java
@@ -97,19 +97,11 @@ public class EventHandler {
     public static final int HardwareAccelerationError         = 0x3000;
 
     private ArrayList<Handler> mEventHandler;
-    private static EventHandler mInstance;
 
     EventHandler() {
         mEventHandler = new ArrayList<Handler>();
     }
 
-    public static EventHandler getInstance() {
-        if (mInstance == null) {
-            mInstance = new EventHandler();
-        }
-        return mInstance;
-    }
-
     public void addHandler(Handler handler) {
         if (!mEventHandler.contains(handler))
             mEventHandler.add(handler);
diff --git a/libvlc/src/org/videolan/libvlc/LibVLC.java b/libvlc/src/org/videolan/libvlc/LibVLC.java
index fde2704..aaf640f 100644
--- a/libvlc/src/org/videolan/libvlc/LibVLC.java
+++ b/libvlc/src/org/videolan/libvlc/LibVLC.java
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * LibVLC.java
  *****************************************************************************
- * Copyright © 2010-2013 VLC authors and VideoLAN
+ * Copyright © 2010-2014 VLC authors and VideoLAN
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -25,7 +25,6 @@ import java.util.ArrayList;
 import java.util.Map;
 
 import android.content.Context;
-import android.os.Build;
 import android.util.Log;
 import android.view.Surface;
 
@@ -61,11 +60,12 @@ public class LibVLC {
 
     private static LibVLC sInstance;
 
+    private final EventHandler eventHandler = new EventHandler();
+
     /** libVLC instance C pointer */
     private long mLibVlcInstance = 0; // Read-only, reserved for JNI
     /** libvlc_media_player pointer and index */
     private int mInternalMediaPlayerIndex = 0; // Read-only, reserved for JNI
-    private long mInternalMediaPlayerInstance = 0; // Read-only, reserved for JNI
 
     private MediaList mMediaList; // Pointer to media list being followed
     private MediaList mPrimaryList; // Primary/default media list; see getPrimaryMediaList()
@@ -99,9 +99,6 @@ public class LibVLC {
     /** Path of application-specific cache */
     private String mCachePath = "";
 
-    /** Native crash handler */
-    private OnNativeCrashListener mOnNativeCrashListener;
-
     /** Check in libVLC already initialized otherwise crash */
     private boolean mIsInitialized = false;
     public native void attachSurface(Surface surface, IVideoPlayer player);
@@ -113,52 +110,6 @@ public class LibVLC {
 
     public native void eventVideoPlayerActivityCreated(boolean created);
 
-    /* Load library before object instantiation */
-    static {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) {
-            try {
-                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR1)
-                    System.loadLibrary("anw.10");
-                else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR2)
-                    System.loadLibrary("anw.13");
-                else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR1)
-                    System.loadLibrary("anw.14");
-                else
-                    System.loadLibrary("anw.18");
-            } catch (Throwable t) {
-                Log.w(TAG, "Unable to load the anw library: " + t);
-            }
-        }
-
-        try {
-            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1)
-                System.loadLibrary("iomx.10");
-            else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR2)
-                System.loadLibrary("iomx.13");
-            else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR1)
-                System.loadLibrary("iomx.14");
-            else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2)
-                System.loadLibrary("iomx.18");
-            else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT)
-                System.loadLibrary("iomx.19");
-        } catch (Throwable t) {
-            // No need to warn if it isn't found, when we intentionally don't build these except for debug
-            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
-                Log.w(TAG, "Unable to load the iomx library: " + t);
-        }
-        try {
-            System.loadLibrary("vlcjni");
-        } catch (UnsatisfiedLinkError ule) {
-            Log.e(TAG, "Can't load vlcjni library: " + ule);
-            /// FIXME Alert user
-            System.exit(1);
-        } catch (SecurityException se) {
-            Log.e(TAG, "Encountered a security issue when loading vlcjni library: " + se);
-            /// FIXME Alert user
-            System.exit(1);
-        }
-    }
-
     /**
      * Singleton constructor of libVLC Without surface and vout to create the
      * thumbnail and get information e.g. on the MediaLibraryActivity
@@ -190,10 +141,9 @@ public class LibVLC {
     }
 
     /**
-     * Constructor
-     * It is private because this class is a singleton.
+     * Constructor.
      */
-    private LibVLC() {
+    public LibVLC() {
         mAout = new AudioOutput();
     }
 
@@ -259,7 +209,7 @@ public class LibVLC {
      */
     public native void setSurface(Surface f);
 
-    public static synchronized void restart(Context context) {
+    public static synchronized void restartInstance(Context context) {
         if (sInstance != null) {
             try {
                 sInstance.destroy();
@@ -270,6 +220,15 @@ public class LibVLC {
         }
     }
 
+    public void restart(Context context) {
+        try {
+            this.destroy();
+            this.init(context);
+        } catch (LibVlcException lve) {
+            Log.e(TAG, "Unable to reinit libvlc: " + lve);
+        }
+    }
+
     /**
      * those get/is* are called from native code to get settings values.
      */
@@ -491,11 +450,11 @@ public class LibVLC {
         applyEqualizer();
     }
 
-    private void applyEqualizer()
+    protected void applyEqualizer()
     {
-        setNativeEqualizer(mInternalMediaPlayerInstance, this.equalizer);
+        setNativeEqualizer(this.equalizer);
     }
-    private native int setNativeEqualizer(long mediaPlayer, float[] bands);
+    private native int setNativeEqualizer(float[] bands);
 
     public boolean frameSkipEnabled() {
         return frameSkip;
@@ -531,7 +490,7 @@ public class LibVLC {
     public void init(Context context) throws LibVlcException {
         Log.v(TAG, "Initializing LibVLC");
         mDebugLogBuffer = new StringBuffer();
-        if (!mIsInitialized) {
+        if (LibVlcUtil.isLibraryLoaded() && !mIsInitialized) {
             if(!LibVlcUtil.hasCompatibleCPU(context)) {
                 Log.e(TAG, LibVlcUtil.getErrorMsg());
                 throw new LibVlcException();
@@ -541,7 +500,6 @@ public class LibVLC {
             mCachePath = (cacheDir != null) ? cacheDir.getAbsolutePath() : null;
             nativeInit();
             mMediaList = mPrimaryList = new MediaList(this);
-            setEventHandler(EventHandler.getInstance());
             mIsInitialized = true;
         }
     }
@@ -553,7 +511,6 @@ public class LibVLC {
     public void destroy() {
         Log.v(TAG, "Destroying LibVLC instance");
         nativeDestroy();
-        detachEventHandler();
         mIsInitialized = false;
     }
 
@@ -833,27 +790,14 @@ public class LibVLC {
         return mMediaList.expandMedia(mInternalMediaPlayerIndex);
     }
 
-    private native void setEventHandler(EventHandler eventHandler);
-
-    private native void detachEventHandler();
-
     public native float[] getBands();
 
     public native String[] getPresets();
 
     public native float[] getPreset(int index);
 
-    public static interface OnNativeCrashListener {
-        public void onNativeCrash();
-    }
-
-    public void setOnNativeCrashListener(OnNativeCrashListener l) {
-        mOnNativeCrashListener = l;
-    }
-
-    private void onNativeCrash() {
-        if (mOnNativeCrashListener != null)
-            mOnNativeCrashListener.onNativeCrash();
+    public EventHandler getEventHandler() {
+        return eventHandler;
     }
 
     public String getCachePath() {
diff --git a/libvlc/src/org/videolan/libvlc/LibVlcUtil.java b/libvlc/src/org/videolan/libvlc/LibVlcUtil.java
index 0ddf780..6c7dc97 100644
--- a/libvlc/src/org/videolan/libvlc/LibVlcUtil.java
+++ b/libvlc/src/org/videolan/libvlc/LibVlcUtil.java
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * LibVlcUtil.java
  *****************************************************************************
- * Copyright © 2011-2013 VLC authors and VideoLAN
+ * Copyright © 2011-2014 VLC authors and VideoLAN
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -39,6 +39,60 @@ import android.util.Log;
 public class LibVlcUtil {
     public final static String TAG = "VLC/LibVLC/Util";
 
+    public static boolean libraryLoaded = false;
+
+    /* Load library before object instantiation */
+    static {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) {
+            try {
+                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR1)
+                    System.loadLibrary("anw.10");
+                else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR2)
+                    System.loadLibrary("anw.13");
+                else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR1)
+                    System.loadLibrary("anw.14");
+                else
+                    System.loadLibrary("anw.18");
+            } catch (Throwable t) {
+                Log.w(TAG, "Unable to load the anw library: " + t);
+            }
+        }
+
+        try {
+            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1)
+                System.loadLibrary("iomx.10");
+            else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR2)
+                System.loadLibrary("iomx.13");
+            else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR1)
+                System.loadLibrary("iomx.14");
+            else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2)
+                System.loadLibrary("iomx.18");
+            else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT)
+                System.loadLibrary("iomx.19");
+        } catch (Throwable t) {
+            // No need to warn if it isn't found, when we intentionally don't build these except for debug
+            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
+                Log.w(TAG, "Unable to load the iomx library: " + t);
+        }
+        try {
+            System.loadLibrary("vlcjni");
+        } catch (UnsatisfiedLinkError ule) {
+            Log.e(TAG, "Can't load vlcjni library: " + ule);
+            /// FIXME Alert user
+            System.exit(1);
+        } catch (SecurityException se) {
+            Log.e(TAG, "Encountered a security issue when loading vlcjni library: " + se);
+            /// FIXME Alert user
+            System.exit(1);
+        }
+
+        libraryLoaded = true;
+    }
+
+    public static boolean isLibraryLoaded() {
+        return libraryLoaded;
+    }
+
     public static boolean isFroyoOrLater()
     {
         return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.FROYO;
diff --git a/libvlc/src/org/videolan/libvlc/NativeCrashHandler.java b/libvlc/src/org/videolan/libvlc/NativeCrashHandler.java
new file mode 100644
index 0000000..ec10698
--- /dev/null
+++ b/libvlc/src/org/videolan/libvlc/NativeCrashHandler.java
@@ -0,0 +1,64 @@
+/*****************************************************************************
+ * NativeCrashHandler.java
+ *****************************************************************************
+ * Copyright © 2014 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+package org.videolan.libvlc;
+
+import android.os.Build;
+import android.util.Log;
+
+public class NativeCrashHandler {
+    public final static String TAG = "VLC/NativeCrashHandler";
+
+    /** Native crash handler */
+    private OnNativeCrashListener mOnNativeCrashListener;
+
+    private static NativeCrashHandler sInstance;
+
+    private NativeCrashHandler() {
+    }
+
+    public static interface OnNativeCrashListener {
+        public void onNativeCrash();
+    }
+
+    public static NativeCrashHandler getInstance() {
+        synchronized (NativeCrashHandler.class) {
+            if (sInstance == null) {
+                /* First call */
+                sInstance = new NativeCrashHandler();
+                if (LibVlcUtil.isLibraryLoaded())
+                    sInstance.nativeInit();
+            }
+        }
+
+        return sInstance;
+    }
+
+    public void setOnNativeCrashListener(OnNativeCrashListener l) {
+        mOnNativeCrashListener = l;
+    }
+
+    public void onNativeCrash() {
+        if (mOnNativeCrashListener != null)
+            mOnNativeCrashListener.onNativeCrash();
+    }
+
+    private native void nativeInit();
+}
\ No newline at end of file
diff --git a/vlc-android/src/org/videolan/vlc/VLCApplication.java b/vlc-android/src/org/videolan/vlc/VLCApplication.java
index e915a46..ba34827 100644
--- a/vlc-android/src/org/videolan/vlc/VLCApplication.java
+++ b/vlc-android/src/org/videolan/vlc/VLCApplication.java
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * VLCApplication.java
  *****************************************************************************
- * Copyright © 2010-2013 VLC authors and VideoLAN
+ * Copyright © 2010-2014 VLC authors and VideoLAN
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,11 +21,14 @@ package org.videolan.vlc;
 
 import java.util.Locale;
 
+import org.videolan.libvlc.NativeCrashHandler;
 import org.videolan.vlc.gui.audio.AudioUtil;
+import org.videolan.vlc.gui.NativeCrashActivity;
 import org.videolan.vlc.util.BitmapCache;
 
 import android.app.Application;
 import android.content.Context;
+import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -81,6 +84,16 @@ public class VLCApplication extends Application {
         MediaDatabase.getInstance();
         // Prepare cache folder constants
         AudioUtil.prepareCacheFolder(this);
+
+        NativeCrashHandler.getInstance().setOnNativeCrashListener(new NativeCrashHandler.OnNativeCrashListener() {
+            @Override
+            public void onNativeCrash() {
+                Intent i = new Intent(instance, NativeCrashActivity.class);
+                i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                i.putExtra("PID", android.os.Process.myPid());
+                instance.startActivity(i);
+            }
+        });
     }
 
     /**
diff --git a/vlc-android/src/org/videolan/vlc/audio/AudioService.java b/vlc-android/src/org/videolan/vlc/audio/AudioService.java
index c33abc8..d039fba 100644
--- a/vlc-android/src/org/videolan/vlc/audio/AudioService.java
+++ b/vlc-android/src/org/videolan/vlc/audio/AudioService.java
@@ -116,7 +116,6 @@ public class AudioService extends Service {
 
     private LibVLC mLibVLC;
     private HashMap<IAudioServiceCallback, Integer> mCallback;
-    private EventHandler mEventHandler;
     private OnAudioFocusChangeListener audioFocusListener;
     private boolean mDetectHeadset = true;
     private PowerManager.WakeLock mWakeLock;
@@ -165,7 +164,6 @@ public class AudioService extends Service {
         mPrevIndex = -1;
         mNextIndex = -1;
         mPrevious = new Stack<Integer>();
-        mEventHandler = EventHandler.getInstance();
         mRemoteControlClientReceiverComponent = new ComponentName(getPackageName(),
                 RemoteControlClientReceiver.class.getName());
 
@@ -346,7 +344,7 @@ public class AudioService extends Service {
             }
 
             /*
-             * Incoming Call : Pause if VLC is playing audio or video. 
+             * Incoming Call : Pause if VLC is playing audio or video.
              */
             if (action.equalsIgnoreCase(VLCApplication.INCOMING_CALL_INTENT)) {
                 mWasPlayingAudio = mLibVLC.isPlaying() && mLibVLC.getVideoTracksCount() < 1;
@@ -625,7 +623,7 @@ public class AudioService extends Service {
         String MRL = mLibVLC.getMediaList().getMRL(mCurrentIndex);
         int index = mCurrentIndex;
         mCurrentIndex = -1;
-        mEventHandler.removeHandler(mVlcEventHandler);
+        mLibVLC.getEventHandler().removeHandler(mVlcEventHandler);
         // Preserve playback when switching to video
         hideNotification(false);
 
@@ -833,7 +831,7 @@ public class AudioService extends Service {
 
     private void stop() {
         mLibVLC.stop();
-        mEventHandler.removeHandler(mVlcEventHandler);
+        mLibVLC.getEventHandler().removeHandler(mVlcEventHandler);
         mLibVLC.getMediaList().getEventHandler().removeHandler(mListEventHandler);
         setRemoteControlClientPlaybackState(EventHandler.MediaPlayerStopped);
         mCurrentIndex = -1;
@@ -1158,7 +1156,7 @@ public class AudioService extends Service {
                 throws RemoteException {
 
             Log.v(TAG, "Loading position " + ((Integer)position).toString() + " in " + mediaPathList.toString());
-            mEventHandler.addHandler(mVlcEventHandler);
+            mLibVLC.getEventHandler().addHandler(mVlcEventHandler);
 
             mLibVLC.getMediaList().getEventHandler().removeHandler(mListEventHandler);
             mLibVLC.setMediaList();
@@ -1226,7 +1224,7 @@ public class AudioService extends Service {
                 mCurrentIndex = 0;
             }
 
-            mEventHandler.addHandler(mVlcEventHandler);
+            mLibVLC.getEventHandler().addHandler(mVlcEventHandler);
             mLibVLC.playIndex(mCurrentIndex);
             mHandler.sendEmptyMessage(SHOW_PROGRESS);
             setUpRemoteControlClient();
@@ -1250,7 +1248,7 @@ public class AudioService extends Service {
 
             if(URI == null || !mLibVLC.isPlaying())
                 return;
-            mEventHandler.addHandler(mVlcEventHandler);
+            mLibVLC.getEventHandler().addHandler(mVlcEventHandler);
             mCurrentIndex = index;
 
             // Notify everyone
diff --git a/vlc-android/src/org/videolan/vlc/gui/PreferencesActivity.java b/vlc-android/src/org/videolan/vlc/gui/PreferencesActivity.java
index 9f0109c..b069452 100644
--- a/vlc-android/src/org/videolan/vlc/gui/PreferencesActivity.java
+++ b/vlc-android/src/org/videolan/vlc/gui/PreferencesActivity.java
@@ -292,7 +292,7 @@ public class PreferencesActivity extends PreferenceActivity implements OnSharedP
                 || key.equalsIgnoreCase("network_caching")
                 || key.equalsIgnoreCase("dev_hardware_decoder")) {
             VLCInstance.updateLibVlcSettings(sharedPreferences);
-            LibVLC.restart(this);
+            LibVLC.restartInstance(this);
         }
     }
 
diff --git a/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.java b/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.java
index 4cf4793..195de50 100644
--- a/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.java
+++ b/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.java
@@ -439,8 +439,7 @@ public class VideoPlayerActivity extends ActionBarActivity implements IVideoPlay
         // SurfaceView is now available for MediaCodec direct rendering.
         mLibVLC.eventVideoPlayerActivityCreated(true);
 
-        EventHandler em = EventHandler.getInstance();
-        em.addHandler(eventHandler);
+        mLibVLC.getEventHandler().addHandler(eventHandler);
 
         this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
 
@@ -590,8 +589,7 @@ public class VideoPlayerActivity extends ActionBarActivity implements IVideoPlay
         super.onDestroy();
         unregisterReceiver(mReceiver);
 
-        EventHandler em = EventHandler.getInstance();
-        em.removeHandler(eventHandler);
+        mLibVLC.getEventHandler().removeHandler(eventHandler);
 
         // MediaCodec opaque direct rendering should not be used anymore since there is no surface to attach.
         mLibVLC.eventVideoPlayerActivityCreated(false);
@@ -1228,8 +1226,7 @@ public class VideoPlayerActivity extends ActionBarActivity implements IVideoPlay
     }
 
     public void eventHardwareAccelerationError() {
-        EventHandler em = EventHandler.getInstance();
-        em.callback(EventHandler.HardwareAccelerationError, new Bundle());
+        mLibVLC.getEventHandler().callback(EventHandler.HardwareAccelerationError, new Bundle());
     }
 
     private void handleHardwareAccelerationError() {
diff --git a/vlc-android/src/org/videolan/vlc/util/VLCInstance.java b/vlc-android/src/org/videolan/vlc/util/VLCInstance.java
index d0212c6..9b65285 100644
--- a/vlc-android/src/org/videolan/vlc/util/VLCInstance.java
+++ b/vlc-android/src/org/videolan/vlc/util/VLCInstance.java
@@ -24,7 +24,6 @@ import org.videolan.libvlc.LibVLC;
 import org.videolan.libvlc.LibVlcException;
 import org.videolan.vlc.VLCApplication;
 import org.videolan.vlc.VLCCrashHandler;
-import org.videolan.vlc.gui.NativeCrashActivity;
 
 import android.content.Context;
 import android.content.Intent;
@@ -45,15 +44,6 @@ public class VLCInstance {
             SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
             VLCInstance.updateLibVlcSettings(pref);
             instance.init(context);
-            instance.setOnNativeCrashListener(new LibVLC.OnNativeCrashListener() {
-                @Override
-                public void onNativeCrash() {
-                    Intent i = new Intent(context, NativeCrashActivity.class);
-                    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    i.putExtra("PID", android.os.Process.myPid());
-                    context.startActivity(i);
-                }
-            });
         }
         return instance;
     }
@@ -81,10 +71,10 @@ public class VLCInstance {
         }
         int vout;
         try {
-        	vout = Integer.parseInt(pref.getString("vout", "-1"));
+            vout = Integer.parseInt(pref.getString("vout", "-1"));
         }
         catch (NumberFormatException nfe) {
-        	vout = -1;
+            vout = -1;
         }
         int deblocking;
         try {
-- 
1.9.3 (Apple Git-50)



More information about the Android mailing list