Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play media from from zip file without unzipping

I know there are already a few questions like this on SO, but they relate to extracting the file before playing it.

In the Android docs here it explains that you can play files directly from a .zip file without extracting it.

Tip: If you're packaging media files into a ZIP, you can use media playback calls on the files with offset and length controls (such as MediaPlayer.setDataSource() and SoundPool.load()) without the need to unpack your ZIP. In order for this to work, you must not perform additional compression on the media files when creating the ZIP packages. For example, when using the zip tool, you should use the -n option to specify the file suffixes that should not be compressed:

zip -n .mp4;.ogg main_expansion media_files

I've made an (uncompressed) zip package, but I cannot figure out how to get from a ZipEntry to a FileDescriptor, and they don't explain any further. How do I get a FileDescriptor without unpacking the zip file?

like image 801
Snailer Avatar asked Feb 24 '13 19:02

Snailer


2 Answers

You can use The APK Expansion Zip Library to do that even if you do not use APK Expansions in your app.

Follow this documentation to get the library: Using the APK Expansion Zip Library

Zip your sound files without compression using your favorite zip tool.

Use this code to load the music:

ZipResourceFile expansionFile = new ZipResourceFile("myZipFile.zip");
AssetFileDescriptor assetFileDescriptor = expansionFile.getAssetFileDescriptor("myMusic.mp3");
try {
    mediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor());
    mediaPlayer.prepare();
    mediaPlayer.start();
}
catch (IOException e) {
    // Handle exception
}
like image 54
Luca Hofmann Avatar answered Sep 18 '22 11:09

Luca Hofmann


There aren't many recent solutions for this issue, so I was stuck on this, too – until I created a new instance of MediaPlayer in the function where I was trying to read the zip file. Suddenly playback started without problems. Now, instead, I'm passing my (global) MediaPlayer to the function like this: (Kotlin)

private fun preparePlayer(mp: MediaPlayer, position: Int) {

    // Path of shared storage
    val root: File = Environment.getExternalStorageDirectory()
    Log.i("ROOT", root.toString())

    // path of the zip file
    val zipFilePath = File(root.absolutePath+"/Android/obb/MY_PACKAGE_NAME/MY_ZIP_FILE.zip")

    // Is zip file recognized?
    val zipFileExists = zipFilePath.exists()
    Log.i("Does zip file exist?", zipFileExists.toString())

    // Define the zip file as ZipResourceFile
    val expansionFile = ZipResourceFile(zipFilePath.absolutePath)

    // Your media in the zip file
    val afd = expansionFile.getAssetFileDescriptor("track_01.mp3")

    // val mp = MediaPlayer()   // not necessary if you pass it as a function parameter
    mp.setDataSource(afd.fileDescriptor, afd.startOffset, afd.length)
    mp.prepare()
    mp.start()   // Music should start playing automatically

Maybe this can help someone else. Good luck!

like image 26
chosenandfree Avatar answered Sep 18 '22 11:09

chosenandfree