Play media from from zip file without unzipping
Asked Answered
L

5

6

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?

Lundy answered 24/2, 2013 at 19:36 Comment(3)
The zip file format uses a fairly simple internal file structure. The header points to the data, so you just need to look for the file header, then use the Relative offset of local file header and Compressed size to find the start of the data and its length. You should also at least check the Compression method to be sure the file is uncompressed, and as long as it is not compressed, use the data, otherwise uncompress the data first, then use it.Happ
The compression method is store using 7zip, and the .zip file's size is equal to the sum of the unzipped files so I think I've zipped them correctly. Other than that, I have no idea what you're talking about :PLundy
I ran into the same kind of problem not long ago, but haven't had any luck making it work. You can check these questions for more details: #12864231 #12920929Glenn
D
4

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
}
Diplegia answered 20/8, 2014 at 11:11 Comment(3)
I've since moved on to other methods, but if anyone can confirm this I'd be happy to accept it.Lundy
This doesn't seem to work f the zip file is compressed.Gallium
at what folder myZipFile.zip should be located?Inelegancy
D
3

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!

Dewie answered 31/10, 2018 at 10:15 Comment(0)
W
1
try {
    ZipFile zf= new ZipFile(filename);
    ZipEntry ze = zip.getEntry(fileName);
    if (ze!= null) {
        InputStream in = zf.getInputStream(ze);
        File f = File.createTempFile("_AUDIO_", ".wav");
        FileOutputStream out = new FileOutputStream(f);
        IOUtils.copy(in, out);
        // play f
    }
} catch (IOException e) {

}

possible duplicate question

Weatherman answered 25/2, 2013 at 4:46 Comment(2)
Thank you for your example, but I already knew how to create temp files.. The question was about accessing the files without unzipping them. Looks like it isn't possible without major hax, though.Lundy
Oh, then may be I am misunderstood. As i never find anything like playing a file without unzipping it or without using temp files. I have a doubt whether you can find a method. If there is any it will be great if you share.Weatherman
I
0

If you want to use a media file from a zip without unzipping you have to add also start offset and length to setDataSource.

ZipResourceFile expansionFile = new ZipResourceFile("myZipFile.zip");
AssetFileDescriptor assetFileDescriptor = expansionFile.getAssetFileDescriptor("myMusic.mp3");
try {
    mediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(),
                              assetFileDescriptor.getStartOffset(),
                              assetFileDescriptor.getLength());
    mediaPlayer.prepare();
    mediaPlayer.start();
}
catch (IOException e) {
    // Handle exception
}
Interrupted answered 26/8, 2015 at 17:47 Comment(0)
T
0

You can create a custom MediaDataSource like this:

public class ZipMediaDataSource extends MediaDataSource {

    private InputStream inputStream;

    public ZipMediaDataSource(ZipFile file, ZipEntry zipEntry) throws IOException {
        inputStream = file.getInputStream(zipEntry);
    }

    @Override
    public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
        return inputStream.read(buffer, offset, size);
    }

    @Override
    public long getSize() throws IOException {
        return inputStream.available();
    }

    @Override
    public void close() throws IOException {
        if (inputStream != null) {
            inputStream.close();
            inputStream = null;
        }
    }
}

usage is:

ZipMediaDataSource zipMediaDataSource = new ZipMediaDataSource(zipFile, zipEntry);
mediaPlayer.setDataSource(zipMediaDataSource);
Tankersley answered 7/2, 2023 at 7:5 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.