[Android] [PATCH 1/2] Support for multiple player instances. Fix ticket #10831 (https://trac.videolan.org/vlc/ticket/10831).

Paulo Vitor Magacho da Silva pvmagacho at gmail.com
Wed Jul 23 08:43:38 CEST 2014


---
 vlc-android/jni/libvlcjni-track.c                  |  99 +++++++++++++++
 vlc-android/jni/libvlcjni.c                        |  44 +++++--
 vlc-android/jni/utils.h                            |  12 ++
 vlc-android/jni/vout.c                             | 134 +++++++++++----------
 vlc-android/jni/vout.h                             |   4 -
 .../src/org/videolan/libvlc/EventHandler.java      |   4 +-
 vlc-android/src/org/videolan/libvlc/LibVLC.java    |  33 ++---
 vlc-android/src/org/videolan/libvlc/MediaList.java |   2 +-
 vlc-android/src/org/videolan/libvlc/TrackInfo.java |   1 +
 9 files changed, 237 insertions(+), 96 deletions(-)

diff --git a/vlc-android/jni/libvlcjni-track.c b/vlc-android/jni/libvlcjni-track.c
index df558ea..e2c6b52 100644
--- a/vlc-android/jni/libvlcjni-track.c
+++ b/vlc-android/jni/libvlcjni-track.c
@@ -161,6 +161,7 @@ jobjectArray read_track_info_internal(JNIEnv *env, jobject thiz, libvlc_media_t*
             setInt(env, item, "Type", p_tracks[i]->i_type);
             setString(env, item, "Codec", (const char*)vlc_fourcc_GetDescription(0,p_tracks[i]->i_codec));
             setString(env, item, "Language", p_tracks[i]->psz_language);
+            setInt(env, item, "Bitrate", p_tracks[i]->i_bitrate);
 
             if (p_tracks[i]->i_type == libvlc_track_video)
             {
@@ -264,6 +265,104 @@ jobject Java_org_videolan_libvlc_LibVLC_getAudioTrackDescription(JNIEnv *env, jo
     return audioTrackMap;
 }
 
+jobject Java_org_videolan_libvlc_LibVLC_getStats(JNIEnv *env, jobject thiz)
+{
+    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
+    if (!mp)
+        return NULL;
+
+    libvlc_media_t *p_mp = libvlc_media_player_get_media(mp);
+    if (!p_mp)
+        return NULL;
+
+    libvlc_media_stats_t p_stats;
+    libvlc_media_get_stats(p_mp, &p_stats);
+
+    jclass mapClass = (*env)->FindClass(env, "java/util/Map");
+    jclass hashMapClass = (*env)->FindClass(env, "java/util/HashMap");
+    jmethodID mapPut = (*env)->GetMethodID(env, mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+    /*
+     * "What are you building? Lay your hand on it. Where is it?"
+     * We need a concrete map to start
+     */
+    jmethodID mapInit = (*env)->GetMethodID(env, hashMapClass, "<init>", "()V");
+    jclass integerCls = (*env)->FindClass(env, "java/lang/Integer");
+    jmethodID integerConstructor = (*env)->GetMethodID(env, integerCls, "<init>", "(I)V");
+    jclass floatCls = (*env)->FindClass(env, "java/lang/Float");
+    jmethodID floatConstructor = (*env)->GetMethodID(env, floatCls, "<init>", "(F)V");
+
+     LOGE("No media player %f", p_stats.f_demux_bitrate);
+
+    jobject statistics = (*env)->NewObject(env, hashMapClass, mapInit);
+    jobject value = (*env)->NewObject(env, floatCls, floatConstructor, p_stats.f_demux_bitrate);
+    jstring name = (*env)->NewStringUTF(env, "demuxBitrate");
+    (*env)->CallObjectMethod(env, statistics, mapPut, name, value);
+
+    value = (*env)->NewObject(env, floatCls, floatConstructor, p_stats.f_input_bitrate);
+    name = (*env)->NewStringUTF(env, "inputBitrate");
+    (*env)->CallObjectMethod(env, statistics, mapPut, name, value);
+
+    value = (*env)->NewObject(env, floatCls, floatConstructor, p_stats.f_send_bitrate);
+    name = (*env)->NewStringUTF(env, "sendBitrate");
+    (*env)->CallObjectMethod(env, statistics, mapPut, name, value);
+
+    value = (*env)->NewObject(env, integerCls, integerConstructor, p_stats.i_decoded_audio);
+    name = (*env)->NewStringUTF(env, "decodedAudio");
+    (*env)->CallObjectMethod(env, statistics, mapPut, name, value);
+
+    value = (*env)->NewObject(env, integerCls, integerConstructor, p_stats.i_decoded_video);
+    name = (*env)->NewStringUTF(env, "decodedVideo");
+    (*env)->CallObjectMethod(env, statistics, mapPut, name, value);
+
+    value = (*env)->NewObject(env, integerCls, integerConstructor, p_stats.i_demux_corrupted);
+    name = (*env)->NewStringUTF(env, "demuxCorrupted");
+    (*env)->CallObjectMethod(env, statistics, mapPut, name, value);
+
+    value = (*env)->NewObject(env, integerCls, integerConstructor, p_stats.i_demux_discontinuity);
+    name = (*env)->NewStringUTF(env, "demuxDiscontinuity");
+    (*env)->CallObjectMethod(env, statistics, mapPut, name, value);
+
+    value = (*env)->NewObject(env, integerCls, integerConstructor, p_stats.i_demux_read_bytes);
+    name = (*env)->NewStringUTF(env, "demuxReadBytes");
+    (*env)->CallObjectMethod(env, statistics, mapPut, name, value);
+
+    value = (*env)->NewObject(env, integerCls, integerConstructor, p_stats.i_displayed_pictures);
+    name = (*env)->NewStringUTF(env, "displayedPictures");
+    (*env)->CallObjectMethod(env, statistics, mapPut, name, value);
+
+    value = (*env)->NewObject(env, integerCls, integerConstructor, p_stats.i_lost_abuffers);
+    name = (*env)->NewStringUTF(env, "lostAbuffers");
+    (*env)->CallObjectMethod(env, statistics, mapPut, name, value);
+
+    value = (*env)->NewObject(env, integerCls, integerConstructor, p_stats.i_lost_pictures);
+    name = (*env)->NewStringUTF(env, "lostPictures");
+    (*env)->CallObjectMethod(env, statistics, mapPut, name, value);
+
+    value = (*env)->NewObject(env, integerCls, integerConstructor, p_stats.i_played_abuffers);
+    name = (*env)->NewStringUTF(env, "playedAbuffers");
+    (*env)->CallObjectMethod(env, statistics, mapPut, name, value);
+
+    value = (*env)->NewObject(env, integerCls, integerConstructor, p_stats.i_read_bytes);
+    name = (*env)->NewStringUTF(env, "readBytes");
+    (*env)->CallObjectMethod(env, statistics, mapPut, value, name);
+
+    value = (*env)->NewObject(env, integerCls, integerConstructor, p_stats.i_sent_bytes);
+    name = (*env)->NewStringUTF(env, "sentBytes");
+    (*env)->CallObjectMethod(env, statistics, mapPut, name, value);
+
+    value = (*env)->NewObject(env, integerCls, integerConstructor, p_stats.i_sent_packets);
+    name = (*env)->NewStringUTF(env, "sentPackets");
+    (*env)->CallObjectMethod(env, statistics, mapPut, name, value);
+
+    // Clean up local references
+    (*env)->DeleteLocalRef(env, mapClass);
+    (*env)->DeleteLocalRef(env, hashMapClass);
+    (*env)->DeleteLocalRef(env, integerCls);
+    (*env)->DeleteLocalRef(env, floatCls);
+
+    return statistics;
+}
+
 jint Java_org_videolan_libvlc_LibVLC_getAudioTrack(JNIEnv *env, jobject thiz)
 {
     libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
diff --git a/vlc-android/jni/libvlcjni.c b/vlc-android/jni/libvlcjni.c
index 9781d76..fa9b6ad 100644
--- a/vlc-android/jni/libvlcjni.c
+++ b/vlc-android/jni/libvlcjni.c
@@ -137,9 +137,13 @@ static void vlc_event_callback(const libvlc_event_t *ev, void *data)
     jmethodID putString = (*env)->GetMethodID(env, clsBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V" );
 
     if (ev->type == libvlc_MediaPlayerPositionChanged) {
-            jstring sData = (*env)->NewStringUTF(env, "data");
-            (*env)->CallVoidMethod(env, bundle, putFloat, sData, ev->u.media_player_position_changed.new_position);
-            (*env)->DeleteLocalRef(env, sData);
+        jstring sData = (*env)->NewStringUTF(env, "data");
+        (*env)->CallVoidMethod(env, bundle, putFloat, sData, ev->u.media_player_position_changed.new_position);
+        (*env)->DeleteLocalRef(env, sData);
+    } else if (ev->type == libvlc_MediaPlayerTimeChanged) {
+        jstring sData = (*env)->NewStringUTF(env, "data");
+        (*env)->CallVoidMethod(env, bundle, putInt, sData, (int) ev->u.media_player_time_changed.new_time);
+        (*env)->DeleteLocalRef(env, sData);
     } else if(ev->type == libvlc_MediaPlayerVout) {
         /* For determining the vout/ES track change */
         jstring sData = (*env)->NewStringUTF(env, "data");
@@ -196,16 +200,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 JNI_VERSION_1_2;
 }
 
 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.");
 }
 
 // FIXME: use atomics
@@ -213,6 +213,13 @@ static bool verbosity;
 
 void Java_org_videolan_libvlc_LibVLC_nativeInit(JNIEnv *env, jobject thiz)
 {
+	vlc_object *object = (vlc_object *) malloc(sizeof(vlc_object));
+
+	pthread_mutex_init(&object->vout_android_lock, NULL);
+	pthread_cond_init(&object->vout_android_surf_attached, NULL);
+
+	setLong(env, thiz, "mVLCObject", (jlong)(intptr_t)object);
+
     //only use OpenSLES if java side says we can
     jclass cls = (*env)->GetObjectClass(env, thiz);
     jmethodID methodId = (*env)->GetMethodID(env, cls, "getAout", "()I");
@@ -282,6 +289,9 @@ void Java_org_videolan_libvlc_LibVLC_nativeInit(JNIEnv *env, jobject thiz)
         /* Remove me when UTF-8 is enforced by law */
         "--subsdec-encoding", subsencodingstr,
 
+        /* Enable statistics */
+        "--stats",
+
         /* XXX: why can't the default be fine ? #7792 */
         (networkCaching > 0) ? networkCachingstr : "",
 
@@ -316,7 +326,16 @@ 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);
+    // clear surface lock and condition
+	vlc_object *object = (vlc_object *)(intptr_t)getLong(env, thiz, "mVLCObject");
+
+    pthread_mutex_destroy(&object->vout_android_lock);
+	pthread_cond_destroy(&object->vout_android_surf_attached);
+
+	free(object);
+	setLong(env, thiz, "mVLCObject", 0);
+
+	destroy_native_crash_handler(env);
 
     releaseMediaPlayer(env, thiz);
     jlong libVlcInstance = getLong(env, thiz, "mLibVlcInstance");
@@ -378,6 +397,7 @@ void Java_org_videolan_libvlc_LibVLC_playMRL(JNIEnv *env, jobject thiz, jlong in
         libvlc_MediaPlayerStopped,
         libvlc_MediaPlayerVout,
         libvlc_MediaPlayerPositionChanged,
+        libvlc_MediaPlayerTimeChanged,
         libvlc_MediaPlayerEncounteredError
     };
     for(int i = 0; i < (sizeof(mp_events) / sizeof(*mp_events)); i++)
@@ -405,9 +425,13 @@ void Java_org_videolan_libvlc_LibVLC_playMRL(JNIEnv *env, jobject thiz, jlong in
             (*env)->ReleaseStringUTFChars(env, option, p_st);
         }
     }
-
+
     (*env)->ReleaseStringUTFChars(env, mrl, p_mrl);
 
+    // set the vlc object
+    vlc_object *object = (vlc_object *)(intptr_t)getLong(env, thiz, "mVLCObject");
+    libvlc_media_player_set_vlcobject(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[] = {
diff --git a/vlc-android/jni/utils.h b/vlc-android/jni/utils.h
index f8502d9..eab61da 100644
--- a/vlc-android/jni/utils.h
+++ b/vlc-android/jni/utils.h
@@ -21,6 +21,18 @@
 #ifndef LIBVLCJNI_UTILS_H
 #define LIBVLCJNI_UTILS_H
 
+#include <pthread.h>
+
+typedef struct vlc_object {
+	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;
+} vlc_object;
+
 libvlc_media_t *new_media(jlong instance, JNIEnv *env, jobject thiz, jstring fileLocation, bool noOmx, bool noVideo);
 
 libvlc_media_player_t *getMediaPlayer(JNIEnv *env, jobject thiz);
diff --git a/vlc-android/jni/vout.c b/vlc-android/jni/vout.c
index f2f4346..cd13a6b 100644
--- a/vlc-android/jni/vout.c
+++ b/vlc-android/jni/vout.c
@@ -23,96 +23,94 @@
 
 #include <jni.h>
 
+#include "utils.h"
+
 /** Unique Java VM instance, as defined in libvlcjni.c */
 extern JavaVM *myVm;
 
-pthread_mutex_t vout_android_lock;
-pthread_cond_t vout_android_surf_attached;
-static void *vout_android_surf = NULL;
-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(vlc_object *object) {
+    pthread_mutex_lock(&object->vout_android_lock);
+    while (object->vout_android_subtitles_surf == NULL)
+        pthread_cond_wait(&object->vout_android_surf_attached, &object->vout_android_lock);
+    return object->vout_android_subtitles_surf;
 }
 
-void *jni_LockAndGetAndroidSurface() {
-    pthread_mutex_lock(&vout_android_lock);
-    while (vout_android_surf == NULL)
-        pthread_cond_wait(&vout_android_surf_attached, &vout_android_lock);
-    return vout_android_surf;
+void *jni_LockAndGetAndroidSurface(vlc_object *object) {
+    pthread_mutex_lock(&object->vout_android_lock);
+    while (object->vout_android_surf == NULL)
+        pthread_cond_wait(&object->vout_android_surf_attached, &object->vout_android_lock);
+    return object->vout_android_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;
+jobject jni_LockAndGetAndroidJavaSurface(vlc_object *object) {
+    pthread_mutex_lock(&object->vout_android_lock);
+    while (object->vout_android_java_surf == NULL)
+        pthread_cond_wait(&object->vout_android_surf_attached, &object->vout_android_lock);
+    return object->vout_android_java_surf;
 }
 
-void jni_UnlockAndroidSurface() {
-    pthread_mutex_unlock(&vout_android_lock);
+void jni_UnlockAndroidSurface(vlc_object *object) {
+    pthread_mutex_unlock(&object->vout_android_lock);
 }
 
-void jni_EventHardwareAccelerationError()
+void jni_EventHardwareAccelerationError(vlc_object *object)
 {
-    if (vout_android_gui == NULL)
+    if (object->vout_android_gui == NULL)
         return;
 
     JNIEnv *env;
     (*myVm)->AttachCurrentThread(myVm, &env, NULL);
 
-    jclass cls = (*env)->GetObjectClass(env, vout_android_gui);
+    jclass cls = (*env)->GetObjectClass(env, object->vout_android_gui);
     jmethodID methodId = (*env)->GetMethodID(env, cls, "eventHardwareAccelerationError", "()V");
-    (*env)->CallVoidMethod(env, vout_android_gui, methodId);
+    (*env)->CallVoidMethod(env, object->vout_android_gui, methodId);
 
     (*env)->DeleteLocalRef(env, cls);
     (*myVm)->DetachCurrentThread(myVm);
 }
 
-void jni_SetAndroidSurfaceSizeEnv(JNIEnv *p_env, int width, int height, int visible_width, int visible_height, int sar_num, int sar_den)
+void jni_SetAndroidSurfaceSizeEnv(JNIEnv *p_env, vlc_object *object, int width, int height, int visible_width, int visible_height, int sar_num, int sar_den)
 {
-    if (vout_android_gui == NULL)
+    if (object->vout_android_gui == NULL)
         return;
 
-    jclass cls = (*p_env)->GetObjectClass (p_env, vout_android_gui);
+    jclass cls = (*p_env)->GetObjectClass (p_env, object->vout_android_gui);
     jmethodID methodId = (*p_env)->GetMethodID (p_env, cls, "setSurfaceSize", "(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, object->vout_android_gui, methodId, width, height, visible_width, visible_height, sar_num, sar_den);
 
     (*p_env)->DeleteLocalRef(p_env, cls);
 }
 
-void jni_SetAndroidSurfaceSize(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den)
+void jni_SetAndroidSurfaceSize(vlc_object *object, int width, int height, int visible_width, int visible_height, int sar_num, int sar_den)
 {
     JNIEnv *p_env;
 
     (*myVm)->AttachCurrentThread (myVm, &p_env, NULL);
-    jni_SetAndroidSurfaceSizeEnv(p_env, width, height, visible_width, visible_height, sar_num, sar_den);
+    jni_SetAndroidSurfaceSizeEnv(p_env, object, width, height, visible_width, visible_height, sar_num, sar_den);
 
     (*myVm)->DetachCurrentThread (myVm);
 }
 
-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(vlc_object *object) {
+    pthread_mutex_lock(&object->vout_android_lock);
+    bool result = object->vout_video_player_activity_created;
+    pthread_mutex_unlock(&object->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);
+	vlc_object * object = (vlc_object *)(intptr_t)getLong(env, thiz, "mVLCObject");
+
+    pthread_mutex_lock(&object->vout_android_lock);
+    object->vout_video_player_activity_created = created;
+    pthread_mutex_unlock(&object->vout_android_lock);
 }
 
 void Java_org_videolan_libvlc_LibVLC_attachSurface(JNIEnv *env, jobject thiz, jobject surf, jobject gui) {
-    pthread_mutex_lock(&vout_android_lock);
+	vlc_object * object = (vlc_object *)(intptr_t)getLong(env, thiz, "mVLCObject");
+
+    pthread_mutex_lock(&object->vout_android_lock);
     jclass clz;
     jfieldID fid;
 
@@ -131,39 +129,45 @@ void Java_org_videolan_libvlc_LibVLC_attachSurface(JNIEnv *env, jobject thiz, jo
             }
             fid = (*env)->GetFieldID(env, clz, "mNativeSurface", "I");
         }
-        vout_android_surf = (void*)(*env)->GetIntField(env, surf, fid);
+        object->vout_android_surf = (void*)(*env)->GetIntField(env, surf, fid);
         (*env)->DeleteLocalRef(env, clz);
     }
-    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);
+    object->vout_android_gui = (*env)->NewGlobalRef(env, gui);
+    object->vout_android_java_surf = (*env)->NewGlobalRef(env, surf);
+    pthread_cond_signal(&object->vout_android_surf_attached);
+    pthread_mutex_unlock(&object->vout_android_lock);
 }
 
 void Java_org_videolan_libvlc_LibVLC_detachSurface(JNIEnv *env, jobject thiz) {
-    pthread_mutex_lock(&vout_android_lock);
-    vout_android_surf = NULL;
-    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);
+	vlc_object *object = (vlc_object *)(intptr_t)getLong(env, thiz, "mVLCObject");
+
+    pthread_mutex_lock(&object->vout_android_lock);
+    object->vout_android_surf = NULL;
+    if (object->vout_android_gui != NULL)
+        (*env)->DeleteGlobalRef(env, object->vout_android_gui);
+    if (object->vout_android_java_surf != NULL)
+        (*env)->DeleteGlobalRef(env, object->vout_android_java_surf);
+    object->vout_android_gui = NULL;
+    object->vout_android_java_surf = NULL;
+    pthread_mutex_unlock(&object->vout_android_lock);
 }
 
 void Java_org_videolan_libvlc_LibVLC_attachSubtitlesSurface(JNIEnv *env, jobject thiz, jobject surf) {
-    pthread_mutex_lock(&vout_android_lock);
-    vout_android_subtitles_surf = (*env)->NewGlobalRef(env, surf);
-    pthread_cond_signal(&vout_android_surf_attached);
-    pthread_mutex_unlock(&vout_android_lock);
+	vlc_object *object = (vlc_object *)(intptr_t)getLong(env, thiz, "mVLCObject");
+
+    pthread_mutex_lock(&object->vout_android_lock);
+    object->vout_android_subtitles_surf = (*env)->NewGlobalRef(env, surf);
+    pthread_cond_signal(&object->vout_android_surf_attached);
+    pthread_mutex_unlock(&object->vout_android_lock);
 }
 
 void Java_org_videolan_libvlc_LibVLC_detachSubtitlesSurface(JNIEnv *env, jobject thiz) {
-    pthread_mutex_lock(&vout_android_lock);
-    (*env)->DeleteGlobalRef(env, vout_android_subtitles_surf);
-    vout_android_subtitles_surf = NULL;
-    pthread_mutex_unlock(&vout_android_lock);
+	vlc_object *object = (vlc_object *)(intptr_t)getLong(env, thiz, "mVLCObject");
+
+    pthread_mutex_lock(&object->vout_android_lock);
+    (*env)->DeleteGlobalRef(env, object->vout_android_subtitles_surf);
+    object->vout_android_subtitles_surf = NULL;
+    pthread_mutex_unlock(&object->vout_android_lock);
 }
 
 static int mouse_x = -1;
diff --git a/vlc-android/jni/vout.h b/vlc-android/jni/vout.h
index c3d4fd7..d14957a 100644
--- a/vlc-android/jni/vout.h
+++ b/vlc-android/jni/vout.h
@@ -21,8 +21,4 @@
 #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;
-
 #endif // LIBVLCJNI_VOUT_H
diff --git a/vlc-android/src/org/videolan/libvlc/EventHandler.java b/vlc-android/src/org/videolan/libvlc/EventHandler.java
index 5c365a6..005bc54 100644
--- a/vlc-android/src/org/videolan/libvlc/EventHandler.java
+++ b/vlc-android/src/org/videolan/libvlc/EventHandler.java
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * EventHandler.java
  *****************************************************************************
- * Copyright © 2011-2014 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
@@ -50,7 +50,7 @@ public class EventHandler {
     //public static final int MediaPlayerBackward             = 0x108;
     public static final int MediaPlayerEndReached             = 0x109;
     public static final int MediaPlayerEncounteredError       = 0x10a;
-    //public static final int MediaPlayerTimeChanged          = 0x10b;
+    public static final int MediaPlayerTimeChanged          = 0x10b;
     public static final int MediaPlayerPositionChanged        = 0x10c;
     //public static final int MediaPlayerSeekableChanged      = 0x10d;
     //public static final int MediaPlayerPausableChanged      = 0x10e;
diff --git a/vlc-android/src/org/videolan/libvlc/LibVLC.java b/vlc-android/src/org/videolan/libvlc/LibVLC.java
index 4af6857..ea7d8d4 100644
--- a/vlc-android/src/org/videolan/libvlc/LibVLC.java
+++ b/vlc-android/src/org/videolan/libvlc/LibVLC.java
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * LibVLC.java
  *****************************************************************************
- * Copyright © 2010-2013 VLC authors and VideoLAN
+ * Copyright 2010-2013 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
@@ -43,7 +43,7 @@ public class LibVLC {
     public static final int HW_ACCELERATION_DECODING = 1;
     public static final int HW_ACCELERATION_FULL = 2;
 
-    private static LibVLC sInstance;
+    // private static LibVLC sInstance;
 
     /** libVLC instance C pointer */
     private long mLibVlcInstance = 0; // Read-only, reserved for JNI
@@ -51,6 +51,9 @@ public class LibVLC {
     private int mInternalMediaPlayerIndex = 0; // Read-only, reserved for JNI
     private long mInternalMediaPlayerInstance = 0; // Read-only, reserved for JNI
 
+    private long mVLCObject = 0;
+    private long mInternalSurface = 0; // Read-only, reserved for JNI
+
     private MediaList mMediaList; // Pointer to media list being followed
     private MediaList mPrimaryList; // Primary/default media list; see getPrimaryMediaList()
 
@@ -125,16 +128,16 @@ public class LibVLC {
      * @return libVLC instance
      * @throws LibVlcException
      */
-    public static LibVLC getInstance() throws LibVlcException {
+    /*public static LibVLC getInstance() throws LibVlcException {
         synchronized (LibVLC.class) {
             if (sInstance == null) {
-                /* First call */
+                // First call //
                 sInstance = new LibVLC();
             }
         }
 
         return sInstance;
-    }
+    }*/
 
     /**
      * Return an existing instance of libVLC Call it when it is NOT important
@@ -142,17 +145,17 @@ public class LibVLC {
      *
      * @return libVLC instance OR null
      */
-    public static LibVLC getExistingInstance() {
+    /*public static LibVLC getExistingInstance() {
         synchronized (LibVLC.class) {
             return sInstance;
         }
-    }
+    }*/
 
     /**
      * Constructor
      * It is private because this class is a singleton.
      */
-    private LibVLC() {
+    protected LibVLC() {
         mAout = new AudioOutput();
     }
 
@@ -218,15 +221,15 @@ public class LibVLC {
      */
     public native void setSurface(Surface f);
 
-    public static synchronized void restart(Context context) {
-        if (sInstance != null) {
+    public synchronized void restart(Context context) {
+        //if (sInstance != null) {
             try {
-                sInstance.destroy();
-                sInstance.init(context);
+                this.destroy();
+                this.init(context);
             } catch (LibVlcException lve) {
                 Log.e(TAG, "Unable to reinit libvlc: " + lve);
             }
-        }
+       // }
     }
 
     /**
@@ -341,7 +344,7 @@ public class LibVLC {
         applyEqualizer();
     }
 
-    private void applyEqualizer()
+    protected void applyEqualizer()
     {
         setNativeEqualizer(mInternalMediaPlayerInstance, this.equalizer);
     }
@@ -628,6 +631,8 @@ public class LibVLC {
 
     public native Map<Integer,String> getAudioTrackDescription();
 
+    public native Map<String, Object> getStats();
+
     public native int getAudioTrack();
 
     public native int setAudioTrack(int index);
diff --git a/vlc-android/src/org/videolan/libvlc/MediaList.java b/vlc-android/src/org/videolan/libvlc/MediaList.java
index 85b2d2a..1889481 100644
--- a/vlc-android/src/org/videolan/libvlc/MediaList.java
+++ b/vlc-android/src/org/videolan/libvlc/MediaList.java
@@ -32,7 +32,7 @@ public class MediaList {
 
     /* Since the libvlc_media_t is not created until the media plays, we have
      * to cache them here. */
-    private static class MediaHolder {
+    private class MediaHolder {
         Media m;
         boolean noVideo; // default false
         boolean noHardwareAcceleration; // default false
diff --git a/vlc-android/src/org/videolan/libvlc/TrackInfo.java b/vlc-android/src/org/videolan/libvlc/TrackInfo.java
index 7cf23f0..b55dc55 100644
--- a/vlc-android/src/org/videolan/libvlc/TrackInfo.java
+++ b/vlc-android/src/org/videolan/libvlc/TrackInfo.java
@@ -32,6 +32,7 @@ public class TrackInfo {
     public int Id;
     public String Codec;
     public String Language;
+    public int Bitrate;
 
     /* Video */
     public int Height;
-- 
1.8.5.2 (Apple Git-48)



More information about the Android mailing list