[Android] [PATCH 07/13] libvlc: add Media, MediaList, MediaDiscoverer

Thomas Guillem thomas at gllm.fr
Thu Jan 15 19:22:24 CET 2015


These classes are quite similar with their native libvlc equivalent.
---
 libvlc/jni/Android.mk                              |   1 +
 libvlc/jni/libvlcjni-media.c                       | 376 ++++++++++++++++++
 libvlc/jni/libvlcjni-mediadiscoverer.c             |  98 +++++
 libvlc/jni/libvlcjni-medialist.c                   | 144 +++++++
 libvlc/jni/libvlcjni.c                             |  26 ++
 libvlc/jni/utils.h                                 |  10 +
 libvlc/src/org/videolan/libvlc/Media.java          | 420 +++++++++++++++++++++
 .../src/org/videolan/libvlc/MediaDiscoverer.java   |  93 +++++
 libvlc/src/org/videolan/libvlc/MediaList.java      | 148 ++++++++
 9 files changed, 1316 insertions(+)
 create mode 100644 libvlc/jni/libvlcjni-media.c
 create mode 100644 libvlc/jni/libvlcjni-mediadiscoverer.c
 create mode 100644 libvlc/jni/libvlcjni-medialist.c
 create mode 100644 libvlc/src/org/videolan/libvlc/Media.java
 create mode 100644 libvlc/src/org/videolan/libvlc/MediaDiscoverer.java
 create mode 100644 libvlc/src/org/videolan/libvlc/MediaList.java

diff --git a/libvlc/jni/Android.mk b/libvlc/jni/Android.mk
index ff0fdd8..5791164 100644
--- a/libvlc/jni/Android.mk
+++ b/libvlc/jni/Android.mk
@@ -6,6 +6,7 @@ LOCAL_MODULE    := libvlcjni
 LOCAL_SRC_FILES := libvlcjni.c libvlcjni-util.c libvlcjni-track.c
 LOCAL_SRC_FILES += libvlcjni-equalizer.c
 LOCAL_SRC_FILES += libvlcjni-vlcobject.c
+LOCAL_SRC_FILES += libvlcjni-media.c libvlcjni-medialist.c libvlcjni-mediadiscoverer.c
 LOCAL_SRC_FILES += event_thread.c
 LOCAL_SRC_FILES += aout.c vout.c native_crash_handler.c thumbnailer.c
 ifneq ($(ANDROID_API),android-21)
