android native improvements
* rename jme_stbi -> jme_decode, which is a new native library that will handle image and audio decoding in native code * add a special version of tremor designed to run on android * adjust the build process to handle these changes
This commit is contained in:
parent
603432790b
commit
5f0c2035c1
BIN
jme3-android-native/TremorAndroid.zip
Normal file
BIN
jme3-android-native/TremorAndroid.zip
Normal file
Binary file not shown.
@ -44,5 +44,6 @@ ext {
|
|||||||
|
|
||||||
// add each native lib build file
|
// add each native lib build file
|
||||||
apply from: file('openalsoft.gradle')
|
apply from: file('openalsoft.gradle')
|
||||||
apply from: file('stb_image.gradle')
|
// apply from: file('stb_image.gradle')
|
||||||
|
// apply from: file('tremor.gradle')
|
||||||
|
apply from: file('decode.gradle')
|
110
jme3-android-native/decode.gradle
Normal file
110
jme3-android-native/decode.gradle
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
String tremorZipFile = "TremorAndroid.zip"
|
||||||
|
String stbiUrl = 'https://raw.githubusercontent.com/nothings/stb/master/stb_image.h'
|
||||||
|
|
||||||
|
// Working directories for the ndk build.
|
||||||
|
String decodeBuildDir = "${buildDir}" + File.separator + 'decode'
|
||||||
|
String decodeBuildJniDir = decodeBuildDir + File.separator + 'jni'
|
||||||
|
String decodeBuildLibsDir = decodeBuildDir + File.separator + 'libs'
|
||||||
|
|
||||||
|
// Pre-compiled libs directory
|
||||||
|
String decodePreCompiledLibsDir = 'libs' + File.separator + 'decode'
|
||||||
|
|
||||||
|
// jME Android Native source files path
|
||||||
|
String decodeSourceDir = 'src/native/jme_decode'
|
||||||
|
|
||||||
|
task downloadStbImage(type: MyDownload) {
|
||||||
|
sourceUrl = stbiUrl
|
||||||
|
target = file('stb_image.h')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy stb_image.h to the source directory.
|
||||||
|
task copyStbiFiles(type: Copy) {
|
||||||
|
def sourceDir = file('stb_image.h')
|
||||||
|
def outputDir = file(decodeSourceDir + File.separator + "STBI")
|
||||||
|
from sourceDir
|
||||||
|
into outputDir
|
||||||
|
}
|
||||||
|
copyStbiFiles.dependsOn {
|
||||||
|
def stbiFile = file('stb_image.h')
|
||||||
|
if (!stbiFile.exists()) {
|
||||||
|
downloadStbImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy libtremor source to the source directory.
|
||||||
|
task copyTremorFiles(type: Copy) {
|
||||||
|
def zipFile = file(tremorZipFile)
|
||||||
|
def outputDir = file(decodeSourceDir + File.separator + "Tremor")
|
||||||
|
|
||||||
|
from (zipTree(zipFile)) {
|
||||||
|
include '*.c'
|
||||||
|
include '*.h'
|
||||||
|
}
|
||||||
|
|
||||||
|
into outputDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate headers via javah
|
||||||
|
task generateJavahHeaders(type: Exec) {
|
||||||
|
executable org.gradle.internal.jvm.Jvm.current().getExecutable('javah')
|
||||||
|
args '-d', decodeSourceDir
|
||||||
|
args '-classpath', project.projectClassPath
|
||||||
|
args "com.jme3.audio.plugins.NativeVorbisFile"
|
||||||
|
args "com.jme3.texture.plugins.AndroidNativeImageLoader"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy jME Android native files to jni directory
|
||||||
|
task copySourceToBuild(type: Copy, dependsOn:[copyTremorFiles, copyStbiFiles, generateJavahHeaders]) {
|
||||||
|
def sourceDir = file(decodeSourceDir)
|
||||||
|
def outputDir = file(decodeBuildJniDir)
|
||||||
|
|
||||||
|
from sourceDir
|
||||||
|
into outputDir
|
||||||
|
}
|
||||||
|
|
||||||
|
task buildNativeLib(type: Exec, dependsOn: copySourceToBuild) {
|
||||||
|
workingDir decodeBuildDir
|
||||||
|
executable rootProject.ndkCommandPath
|
||||||
|
args '-j8'
|
||||||
|
}
|
||||||
|
|
||||||
|
task updatePreCompiledLibs(type: Copy, dependsOn: buildNativeLib) {
|
||||||
|
def sourceDir = new File(decodeBuildLibsDir)
|
||||||
|
def outputDir = new File(decodePreCompiledLibsDir)
|
||||||
|
|
||||||
|
from sourceDir
|
||||||
|
into outputDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy pre-compiled libs to build directory (when not building new libs)
|
||||||
|
task copyPreCompiledLibs(type: Copy) {
|
||||||
|
def sourceDir = file(decodePreCompiledLibsDir)
|
||||||
|
def outputDir = file(decodeBuildLibsDir)
|
||||||
|
|
||||||
|
from sourceDir
|
||||||
|
into outputDir
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rootProject.ndkExists) {
|
||||||
|
// build native libs and update stored pre-compiled libs to commit
|
||||||
|
compileJava.dependsOn { updatePreCompiledLibs }
|
||||||
|
} else {
|
||||||
|
// use pre-compiled native libs (not building new ones)
|
||||||
|
compileJava.dependsOn { copyPreCompiledLibs }
|
||||||
|
}
|
||||||
|
|
||||||
|
jar.into("lib") { from decodeBuildLibsDir }
|
||||||
|
|
||||||
|
// Helper class to wrap ant dowload task
|
||||||
|
class MyDownload extends DefaultTask {
|
||||||
|
@Input
|
||||||
|
String sourceUrl
|
||||||
|
|
||||||
|
@OutputFile
|
||||||
|
File target
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
void download() {
|
||||||
|
ant.get(src: sourceUrl, dest: target)
|
||||||
|
}
|
||||||
|
}
|
39
jme3-android-native/src/native/jme_decode/Android.mk
Normal file
39
jme3-android-native/src/native/jme_decode/Android.mk
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
TARGET_PLATFORM := android-9
|
||||||
|
|
||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_MODULE := decodejme
|
||||||
|
|
||||||
|
LOCAL_C_INCLUDES:= \
|
||||||
|
$(LOCAL_PATH) \
|
||||||
|
$(LOCAL_PATH)/Tremor
|
||||||
|
|
||||||
|
LOCAL_CFLAGS := -std=gnu99
|
||||||
|
LOCAL_LDLIBS := -lz -llog -Wl,-s
|
||||||
|
|
||||||
|
ifeq ($(TARGET_ARCH),arm)
|
||||||
|
LOCAL_CFLAGS+= -D_ARM_ASSEM_
|
||||||
|
endif
|
||||||
|
|
||||||
|
LOCAL_ARM_MODE := arm
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := \
|
||||||
|
Tremor/bitwise.c \
|
||||||
|
Tremor/codebook.c \
|
||||||
|
Tremor/dsp.c \
|
||||||
|
Tremor/floor0.c \
|
||||||
|
Tremor/floor1.c \
|
||||||
|
Tremor/floor_lookup.c \
|
||||||
|
Tremor/framing.c \
|
||||||
|
Tremor/info.c \
|
||||||
|
Tremor/mapping0.c \
|
||||||
|
Tremor/mdct.c \
|
||||||
|
Tremor/misc.c \
|
||||||
|
Tremor/res012.c \
|
||||||
|
Tremor/vorbisfile.c \
|
||||||
|
com_jme3_audio_plugins_NativeVorbisFile.c \
|
||||||
|
com_jme3_texture_plugins_AndroidNativeImageLoader.c
|
||||||
|
|
||||||
|
include $(BUILD_SHARED_LIBRARY)
|
3
jme3-android-native/src/native/jme_decode/Application.mk
Normal file
3
jme3-android-native/src/native/jme_decode/Application.mk
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
APP_PLATFORM := android-9
|
||||||
|
APP_OPTIM := debug
|
||||||
|
APP_ABI := all
|
@ -0,0 +1,177 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "Tremor/ivorbisfile.h"
|
||||||
|
|
||||||
|
#include "com_jme3_audio_plugins_NativeVorbisFile.h"
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#include <android/log.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#define LOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, \
|
||||||
|
"NativeVorbisFile", fmt, ##__VA_ARGS__);
|
||||||
|
#else
|
||||||
|
#error We are building in release mode, arent we?
|
||||||
|
#define LOGI(fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
JNIEnv* env;
|
||||||
|
int fd;
|
||||||
|
}
|
||||||
|
FileDescWrapper;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return totalRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
LOGI("seek(%lld, %s) = %d", offset, whenceStr, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int FileDesc_close(void *datasource)
|
||||||
|
{
|
||||||
|
FileDescWrapper* wrapper = (FileDescWrapper*)datasource;
|
||||||
|
|
||||||
|
LOGI("close");
|
||||||
|
|
||||||
|
return close(wrapper->fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long FileDesc_tell(void *datasource)
|
||||||
|
{
|
||||||
|
FileDescWrapper* wrapper = (FileDescWrapper*)datasource;
|
||||||
|
long result = lseek64(wrapper->fd, 0, SEEK_CUR);
|
||||||
|
|
||||||
|
LOGI("tell = %ld", result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ov_callbacks FileDescCallbacks = {
|
||||||
|
FileDesc_read,
|
||||||
|
FileDesc_seek,
|
||||||
|
FileDesc_close,
|
||||||
|
FileDesc_tell
|
||||||
|
};
|
||||||
|
|
||||||
|
static void throwIOException(JNIEnv* env, const char* message)
|
||||||
|
{
|
||||||
|
jclass ioExClazz = (*env)->FindClass(env, "java/io/IOException");
|
||||||
|
(*env)->ThrowNew(env, ioExClazz, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static jfieldID nvf_field_ovf;
|
||||||
|
static jfieldID nvf_field_seekable;
|
||||||
|
static jfieldID nvf_field_channels;
|
||||||
|
static jfieldID nvf_field_sampleRate;
|
||||||
|
static jfieldID nvf_field_bitRate;
|
||||||
|
static jfieldID nvf_field_totalBytes;
|
||||||
|
static jfieldID nvf_field_duration;
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_nativeInit
|
||||||
|
(JNIEnv *env, jclass clazz)
|
||||||
|
{
|
||||||
|
LOGI("nativeInit");
|
||||||
|
|
||||||
|
nvf_field_ovf = (*env)->GetFieldID(env, clazz, "ovf", "Ljava/nio/ByteBuffer;");;
|
||||||
|
nvf_field_seekable = (*env)->GetFieldID(env, clazz, "seekable", "Z");
|
||||||
|
nvf_field_channels = (*env)->GetFieldID(env, clazz, "channels", "I");
|
||||||
|
nvf_field_sampleRate = (*env)->GetFieldID(env, clazz, "sampleRate", "I");
|
||||||
|
nvf_field_bitRate = (*env)->GetFieldID(env, clazz, "bitRate", "I");
|
||||||
|
nvf_field_totalBytes = (*env)->GetFieldID(env, clazz, "totalBytes", "I");
|
||||||
|
nvf_field_duration = (*env)->GetFieldID(env, clazz, "duration", "F");
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_open
|
||||||
|
(JNIEnv *env, jobject nvf, jint fd)
|
||||||
|
{
|
||||||
|
LOGI("open: %d", fd)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
int result = ov_open_callbacks((void*)wrapper, ovf, NULL, 0, FileDescCallbacks);
|
||||||
|
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
LOGI("ov_open fail");
|
||||||
|
|
||||||
|
free(ovf);
|
||||||
|
free(wrapper);
|
||||||
|
|
||||||
|
char err[512];
|
||||||
|
sprintf(err, "ov_open failed: %d", result);
|
||||||
|
throwIOException(env, err);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI("ov_open OK");
|
||||||
|
jobject ovfBuf = (*env)->NewDirectByteBuffer(env, ovf, sizeof(OggVorbis_File));
|
||||||
|
|
||||||
|
vorbis_info* info = ov_info(ovf, -1);
|
||||||
|
jint total_bytes = ov_pcm_total(ovf, -1);
|
||||||
|
jboolean seekable = ov_seekable(ovf) != 0;
|
||||||
|
jfloat duration = (jfloat) ov_time_total(ovf, -1);
|
||||||
|
|
||||||
|
(*env)->SetObjectField(env, nvf, nvf_field_ovf, ovfBuf);
|
||||||
|
(*env)->SetBooleanField(env, nvf, nvf_field_seekable, seekable);
|
||||||
|
(*env)->SetIntField(env, nvf, nvf_field_channels, info->channels);
|
||||||
|
(*env)->SetIntField(env, nvf, nvf_field_sampleRate, info->rate);
|
||||||
|
(*env)->SetIntField(env, nvf, nvf_field_bitRate, info->bitrate_nominal);
|
||||||
|
(*env)->SetIntField(env, nvf, nvf_field_totalBytes, total_bytes);
|
||||||
|
(*env)->SetFloatField(env, nvf, nvf_field_duration, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_seekTime
|
||||||
|
(JNIEnv *env, jobject nvf, jdouble time)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_read
|
||||||
|
(JNIEnv *env, jobject nvf, jbyteArray buf, jint off, jint len)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_readFully
|
||||||
|
(JNIEnv *env, jobject nvf, jobject buf)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_com_jme3_audio_plugins_NativeVorbisFile_close
|
||||||
|
(JNIEnv *env, jobject nvf)
|
||||||
|
{
|
||||||
|
LOGI("close");
|
||||||
|
|
||||||
|
jobject ovfBuf = (*env)->GetObjectField(env, nvf, nvf_field_ovf);
|
||||||
|
OggVorbis_File* ovf = (OggVorbis_File*) (*env)->GetDirectBufferAddress(env, ovfBuf);
|
||||||
|
FileDescWrapper* wrapper = (FileDescWrapper*) ovf->datasource;
|
||||||
|
free(wrapper);
|
||||||
|
free(ovf);
|
||||||
|
(*env)->SetObjectField(env, nvf, nvf_field_ovf, NULL);
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
#include "com_jme3_texture_plugins_AndroidNativeImageLoader.h"
|
#include "com_jme3_texture_plugins_AndroidNativeImageLoader.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifndef NDEBUG
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
#define LOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, \
|
#define LOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, \
|
||||||
"NativeImageLoader", fmt, ##__VA_ARGS__);
|
"NativeImageLoader", fmt, ##__VA_ARGS__);
|
||||||
@ -12,7 +12,7 @@
|
|||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#define STBI_NO_STDIO
|
#define STBI_NO_STDIO
|
||||||
#define STBI_NO_HDR
|
#define STBI_NO_HDR
|
||||||
#include "stb_image.h"
|
#include "STBI/stb_image.h"
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
@ -1,16 +0,0 @@
|
|||||||
TARGET_PLATFORM := android-9
|
|
||||||
|
|
||||||
LOCAL_PATH := $(call my-dir)
|
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
|
||||||
|
|
||||||
LOCAL_MODULE := stbijme
|
|
||||||
|
|
||||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)
|
|
||||||
|
|
||||||
LOCAL_CFLAGS := -std=c99
|
|
||||||
LOCAL_LDLIBS := -lz -llog -Wl,-s
|
|
||||||
|
|
||||||
LOCAL_SRC_FILES := com_jme3_texture_plugins_AndroidNativeImageLoader.c
|
|
||||||
|
|
||||||
include $(BUILD_SHARED_LIBRARY)
|
|
@ -1,3 +0,0 @@
|
|||||||
APP_PLATFORM := android-9
|
|
||||||
APP_OPTIM := release
|
|
||||||
APP_ABI := all
|
|
@ -1,123 +0,0 @@
|
|||||||
// stb_image url for download
|
|
||||||
String stbiUrl = 'https://raw.githubusercontent.com/nothings/stb/master/stb_image.h'
|
|
||||||
String stbiDownloadTarget = 'stb_image.h'
|
|
||||||
|
|
||||||
// stb_image is not downloaded. The single source file is included in the repo
|
|
||||||
String stbiFolder = 'stb_image'
|
|
||||||
|
|
||||||
//Working directories for the ndk build.
|
|
||||||
String stbiBuildDir = "${buildDir}" + File.separator + 'stb_image'
|
|
||||||
String stbiBuildJniDir = stbiBuildDir + File.separator + 'jni'
|
|
||||||
String stbiBuildLibsDir = stbiBuildDir + File.separator + 'libs'
|
|
||||||
|
|
||||||
//Pre-compiled libs directory
|
|
||||||
String stbiPreCompiledLibsDir = 'libs' + File.separator + 'stb_image'
|
|
||||||
|
|
||||||
// jME Android Native source files path
|
|
||||||
String stbiJmeAndroidPath = 'src/native/jme_stbi'
|
|
||||||
|
|
||||||
// Download external source files if not available
|
|
||||||
task downloadStbImage(type: MyDownload) {
|
|
||||||
sourceUrl = stbiUrl
|
|
||||||
target = file(stbiFolder + File.separator + stbiDownloadTarget)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy stb_image.h to the source directory.
|
|
||||||
task copyStbiFiles(type: Copy) {
|
|
||||||
def sourceDir = file(stbiFolder)
|
|
||||||
def outputDir = file(stbiJmeAndroidPath)
|
|
||||||
// println "copyStbiFiles sourceDir: " + sourceDir
|
|
||||||
// println "copyStbiFiles outputDir: " + outputDir
|
|
||||||
|
|
||||||
from sourceDir
|
|
||||||
into outputDir
|
|
||||||
}
|
|
||||||
copyStbiFiles.dependsOn {
|
|
||||||
def stbiFilePath = project.projectDir.absolutePath + stbiFolder + File.separator + stbiDownloadTarget
|
|
||||||
def stbiFile = new File(stbiFilePath)
|
|
||||||
// println "zipFile path: " + zipFile.absolutePath
|
|
||||||
// println "zipFile exists: " + zipFile.exists()
|
|
||||||
if (!stbiFile.exists()) {
|
|
||||||
downloadStbImage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task generateStbiHeaders(type: Exec) {
|
|
||||||
String destDirPath = stbiJmeAndroidPath
|
|
||||||
String classes = ""
|
|
||||||
.concat("com.jme3.texture.plugins.AndroidNativeImageLoader, ")
|
|
||||||
|
|
||||||
// println "stb_image classes = " + classes
|
|
||||||
// println "stb_image destDir = " + destDir
|
|
||||||
// println "stb_image classpath = " + project.projectClassPath
|
|
||||||
|
|
||||||
executable org.gradle.internal.jvm.Jvm.current().getExecutable('javah')
|
|
||||||
args '-d', destDirPath
|
|
||||||
args '-classpath', project.projectClassPath
|
|
||||||
args "com.jme3.texture.plugins.AndroidNativeImageLoader"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy jME Android native files to jni directory
|
|
||||||
task copyStbiJmeFiles(type: Copy, dependsOn:[copyStbiFiles, generateStbiHeaders]) {
|
|
||||||
def sourceDir = file(stbiJmeAndroidPath)
|
|
||||||
def outputDir = file(stbiBuildJniDir)
|
|
||||||
// println "copyStbiJmeFiles sourceDir: " + sourceDir
|
|
||||||
// println "copyStbiJmeFiles outputDir: " + outputDir
|
|
||||||
|
|
||||||
from sourceDir
|
|
||||||
into outputDir
|
|
||||||
}
|
|
||||||
|
|
||||||
task buildStbiNativeLib(type: Exec, dependsOn: copyStbiJmeFiles) {
|
|
||||||
// println "stb_image build dir: " + stbiBuildDir
|
|
||||||
// println "ndkCommandPath: " + rootProject.ndkCommandPath
|
|
||||||
|
|
||||||
workingDir stbiBuildDir
|
|
||||||
executable rootProject.ndkCommandPath
|
|
||||||
args '-j8'
|
|
||||||
}
|
|
||||||
|
|
||||||
task updatePreCompiledStbiLibs(type: Copy, dependsOn: buildStbiNativeLib) {
|
|
||||||
def sourceDir = new File(stbiBuildLibsDir)
|
|
||||||
def outputDir = new File(stbiPreCompiledLibsDir)
|
|
||||||
// println "updatePreCompiledStbiLibs sourceDir: " + sourceDir
|
|
||||||
// println "updatePreCompiledStbiLibs outputDir: " + outputDir
|
|
||||||
|
|
||||||
from sourceDir
|
|
||||||
into outputDir
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy pre-compiled libs to build directory (when not building new libs)
|
|
||||||
task copyPreCompiledStbiLibs(type: Copy) {
|
|
||||||
def sourceDir = file(stbiPreCompiledLibsDir)
|
|
||||||
def outputDir = file(stbiBuildLibsDir)
|
|
||||||
// println "copyStbiJmeFiles sourceDir: " + sourceDir
|
|
||||||
// println "copyStbiJmeFiles outputDir: " + outputDir
|
|
||||||
|
|
||||||
from sourceDir
|
|
||||||
into outputDir
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rootProject.ndkExists) {
|
|
||||||
// build native libs and update stored pre-compiled libs to commit
|
|
||||||
compileJava.dependsOn { updatePreCompiledStbiLibs }
|
|
||||||
} else {
|
|
||||||
// use pre-compiled native libs (not building new ones)
|
|
||||||
compileJava.dependsOn { copyPreCompiledStbiLibs }
|
|
||||||
}
|
|
||||||
|
|
||||||
jar.into("lib") { from stbiBuildLibsDir }
|
|
||||||
|
|
||||||
// Helper class to wrap ant dowload task
|
|
||||||
class MyDownload extends DefaultTask {
|
|
||||||
@Input
|
|
||||||
String sourceUrl
|
|
||||||
|
|
||||||
@OutputFile
|
|
||||||
File target
|
|
||||||
|
|
||||||
@TaskAction
|
|
||||||
void download() {
|
|
||||||
ant.get(src: sourceUrl, dest: target)
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.jme3.audio.plugins;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class NativeVorbisFile {
|
||||||
|
|
||||||
|
public int fd;
|
||||||
|
public ByteBuffer ovf;
|
||||||
|
public boolean seekable;
|
||||||
|
public int channels;
|
||||||
|
public int sampleRate;
|
||||||
|
public int bitRate;
|
||||||
|
public int totalBytes;
|
||||||
|
public float duration;
|
||||||
|
|
||||||
|
static {
|
||||||
|
System.loadLibrary("decodejme");
|
||||||
|
nativeInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NativeVorbisFile(int fd) throws IOException {
|
||||||
|
open(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private native void open(int fd) throws IOException;
|
||||||
|
|
||||||
|
public native void seekTime(double time) throws IOException;
|
||||||
|
|
||||||
|
public native int read(byte[] buf, int off, int len) throws IOException;
|
||||||
|
|
||||||
|
public native void readFully(ByteBuffer out) throws IOException;
|
||||||
|
|
||||||
|
public native void close();
|
||||||
|
|
||||||
|
public static native void nativeInit();
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
package com.jme3.audio.plugins;
|
||||||
|
|
||||||
|
import android.content.res.AssetFileDescriptor;
|
||||||
|
import com.jme3.asset.AssetInfo;
|
||||||
|
import com.jme3.asset.AssetLoader;
|
||||||
|
import com.jme3.asset.plugins.AndroidLocator;
|
||||||
|
import com.jme3.asset.plugins.AndroidLocator.AndroidAssetInfo;
|
||||||
|
import com.jme3.audio.AudioBuffer;
|
||||||
|
import com.jme3.audio.AudioKey;
|
||||||
|
import com.jme3.audio.SeekableStream;
|
||||||
|
import com.jme3.util.BufferUtils;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class NativeVorbisLoader implements AssetLoader {
|
||||||
|
|
||||||
|
private static class VorbisInputStream extends InputStream implements SeekableStream {
|
||||||
|
|
||||||
|
private final NativeVorbisFile file;
|
||||||
|
|
||||||
|
public VorbisInputStream(NativeVorbisFile file) {
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] buf) throws IOException {
|
||||||
|
return file.read(buf, 0, buf.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] buf, int off, int len) throws IOException {
|
||||||
|
return file.read(buf, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long skip(long n) throws IOException {
|
||||||
|
throw new IOException("Not supported for audio streams");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTime(float time) {
|
||||||
|
try {
|
||||||
|
file.seekTime(time);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object load(AssetInfo assetInfo) throws IOException {
|
||||||
|
AudioKey key = (AudioKey) assetInfo.getKey();
|
||||||
|
if (!(assetInfo instanceof AndroidLocator.AndroidAssetInfo)) {
|
||||||
|
throw new UnsupportedOperationException("Cannot load audio files from classpath." +
|
||||||
|
"Place your audio files in " +
|
||||||
|
"Android's assets directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidAssetInfo aai = (AndroidAssetInfo) assetInfo;
|
||||||
|
AssetFileDescriptor afd = aai.openFileDescriptor();
|
||||||
|
int fd = afd.getParcelFileDescriptor().getFd();
|
||||||
|
|
||||||
|
NativeVorbisFile file = new NativeVorbisFile(fd);
|
||||||
|
ByteBuffer data = BufferUtils.createByteBuffer(file.totalBytes);
|
||||||
|
file.readFully(data);
|
||||||
|
AudioBuffer ab = new AudioBuffer();
|
||||||
|
ab.setupFormat(file.channels, 16, file.sampleRate);
|
||||||
|
ab.updateData(data);
|
||||||
|
return ab;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user