[Android] Media: add a new constructor from an AssetFileDescriptor

Thomas Guillem git at videolan.org
Fri Aug 24 10:48:31 CEST 2018


vlc-android | branch: master | Thomas Guillem <thomas at gllm.fr> | Fri Aug 24 09:46:22 2018 +0200| [6a39b3a468d6b4a2427cfa44f6cb5c1c9a09349f] | committer: Thomas Guillem

Media: add a new constructor from an AssetFileDescriptor

This can be used to open files from the apk asset folder.

Using the simple FileDescriptor constructor can't work since we need 2 extra
infos: the length and the offset of the file to read.

This new constructor uses the libvlc_media_new_callbacks() function.

> https://code.videolan.org/videolan/vlc-android/commit/6a39b3a468d6b4a2427cfa44f6cb5c1c9a09349f
---

 libvlc/jni/libvlcjni-media.c              | 119 +++++++++++++++++++++++++++++-
 libvlc/src/org/videolan/libvlc/Media.java |  16 ++++
 2 files changed, 133 insertions(+), 2 deletions(-)

diff --git a/libvlc/jni/libvlcjni-media.c b/libvlc/jni/libvlcjni-media.c
index f15fede05..33ecc5bfa 100644
--- a/libvlc/jni/libvlcjni-media.c
+++ b/libvlc/jni/libvlcjni-media.c
@@ -20,17 +20,31 @@
 
 #include <stdlib.h>
 #include <pthread.h>
+#include <unistd.h>
 
 #include "libvlcjni-vlcobject.h"
 
 #define META_MAX 25
 
+struct media_cb
+{
+    int fd;
+    uint64_t fd_offset;
+    uint64_t fd_length;
+    uint64_t offset;
+};
+
 struct vlcjni_object_sys
 {
     pthread_mutex_t lock;
     pthread_cond_t  wait;
     bool b_parsing_sync;
     bool b_parsing_async;
+    struct {
+        int fd;
+        uint64_t offset;
+        uint64_t length;
+    } media_cb;
 };
 static const libvlc_event_type_t m_events[] = {
     libvlc_MediaMetaChanged,
@@ -95,7 +109,7 @@ Media_event_cb(vlcjni_object *p_obj, const libvlc_event_t *p_ev,
     return true;
 }
 
-static void
+static int
 Media_nativeNewCommon(JNIEnv *env, jobject thiz, vlcjni_object *p_obj)
 {
     p_obj->p_sys = calloc(1, sizeof(vlcjni_object_sys));
@@ -107,15 +121,17 @@ Media_nativeNewCommon(JNIEnv *env, jobject thiz, vlcjni_object *p_obj)
         throw_Exception(env,
                         !p_obj->u.p_m ? VLCJNI_EX_ILLEGAL_STATE : VLCJNI_EX_OUT_OF_MEMORY,
                         "can't create Media instance");
-        return;
+        return -1;
     }
 
     pthread_mutex_init(&p_obj->p_sys->lock, NULL);
     pthread_cond_init(&p_obj->p_sys->wait, NULL);
+    p_obj->p_sys->media_cb.fd = -1;
 
     VLCJniObject_attachEvents(p_obj, Media_event_cb,
                               libvlc_media_event_manager(p_obj->u.p_m),
                               m_events);
+    return 0;
 }
 
 static void
@@ -197,6 +213,105 @@ Java_org_videolan_libvlc_Media_nativeNewFromFd(JNIEnv *env, jobject thiz,
     Media_nativeNewCommon(env, thiz, p_obj);
 }
 
