Browse Source

More work on vorbis decoder
* added support for decoding from a section of a file descriptor (needed if decoding from an asset inside APK)
* implemented seek function

shadowislord 10 years ago
parent
commit
891ffa175d

+ 103 - 17
jme3-android-native/src/native/jme_decode/com_jme3_audio_plugins_NativeVorbisFile.c

@@ -1,5 +1,6 @@
 #include <unistd.h>
 #include <stdlib.h>
+#include <errno.h>
 #include "Tremor/ivorbisfile.h"
 
 #include "com_jme3_audio_plugins_NativeVorbisFile.h"
@@ -18,40 +19,105 @@ typedef struct
 {
     JNIEnv* env;
     int fd;
+    int start;
+    int end;
+    int current;
 }
 FileDescWrapper;
 
+// size_t read (int fd, void *buf, size_t nbytes)
 static size_t FileDesc_read(void *ptr, size_t size, size_t nmemb, void *datasource)
 {
     FileDescWrapper* wrapper = (FileDescWrapper*)datasource;
-    size_t totalRead = read(wrapper->fd, ptr, size * nmemb);
     
-    LOGI("read(%zu) = %zu", size * nmemb, totalRead);
+    int req_size = size * nmemb;
+    int to_read = req_size;
     
-    return totalRead;
+    if (wrapper->end - wrapper->current > req_size)
+    {
+        to_read = wrapper->end - wrapper->current;
+    }
+    
+    if (to_read <= 0) 
+    {
+        return 0;
+    }
+    
+    size_t total_read = read(wrapper->fd, ptr, to_read);
+    
+    if (total_read > 0)
+    {
+        wrapper->current += total_read;
+    }
+    
+    LOGI("FD read(%d) = %zu", to_read, total_read);
+    
+    return total_read;
 }
 
 // off64_t lseek64(int fd, off64_t offset, int whence); 
 static int FileDesc_seek(void *datasource, ogg_int64_t offset, int whence)
 {
     FileDescWrapper* wrapper = (FileDescWrapper*)datasource;
-    int result = lseek64(wrapper->fd, offset, whence);
-    
-    char* whenceStr;
-    switch (whence) {
-        case SEEK_CUR: whenceStr = "SEEK_CUR"; break;
-        case SEEK_END: whenceStr = "SEEK_END"; break;
-        case SEEK_SET: whenceStr = "SEEK_SET"; break;
-        default: whenceStr = "unknown"; break;
+    
+    int actual_offset;
+    
+    switch (whence)
+    {
+        case SEEK_SET:
+            // set the offset relative to start location.
+            actual_offset = wrapper->start + offset;
+            break;
+        case SEEK_END:
+            // seek from the end of the file.
+            // offset needs to be negative in this case.
+            actual_offset = wrapper->end + offset;
+            break;
+        case SEEK_CUR:
+            // seek relative to current position.
+            actual_offset = wrapper->current + offset;
+            break;
+        default:
+            // invalid whence.
+            errno = EINVAL;
+            return (off_t)-1;
     }
-    LOGI("seek(%lld, %s) = %d", offset, whenceStr, result);
+    
+    if (actual_offset < wrapper->start || 
+        actual_offset > wrapper->end)
+    {
+        // actual offset should be within our acceptable range.
+        errno = EINVAL;
+        return (off_t)-1;
+    }
+    
+    int result = lseek64(wrapper->fd, actual_offset, SEEK_SET);
+    
+    LOGI("FD seek(%d) = %d", actual_offset, result);
+    
+    if (result < 0)
+    {
+        // failed, errno should have been set by lseek.
+        return (off_t)-1;
+    }
+    
+    if (result != actual_offset)
+    {
+        // did not seek the expected amount. something wrong here.
+        errno = EINVAL;
+        return (off_t)-1;
+    }
+    
+    // seek succeeded.
+    // update current position
+    wrapper->current = actual_offset;
 }
 
 static int FileDesc_close(void *datasource)
 {
     FileDescWrapper* wrapper = (FileDescWrapper*)datasource;
     
-    LOGI("close");
+    LOGI("FD close");
     
     return close(wrapper->fd);
 }
@@ -61,7 +127,14 @@ static long FileDesc_tell(void *datasource)
     FileDescWrapper* wrapper = (FileDescWrapper*)datasource;
     long result = lseek64(wrapper->fd, 0, SEEK_CUR);
     
-    LOGI("tell = %ld", result);
+    LOGI("FD tell = %ld", result);
+    
+    if (wrapper->current != result)
+    {
+        // Not sure how to deal with this.
+        LOGI("PROBLEM: stored offset does not match actual: %d != %ld", 
+             wrapper->current, result);
+    }
     
     return result;
 }
@@ -102,15 +175,18 @@ JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_nativeInit
 }
 
 JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_open
-  (JNIEnv *env, jobject nvf, jint fd)
+  (JNIEnv *env, jobject nvf, jint fd, jlong off, jlong len)
 {
-    LOGI("open: %d", fd)
-            
+    LOGI("open: fd = %d, off = %lld, len = %lld", fd, off, len);
+    
     OggVorbis_File* ovf = (OggVorbis_File*) malloc(sizeof(OggVorbis_File));
     
     FileDescWrapper* wrapper = (FileDescWrapper*) malloc(sizeof(FileDescWrapper));
     wrapper->fd = fd;
     wrapper->env = env; // NOTE: every java call has to update this
+    wrapper->start = off;
+    wrapper->current = off;
+    wrapper->end = off + len;
     
     int result = ov_open_callbacks((void*)wrapper, ovf, NULL, 0, FileDescCallbacks);
     
@@ -148,7 +224,17 @@ JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_open
 JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_seekTime
   (JNIEnv *env, jobject nvf, jdouble time)
 {
+    jobject nvfBuf = (*env)->GetObjectField(env, nvf, nvf_field_ovf);
+    OggVorbis_File* ovf = (OggVorbis_File*) (*env)->GetDirectBufferAddress(env, nvfBuf);
     
+    int result = ov_time_seek(ovf, time);
+    
+    if (result != 0)
+    {
+        char err[512];
+        sprintf(err, "ov_time_seek failed: %d", result);
+        throwIOException(env, err);
+    }
 }
 
 JNIEXPORT jint JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_read

+ 3 - 3
jme3-android/src/main/java/com/jme3/audio/plugins/NativeVorbisFile.java

@@ -19,11 +19,11 @@ public class NativeVorbisFile {
         nativeInit();
     }
     
-    public NativeVorbisFile(int fd) throws IOException {
-        open(fd);
+    public NativeVorbisFile(int fd, long off, long len) throws IOException {
+        open(fd, off, len);
     }
     
-    private native void open(int fd) throws IOException;
+    private native void open(int fd, long off, long len) throws IOException;
     
     public native void seekTime(double time) throws IOException;
     

+ 3 - 1
jme3-android/src/main/java/com/jme3/audio/plugins/NativeVorbisLoader.java

@@ -65,7 +65,9 @@ public class NativeVorbisLoader implements AssetLoader {
         AssetFileDescriptor afd = aai.openFileDescriptor();
         int fd = afd.getParcelFileDescriptor().getFd();
         
-        NativeVorbisFile file = new NativeVorbisFile(fd);
+        NativeVorbisFile file = new NativeVorbisFile(fd, afd.getStartOffset(), 
+                                                         afd.getLength());
+        
         ByteBuffer data = BufferUtils.createByteBuffer(file.totalBytes);
         file.readFully(data);
         AudioBuffer ab = new AudioBuffer();