[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