[Android] [PATCH 3/3] Add support for multiple video instance.
Paulo Vitor Magacho da Silva
pvmagacho at gmail.com
Tue Nov 25 01:28:53 CET 2014
---
libvlc/jni/libvlcjni-util.c | 2 +-
libvlc/jni/libvlcjni.c | 59 ++++++--
libvlc/jni/native_crash_handler.c | 81 +++++++++-
libvlc/jni/native_crash_handler.h | 4 +-
libvlc/jni/vout.c | 163 ++++++++++++---------
libvlc/jni/vout.h | 14 +-
libvlc/src/org/videolan/libvlc/EventHandler.java | 33 +++--
libvlc/src/org/videolan/libvlc/LibVLC.java | 21 ++-
libvlc/src/org/videolan/libvlc/MediaList.java | 8 +-
.../src/org/videolan/vlc/audio/AudioService.java | 16 +-
.../src/org/videolan/vlc/gui/HistoryAdapter.java | 2 +-
.../org/videolan/vlc/gui/PreferencesActivity.java | 2 +-
.../vlc/gui/video/VideoPlayerActivity.java | 6 +-
13 files changed, 290 insertions(+), 121 deletions(-)
diff --git a/libvlc/jni/libvlcjni-util.c b/libvlc/jni/libvlcjni-util.c
index 205d59d..0a3cae9 100644
--- a/libvlc/jni/libvlcjni-util.c
+++ b/libvlc/jni/libvlcjni-util.c
@@ -139,7 +139,7 @@ jobject getEventHandlerReference(JNIEnv *env, jobject thiz, jobject eventHandler
return NULL;
}
- jmethodID methodID = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;)V");
+ jmethodID methodID = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;Lorg/videolan/libvlc/LibVLC;)V");
if (!methodID) {
LOGE("setEventHandler: failed to get the callback method");
return NULL;
diff --git a/libvlc/jni/libvlcjni.c b/libvlc/jni/libvlcjni.c
index 7edd52f..833bbef 100644
--- a/libvlc/jni/libvlcjni.c
+++ b/libvlc/jni/libvlcjni.c
@@ -195,9 +195,10 @@ static void vlc_event_callback(const libvlc_event_t *ev, void *data)
}
/* Find the callback ID */
- jmethodID methodID = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;)V");
+ jobject vlcObject = (jobject) data;
+ jmethodID methodID = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;Lorg/videolan/libvlc/LibVLC;)V");
if (methodID) {
- (*env)->CallVoidMethod(env, eventHandlerInstance, methodID, ev->type, bundle);
+ (*env)->CallVoidMethod(env, eventHandlerInstance, methodID, ev->type, bundle, vlcObject);
} else {
LOGE("EventHandler: failed to get the callback method");
}
@@ -213,16 +214,27 @@ 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);
+ JNIEnv* env;
+ if (jni_get_env(&env) < 0) {
+ return -1;
+ }
+
+ jclass eventHandlerCls = (*env)->FindClass(env, "org/videolan/libvlc/EventHandler");
+ jmethodID methodId = (*env)->GetStaticMethodID(env, eventHandlerCls, "getInstance", "()Lorg/videolan/libvlc/EventHandler;");
+ jobject eventHandler = (*env)->CallStaticObjectMethod(env, eventHandlerCls, methodId);
+
+ eventHandlerInstance = (*env)->NewGlobalRef(env, eventHandler);
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);
+ JNIEnv* env;
+ if (jni_get_env(&env) == 0 && eventHandlerInstance != NULL) {
+ (*env)->DeleteGlobalRef(env, eventHandlerInstance);
+ }
+ LOGD("JNI interface un-loaded.");
}
int jni_attach_thread(JNIEnv **env, const char *thread_name)
@@ -251,8 +263,22 @@ int jni_get_env(JNIEnv **env)
// FIXME: use atomics
static bool verbosity;
+
void Java_org_videolan_libvlc_LibVLC_nativeInit(JNIEnv *env, jobject thiz)
{
+ // initialize android_surface_value_t structure
+ android_surf_value_t *android_surface = (android_surf_value_t *) malloc(sizeof(android_surf_value_t));
+
+ android_surface->vout_android_surf = NULL;
+ android_surface->vout_android_gui = NULL;
+ android_surface->vout_android_java_surf = NULL;
+ android_surface->vout_android_subtitles_surf = NULL;
+
+ pthread_mutex_init(&android_surface->vout_android_lock, NULL);
+ pthread_cond_init(&android_surface->vout_android_surf_attached, NULL);
+
+ setLong(env, thiz, "mAndroidSurfaceValue", (jlong)(intptr_t)android_surface);
+
//only use OpenSLES if java side says we can
jclass cls = (*env)->GetObjectClass(env, thiz);
jmethodID methodId = (*env)->GetMethodID(env, cls, "getAout", "()I");
@@ -373,9 +399,13 @@ void Java_org_videolan_libvlc_LibVLC_nativeInit(JNIEnv *env, jobject thiz)
void Java_org_videolan_libvlc_LibVLC_nativeDestroy(JNIEnv *env, jobject thiz)
{
- destroy_native_crash_handler(env);
+ destroy_native_crash_handler(env, thiz);
releaseMediaPlayer(env, thiz);
+
+ // set the Android surface value structure before playing
+ android_surf_value_t *android_surface = (android_surf_value_t *)(intptr_t)getLong(env, thiz, "mAndroidSurfaceValue");
+
jlong libVlcInstance = getLong(env, thiz, "mLibVlcInstance");
if (!libVlcInstance)
return; // Already destroyed
@@ -385,6 +415,13 @@ void Java_org_videolan_libvlc_LibVLC_nativeDestroy(JNIEnv *env, jobject thiz)
libvlc_release(instance);
setLong(env, thiz, "mLibVlcInstance", 0);
+
+ pthread_mutex_destroy(&android_surface->vout_android_lock);
+ pthread_cond_destroy(&android_surface->vout_android_surf_attached);
+
+ free(android_surface);
+
+ setLong(env, thiz, "mAndroidSurfaceValue", 0);
}
void Java_org_videolan_libvlc_LibVLC_detachEventHandler(JNIEnv *env, jobject thiz)
@@ -439,7 +476,7 @@ void Java_org_videolan_libvlc_LibVLC_playMRL(JNIEnv *env, jobject thiz, jlong in
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);
+ libvlc_event_attach(ev, mp_events[i], vlc_event_callback, (void*) myJavaLibVLC);
/* Keep a pointer to this media player */
setLong(env, thiz, "mInternalMediaPlayerInstance", (jlong)(intptr_t)mp);
@@ -457,13 +494,17 @@ void Java_org_videolan_libvlc_LibVLC_playMRL(JNIEnv *env, jobject thiz, jlong in
(*env)->ReleaseStringUTFChars(env, mrl, p_mrl);
+ // set the Android surface value structure before playing
+ android_surf_value_t *object = (android_surf_value_t *)(intptr_t)getLong(env, thiz, "mAndroidSurfaceValue");
+ libvlc_media_player_set_surfacevalue(mp, object);
+
/* 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[] = {
libvlc_MediaParsedChanged
};
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, (void*) myJavaLibVLC);
libvlc_media_player_set_media(mp, p_md);
libvlc_media_player_play(mp);
diff --git a/libvlc/jni/native_crash_handler.c b/libvlc/jni/native_crash_handler.c
index 2cb1590..f4a97be 100644
--- a/libvlc/jni/native_crash_handler.c
+++ b/libvlc/jni/native_crash_handler.c
@@ -19,11 +19,19 @@
*****************************************************************************/
#include <signal.h>
+#include <pthread.h>
#include "native_crash_handler.h"
+struct libvlc_crash_handler_t {
+ jobject j_libVLC;
+ libvlc_crash_handler_t *next;
+ libvlc_crash_handler_t *prev;
+};
+
static struct sigaction old_actions[NSIG];
-static jobject j_libVLC;
+static libvlc_crash_handler_t *first = NULL;
+static libvlc_crash_handler_t *last = NULL;
#define THREAD_NAME "native_crash_handler"
extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
@@ -45,6 +53,8 @@ static const int monitored_signals[] = {
};
+pthread_mutex_t native_handler_lock = PTHREAD_MUTEX_INITIALIZER;
+
/**
* Callback called when a monitored signal is triggered.
*/
@@ -54,11 +64,24 @@ 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);
- jmethodID methodId = (*env)->GetMethodID(env, cls, "onNativeCrash", "()V");
- (*env)->CallVoidMethod(env, j_libVLC, methodId);
+ pthread_mutex_lock(&native_handler_lock);
+
+ libvlc_crash_handler_t *lp = first;
+ while (lp != NULL)
+ {
+ jclass cls = (*env)->GetObjectClass(env, lp->j_libVLC);
+ jmethodID methodId = (*env)->GetMethodID(env, cls, "onNativeCrash", "()V");
+ (*env)->CallVoidMethod(env, lp->j_libVLC, methodId);
+
+ (*env)->DeleteLocalRef(env, cls);
+
+ libvlc_crash_handler_t *todelete = lp;
+ lp = lp->next;
+
+ free(todelete);
+ }
+ pthread_mutex_unlock(&native_handler_lock);
- (*env)->DeleteLocalRef(env, cls);
jni_detach_thread();
// Call the old signal handler.
@@ -68,7 +91,19 @@ void sigaction_callback(int signal, siginfo_t *info, void *reserved)
void init_native_crash_handler(JNIEnv *env, jobject j_libVLC_local)
{
- j_libVLC = (*env)->NewGlobalRef(env, j_libVLC_local);
+ pthread_mutex_lock(&native_handler_lock);
+
+ libvlc_crash_handler_t *current = (libvlc_crash_handler_t *) malloc(sizeof(libvlc_crash_handler_t));
+ current->j_libVLC = (*env)->NewGlobalRef(env, j_libVLC_local);
+ current->prev = last;
+
+ // update values
+ if (first == NULL)
+ first = current;
+ if (last != NULL)
+ last->next = current;
+ last = current;
+
struct sigaction handler;
memset(&handler, 0, sizeof(struct sigaction));
@@ -81,11 +116,15 @@ void init_native_crash_handler(JNIEnv *env, jobject j_libVLC_local)
const int s = monitored_signals[i];
sigaction(s, &handler, &old_actions[s]);
}
+
+ pthread_mutex_unlock(&native_handler_lock);
}
-void destroy_native_crash_handler(JNIEnv *env)
+void destroy_native_crash_handler(JNIEnv *env, jobject j_libVLC_local)
{
+ pthread_mutex_lock(&native_handler_lock);
+
// Uninstall the signal handlers and restore their old actions.
for (unsigned i = 0; i < sizeof(monitored_signals) / sizeof(int); ++i)
{
@@ -93,5 +132,31 @@ void destroy_native_crash_handler(JNIEnv *env)
sigaction(s, &old_actions[s], NULL);
}
- (*env)->DeleteGlobalRef(env, j_libVLC);
+ libvlc_crash_handler_t *lp = first;
+ while (lp != NULL)
+ {
+ if (j_libVLC_local == lp->j_libVLC) {
+ (*env)->DeleteGlobalRef(env, lp->j_libVLC);
+
+ libvlc_crash_handler_t *todelete = lp;
+ libvlc_crash_handler_t *prev = lp->prev;
+ libvlc_crash_handler_t *next = lp->next;
+ if (lp == first) {
+ first = next;
+ if (first != NULL)
+ first->prev = NULL;
+ } else if (lp == last) {
+ last = prev;
+ last->next = NULL;
+ } else {
+ prev->next = next;
+ next->prev = prev;
+ }
+
+ free(todelete);
+ break;
+ }
+ }
+
+ pthread_mutex_unlock(&native_handler_lock);
}
diff --git a/libvlc/jni/native_crash_handler.h b/libvlc/jni/native_crash_handler.h
index a57e61e..4c5530b 100644
--- a/libvlc/jni/native_crash_handler.h
+++ b/libvlc/jni/native_crash_handler.h
@@ -23,7 +23,9 @@
#include <jni.h>
+typedef struct libvlc_crash_handler_t libvlc_crash_handler_t;
+
void init_native_crash_handler(JNIEnv *env, jobject j_libVLC_local);
-void destroy_native_crash_handler(JNIEnv *env);
+void destroy_native_crash_handler(JNIEnv *env, jobject j_libVLC_local);
#endif // LIBVLCJNI_NATIVE_CRASH_HANDLER_H
diff --git a/libvlc/jni/vout.c b/libvlc/jni/vout.c
index 06dc605..107417b 100644
--- a/libvlc/jni/vout.c
+++ b/libvlc/jni/vout.c
@@ -22,43 +22,53 @@
#include <vlc_common.h>
#include <jni.h>
+#include "vout.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(android_surf_value_t *android_surface) {
+ if (android_surface->vout_android_subtitles_surf == NULL)
+ return;
-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;
+ 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() {
- 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_LockAndGetAndroidSurface(android_surf_value_t *android_surface) {
+ if (android_surface->vout_android_surf == NULL)
+ return;
+
+ pthread_mutex_lock(&android_surface->vout_android_lock);
+ while (android_surface->vout_android_surf == NULL)
+ pthread_cond_wait(&android_surface->vout_android_surf_attached, &android_surface->vout_android_lock);
+ return android_surface->vout_android_surf;
}
-void jni_UnlockAndroidSurface() {
- pthread_mutex_unlock(&vout_android_lock);
+jobject jni_LockAndGetAndroidJavaSurface(android_surf_value_t *android_surface) {
+ if (android_surface->vout_android_java_surf == NULL)
+ return;
+
+ 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;
}
-void jni_EventHardwareAccelerationError()
+void jni_UnlockAndroidSurface(android_surf_value_t *android_surface) {
+ pthread_mutex_unlock(&android_surface->vout_android_lock);
+}
+
+void jni_EventHardwareAccelerationError(android_surf_value_t *android_surface)
{
JNIEnv *env;
bool isAttached = false;
- if (vout_android_gui == NULL)
+ if (android_surface->vout_android_gui == NULL)
return;
if (jni_get_env(&env) < 0) {
@@ -67,39 +77,42 @@ void jni_EventHardwareAccelerationError()
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();
}
-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)
{
- if (vout_android_gui == NULL)
+ if (android_surface->vout_android_gui == NULL)
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);
}
-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();
@@ -144,7 +157,7 @@ void *jni_AndroidJavaSurfaceToNativeSurface(jobject *surf)
return native_surface;
}
-int jni_ConfigureSurface(jobject jsurf, int width, int height, int hal, bool *configured)
+int jni_ConfigureSurface(jobject jsurf, android_surf_value_t *android_surface, int width, int height, int hal, bool *configured)
{
JNIEnv *p_env;
bool isAttached = false;
@@ -155,9 +168,9 @@ int jni_ConfigureSurface(jobject jsurf, int width, int height, int hal, bool *co
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, jsurf, width, height, hal);
if (ret >= 0 && configured)
*configured = ret == 1;
@@ -166,58 +179,76 @@ int jni_ConfigureSurface(jobject jsurf, int width, int height, int hal, bool *co
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 = (android_surf_value_t *)(intptr_t)getLong(env, thiz, "mAndroidSurfaceValue");
+ 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);
+ android_surf_value_t * android_surface = (android_surf_value_t *)(intptr_t)getLong(env, thiz, "mAndroidSurfaceValue");
+ if (android_surface == NULL)
+ return;
+
+ pthread_mutex_lock(&android_surface->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);
+ 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 = (android_surf_value_t *)(intptr_t)getLong(env, thiz, "mAndroidSurfaceValue");
+ if (android_surface == NULL)
+ return;
+
+ pthread_mutex_lock(&android_surface->vout_android_lock);
+ android_surface->vout_android_surf = NULL;
+ 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 = (android_surf_value_t *)(intptr_t)getLong(env, thiz, "mAndroidSurfaceValue");
+ 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 = (android_surf_value_t *)(intptr_t)getLong(env, thiz, "mAndroidSurfaceValue");
+ 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..c439c12 100644
--- a/libvlc/jni/vout.h
+++ b/libvlc/jni/vout.h
@@ -21,8 +21,16 @@
#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_surf;
+ void *vout_android_gui;
+ jobject vout_android_java_surf;
+ jobject vout_android_subtitles_surf;
+ bool vout_video_player_activity_created;
+} android_surf_value_t;
#endif // LIBVLCJNI_VOUT_H
diff --git a/libvlc/src/org/videolan/libvlc/EventHandler.java b/libvlc/src/org/videolan/libvlc/EventHandler.java
index 16a0791..03b8821 100644
--- a/libvlc/src/org/videolan/libvlc/EventHandler.java
+++ b/libvlc/src/org/videolan/libvlc/EventHandler.java
@@ -21,6 +21,9 @@
package org.videolan.libvlc;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import android.os.Bundle;
import android.os.Handler;
@@ -96,36 +99,44 @@ public class EventHandler {
public static final int HardwareAccelerationError = 0x3000;
- private ArrayList<Handler> mEventHandler;
+ private Map<LibVLC, ArrayList<Handler>> mMapHandler;
private static EventHandler mInstance;
EventHandler() {
- mEventHandler = new ArrayList<Handler>();
+ mMapHandler = new HashMap<LibVLC, ArrayList<Handler>>();
}
- public static EventHandler getInstance() {
+ public synchronized static EventHandler getInstance() {
if (mInstance == null) {
mInstance = new EventHandler();
}
return mInstance;
}
- public void addHandler(Handler handler) {
- if (!mEventHandler.contains(handler))
- mEventHandler.add(handler);
+ public synchronized void addHandler(LibVLC vlcObject, Handler handler) {
+ if (!mMapHandler.containsKey(vlcObject)) {
+ mMapHandler.put(vlcObject, new ArrayList<Handler>());
+ }
+ mMapHandler.get(vlcObject).add(handler);
}
- public void removeHandler(Handler handler) {
- mEventHandler.remove(handler);
+ public synchronized void removeHandler(LibVLC vlcObject, Handler handler) {
+ mMapHandler.get(vlcObject).remove(handler);
}
/** This method is called by a native thread **/
- public void callback(int event, Bundle b) {
+ public synchronized void callback(int event, Bundle b, LibVLC vlcObject) {
+ List<Handler> eventHandlers = mMapHandler.get(vlcObject);
+ if (eventHandlers == null) {
+ return;
+ }
+
b.putInt("event", event);
- for (int i = 0; i < mEventHandler.size(); i++) {
+ for (int i = 0; i < eventHandlers.size(); i++) {
Message msg = Message.obtain();
msg.setData(b);
- mEventHandler.get(i).sendMessage(msg);
+ msg.obj = vlcObject;
+ eventHandlers.get(i).sendMessage(msg);
}
}
}
diff --git a/libvlc/src/org/videolan/libvlc/LibVLC.java b/libvlc/src/org/videolan/libvlc/LibVLC.java
index 8eb25ad..4a2aa2f 100644
--- a/libvlc/src/org/videolan/libvlc/LibVLC.java
+++ b/libvlc/src/org/videolan/libvlc/LibVLC.java
@@ -67,6 +67,9 @@ public class LibVLC {
private int mInternalMediaPlayerIndex = 0; // Read-only, reserved for JNI
private long mInternalMediaPlayerInstance = 0; // Read-only, reserved for JNI
+ // Android surface structure
+ protected long mAndroidSurfaceValue = 0; // Read-only, reserved for JNI
+
private MediaList mMediaList; // Pointer to media list being followed
private MediaList mPrimaryList; // Primary/default media list; see getPrimaryMediaList()
@@ -192,10 +195,9 @@ public class LibVLC {
}
/**
- * Constructor
- * It is private because this class is a singleton.
+ * Constructor.
*/
- private LibVLC() {
+ public LibVLC() {
mAout = new AudioOutput();
}
@@ -261,7 +263,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();
@@ -272,6 +274,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.
*/
@@ -490,7 +501,7 @@ public class LibVLC {
applyEqualizer();
}
- private void applyEqualizer()
+ protected void applyEqualizer()
{
setNativeEqualizer(mInternalMediaPlayerInstance, this.equalizer);
}
diff --git a/libvlc/src/org/videolan/libvlc/MediaList.java b/libvlc/src/org/videolan/libvlc/MediaList.java
index 666568e..5c60236 100644
--- a/libvlc/src/org/videolan/libvlc/MediaList.java
+++ b/libvlc/src/org/videolan/libvlc/MediaList.java
@@ -105,12 +105,12 @@ public class MediaList {
ArrayList<String> children = new ArrayList<String>();
int ret = expandMedia(mLibVLC, position, children);
if(ret == 0) {
- mEventHandler.callback(EventHandler.CustomMediaListExpanding, new Bundle());
+ mEventHandler.callback(EventHandler.CustomMediaListExpanding, new Bundle(), mLibVLC);
this.remove(position);
for(String mrl : children) {
this.insert(position, mrl);
}
- mEventHandler.callback(EventHandler.CustomMediaListExpandingEnd, new Bundle());
+ mEventHandler.callback(EventHandler.CustomMediaListExpandingEnd, new Bundle(), mLibVLC);
}
return ret;
}
@@ -155,7 +155,7 @@ public class MediaList {
Bundle b = new Bundle();
b.putInt("index_before", startPosition);
b.putInt("index_after", endPosition);
- mEventHandler.callback(EventHandler.CustomMediaListItemMoved, b);
+ mEventHandler.callback(EventHandler.CustomMediaListItemMoved, b, mLibVLC);
}
public void remove(int position) {
@@ -231,6 +231,6 @@ public class MediaList {
Bundle b = new Bundle();
b.putString("item_uri", uri);
b.putInt("item_index", position);
- mEventHandler.callback(event, b);
+ mEventHandler.callback(event, b, mLibVLC);
}
}
diff --git a/vlc-android/src/org/videolan/vlc/audio/AudioService.java b/vlc-android/src/org/videolan/vlc/audio/AudioService.java
index bf4e85f..6420d72 100644
--- a/vlc-android/src/org/videolan/vlc/audio/AudioService.java
+++ b/vlc-android/src/org/videolan/vlc/audio/AudioService.java
@@ -618,7 +618,7 @@ public class AudioService extends Service {
String MRL = mLibVLC.getMediaList().getMRL(mCurrentIndex);
int index = mCurrentIndex;
mCurrentIndex = -1;
- mEventHandler.removeHandler(mVlcEventHandler);
+ mEventHandler.removeHandler(mLibVLC, mVlcEventHandler);
// Preserve playback when switching to video
hideNotification(false);
@@ -821,8 +821,8 @@ public class AudioService extends Service {
private void stop() {
mLibVLC.stop();
- mEventHandler.removeHandler(mVlcEventHandler);
- mLibVLC.getMediaList().getEventHandler().removeHandler(mListEventHandler);
+ mEventHandler.removeHandler(mLibVLC, mVlcEventHandler);
+ mLibVLC.getMediaList().getEventHandler().removeHandler(mLibVLC, mListEventHandler);
setRemoteControlClientPlaybackState(EventHandler.MediaPlayerStopped);
mCurrentIndex = -1;
mPrevious.clear();
@@ -1138,9 +1138,9 @@ public class AudioService extends Service {
throws RemoteException {
Log.v(TAG, "Loading position " + ((Integer)position).toString() + " in " + mediaPathList.toString());
- mEventHandler.addHandler(mVlcEventHandler);
+ mEventHandler.addHandler(mLibVLC, mVlcEventHandler);
- mLibVLC.getMediaList().getEventHandler().removeHandler(mListEventHandler);
+ mLibVLC.getMediaList().getEventHandler().removeHandler(mLibVLC, mListEventHandler);
mLibVLC.setMediaList();
mLibVLC.getPrimaryMediaList().clear();
MediaList mediaList = mLibVLC.getMediaList();
@@ -1175,7 +1175,7 @@ public class AudioService extends Service {
}
// Add handler after loading the list
- mLibVLC.getMediaList().getEventHandler().addHandler(mListEventHandler);
+ mLibVLC.getMediaList().getEventHandler().addHandler(mLibVLC, mListEventHandler);
mLibVLC.playIndex(mCurrentIndex);
mHandler.sendEmptyMessage(SHOW_PROGRESS);
@@ -1206,7 +1206,7 @@ public class AudioService extends Service {
mCurrentIndex = 0;
}
- mEventHandler.addHandler(mVlcEventHandler);
+ mEventHandler.addHandler(mLibVLC, mVlcEventHandler);
mLibVLC.playIndex(mCurrentIndex);
mHandler.sendEmptyMessage(SHOW_PROGRESS);
setUpRemoteControlClient();
@@ -1230,7 +1230,7 @@ public class AudioService extends Service {
if(URI == null || !mLibVLC.isPlaying())
return;
- mEventHandler.addHandler(mVlcEventHandler);
+ mEventHandler.addHandler(mLibVLC, mVlcEventHandler);
mCurrentIndex = index;
// Notify everyone
diff --git a/vlc-android/src/org/videolan/vlc/gui/HistoryAdapter.java b/vlc-android/src/org/videolan/vlc/gui/HistoryAdapter.java
index f24577c..b80438b 100644
--- a/vlc-android/src/org/videolan/vlc/gui/HistoryAdapter.java
+++ b/vlc-android/src/org/videolan/vlc/gui/HistoryAdapter.java
@@ -56,7 +56,7 @@ public class HistoryAdapter extends BaseAdapter {
}
EventHandler em = mLibVLC.getPrimaryMediaList().getEventHandler();
- em.addHandler(new HistoryEventHandler(this));
+ em.addHandler(mLibVLC, new HistoryEventHandler(this));
}
@Override
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 faf4d10..2fa6236 100644
--- a/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.java
+++ b/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.java
@@ -438,7 +438,7 @@ public class VideoPlayerActivity extends ActionBarActivity implements IVideoPlay
mLibVLC.eventVideoPlayerActivityCreated(true);
EventHandler em = EventHandler.getInstance();
- em.addHandler(eventHandler);
+ em.addHandler(mLibVLC, eventHandler);
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
@@ -561,7 +561,7 @@ public class VideoPlayerActivity extends ActionBarActivity implements IVideoPlay
unregisterReceiver(mReceiver);
EventHandler em = EventHandler.getInstance();
- em.removeHandler(eventHandler);
+ em.removeHandler(mLibVLC, eventHandler);
// MediaCodec opaque direct rendering should not be used anymore since there is no surface to attach.
mLibVLC.eventVideoPlayerActivityCreated(false);
@@ -1205,7 +1205,7 @@ public class VideoPlayerActivity extends ActionBarActivity implements IVideoPlay
public void eventHardwareAccelerationError() {
EventHandler em = EventHandler.getInstance();
- em.callback(EventHandler.HardwareAccelerationError, new Bundle());
+ em.callback(EventHandler.HardwareAccelerationError, new Bundle(), mLibVLC);
}
private void handleHardwareAccelerationError() {
--
1.9.3 (Apple Git-50)
More information about the Android
mailing list