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
experimental
shadowislord 11 years ago
parent d8c5985a73
commit 891ffa175d
  1. 120
      jme3-android-native/src/native/jme_decode/com_jme3_audio_plugins_NativeVorbisFile.c
  2. 6
      jme3-android/src/main/java/com/jme3/audio/plugins/NativeVorbisFile.java
  3. 4
      jme3-android/src/main/java/com/jme3/audio/plugins/NativeVorbisLoader.java

@ -1,5 +1,6 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h>
#include "Tremor/ivorbisfile.h" #include "Tremor/ivorbisfile.h"
#include "com_jme3_audio_plugins_NativeVorbisFile.h" #include "com_jme3_audio_plugins_NativeVorbisFile.h"
@ -18,40 +19,105 @@ typedef struct
{ {
JNIEnv* env; JNIEnv* env;
int fd; int fd;
int start;
int end;
int current;
} }
FileDescWrapper; 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) static size_t FileDesc_read(void *ptr, size_t size, size_t nmemb, void *datasource)
{ {
FileDescWrapper* wrapper = (FileDescWrapper*)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); // off64_t lseek64(int fd, off64_t offset, int whence);
static int FileDesc_seek(void *datasource, ogg_int64_t offset, int whence) static int FileDesc_seek(void *datasource, ogg_int64_t offset, int whence)
{ {
FileDescWrapper* wrapper = (FileDescWrapper*)datasource; FileDescWrapper* wrapper = (FileDescWrapper*)datasource;
int result = lseek64(wrapper->fd, offset, whence);
int actual_offset;
char* whenceStr;
switch (whence) { switch (whence)
case SEEK_CUR: whenceStr = "SEEK_CUR"; break; {
case SEEK_END: whenceStr = "SEEK_END"; break; case SEEK_SET:
case SEEK_SET: whenceStr = "SEEK_SET"; break; // set the offset relative to start location.
default: whenceStr = "unknown"; break; 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) static int FileDesc_close(void *datasource)
{ {
FileDescWrapper* wrapper = (FileDescWrapper*)datasource; FileDescWrapper* wrapper = (FileDescWrapper*)datasource;
LOGI("close"); LOGI("FD close");
return close(wrapper->fd); return close(wrapper->fd);
} }
@ -61,7 +127,14 @@ static long FileDesc_tell(void *datasource)
FileDescWrapper* wrapper = (FileDescWrapper*)datasource; FileDescWrapper* wrapper = (FileDescWrapper*)datasource;
long result = lseek64(wrapper->fd, 0, SEEK_CUR); 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; 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 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)); OggVorbis_File* ovf = (OggVorbis_File*) malloc(sizeof(OggVorbis_File));
FileDescWrapper* wrapper = (FileDescWrapper*) malloc(sizeof(FileDescWrapper)); FileDescWrapper* wrapper = (FileDescWrapper*) malloc(sizeof(FileDescWrapper));
wrapper->fd = fd; wrapper->fd = fd;
wrapper->env = env; // NOTE: every java call has to update this 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); 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 JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_seekTime
(JNIEnv *env, jobject nvf, jdouble time) (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 JNIEXPORT jint JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_read

@ -19,11 +19,11 @@ public class NativeVorbisFile {
nativeInit(); nativeInit();
} }
public NativeVorbisFile(int fd) throws IOException { public NativeVorbisFile(int fd, long off, long len) throws IOException {
open(fd); 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; public native void seekTime(double time) throws IOException;

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

Loading…
Cancel
Save