[Android] [WIP PATCH 08/11] libvlc: add VlcObject

Thomas Guillem thomas at gllm.fr
Tue Dec 23 18:38:29 CET 2014


base class for all future Vlc objects (Media, MediaList, MediaDiscoverer...)
---
 libvlc/jni/Android.mk                         |   1 +
 libvlc/jni/libvlcjni-vlcobject.c              | 199 ++++++++++++++++++++++++++
 libvlc/jni/libvlcjni-vlcobject.h              |  63 ++++++++
 libvlc/src/org/videolan/libvlc/VlcObject.java | 166 +++++++++++++++++++++
 4 files changed, 429 insertions(+)
 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..e2f1166 100644
--- a/libvlc/jni/Android.mk
+++ b/libvlc/jni/Android.mk
@@ -5,6 +5,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 += 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/libvlcjni-vlcobject.c b/libvlc/jni/libvlcjni-vlcobject.c
new file mode 100644
index 0000000..d62d05a
--- /dev/null
+++ b/libvlc/jni/libvlcjni-vlcobject.c
@@ -0,0 +1,199 @@
+/*****************************************************************************
+ * libvlcjni-vlcobject.c
+ *****************************************************************************
+ * Copyright © 2014 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * 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 THREAD_NAME "VlcObject"
+extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
+extern void jni_detach_thread();
+extern int jni_get_env(JNIEnv **env);
+
+struct vlcjni_object_owner
+{
+    bool b_dispatch_events;
+    libvlc_event_manager_t *p_ev;
+    const int *p_events;
+    jobject thiz;
+    jmethodID dispatchEventID;
+};
+
+// XXX DBG
+#include <pthread.h>
+static int DBG_allocCount = 0;
+static pthread_mutex_t DBG_allocMtx = PTHREAD_MUTEX_INITIALIZER;
+
+vlcjni_object *
+VlcJniObject_getInstance(JNIEnv *env, jobject thiz)
+{
+    return (vlcjni_object*)(intptr_t)getLong(env, thiz, "mInstance");
+}
+
+static void
+VlcJniObject_setInstance(JNIEnv *env, jobject thiz, vlcjni_object *p_obj)
+{
+    setLong(env, thiz, "mInstance", (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;
+    jclass cls;
+
+    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)->NewGlobalRef(env, thiz);
+    if (!p_obj->p_owner->thiz)
+        goto error;
+
+    cls = (*env)->FindClass(env, "org/videolan/libvlc/VlcObject");
+    if (!cls)
+        goto error;
+
+    p_obj->p_owner->dispatchEventID = (*env)->GetMethodID(env, cls,
+                                                          "dispatchEventFromNative",
+                                                          "(IJJ)V");
+    if (!p_obj->p_owner->dispatchEventID)
+        goto error;
+
+    VlcJniObject_setInstance(env, thiz, p_obj);
+
+pthread_mutex_lock(&DBG_allocMtx);
+DBG_allocCount++;
+LOGE("DBG_allocCount: %d", DBG_allocCount);
+pthread_mutex_unlock(&DBG_allocMtx);
+    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->thiz)
+            (*env)->DeleteGlobalRef(env, p_obj->p_owner->thiz);
+
+        free(p_obj->p_owner);
+        free(p_obj);
+        VlcJniObject_setInstance(env, thiz, NULL);
+
+pthread_mutex_lock(&DBG_allocMtx);
+DBG_allocCount--;
+LOGE("DBG_allocCount: %d", DBG_allocCount);
+pthread_mutex_unlock(&DBG_allocMtx);
+    }
+}
+
+static void
+VlcJniObject_eventCallback(const libvlc_event_t *ev, void *data)
+{
+    JNIEnv *env;
+    vlcjni_object *p_obj = data;
+    int64_t arg1 = -1, arg2 = -1;
+    bool isAttached = false;
+
+    if (ev->type == libvlc_MediaListWillAddItem
+     || ev->type == libvlc_MediaListWillDeleteItem
+     || ev->type == libvlc_MediaListViewWillAddItem
+     || ev->type == libvlc_MediaListViewWillDeleteItem)
+        return;
+
+    switch (ev->type) {
+        case libvlc_MediaListItemAdded:
+            arg1 = ev->u.media_list_item_added.index;
+            break;
+        case libvlc_MediaListItemDeleted:
+            arg1 = ev->u.media_list_item_deleted.index;
+    }
+
+    if (jni_get_env(&env) < 0) {
+        if (jni_attach_thread(&env, THREAD_NAME) < 0)
+            return;
+        isAttached = true;
+    }
+
+    (*env)->CallVoidMethod(env, p_obj->p_owner->thiz,
+                           p_obj->p_owner->dispatchEventID,
+                           ev->type, arg1, arg2);
+
+    if (isAttached)
+        jni_detach_thread();
+}
+
+void
+VlcJniObject_attachEvents(vlcjni_object *p_obj, libvlc_event_manager_t *p_ev,
+                          const int *p_events)
+{
+    if (!p_ev || !p_events)
+        return;
+    p_obj->p_owner->p_ev = p_ev;
+    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_ev, 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_ev || !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_ev, p_obj->p_owner->p_events[i],
+                            VlcJniObject_eventCallback, p_obj);
+    p_obj->p_owner->p_ev = NULL;
+    p_obj->p_owner->p_events = NULL;
+}
diff --git a/libvlc/jni/libvlcjni-vlcobject.h b/libvlc/jni/libvlcjni-vlcobject.h
new file mode 100644
index 0000000..6d2d84f
--- /dev/null
+++ b/libvlc/jni/libvlcjni-vlcobject.h
@@ -0,0 +1,63 @@
+/*****************************************************************************
+ * libvlcjni-vlcobject.h
+ *****************************************************************************
+ * Copyright © 2014 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * 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 "utils.h"
+#define LOG_TAG "VLC/JNI/VlcObject"
+#include "log.h"
+
+typedef struct vlcjni_object_owner vlcjni_object_owner;
+
+typedef struct vlcjni_object vlcjni_object;
+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;
+};
+
+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,
+                               libvlc_event_manager_t *p_ev,
+                               const int *p_events);
+
+#endif // LIBVLCJNI_VLCOBJECT_H
diff --git a/libvlc/src/org/videolan/libvlc/VlcObject.java b/libvlc/src/org/videolan/libvlc/VlcObject.java
new file mode 100644
index 0000000..91e4cd8
--- /dev/null
+++ b/libvlc/src/org/videolan/libvlc/VlcObject.java
@@ -0,0 +1,166 @@
+/*****************************************************************************
+ * LibVLC.java
+ *****************************************************************************
+ * Copyright © 2010-2014 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * 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 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 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;
+
+    public interface Listener {
+        public void onEvent(int event, long arg1, long arg2);
+    }
+
+    private class EventRunnable implements Runnable {
+        public final Listener listener;
+        public final int event;
+        public final long arg1;
+        public final long arg2;
+
+        public EventRunnable(Listener listener, int event, long arg1, long arg2) {
+            this.listener = listener;
+            this.event = event;
+            this.arg1 = arg1;
+            this.arg2 = arg2;
+        }
+        @Override
+        public void run() {
+            listener.onEvent(event, arg1, arg2);
+        }
+    }
+
+    private Listener mListener = null;
+    private Handler mHandler = null;
+    private int mRefCount = 1;
+    
+    /**
+     * increment internal ref count
+     */
+    public synchronized final void retain() {
+        if (mRefCount > 0)
+            mRefCount++;
+    }
+
+    /**
+     * release the object if ref count is 1
+     */
+    public final void release() {
+        int refCount = -1;
+        synchronized (this) {
+            if (mRefCount > 0) {
+                refCount = --mRefCount;
+            }
+            // clear event list
+            if (refCount == 0)
+                setListener(null);
+        }
+        if (refCount == 0) {
+            // detach events when not synchronized since onEvent is executed synchronized
+            nativeDetachEvents();
+            synchronized (this) {
+                onRelease();
+            }
+        }
+    }
+
+    /**
+     * Set a listener
+     * 
+     * @param listener
+     * @throws LibVlcException
+     */
+    public synchronized final void setListener(Listener listener) {
+        if (mHandler != null)
+            mHandler.removeCallbacksAndMessages(null);
+        mListener = listener;
+        if (mListener != null && mHandler == null)
+            mHandler = new Handler(Looper.getMainLooper());
+    }
+
+    protected abstract void onEvent(int event, long arg1, long arg2);
+    protected abstract void onRelease();
+
+    /* JNI */
+    private long mInstance = 0; // Read-only, reserved for JNI
+    private synchronized void dispatchEventFromNative(int event, long arg1, long arg2) {
+        onEvent(event, arg1, arg2);
+        if (mListener != null)
+            mHandler.post(new EventRunnable(mListener, event, arg1, arg2));
+    }
+    private final native void nativeDetachEvents();
+}
-- 
2.1.3



More information about the Android mailing list