diff --git a/libvlc/jni/libvlcjni-media.c b/libvlc/jni/libvlcjni-media.c
new file mode 100644
index 0000000..b1b1a95
--- /dev/null
+++ b/libvlc/jni/libvlcjni-media.c
@@ -0,0 +1,376 @@
+/*****************************************************************************
+ * libvlcjni-media.c
+ *****************************************************************************
+ * Copyright © 2015 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
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ *****************************************************************************/
+
+#include <stdlib.h>
+
+#include "libvlcjni-vlcobject.h"
+
+#define META_MAX 25
+
+static const libvlc_event_type_t m_events[] = {
+    libvlc_MediaMetaChanged,
+    libvlc_MediaSubItemAdded,
+    //libvlc_MediaFreed,
+    libvlc_MediaDurationChanged,
+    libvlc_MediaStateChanged,
+    libvlc_MediaParsedChanged,
+    libvlc_MediaSubItemTreeAdded,
+    -1,
+};
+
+static void
+Media_nativeNewCommon(JNIEnv *env, jobject thiz, vlcjni_object *p_obj)
+{
+    if (!p_obj->u.p_m)
+    {
+        VLCJniObject_release(env, thiz, p_obj);
+        throw_IllegalStateException(env, "can't create Media instance");
+        return;
+    }
+
+    libvlc_media_add_option(p_obj->u.p_m, ":file-caching=1500");
+    libvlc_media_add_option(p_obj->u.p_m, ":network-caching=1500");
+    libvlc_media_add_option(p_obj->u.p_m, ":no-video");
+    VLCJniObject_attachEvents(p_obj,
+                              libvlc_media_event_manager(p_obj->u.p_m),
+                              m_events);
+}
+
+void
+Java_org_videolan_libvlc_Media_nativeNewFromMrl(JNIEnv *env, jobject thiz,
+                                                jobject libVlc, jstring jmrl)
+{
+    vlcjni_object *p_obj;
+    const char* p_mrl;
+
+    if (!jmrl || !(p_mrl = (*env)->GetStringUTFChars(env, jmrl, 0)))
+    {
+        throw_IllegalArgumentException(env, "mrl invalid");
+        return;
+    }
+
+    p_obj = VLCJniObject_newFromJavaLibVlc(env, thiz, libVlc);
+
+    if (!p_obj)
+    {
+        (*env)->ReleaseStringUTFChars(env, jmrl, p_mrl);
+        throw_IllegalStateException(env, "can't create VLCObject");
+        return;
+    }
+
+    if (p_mrl[0] == '/' || p_mrl[0] == '\\')
+        p_obj->u.p_m = libvlc_media_new_path(p_obj->p_libvlc, p_mrl);
+    else
+        p_obj->u.p_m = libvlc_media_new_location(p_obj->p_libvlc, p_mrl);
+
+    (*env)->ReleaseStringUTFChars(env, jmrl, p_mrl);
+
+    Media_nativeNewCommon(env, thiz, p_obj);
+}
+
+void
+Java_org_videolan_libvlc_Media_nativeNewFromMediaList(JNIEnv *env, jobject thiz,
+                                                      jobject ml, jint index)
+{
+    vlcjni_object *p_ml_obj = VLCJniObject_getInstance(env, ml);
+    vlcjni_object *p_obj;
+
+    if (!p_ml_obj)
+    {
+        throw_IllegalStateException(env, "can't get MediaList instance");
+        return;
+    }
+
+    p_obj = VLCJniObject_newFromLibVlc(env, thiz, p_ml_obj->p_libvlc);
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't create VLCObject");
+        return;
+    }
+
+    libvlc_media_list_lock(p_ml_obj->u.p_ml);
+    p_obj->u.p_m = libvlc_media_list_item_at_index(p_ml_obj->u.p_ml, index);
+    libvlc_media_list_unlock(p_ml_obj->u.p_ml);
+
+    Media_nativeNewCommon(env, thiz, p_obj);
+}
+
+void
+Java_org_videolan_libvlc_Media_nativeRelease(JNIEnv *env, jobject thiz)
+{
+    vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+
+    if (!p_obj)
+        return;
+
+    libvlc_media_release(p_obj->u.p_m);
+
+    VLCJniObject_release(env, thiz, p_obj);
+}
+
+jstring
+Java_org_videolan_libvlc_Media_nativeGetMrl(JNIEnv *env, jobject thiz)
+{
+    vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+    const char *psz_mrl;
+
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't get Media instance");
+        return NULL;
+    }
+
+    psz_mrl = libvlc_media_get_mrl(p_obj->u.p_m);
+    if (psz_mrl)
+        return (*env)->NewStringUTF(env, psz_mrl);
+
+    return NULL;
+}
+
+jint
+Java_org_videolan_libvlc_Media_nativeGetState(JNIEnv *env, jobject thiz)
+{
+    vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't get Media instance");
+        return libvlc_Error;
+    }
+    return libvlc_media_get_state(p_obj->u.p_m);
+}
+
+jstring
+Java_org_videolan_libvlc_Media_nativeGetMeta(JNIEnv *env, jobject thiz, jint id)
+{
+    vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+    jstring jmeta = NULL;
+
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't get Media instance");
+        return NULL;
+    }
+    if (id >= 0 && id < META_MAX) {
+        char *psz_media = libvlc_media_get_meta(p_obj->u.p_m, id);
+        if (psz_media) {
+            jmeta = (*env)->NewStringUTF(env, psz_media);
+            free(psz_media);
+        }
+    }
+    return jmeta;
+}
+
+jobject
+Java_org_videolan_libvlc_Media_nativeGetMetas(JNIEnv *env, jobject thiz)
+{
+    vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+    jobjectArray array;
+
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't get Media instance");
+        return NULL;
+    }
+    array = (*env)->NewObjectArray(env, META_MAX, fields.String.clazz, NULL);
+    if (!array)
+        return NULL;
+
+    for (int i = 0; i < META_MAX; ++i)
+    {
+        char *psz_media = libvlc_media_get_meta(p_obj->u.p_m, i);
+        if (psz_media)
+        {
+            jstring jmedia = (*env)->NewStringUTF(env, psz_media);
+            free(psz_media);
+            if (!jmedia)
+            {
+                (*env)->DeleteLocalRef(env, array);
+                return NULL;
+            }
+            (*env)->SetObjectArrayElement(env, array, i, jmedia);
+        }
+    }
+
+    return array;
+}
+
+static jobject
+media_track_to_object(JNIEnv *env, libvlc_media_track_t *p_tracks)
+{
+    const char *psz_desc;
+    jstring jcodec = NULL;
+    jstring joriginalCodec = NULL;
+    jstring jlanguage = NULL;
+    jstring jdescription = NULL;
+
+    if (!p_tracks || p_tracks->i_type == libvlc_track_unknown)
+        return NULL;
+
+    psz_desc = libvlc_media_get_codec_description(p_tracks->i_id,
+                                                  p_tracks->i_codec);
+    if (psz_desc)
+        jcodec = (*env)->NewStringUTF(env, psz_desc);
+
+    psz_desc = libvlc_media_get_codec_description(p_tracks->i_id,
+                                                  p_tracks->i_original_fourcc);
+    if (psz_desc)
+        joriginalCodec = (*env)->NewStringUTF(env, psz_desc);
+
+    if (p_tracks->psz_language)
+        jlanguage = (*env)->NewStringUTF(env, p_tracks->psz_language);
+
+    if (p_tracks->psz_description)
+        jdescription = (*env)->NewStringUTF(env, p_tracks->psz_description);
+
+    switch (p_tracks->i_type)
+    {
+        case libvlc_track_audio:
+            return (*env)->CallStaticObjectMethod(env, fields.Media.clazz,
+                                fields.Media.createAudioTrackFromNativeID,
+                                jcodec,
+                                joriginalCodec,
+                                (jint)p_tracks->i_id,
+                                (jint)p_tracks->i_profile,
+                                (jint)p_tracks->i_level,
+                                (jint)p_tracks->i_bitrate,
+                                jlanguage,
+                                jdescription,
+                                (jint)p_tracks->audio->i_channels,
+                                (jint)p_tracks->audio->i_rate);
+        case libvlc_track_video:
+            return (*env)->CallStaticObjectMethod(env, fields.Media.clazz,
+                                fields.Media.createVideoTrackFromNativeID,
+                                jcodec,
+                                joriginalCodec,
+                                (jint)p_tracks->i_id,
+                                (jint)p_tracks->i_profile,
+                                (jint)p_tracks->i_level,
+                                (jint)p_tracks->i_bitrate,
+                                jlanguage,
+                                jdescription,
+                                (jint)p_tracks->video->i_height,
+                                (jint)p_tracks->video->i_width,
+                                (jint)p_tracks->video->i_sar_num,
+                                (jint)p_tracks->video->i_sar_den,
+                                (jint)p_tracks->video->i_frame_rate_num,
+                                (jint)p_tracks->video->i_frame_rate_den);
+        case libvlc_track_text: {
+            jstring jencoding = NULL;
+
+            if (p_tracks->subtitle->psz_encoding)
+                jencoding = (*env)->NewStringUTF(env, p_tracks->subtitle->psz_encoding);
+
+            return (*env)->CallStaticObjectMethod(env, fields.Media.clazz,
+                                fields.Media.createSubtitleTrackFromNativeID,
+                                jcodec,
+                                joriginalCodec,
+                                (jint)p_tracks->i_id,
+                                (jint)p_tracks->i_profile,
+                                (jint)p_tracks->i_level,
+                                (jint)p_tracks->i_bitrate,
+                                jlanguage,
+                                jdescription,
+                                jencoding);
+        }
+        default:
+            return NULL;
+    }
+}
+
+jobject
+Java_org_videolan_libvlc_Media_nativeGetTracks(JNIEnv *env, jobject thiz)
+{
+    vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+    libvlc_media_track_t **pp_tracks = NULL;
+    unsigned int i_nb_tracks = 0;
+    jobjectArray array;
+
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't get Media instance");
+        return NULL;
+    }
+
+    i_nb_tracks = libvlc_media_tracks_get(p_obj->u.p_m, &pp_tracks);
+    if (!i_nb_tracks)
+        return NULL;
+
+    array = (*env)->NewObjectArray(env, i_nb_tracks, fields.Media.Track.clazz,
+                                   NULL);
+    if (!array)
+        goto error;
+
+    for (int i = 0; i < i_nb_tracks; ++i)
+    {
+        jobject jtrack = media_track_to_object(env, pp_tracks[i]);
+
+        if (jtrack) 
+            (*env)->SetObjectArrayElement(env, array, i, jtrack);
+    }
+
+error:
+    if (pp_tracks)
+        libvlc_media_tracks_release(pp_tracks, i_nb_tracks);
+    return array;
+}
+
+jboolean
+Java_org_videolan_libvlc_Media_nativeParseWithOptions(JNIEnv *env, jobject thiz,
+                                                      jint flags)
+{
+    vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't get Media instance");
+        return false;
+    }
+
+    return libvlc_media_parse_with_options(p_obj->u.p_m, flags) == 0 ? true : false;
+}
+
+void
+Java_org_videolan_libvlc_Media_nativeParse(JNIEnv *env, jobject thiz)
+{
+    vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't get Media instance");
+        return false;
+    }
+
+    libvlc_media_parse(p_obj->u.p_m);
+}
+
+jlong
+Java_org_videolan_libvlc_Media_nativeGetDuration(JNIEnv *env, jobject thiz)
+{
+    vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't get Media instance");
+        return 0;
+    }
+
+    return libvlc_media_get_duration(p_obj->u.p_m);
+}
diff --git a/libvlc/jni/libvlcjni-mediadiscoverer.c b/libvlc/jni/libvlcjni-mediadiscoverer.c
new file mode 100644
index 0000000..502943d
--- /dev/null
+++ b/libvlc/jni/libvlcjni-mediadiscoverer.c
@@ -0,0 +1,98 @@
+/*****************************************************************************
+ * libvlcjni-mediadiscoverer.c
+ *****************************************************************************
+ * Copyright © 2015 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
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ *****************************************************************************/
+
+#include "libvlcjni-vlcobject.h"
+
+void
+Java_org_videolan_libvlc_MediaDiscoverer_nativeNew(JNIEnv *env,
+                                                   jobject thiz, jobject libVlc,
+                                                   jstring jname)
+{
+    vlcjni_object *p_obj;
+    const char* p_name;
+
+    if (!jname || !(p_name = (*env)->GetStringUTFChars(env, jname, 0)))
+    {
+        throw_IllegalArgumentException(env, "jname invalid");
+        return;
+    }
+
+    p_obj = VLCJniObject_newFromJavaLibVlc(env, thiz, libVlc);
+
+    if (!p_obj)
+    {
+        (*env)->ReleaseStringUTFChars(env, jname, p_name);
+        throw_IllegalStateException(env, "can't create VLCObject");
+        return;
+    }
+
+    p_obj->u.p_md = libvlc_media_discoverer_new(p_obj->p_libvlc, p_name);
+
+    (*env)->ReleaseStringUTFChars(env, jname, p_name);
+
+    if (!p_obj->u.p_md)
+    {
+        VLCJniObject_release(env, thiz, p_obj);
+        throw_IllegalStateException(env, "can't create MediaDiscoverer instance");
+        return;
+    }
+}
+
+void
+Java_org_videolan_libvlc_MediaDiscoverer_nativeRelease(JNIEnv *env,
+                                                       jobject thiz)
+{
+    vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+
+    if (!p_obj)
+        return;
+
+    libvlc_media_discoverer_release(p_obj->u.p_md);
+
+    VLCJniObject_release(env, thiz, p_obj);
+}
+
+jboolean
+Java_org_videolan_libvlc_MediaDiscoverer_nativeStart(JNIEnv *env, jobject thiz)
+{
+    vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't get MediaDiscoverer instance");
+        return false;
+    }
+
+    return libvlc_media_discoverer_start(p_obj->u.p_md) == 0 ? true : false;
+}
+
+void
+Java_org_videolan_libvlc_MediaDiscoverer_nativeStop(JNIEnv *env, jobject thiz)
+{
+    vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't get MediaDiscoverer instance");
+        return;
+    }
+
+    libvlc_media_discoverer_stop(p_obj->u.p_md);
+}
diff --git a/libvlc/jni/libvlcjni-medialist.c b/libvlc/jni/libvlcjni-medialist.c
new file mode 100644
index 0000000..efa281c
--- /dev/null
+++ b/libvlc/jni/libvlcjni-medialist.c
@@ -0,0 +1,144 @@
+/*****************************************************************************
+ * libvlcjni-medialist.c
+ *****************************************************************************
+ * Copyright © 2015 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
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ *****************************************************************************/
+
+#include "libvlcjni-vlcobject.h"
+
+static const libvlc_event_type_t ml_events[] = {
+    libvlc_MediaListItemAdded,
+    //libvlc_MediaListWillAddItem,
+    libvlc_MediaListItemDeleted,
+    //libvlc_MediaListWillDeleteItem,
+    -1,
+};
+
+static void
+MediaList_nativeNewCommon(JNIEnv *env, jobject thiz, vlcjni_object *p_obj)
+{
+    if (!p_obj->u.p_ml)
+    {
+        VLCJniObject_release(env, thiz, p_obj);
+        throw_IllegalStateException(env, "can't create MediaList instance");
+        return;
+    }
+    VLCJniObject_attachEvents(p_obj,
+                              libvlc_media_list_event_manager(p_obj->u.p_ml),
+                              ml_events);
+}
+
+void
+Java_org_videolan_libvlc_MediaList_nativeNewFromLibVlc(JNIEnv *env,
+                                                       jobject thiz,
+                                                       jobject libVlc)
+{
+    vlcjni_object *p_obj = VLCJniObject_newFromJavaLibVlc(env, thiz, libVlc);
+
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't create VLCObject");
+        return;
+    }
+
+    p_obj->u.p_ml = libvlc_media_list_new(p_obj->p_libvlc);
+
+    MediaList_nativeNewCommon(env, thiz, p_obj);
+}
+
+void
+Java_org_videolan_libvlc_MediaList_nativeNewFromMediaDiscoverer(JNIEnv *env,
+                                                                jobject thiz,
+                                                                jobject md)
+{
+    vlcjni_object *p_md_obj = VLCJniObject_getInstance(env, md);
+    vlcjni_object *p_obj;
+
+    if (!p_md_obj)
+    {
+        throw_IllegalStateException(env, "can't get MediaDiscoverer instance");
+        return;
+    }
+
+    p_obj = VLCJniObject_newFromLibVlc(env, thiz, p_md_obj->p_libvlc);
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't create VLCObject");
+        return;
+    }
+
+    p_obj->u.p_ml = libvlc_media_discoverer_media_list(p_md_obj->u.p_md);
+
+    MediaList_nativeNewCommon(env, thiz, p_obj);
+}
+
+void
+Java_org_videolan_libvlc_MediaList_nativeNewFromMedia(JNIEnv *env,
+                                                      jobject thiz,
+                                                      jobject m)
+{
+    vlcjni_object *p_m_obj = VLCJniObject_getInstance(env, m);
+    vlcjni_object *p_obj;
+
+    if (!p_m_obj)
+    {
+        throw_IllegalStateException(env, "can't get Media instance");
+        return;
+    }
+
+    p_obj = VLCJniObject_newFromLibVlc(env, thiz, p_m_obj->p_libvlc);
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't create VLCObject");
+        return;
+    }
+
+    p_obj->u.p_ml = libvlc_media_subitems(p_m_obj->u.p_m);
+
+    MediaList_nativeNewCommon(env, thiz, p_obj);
+}
+
+void
+Java_org_videolan_libvlc_MediaList_nativeRelease(JNIEnv *env, jobject thiz)
+{
+    vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+
+    if (!p_obj)
+        return;
+
+    libvlc_media_list_release(p_obj->u.p_ml);
+
+    VLCJniObject_release(env, thiz, p_obj);
+}
+
+jint
+Java_org_videolan_libvlc_MediaList_nativeGetCount(JNIEnv *env, jobject thiz)
+{
+    vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+    jint count;
+
+    if (!p_obj)
+    {
+        throw_IllegalStateException(env, "can't get MediaList instance");
+        return 0;
+    }
+
+    libvlc_media_list_lock(p_obj->u.p_ml);
+    count = libvlc_media_list_count(p_obj->u.p_ml);
+    libvlc_media_list_unlock(p_obj->u.p_ml);
+    return count;
+}
diff --git a/libvlc/jni/libvlcjni.c b/libvlc/jni/libvlcjni.c
index 393dc04..033c47c 100644
--- a/libvlc/jni/libvlcjni.c
+++ b/libvlc/jni/libvlcjni.c
@@ -260,6 +260,10 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved)
               "java/lang/String");
     GET_CLASS(fields.VLCObject.clazz,
               "org/videolan/libvlc/VLCObject");
