SDL2のAndroidアプリケーションでseekが遅くなる


Table of Contents

1 SDL2のI/O処理

SDL_RWops構造体経由で実行します。以下のコードはfoo.barというファイルを開いて、ファイルポインタを末尾に移動します。

SDL_RWops *rwops;static char buffer[1024];rwops = SDL_RWFromFile(“foo.bar”, “rt”);if (rwops == nullptr) return 1;SDL_RWseek(rwops, 0, RW_SEEK_END);SDL_RWclose(rwops);return 0;

SDL_RWops構造体でI/O処理の実装は隠蔽されています。

2 AndroidのSDL_RWops構造体のメンバ

Androidの場合、SDL_RWops構造体はAssetManagerを使おうと試みます。assetFileDescriptorRefにAssetManager.openFdのJNIグローバル参照を設定します。

Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence){ if (ctx->hidden.androidio.assetFileDescriptorRef) { /** AssetManager. */ } else { /** Not AssetManager. */ } return ctx->hidden.androidio.position;}

AssetManager.openFdは独自形式のファイルの場合にnullを返します(1MByteを超える場合?)。

 

AssetManager.openFdが成功した場合、Android_JNI_FileSeekのif文が真となり、seek関数を呼び出します。

 

失敗した場合、else文が実行されます。

else文ではseek関数の代わりにread関数を何度も呼び、ファイルポインタを進めることで代用します。

read関数はコピーが発生する為、seek関数に比べて相当に重くなります。

これがseek処理が重い原因です。

3 aapt

assetsディレクトリのファイルをパッケージングするツールです。

jpgやmp3等の登録された拡張子はそのままパッケージングされます。

登録されていない拡張子の場合は圧縮されます。

1MByteを超えるような大きいファイルの場合は展開されないようです。

4 custom_rules.xml

aaptはAndroid SDKのtools/ant/build.xmlのタスクとして定義されています。

各プロジェクトのcustom_rules.xmlでaaptのタスクを上書きし、登録されていない拡張子を非圧縮の対象として登録することで、1MByte以上の登録されていなかった拡張子のファイルをAssetManager.openFdで開くことができるようになります。

 

以下は-pre-buildでjniディレクトリをndk-buildでビルドし、-package-resourcesでaaptを実行するcustom_rules.xmlです。

<?xml version=”1.0″ encoding=”UTF-8″?><project> <target name=”-pre-build”> <exec executable=”ndk-build” failonerror=”true”/> </target> <target name=”-package-resources” depends=”-crunch”> <!– only package resources if *not* a library project –> <do-only-if-not-library elseText=”Library project: do not package resources…” > <aapt executable=”${aapt}” command=”package” versioncode=”${version.code}” versionname=”${version.name}” debug=”${build.is.packaging.debug}” manifest=”${out.manifest.abs.file}” assets=”${asset.absolute.dir}” androidjar=”${project.target.android.jar}” apkfolder=”${out.absolute.dir}” nocrunch=”${build.packaging.nocrunch}” resourcefilename=”${resource.package.file.name}” resourcefilter=”${aapt.resource.filter}” libraryResFolderPathRefid=”project.library.res.folder.path” libraryPackagesRefid=”project.library.packages” libraryRFileRefid=”project.library.bin.r.file.path” previousBuildType=”${build.last.target}” buildType=”${build.target}” ignoreAssets=”${aapt.ignore.assets}”> <res path=”${out.res.absolute.dir}” /> <res path=”${resource.absolute.dir}” /> <nocompress extension=”bar” /> <!– <nocompress /> forces no compression on any files in assets or res/raw –> <!– <nocompress extension=”xml” /> forces no compression on specific file extensions in assets and res/raw –> </aapt> </do-only-if-not-library> </target></project>

上の例では<nocompress extension=”bar” />で.barファイルを非圧縮にしています。

複数の拡張子を登録する場合はnocompress属性を複数記述します。

Android | Linux | SDL - Narrow Escape