[Android] [PATCH 07/14] libvlc: add VLCObject
Thomas Guillem
thomas at gllm.fr
Fri Jan 16 17:12:07 CET 2015
Base class for all future VLC objects: Media, MediaList, MediaDiscoverer, and
MediaPlayer in the future.
---
libvlc/jni/Android.mk | 2 +
libvlc/jni/java_event_thread.c | 154 +++++++++++++++++++
libvlc/jni/java_event_thread.h | 43 ++++++
libvlc/jni/libvlcjni-vlcobject.c | 178 +++++++++++++++++++++
libvlc/jni/libvlcjni-vlcobject.h | 83 ++++++++++
libvlc/jni/libvlcjni.c | 61 +++++++-
libvlc/jni/utils.h | 19 +++
libvlc/src/org/videolan/libvlc/VLCObject.java | 212 ++++++++++++++++++++++++++
8 files changed, 751 insertions(+), 1 deletion(-)
create mode 100644 libvlc/jni/java_event_thread.c
create mode 100644 libvlc/jni/java_event_thread.h
create mode 100644 libvlc/jni/libvlcjni-vlcobject.c
create mode 100644 libvlc/jni/libvlcjni-vlcobject.h
create mode 100644 libvlc/src/org/videolan/libvlc/VLCObject.java
diff --git a/libvlc/jni/Android.mk b/libvlc/jni/Android.mk
index e6308d1..f2e61c1 100644
--- a/libvlc/jni/Android.mk
+++ b/libvlc/jni/Android.mk
@@ -5,6 +5,8 @@ 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 += java_event_thread.c
LOCAL_SRC_FILES += aout.c vout.c native_crash_handler.c thumbnailer.c
ifneq ($(ANDROID_API),android-21)
# compat functions not needed after android-21
diff --git a/libvlc/jni/java_event_thread.c b/libvlc/jni/java_event_thread.c
new file mode 100644
index 0000000..1dc9961
--- /dev/null
+++ b/libvlc/jni/java_event_thread.c
@@ -0,0 +1,154 @@
+/*****************************************************************************
+ * java_java_event_thread.c
+ *****************************************************************************
+ * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
+ *
+ * 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 <sys/queue.h>
+#include <pthread.h>
+
+#include "java_event_thread.h"
+#include "utils.h"
+
+#define LOG_TAG "JavaEventThread"
+#include "log.h"
+
+#define THREAD_NAME "JavaEventThread"
+extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
+extern void jni_detach_thread();
+extern int jni_get_env(JNIEnv **env);
+
+typedef struct event_queue_elm event_queue_elm;
+struct event_queue_elm
+{
+ java_event event;
+ TAILQ_ENTRY(event_queue_elm) next;
+};
+typedef TAILQ_HEAD(, event_queue_elm) EVENT_QUEUE;
+
+struct java_event_thread {
+ bool b_run;
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+ pthread_t thread;
+ EVENT_QUEUE queue;
+ jweak jobj;
+};
+
+static void *
+JavaEventThread_thread(void *data)
+{
+ JNIEnv *env;
+ java_event_thread *p_java_event_thread = data;
+
+ if (jni_attach_thread(&env, THREAD_NAME) < 0)
+ return NULL;
+
+ pthread_mutex_lock(&p_java_event_thread->lock);
+ while (p_java_event_thread->b_run)
+ {
+ event_queue_elm *event_elm;
+ java_event *p_jevent;
+
+ while (p_java_event_thread->b_run &&
+ !(event_elm = TAILQ_FIRST(&p_java_event_thread->queue)))
+ pthread_cond_wait(&p_java_event_thread->cond,
+ &p_java_event_thread->lock);
+
+ if (!p_java_event_thread->b_run || event_elm == NULL)
+ continue;
+
+ p_jevent = &event_elm->event;
+ TAILQ_REMOVE(&p_java_event_thread->queue, event_elm, next);
+
+ pthread_mutex_unlock(&p_java_event_thread->lock);
+
+ (*env)->CallVoidMethod(env, p_java_event_thread->jobj,
+ fields.VLCObject.dispatchEventFromNativeID,
+ p_jevent->type, p_jevent->arg1, p_jevent->arg2);
+
+ free(event_elm);
+
+ pthread_mutex_lock(&p_java_event_thread->lock);
+ }
+ pthread_mutex_unlock(&p_java_event_thread->lock);
+
+ jni_detach_thread();
+
+ return NULL;
+}
+
+java_event_thread *
+JavaEventThread_create(jweak jobj)
+{
+ java_event_thread *p_java_event_thread = calloc(1, sizeof(java_event_thread));
+ if (!p_java_event_thread)
+ return NULL;
+
+ pthread_mutex_init(&p_java_event_thread->lock, NULL);
+ pthread_cond_init(&p_java_event_thread->cond, NULL);
+ TAILQ_INIT(&p_java_event_thread->queue);
+
+ p_java_event_thread->jobj = jobj;
+ p_java_event_thread->b_run = true;
+ pthread_create(&p_java_event_thread->thread, NULL,
+ JavaEventThread_thread, p_java_event_thread);
+
+ return p_java_event_thread;
+}
+
+void
+JavaEventThread_destroy(java_event_thread *p_java_event_thread)
+{
+ event_queue_elm *event_elm, *event_elm_next;
+
+ pthread_mutex_lock(&p_java_event_thread->lock);
+ p_java_event_thread->b_run = false;
+
+ for (event_elm = TAILQ_FIRST(&p_java_event_thread->queue);
+ event_elm != NULL; event_elm = event_elm_next)
+ {
+ event_elm_next = TAILQ_NEXT(event_elm, next);
+ TAILQ_REMOVE(&p_java_event_thread->queue, event_elm, next);
+ free(event_elm);
+ }
+ pthread_cond_signal(&p_java_event_thread->cond);
+ pthread_mutex_unlock(&p_java_event_thread->lock);
+
+ pthread_join(p_java_event_thread->thread, NULL);
+
+ pthread_mutex_destroy(&p_java_event_thread->lock);
+ pthread_cond_destroy(&p_java_event_thread->cond);
+
+ free(p_java_event_thread);
+}
+
+void
+JavaEventThread_add(java_event_thread *p_java_event_thread,
+ java_event *p_java_event)
+{
+ event_queue_elm *event_elm = calloc(1, sizeof(event_queue_elm));
+ if (!event_elm)
+ return;
+ event_elm->event = *p_java_event;
+
+ pthread_mutex_lock(&p_java_event_thread->lock);
+ TAILQ_INSERT_TAIL(&p_java_event_thread->queue, event_elm, next);
+ pthread_cond_signal(&p_java_event_thread->cond);
+ pthread_mutex_unlock(&p_java_event_thread->lock);
+}
diff --git a/libvlc/jni/java_event_thread.h b/libvlc/jni/java_event_thread.h
new file mode 100644
index 0000000..d90dd65
--- /dev/null
+++ b/libvlc/jni/java_event_thread.h
@@ -0,0 +1,43 @@
+/*****************************************************************************
+ * java_java_event_thread.h
+ *****************************************************************************
+ * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifndef JAVA_EVENT_THREAD_H
+#define JAVA_EVENT_THREAD_H
+
+#include <jni.h>
+#include <vlc/vlc.h>
+#include <vlc/libvlc_events.h>
+
+typedef struct java_event_thread java_event_thread;
+
+typedef struct java_event java_event;
+struct java_event
+{
+ int type;
+ long arg1;
+ long arg2;
+};
+
+java_event_thread *JavaEventThread_create(jweak jobj);
+void JavaEventThread_destroy(java_event_thread *p_java_event_thread);
+void JavaEventThread_add(java_event_thread *p_java_event_thread,
+ java_event *p_java_event);
+
+#endif // JAVA_EVENT_THREAD_H
diff --git a/libvlc/jni/libvlcjni-vlcobject.c b/libvlc/jni/libvlcjni-vlcobject.c
new file mode 100644
index 0000000..2b1da7c
--- /dev/null
+++ b/libvlc/jni/libvlcjni-vlcobject.c
@@ -0,0 +1,178 @@
+/*****************************************************************************
+ * libvlcjni-vlcobject.c
+ *****************************************************************************
+ * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
+ *
+ * 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 <sys/queue.h>
+#include <pthread.h>
+
+#include "java_event_thread.h"
+#include "libvlcjni-vlcobject.h"
+
+struct vlcjni_object_owner
+{
+ jweak thiz;
+
+ libvlc_event_manager_t *p_event_manager;
+ const int *p_events;
+
+ java_event_thread *p_java_event_thread;
+ event_cb pf_event_cb;
+};
+
+vlcjni_object *
+VLCJniObject_getInstance(JNIEnv *env, jobject thiz)
+{
+ return (vlcjni_object*)(intptr_t) (*env)->GetLongField(env, thiz,
+ fields.VLCObject.mInstanceID);
+}
+
+static void
+VLCJniObject_setInstance(JNIEnv *env, jobject thiz, vlcjni_object *p_obj)
+{
+ (*env)->SetLongField(env, thiz,
+ fields.VLCObject.mInstanceID,
+ (jlong)(intptr_t)p_obj);
+}
+
+vlcjni_object *
+VLCJniObject_newFromLibVlc(JNIEnv *env, jobject thiz,
+ libvlc_instance_t *p_libvlc)
+{
+ vlcjni_object *p_obj;
+ libvlc_event_manager_t *ev;
+
+ p_obj = VLCJniObject_getInstance(env, thiz);
+ if (p_obj)
+ return NULL;
+
+ p_obj = calloc(1, sizeof(vlcjni_object));
+ if (!p_obj)
+ goto error;
+
+ p_obj->p_owner = calloc(1, sizeof(vlcjni_object_owner));
+ if (!p_obj->p_owner)
+ goto error;
+
+ p_obj->p_libvlc = p_libvlc;
+ libvlc_retain(p_libvlc);
+
+ p_obj->p_owner->thiz = (*env)->NewWeakGlobalRef(env, thiz);
+ if (!p_obj->p_owner->thiz)
+ goto error;
+
+ VLCJniObject_setInstance(env, thiz, p_obj);
+
+ return p_obj;
+
+error:
+ VLCJniObject_release(env, thiz, p_obj);
+ return NULL;
+}
+
+vlcjni_object *
+VLCJniObject_newFromJavaLibVlc(JNIEnv *env, jobject thiz,
+ jobject libVlc)
+{
+ libvlc_instance_t *p_libvlc = getLibVlcInstance(env, libVlc);
+ if (!p_libvlc)
+ return NULL;
+ return VLCJniObject_newFromLibVlc(env, thiz, p_libvlc);
+}
+
+void
+VLCJniObject_release(JNIEnv *env, jobject thiz, vlcjni_object *p_obj)
+{
+ if (p_obj)
+ {
+ if (p_obj->p_libvlc)
+ libvlc_release(p_obj->p_libvlc);
+
+ if (p_obj->p_owner && p_obj->p_owner->thiz)
+ (*env)->DeleteWeakGlobalRef(env, p_obj->p_owner->thiz);
+
+ free(p_obj->p_owner);
+ free(p_obj);
+ VLCJniObject_setInstance(env, thiz, NULL);
+ }
+}
+
+static void
+VLCJniObject_eventCallback(const libvlc_event_t *ev, void *data)
+{
+ vlcjni_object *p_obj = data;
+ java_event jevent;
+
+ jevent.type = -1;
+ jevent.arg1 = jevent.arg2 = 0;
+
+ if (!p_obj->p_owner->pf_event_cb(p_obj, ev, &jevent))
+ return;
+
+ if (!p_obj->p_owner->p_java_event_thread)
+ {
+ p_obj->p_owner->p_java_event_thread =
+ JavaEventThread_create(p_obj->p_owner->thiz);
+ if (!p_obj->p_owner->p_java_event_thread)
+ return;
+ }
+ JavaEventThread_add(p_obj->p_owner->p_java_event_thread, &jevent);
+}
+
+void
+VLCJniObject_attachEvents(vlcjni_object *p_obj,
+ event_cb pf_event_cb,
+ libvlc_event_manager_t *p_event_manager,
+ const int *p_events)
+{
+ if (!pf_event_cb || !p_event_manager || !p_events
+ || p_obj->p_owner->p_event_manager
+ || p_obj->p_owner->p_events)
+ return;
+
+ p_obj->p_owner->pf_event_cb = pf_event_cb;
+
+ p_obj->p_owner->p_event_manager = p_event_manager;
+ p_obj->p_owner->p_events = p_events;
+
+ for(int i = 0; p_obj->p_owner->p_events[i] != -1; ++i)
+ libvlc_event_attach(p_obj->p_owner->p_event_manager,
+ p_obj->p_owner->p_events[i],
+ VLCJniObject_eventCallback, p_obj);
+}
+
+void
+Java_org_videolan_libvlc_VLCObject_nativeDetachEvents(JNIEnv *env, jobject thiz)
+{
+ vlcjni_object *p_obj = VLCJniObject_getInstance(env, thiz);
+
+ if (!p_obj || !p_obj->p_owner->p_event_manager
+ || !p_obj->p_owner->p_events)
+ return;
+
+ for(int i = 0; p_obj->p_owner->p_events[i] != -1; ++i)
+ libvlc_event_detach(p_obj->p_owner->p_event_manager,
+ p_obj->p_owner->p_events[i],
+ VLCJniObject_eventCallback, p_obj);
+ p_obj->p_owner->p_event_manager = NULL;
+ p_obj->p_owner->p_events = NULL;
+
+ if (p_obj->p_owner->p_java_event_thread)
+ JavaEventThread_destroy(p_obj->p_owner->p_java_event_thread);
+}
diff --git a/libvlc/jni/libvlcjni-vlcobject.h b/libvlc/jni/libvlcjni-vlcobject.h
new file mode 100644
index 0000000..b74a8d1
--- /dev/null
+++ b/libvlc/jni/libvlcjni-vlcobject.h
@@ -0,0 +1,83 @@
+/*****************************************************************************
+ * libvlcjni-vlcobject.h
+ *****************************************************************************
+ * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
+ *
+ * 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.
+ *****************************************************************************/
+
+#ifndef LIBVLCJNI_VLCOBJECT_H
+#define LIBVLCJNI_VLCOBJECT_H
+
+#include <stdbool.h>
+
+#include <jni.h>
+#include <vlc/vlc.h>
+#include <vlc/libvlc_media_list.h>
+#include <vlc/libvlc_media_discoverer.h>
+
+#include "java_event_thread.h"
+#include "utils.h"
+#define LOG_TAG "VLC/JNI/VLCObject"
+#include "log.h"
+
+typedef struct vlcjni_object vlcjni_object;
+typedef struct vlcjni_object_owner vlcjni_object_owner;
+typedef struct vlcjni_object_sys vlcjni_object_sys;
+
+struct vlcjni_object
+{
+ libvlc_instance_t *p_libvlc;
+ union {
+ libvlc_media_t *p_m;
+ libvlc_media_list_t *p_ml;
+ libvlc_media_discoverer_t *p_md;
+ } u;
+ vlcjni_object_owner *p_owner; // used by vlcobject
+ vlcjni_object_sys *p_sys; // used by media, medialist, mediadiscoverer...
+};
+
+/* event manager callback dispatched to native struct implementing a
+ * vlcjni_object. If the callback returns true, the event is dispatched to Java
+ * */
+typedef bool (*event_cb)(vlcjni_object *p_obj, const libvlc_event_t *p_ev,
+ java_event *p_java_event);
+
+
+vlcjni_object *VLCJniObject_getInstance(JNIEnv *env, jobject thiz);
+
+vlcjni_object *VLCJniObject_newFromJavaLibVlc(JNIEnv *env, jobject thiz,
+ jobject libVlc);
+
+vlcjni_object *VLCJniObject_newFromLibVlc(JNIEnv *env, jobject thiz,
+ libvlc_instance_t *p_libvlc);
+
+void VLCJniObject_release(JNIEnv *env, jobject thiz, vlcjni_object *p_obj);
+
+void VLCJniObject_attachEvents(vlcjni_object *p_obj, event_cb pf_event_cb,
+ libvlc_event_manager_t *p_event_manager,
+ const int *p_events);
+
+static inline void throw_IllegalStateException(JNIEnv *env, const char *p_error)
+{
+ (*env)->ThrowNew(env, fields.IllegalStateException.clazz, p_error);
+}
+
+static inline void throw_IllegalArgumentException(JNIEnv *env, const char *p_error)
+{
+ (*env)->ThrowNew(env, fields.IllegalArgumentException.clazz, p_error);
+}
+
+#endif // LIBVLCJNI_VLCOBJECT_H
diff --git a/libvlc/jni/libvlcjni.c b/libvlc/jni/libvlcjni.c
index 664092a..b14281b 100644
--- a/libvlc/jni/libvlcjni.c
+++ b/libvlc/jni/libvlcjni.c
@@ -48,6 +48,8 @@
#define LOG_TAG "VLC/JNI/main"
#include "log.h"
+struct fields fields;
+
#define VLC_JNI_VERSION JNI_VERSION_1_2
#define THREAD_NAME "libvlcjni"
@@ -211,19 +213,76 @@ end:
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
+ JNIEnv* env = NULL;
// Keep a reference on the Java VM.
myVm = vm;
+ if ((*vm)->GetEnv(vm, (void**) &env, VLC_JNI_VERSION) != JNI_OK)
+ return -1;
pthread_mutex_init(&vout_android_lock, NULL);
pthread_cond_init(&vout_android_surf_attached, NULL);
+#define GET_CLASS(clazz, str) do { \
+ (clazz) = (*env)->FindClass(env, (str)); \
+ if (!(clazz)) { \
+ LOGE("FindClass(%s) failed", (str)); \
+ return -1; \
+ } \
+ (clazz) = (jclass) (*env)->NewGlobalRef(env, (clazz)); \
+ if (!(clazz)) { \
+ LOGE("NewGlobalRef(%s) failed", (str)); \
+ return -1; \
+ } \
+} while (0)
+
+#define GET_ID(get, id, clazz, str, args) do { \
+ (id) = (*env)->get(env, (clazz), (str), (args)); \
+ if (!(id)) { \
+ LOGE(#get"(%s) failed", (str)); \
+ return -1; \
+ } \
+} while (0)
+
+ GET_CLASS(fields.IllegalStateException.clazz,
+ "java/lang/IllegalStateException");
+ GET_CLASS(fields.IllegalArgumentException.clazz,
+ "java/lang/IllegalArgumentException");
+ GET_CLASS(fields.String.clazz,
+ "java/lang/String");
+ GET_CLASS(fields.VLCObject.clazz,
+ "org/videolan/libvlc/VLCObject");
+
+ GET_ID(GetFieldID,
+ fields.VLCObject.mInstanceID,
+ fields.VLCObject.clazz,
+ "mInstance", "J");
+
+ GET_ID(GetMethodID,
+ fields.VLCObject.dispatchEventFromNativeID,
+ fields.VLCObject.clazz,
+ "dispatchEventFromNative", "(IJJ)V");
+
+#undef GET_CLASS
+#undef GET_ID
+
LOGD("JNI interface loaded.");
return VLC_JNI_VERSION;
}
-void JNI_OnUnload(JavaVM* vm, void* reserved) {
+void JNI_OnUnload(JavaVM* vm, void* reserved)
+{
+ JNIEnv* env = NULL;
+
pthread_mutex_destroy(&vout_android_lock);
pthread_cond_destroy(&vout_android_surf_attached);
+
+ if ((*vm)->GetEnv(vm, (void**) &env, VLC_JNI_VERSION) != JNI_OK)
+ return;
+
+ (*env)->DeleteGlobalRef(env, fields.IllegalStateException.clazz);
+ (*env)->DeleteGlobalRef(env, fields.IllegalArgumentException.clazz);
+ (*env)->DeleteGlobalRef(env, fields.String.clazz);
+ (*env)->DeleteGlobalRef(env, fields.VLCObject.clazz);
}
int jni_attach_thread(JNIEnv **env, const char *thread_name)
diff --git a/libvlc/jni/utils.h b/libvlc/jni/utils.h
index 5da3514..14879bc 100644
--- a/libvlc/jni/utils.h
+++ b/libvlc/jni/utils.h
@@ -21,6 +21,25 @@
#ifndef LIBVLCJNI_UTILS_H
#define LIBVLCJNI_UTILS_H
+struct fields {
+ struct {
+ jclass clazz;
+ } IllegalStateException;
+ struct {
+ jclass clazz;
+ } IllegalArgumentException;
+ struct {
+ jclass clazz;
+ } String;
+ struct {
+ jclass clazz;
+ jfieldID mInstanceID;
+ jmethodID dispatchEventFromNativeID;
+ } VLCObject;
+};
+
+extern struct fields fields;
+
libvlc_media_t *new_media(JNIEnv *env, jobject thiz, jstring fileLocation, bool noOmx, bool noVideo);
libvlc_instance_t *getLibVlcInstance(JNIEnv *env, jobject thiz);
diff --git a/libvlc/src/org/videolan/libvlc/VLCObject.java b/libvlc/src/org/videolan/libvlc/VLCObject.java
new file mode 100644
index 0000000..c6816cf
--- /dev/null
+++ b/libvlc/src/org/videolan/libvlc/VLCObject.java
@@ -0,0 +1,212 @@
+/*****************************************************************************
+ * VLCObject.java
+ *****************************************************************************
+ * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
+ *
+ * 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.os.Handler;
+import android.os.Looper;
+
+public abstract class VLCObject {
+ private final static String TAG = "LibVLC/VlcObject";
+
+ public static class Events {
+ public static final int MediaMetaChanged = 0;
+ public static final int MediaSubItemAdded = 1;
+ public static final int MediaDurationChanged = 2;
+ public static final int MediaParsedChanged = 3;
+ //public static final int MediaFreed = 4;
+ public static final int MediaStateChanged = 5;
+ public static final int MediaSubItemTreeAdded = 6;
+
+ //public static final int MediaPlayerMediaChanged = 0x100;
+ //public static final int MediaPlayerNothingSpecial = 0x101;
+ //public static final int MediaPlayerOpening = 0x102;
+ //public static final int MediaPlayerBuffering = 0x103;
+ //public static final int MediaPlayerPlaying = 0x104;
+ //public static final int MediaPlayerPaused = 0x105;
+ //public static final int MediaPlayerStopped = 0x106;
+ //public static final int MediaPlayerForward = 0x107;
+ //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 MediaPlayerPositionChanged = 0x10c;
+ //public static final int MediaPlayerSeekableChanged = 0x10d;
+ //public static final int MediaPlayerPausableChanged = 0x10e;
+ //public static final int MediaPlayerTitleChanged = 0x10f;
+ //public static final int MediaPlayerSnapshotTaken = 0x110;
+ //public static final int MediaPlayerLengthChanged = 0x111;
+ //public static final int MediaPlayerVout = 0x112;
+
+ public static final int MediaListItemAdded = 0x200;
+ //public static final int MediaListWillAddItem = 0x201;
+ public static final int MediaListItemDeleted = 0x202;
+ //public static final int MediaListWillDeleteItem = 0x203;
+
+ //public static final int MediaListViewItemAdded = 0x300;
+ //public static final int MediaListViewWillAddItem = 0x301;
+ //public static final int MediaListViewItemDeleted = 0x302;
+ //public static final int MediaListViewWillDeleteItem = 0x303;
+
+ //public static final int MediaListPlayerPlayed = 0x400;
+ //public static final int MediaListPlayerNextItemSet = 0x401;
+ //public static final int MediaListPlayerStopped = 0x402;
+
+ public static final int MediaDiscovererStarted = 0x500;
+ public static final int MediaDiscovererEnded = 0x501;
+
+ //public static final int VlmMediaAdded = 0x600;
+ //public static final int VlmMediaRemoved = 0x601;
+ //public static final int VlmMediaChanged = 0x602;
+ //public static final int VlmMediaInstanceStarted = 0x603;
+ //public static final int VlmMediaInstanceStopped = 0x604;
+ //public static final int VlmMediaInstanceStatusInit = 0x605;
+ //public static final int VlmMediaInstanceStatusOpening = 0x606;
+ //public static final int VlmMediaInstanceStatusPlaying = 0x607;
+ //public static final int VlmMediaInstanceStatusPause = 0x608;
+ //public static final int VlmMediaInstanceStatusEnd = 0x609;
+ //public static final int VlmMediaInstanceStatusError = 0x60a;
+ }
+
+ /**
+ * Event used by EventListener
+ * Can be casted to inherited class Event (like {@link MediaList.Event}).
+ */
+ public static class Event {
+ /**
+ * @see Events
+ */
+ public final int type;
+ protected Event(int type) {
+ this.type = type;
+ }
+ }
+
+ /**
+ * Listener for libvlc events
+ *
+ * @see Event
+ */
+ public interface EventListener {
+ public void onEvent(Event event);
+ }
+
+ private static class EventRunnable implements Runnable {
+ private final EventListener listener;
+ private final Event event;
+
+ private EventRunnable(EventListener listener, Event event) {
+ this.listener = listener;
+ this.event = event;
+ }
+ @Override
+ public void run() {
+ listener.onEvent(event);
+ }
+ }
+
+ private EventListener mEventListener = null;
+ private Handler mHandler = null;
+ private int mNativeRefCount = 1;
+
+ /**
+ * Returns true if native object is released
+ */
+ public synchronized boolean isReleased() {
+ return mNativeRefCount == 0;
+ }
+
+ /**
+ * Increment internal ref count of the native object.
+ */
+ public synchronized final void retain() {
+ if (mNativeRefCount > 0)
+ mNativeRefCount++;
+ }
+
+ /**
+ * Release the native object if ref count is 1.
+ *
+ * After this call, native calls are not possible anymore.
+ * You can still call others methods to retrieve cached values.
+ * For example: if you parse, then release a media, you'll still be able to retrieve all Metas or Tracks infos.
+ */
+ public final void release() {
+ int refCount = -1;
+ synchronized (this) {
+ if (mNativeRefCount == 0)
+ return;
+ if (mNativeRefCount > 0) {
+ refCount = --mNativeRefCount;
+ }
+ // clear event list
+ if (refCount == 0)
+ setEventListener(null);
+ }
+ if (refCount == 0) {
+ // detach events when not synchronized since onEvent is executed synchronized
+ nativeDetachEvents();
+ synchronized (this) {
+ onReleaseNative();
+ }
+ }
+ }
+
+ /**
+ * Set an event listener.
+ *
+ * @param listener see {@link EventListener}
+ */
+ public synchronized final void setEventListener(EventListener listener) {
+ if (mHandler != null)
+ mHandler.removeCallbacksAndMessages(null);
+ mEventListener = listener;
+ if (mEventListener != null && mHandler == null)
+ mHandler = new Handler(Looper.getMainLooper());
+ }
+
+ /**
+ * Called when libvlc send events.
+ *
+ * @param eventType
+ * @param arg1
+ * @param arg2
+ * @return Event that will be dispatched to listeners
+ */
+ protected abstract Event onEventNative(int eventType, long arg1, long arg2);
+
+ /**
+ * Called when native object is released (refcount is 0).
+ *
+ * This is where you must release native resources.
+ */
+ protected abstract void onReleaseNative();
+
+ /* JNI */
+ private long mInstance = 0; // Read-only, reserved for JNI
+ private synchronized void dispatchEventFromNative(int eventType, long arg1, long arg2) {
+ if (isReleased())
+ return;
+ final Event event = onEventNative(eventType, arg1, arg2);
+ if (event != null && mEventListener != null && mHandler != null)
+ mHandler.post(new EventRunnable(mEventListener, event));
+ }
+ private final native void nativeDetachEvents();
+}
--
2.1.3
More information about the Android
mailing list