+    GET_CLASS(fields.Media.clazz,
+              "org/videolan/libvlc/Media");
+    GET_CLASS(fields.Media.Track.clazz,
+              "org/videolan/libvlc/Media$Track");
 
     GET_ID(GetFieldID,
            fields.VLCObject.mInstanceID,
@@ -271,6 +275,27 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved)
            fields.VLCObject.clazz,
            "dispatchEventFromNative", "(IJJ)V");
 
+    GET_ID(GetStaticMethodID,
+           fields.Media.createAudioTrackFromNativeID,
+           fields.Media.clazz,
+           "createAudioTrackFromNative",
+           "(Ljava/lang/String;Ljava/lang/String;IIIILjava/lang/String;Ljava/lang/String;II)"
+           "Lorg/videolan/libvlc/Media$Track;");
+
+    GET_ID(GetStaticMethodID,
+           fields.Media.createVideoTrackFromNativeID,
+           fields.Media.clazz,
+           "createVideoTrackFromNative",
+           "(Ljava/lang/String;Ljava/lang/String;IIIILjava/lang/String;Ljava/lang/String;IIIIII)"
+           "Lorg/videolan/libvlc/Media$Track;");
+
+    GET_ID(GetStaticMethodID,
+           fields.Media.createSubtitleTrackFromNativeID,
+           fields.Media.clazz,
+           "createSubtitleTrackFromNative",
+           "(Ljava/lang/String;Ljava/lang/String;IIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)"
+           "Lorg/videolan/libvlc/Media$Track;");
+
 #undef GET_CLASS
 #undef GET_ID
 