+static int
+media_cb_seek(void *opaque, uint64_t offset)
+{
+    struct media_cb *mcb = opaque;
+    if (lseek(mcb->fd, mcb->fd_offset + offset, SEEK_SET) == (off_t)-1)
+        return -1;
+    mcb->offset = offset;
+    return 0;
+}
+
+static int
+media_cb_open(void *opaque, void **datap, uint64_t *sizep)
+{
+    vlcjni_object *p_obj = opaque;
+    vlcjni_object_sys *p_sys = p_obj->p_sys;
+
+    struct media_cb *mcb = malloc(sizeof(*mcb));
+    if (!mcb)
+        return -1;
+
+    mcb->fd = dup(p_sys->media_cb.fd);
+    if (mcb->fd == -1)
+    {
+        free(mcb);
+        return -1;
+    }
+    mcb->fd_offset = p_sys->media_cb.offset;
+    mcb->fd_length = p_sys->media_cb.length;
+    mcb->offset = 0;
+
+    if (media_cb_seek(mcb, 0) != 0)
+    {
+        close(mcb->fd);
+        free(mcb);
+        return -1;
+    }
+
+    *sizep = p_sys->media_cb.length;
+    *datap = mcb;
+    return 0;
+}
+
+static ssize_t
+media_cb_read(void *opaque, unsigned char *buf, size_t len)
+{
+#define __MIN(a, b) ( ((a) < (b)) ? (a) : (b) )
+
+    struct media_cb *mcb = opaque;
+    len = __MIN(len, mcb->fd_length - mcb->offset);
+    if (len == 0)
+        return 0;
+
+    ssize_t ret = read(mcb->fd, buf, len);
+    if (ret > 0)
+        mcb->offset += ret;
+    return ret;
+
+#undef __MIN
+}
+
+static void
+media_cb_close(void *opaque)
+{
+    struct media_cb *mcb = opaque;
+    close(mcb->fd);
+    free(mcb);
+}
+
+void
+Java_org_videolan_libvlc_Media_nativeNewFromFdWithOffsetLength(
+    JNIEnv *env, jobject thiz, jobject libVlc, jobject jfd, jlong offset, jlong length)
+{
+    vlcjni_object *p_obj;
+    int fd = FDObject_getInt(env, jfd);
+    if (fd == -1)
+        return;
+
+    p_obj = VLCJniObject_newFromJavaLibVlc(env, thiz, libVlc);
+    if (!p_obj)
+        return;
+
+    p_obj->u.p_m =
+        libvlc_media_new_callbacks(p_obj->p_libvlc,
+                                   media_cb_open,
+                                   media_cb_read,
+                                   media_cb_seek,
+                                   media_cb_close,
+                                   p_obj);
+
+
+    if (Media_nativeNewCommon(env, thiz, p_obj) == 0)
+    {
+        vlcjni_object_sys *p_sys = p_obj->p_sys;
+        p_sys->media_cb.fd = fd;
+        p_sys->media_cb.offset = offset;
+        p_sys->media_cb.length = length >= 0 ? length : UINT64_MAX;
+    }
+}
+
 /* MediaList must be locked */
 void
 Java_org_videolan_libvlc_Media_nativeNewFromMediaList(JNIEnv *env, jobject thiz,
diff --git a/libvlc/src/org/videolan/libvlc/Media.java b/libvlc/src/org/videolan/libvlc/Media.java
index f297a3f39..0af51d6fb 100644
--- a/libvlc/src/org/videolan/libvlc/Media.java
+++ b/libvlc/src/org/videolan/libvlc/Media.java
@@ -20,6 +20,7 @@
 
 package org.videolan.libvlc;
 
+import android.content.res.AssetFileDescriptor;
 import android.net.Uri;
 import android.support.annotation.Nullable;
 
@@ -457,6 +458,20 @@ public class Media extends VLCObject<Media.Event> {
         mUri = VLCUtil.UriFromMrl(nativeGetMrl());
     }
 
+    /**
+     * Create a Media from libVLC and an AssetFileDescriptor
+     *
+     * @param libVLC a valid LibVLC
+     * @param afd asset file descriptor object
+     */
+    public Media(LibVLC libVLC, AssetFileDescriptor afd) {
+        super(libVLC);
+        long offset = afd.getStartOffset();
+        long length = afd.getLength();
+        nativeNewFromFdWithOffsetLength(libVLC, afd.getFileDescriptor(), offset, length);
+        mUri = VLCUtil.UriFromMrl(nativeGetMrl());
+    }
+
     /**
      *
      * @param ml Should not be released and locked
@@ -862,6 +877,7 @@ public class Media extends VLCObject<Media.Event> {
     private native void nativeNewFromPath(LibVLC libVLC, String path);
     private native void nativeNewFromLocation(LibVLC libVLC, String location);
     private native void nativeNewFromFd(LibVLC libVLC, FileDescriptor fd);
+    private native void nativeNewFromFdWithOffsetLength(LibVLC libVLC, FileDescriptor fd, long offset, long length);
     private native void nativeNewFromMediaList(MediaList ml, int index);
     private native void nativeRelease();
     private native boolean nativeParseAsync(int flags, int timeout);



More information about the Android mailing list