@@ -300,6 +325,7 @@ void JNI_OnUnload(JavaVM* vm, void* reserved)
     (*env)->DeleteGlobalRef(env, fields.IllegalArgumentException.clazz);
     (*env)->DeleteGlobalRef(env, fields.String.clazz);
     (*env)->DeleteGlobalRef(env, fields.VLCObject.clazz);
+    (*env)->DeleteGlobalRef(env, fields.Media.clazz);
 }
 
 int jni_attach_thread(JNIEnv **env, const char *thread_name)
diff --git a/libvlc/jni/utils.h b/libvlc/jni/utils.h
index 14879bc..30df7ca 100644
--- a/libvlc/jni/utils.h
+++ b/libvlc/jni/utils.h
@@ -36,6 +36,16 @@ struct fields {
         jfieldID mInstanceID;
         jmethodID dispatchEventFromNativeID;
     } VLCObject;
+    struct {
+        struct {
+            jclass clazz;
+        } Track;
+
+        jclass clazz;
+        jmethodID createAudioTrackFromNativeID;
+        jmethodID createVideoTrackFromNativeID;
+        jmethodID createSubtitleTrackFromNativeID;
+    } Media;
 };
 
 extern struct fields fields;
diff --git a/libvlc/src/org/videolan/libvlc/Media.java b/libvlc/src/org/videolan/libvlc/Media.java
new file mode 100644
index 0000000..a3229ec
--- /dev/null
+++ b/libvlc/src/org/videolan/libvlc/Media.java
@@ -0,0 +1,420 @@
+/*****************************************************************************
+ * Media.java
+ *****************************************************************************
+ * Copyright © 2015 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
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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;
+
+public final class Media extends VLCObject {
+    private final static String TAG = "LibVLC/Media";
+
+    /**
+     * see libvlc_meta_t
+     */
+    public static class Meta {
+        public static final int Title = 0;
+        public static final int Artist = 1;
+        public static final int Genre = 2;
+        public static final int Copyright = 3;
+        public static final int Album = 4;
+        public static final int TrackNumber = 5;
+        public static final int Description = 6;
+        public static final int Rating = 7;
+        public static final int Date = 8;
+        public static final int Setting = 9;
+        public static final int URL = 10;
+        public static final int Language = 11;
+        public static final int NowPlaying = 12;
+        public static final int Publisher = 13;
+        public static final int EncodedBy = 14;
+        public static final int ArtworkURL = 15;
+        public static final int TrackID = 16;
+        public static final int TrackTotal = 17;
+        public static final int Director = 18;
+        public static final int Season = 19;
+        public static final int Episode = 20;
+        public static final int ShowName = 21;
+        public static final int Actors = 22;
+        public static final int AlbumArtist = 23;
+        public static final int DiscNumber = 24;
+        public static final int MAX = 25;
+    }
+
+    /**
+     * see libvlc_state_t
+     */
+    public static class State {
+        public static final int NothingSpecial = 0;
+        public static final int Opening = 1;
+        public static final int Buffering = 2;
+        public static final int Playing = 3;
+        public static final int Paused = 4;
+        public static final int Stopped = 5;
+        public static final int Ended = 6;
+        public static final int Error = 7;
+        public static final int MAX = 8;
+    }
+
+    /**
+     * see libvlc_media_parse_flag_t
+     */
+    public static class Parse {
+        public static final int FetchArtLocal = 0x01;
+        public static final int FetchArtNetwork = 0x02;
+        public static final int ParseNetwork = 0x04;
+    }
+
+    /**
+     * see libvlc_media_track_t
+     */
+    public static abstract class Track {
+        public static class Type {
+            public static final int Unknown = -1;
+            public static final int Audio = 0;
+            public static final int Video = 1;
+            public static final int Text = 2;
+        }
+
+        public final int type;
+        public final String codec;
+        public final String originalCodec;
+        public final int id;
+        public final int profile;
+        public final int level;
+        public final int bitrate;
+        public final String language;
+        public final String description;
+
+        private Track(int type, String codec, String originalCodec, int id, int profile,
+                int level, int bitrate, String language, String description) {
+            this.type = type;
+            this.codec = codec;
+            this.originalCodec = originalCodec;
+            this.id = id;
+            this.profile = profile;
+            this.level = level;
+            this.bitrate = bitrate;
+            this.language = language;
+            this.description = description;
+        }
+    }
+
+    /**
+     * see libvlc_audio_track_t
+     */
+    public static class AudioTrack extends Track {
+        public final int channels;
+        public final int rate;
+
+        private AudioTrack(String codec, String originalCodec, int id, int profile,
+                int level, int bitrate, String language, String description,
+                int channels, int rate) {
+            super(Type.Audio, codec, originalCodec, id, profile, level, bitrate, language, description);
+            this.channels = channels;
+            this.rate = rate;
+        }
+    }
+
+    /* Used from JNI */
+    private static Track createAudioTrackFromNative(String codec, String originalCodec, int id, int profile,
+            int level, int bitrate, String language, String description,
+            int channels, int rate) {
+        return new AudioTrack(codec, originalCodec, id, profile,
+                level, bitrate, language, description,
+                channels, rate);
+    }
+
+    /**
+     * see libvlc_video_track_t
+     */
+    public static class VideoTrack extends Track {
+        public final int height;
+        public final int width;
+        public final int sarNum;
+        public final int sarDen;
+        public final int frameRateNum;
+        public final int frameRateDen;
+
+        private VideoTrack(String codec, String originalCodec, int id, int profile,
+                int level, int bitrate, String language, String description,
+                int height, int width, int sarNum, int sarDen, int frameRateNum, int frameRateDen) {
+            super(Type.Video, codec, originalCodec, id, profile, level, bitrate, language, description);
+            this.height = height;
+            this.width = width;
+            this.sarNum = sarNum;
+            this.sarDen = sarDen;
+            this.frameRateNum = frameRateNum;
+            this.frameRateDen = frameRateDen;
+        }
+    }
+
+    /* Used from JNI */
+    private static Track createVideoTrackFromNative(String codec, String originalCodec, int id, int profile,
+            int level, int bitrate, String language, String description,
+            int height, int width, int sarNum, int sarDen, int frameRateNum, int frameRateDen) {
+        return new VideoTrack(codec, originalCodec, id, profile,
+                level, bitrate, language, description,
+                height, width, sarNum, sarDen, frameRateNum, frameRateDen);
+    }
+
+    /**
+     * see libvlc_subtitle_track_t
+     */
+    public static class SubtitleTrack extends Track {
+        public final String encoding;
+
+        private SubtitleTrack(String codec, String originalCodec, int id, int profile,
+                int level, int bitrate, String language, String description,
+                String encoding) {
+            super(Type.Text, codec, originalCodec, id, profile, level, bitrate, language, description);
+            this.encoding = encoding;
+        }
+    }
+
+    /* Used from JNI */
+    private static Track createSubtitleTrackFromNative(String codec, String originalCodec, int id, int profile,
+            int level, int bitrate, String language, String description,
+            String encoding) {
+        return new SubtitleTrack(codec, originalCodec, id, profile,
+                level, bitrate, language, description,
+                encoding);
+    }
+
+    private static final int PARSE_STATUS_INIT = 0x00;
+    private static final int PARSE_STATUS_PARSING = 0x01;
+    private static final int PARSE_STATUS_PARSED = 0x02;
+    private static final int PARSE_STATUS_PARSED_EVENT = 0x04;
+
+    private String mMrl = null;
+    private MediaList mSubItems = null;
+    private int mParseStatus = PARSE_STATUS_INIT;
+    private String mMetas[] = new String[Meta.MAX];
+    private String mNativeMetas[] = null;
+    private Track mNativeTracks[] = null;
+    private long mDuration;
+    private int mState = State.NothingSpecial;
+
+    /**
+     * Create a Media from libVLC and a mrl.
+     *
+     * @param libVLC
+     * @param mrl
+     */
+    public Media(LibVLC libVLC, String mrl) {
+        nativeNewFromMrl(libVLC, mrl);
+        mMrl = nativeGetMrl();
+    }
+
+    /**
+     *
+     * @param ml Should not be released
+     * @param index
+     */
+    protected Media(MediaList ml, int index) {
+        if (ml.isReleased())
+            throw new IllegalArgumentException("MediaList is not native");
+        nativeNewFromMediaList(ml, index);
+        mMrl = nativeGetMrl();
+    }
+
+    @Override
+    protected synchronized boolean onEventNative(int event, long arg1, long arg2) {
+        switch (event) {
+        case VLCObject.Events.MediaMetaChanged:
+            /* fetch specific meta only when MediaParsedChanged
+             * event is received (avoid to fetch more than one time a meta). */
+            if ((mParseStatus & PARSE_STATUS_PARSED_EVENT) != 0) {
+                int id = (int) arg1;
+                if (id >= 0 && id < Meta.MAX)
+                    mNativeMetas[id] = nativeGetMeta(id);
+                return true;
+            } else
+                return false;
+        case VLCObject.Events.MediaSubItemAdded:
+            return true;
+        case VLCObject.Events.MediaDurationChanged:
+            mDuration = nativeGetDuration();
+            return true;
+        case VLCObject.Events.MediaParsedChanged:
+            mParseStatus |= PARSE_STATUS_PARSED_EVENT;
+            postParse();
+            return true;
+        case VLCObject.Events.MediaStateChanged: {
+            mState = nativeGetState();
+            return true;
+        }
+        case VLCObject.Events.MediaSubItemTreeAdded:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    /**
+     * Get the MRL associated with the Media.
+     */
+    public synchronized String getMrl() {
+        return mMrl;
+    }
+
+    /**
+     * Get the duration of the media.
+     */
+    public synchronized long getDuration() {
+        return mDuration;
+    }
+
+    /**
+     * Get the state of the media.
+     *
+     * @see State
+     */
+    public synchronized int getState() {
+        return mState;
+    }
+
+    /**
+     * Get the subItems MediaList associated with the Media.
+     *
+     * @return subItems as a MediaList, Should NOT be released.
+     */
+    public synchronized MediaList subItems() {
+        if (mSubItems == null && !isReleased())
+            mSubItems = new MediaList(this);
+        return mSubItems;
+    }
+
+    private synchronized void postParse() {
+        // fetch if native, parsed and not fetched
+        if (!isReleased() && (mParseStatus & PARSE_STATUS_PARSING) != 0
+                && (mParseStatus & PARSE_STATUS_PARSED) == 0) {
+            mParseStatus &= ~PARSE_STATUS_PARSING;
+            mParseStatus |= PARSE_STATUS_PARSED;
+            mNativeTracks = nativeGetTracks();
+            mNativeMetas = nativeGetMetas();
+            if (mNativeMetas.length != Meta.MAX)
+                throw new IllegalStateException("native metas size doesn't match");
+            mDuration = nativeGetDuration();
+            mState = nativeGetState();
+        }
+    }
+
+    /**
+     * Parse the media and local art.
+     */
+    public synchronized void parse() {
+        if (!isReleased() && (mParseStatus & (PARSE_STATUS_PARSED|PARSE_STATUS_PARSING)) == 0) {
+            mParseStatus |= PARSE_STATUS_PARSING;
+            nativeParse();
+            postParse();
+        }
+    }
+
+    private synchronized boolean parseWithOptions(int flags) {
+        if (!isReleased() && (mParseStatus & (PARSE_STATUS_PARSED|PARSE_STATUS_PARSING)) == 0) {
+            mParseStatus |= PARSE_STATUS_PARSING;
+            return nativeParseWithOptions(flags);
+        } else
+            return false;
+    }
+
+    /**
+     * Parse the media asynchronously with a flag.
+     *
+     * To track when this is over you can listen to {@link VLCObject.Events#MediaParsedChanged}
+     * event (only if this methods returned true).
+     *
+     * @param flags see {@link Parse}
+     * @param return true in case of success, false otherwise.
+     */
+    public synchronized boolean parseAsync(int flags) {
+        return parseWithOptions(flags);
+    }
+
+    /**
+     * Parse the media and local art asynchronously.
+     *
+     * @see #parseAsync(int)
+     */
+    public synchronized boolean parseAsync() {
+        return parseAsync(Parse.FetchArtLocal);
+    }
+
+    /**
+     * Returns true if the media is parsed
+     */
+    public synchronized boolean isParsed() {
+        return (mState & PARSE_STATUS_PARSED) != 0;
+    }
+
+    /**
+     * Get the Track count.
+     */
+    public synchronized int getTrackCount() {
+        return mNativeTracks != null ? mNativeTracks.length : 0;
+    }
+
+    /**
+     * Get a Track
+     * The Track can be casted to {@link AudioTrack}, {@link VideoTrack} or {@link SubtitleTrack} in function of the {@link Track.Type}.
+     *
+     * @param idx
+     * @return Track or null if not idx is not valid
+     * @see #getTrackCount()
+     */
+    public synchronized Track getTrack(int idx) {
+        if (mNativeTracks == null || idx < 0 || idx >= mNativeTracks.length)
+            return null;
+        return mNativeTracks[idx];
+    }
+
+    /**
+     * Get a Meta.
+     *
+     * @param id see {@link Meta}
+     * @return meta or null if not found
+     */
+    public synchronized String getMeta(int id) {
+        if (id < 0 || id >= Meta.MAX)
+            return null;
+        if (mMetas[id] != null)
+            return mMetas[id];
+        else
+            return mNativeMetas != null ? mNativeMetas[id] : null;
+    }
+
+    @Override
+    protected void onReleaseNative() {
+        if (mSubItems != null)
+            mSubItems.release();
+        nativeRelease();
+    }
+
+    /* JNI */
+    private native void nativeNewFromMrl(LibVLC libVLC, String mrl);
+    private native void nativeNewFromMediaList(MediaList ml, int index);
+    private native void nativeRelease();
+    private native boolean nativeParseWithOptions(int flags);
+    private native void nativeParse();
+    private native String nativeGetMrl();
+    private native int nativeGetState();
+    private native String nativeGetMeta(int id);
+    private native String[] nativeGetMetas();
+    private native Track[] nativeGetTracks();
+    private native long nativeGetDuration();
+}
diff --git a/libvlc/src/org/videolan/libvlc/MediaDiscoverer.java b/libvlc/src/org/videolan/libvlc/MediaDiscoverer.java
new file mode 100644
index 0000000..9085b91
--- /dev/null
+++ b/libvlc/src/org/videolan/libvlc/MediaDiscoverer.java
@@ -0,0 +1,93 @@
+/*****************************************************************************
+ * MediaDiscoverer.java
+ *****************************************************************************
+ * Copyright © 2015 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
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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;
+
+public final class MediaDiscoverer extends VLCObject {
+    private final static String TAG = "LibVLC/MediaDiscoverer";
+    private MediaList mMediaList;
+
+    /**
+     * Create a MediaDiscover.
+     *
+     * @param libVLC
+     * @param name Name of the vlc service discovery ("dsm", "upnp", "bonjour"...).
+     */
+    public MediaDiscoverer(LibVLC libVLC, String name) {
+        nativeNew(libVLC, name);
+    }
+
+    /**
+     * Starts the discovery.
+     *
+     * @return true the serive is started
+     */
+    public boolean start() {
+        if (!isReleased())
+            return nativeStart();
+        else
+            return false;
+    }
+
+    /**
+     * Stops the discovery.
+     * (You can also call {@link #release() to stop the discovery directly}.
+     */
+    public void stop() {
+        if (!isReleased())
+            nativeStop();
+    }
+
+    @Override
+    protected boolean onEventNative(int event, long arg1, long arg2) {
+        switch (event) {
+        case VLCObject.Events.MediaDiscovererStarted:
+        case VLCObject.Events.MediaDiscovererEnded:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    /**
+     * Get the MediaList associated with the MediaDiscoverer.
+     *
+     * @return MediaList, Should NOT be released.
+     */
+    public synchronized MediaList getMediaList() {
+        if (mMediaList == null && !isReleased())
+            mMediaList = new MediaList(this);
+        return mMediaList;
+    }
+
+    @Override
+    protected void onReleaseNative() {
+        if (mMediaList != null)
+            mMediaList.release();
+        nativeRelease();
+    }
+
+    /* JNI */
+    private long mInstance = 0; // Read-only, reserved for JNI
+    private native void nativeNew(LibVLC libVLC, String name);
+    private native void nativeRelease();
+    private native boolean nativeStart();
+    private native void nativeStop();
+}
diff --git a/libvlc/src/org/videolan/libvlc/MediaList.java b/libvlc/src/org/videolan/libvlc/MediaList.java
new file mode 100644
index 0000000..adf12a3
--- /dev/null
+++ b/libvlc/src/org/videolan/libvlc/MediaList.java
@@ -0,0 +1,148 @@
+/*****************************************************************************
+ * MediaList.java
+ *****************************************************************************
+ * Copyright © 2015 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
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.util.SparseArray;
+
+public final class MediaList extends VLCObject {
+    private final static String TAG = "LibVLC/MediaList";
+
+    private int mCount = 0;
+    private SparseArray<Media> mMediaArray = new SparseArray<Media>();
+
+    private void init() {
+        mCount = nativeGetCount();
+    }
+
+    /**
+     * Create a MediaList from libVLC
+     * @param libVLC
+     */
+    public MediaList(LibVLC libVLC) {
+        nativeNewFromLibVlc(libVLC);
+        init();
+    }
+
+    /**
+     *
+     * @param md Should not be released
+     */
+    protected MediaList(MediaDiscoverer md) {
+        if (md.isReleased())
+            throw new IllegalArgumentException("MediaDiscoverer is not native");
+        nativeNewFromMediaDiscoverer(md);
+        init();
+    }
+
+    /**
+     *
+     * @param m Should not be released
+     */
+    protected MediaList(Media m) {
+        if (m.isReleased())
+            throw new IllegalArgumentException("Media is not native");
+        nativeNewFromMedia(m);
+        init();
+    }
+
+    private synchronized void insertMedia(int index) {
+        mCount++;
+
+        for (int i = mCount - 1; i >= index; --i)
+            mMediaArray.put(i + 1, mMediaArray.valueAt(i));
+        mMediaArray.put(index, null);
+    }
+
+    private synchronized void removeMedia(int index) {
+        mCount--;
+        Media media = mMediaArray.get(index);
+        if (media != null)
+            media.release();
+        for (int i = index; i < mCount; ++i) {
+            mMediaArray.put(i, mMediaArray.valueAt(i + 1));
+        }
+    }
+
+    @Override
+    protected boolean onEventNative(int event, long arg1, long arg2) {
+        int index = -1;
+        switch (event) {
+        case Events.MediaListItemAdded:
+            index = (int) arg1;
+            if (index != -1) {
+                insertMedia(index);
+                return true;
+            } else
+                return false;
+        case Events.MediaListItemDeleted:
+            index = (int) arg1;
+            if (index != -1) {
+                removeMedia(index);
+                return true;
+            } else
+                return false;
+        default:
+            return false;
+        }
+    }
+
+    /**
+     * Get the number of Media.
+     */
+    public synchronized int getCount() {
+        return mCount;
+    }
+
+    /**
+     * Get a Media at specified index.
+     *
+     * @param index
+     * @return Media hold by MediaList, Should NOT be released.
+     */
+    public synchronized Media getMediaAt(int index) {
+        if (index < 0 || index > getCount())
+            return null;
+        Media media = mMediaArray.get(index);
+        if (media == null && !isReleased()) {
+            media = new Media(this, index);
+            mMediaArray.put(index, media);
+        }
+        return media;
+    }
+
+    @Override
+    public void onReleaseNative() {
+        for (int i = 0; i < mMediaArray.size(); ++i) {
+            final Media media = mMediaArray.get(i);
+            if (media != null)
+                media.release();
+        }
+
+        nativeRelease();
+    }
+
+    /* JNI */
+    private native void nativeNewFromLibVlc(LibVLC libvlc);
+    private native void nativeNewFromMediaDiscoverer(MediaDiscoverer md);
+    private native void nativeNewFromMedia(Media m);
+    private native void nativeRelease();
+    private native int nativeGetCount();
+}
-- 
2.1.3




More information about the Android mailing list