-
-
Save a-m-s/1991ab18fbcb0fcc2cf9 to your computer and use it in GitHub Desktop.
| /* MediaDecoder | |
| Author: Andrew Stubbs (based on some examples from the docs) | |
| This class opens a file, reads the first audio channel it finds, and returns raw audio data. | |
| Usage: | |
| MediaDecoder decoder = new MediaDecoder("myfile.m4a"); | |
| short[] data; | |
| while ((data = decoder.readShortData()) != null) { | |
| // process data here | |
| } | |
| */ | |
| import java.nio.ByteBuffer; | |
| import android.media.MediaCodec; | |
| import android.media.MediaCodec.BufferInfo; | |
| import android.media.MediaExtractor; | |
| import android.media.MediaFormat; | |
| public class MediaDecoder { | |
| private MediaExtractor extractor = new MediaExtractor(); | |
| private MediaCodec decoder; | |
| private MediaFormat inputFormat; | |
| private ByteBuffer[] inputBuffers; | |
| private boolean end_of_input_file; | |
| private ByteBuffer[] outputBuffers; | |
| private int outputBufferIndex = -1; | |
| public MediaDecoder(String inputFilename) { | |
| extractor.setDataSource(inputFilename); | |
| // Select the first audio track we find. | |
| int numTracks = extractor.getTrackCount(); | |
| for (int i = 0; i < numTracks; ++i) { | |
| MediaFormat format = extractor.getTrackFormat(i); | |
| String mime = format.getString(MediaFormat.KEY_MIME); | |
| if (mime.startsWith("audio/")) { | |
| extractor.selectTrack(i); | |
| decoder = MediaCodec.createDecoderByType(mime); | |
| decoder.configure(format, null, null, 0); | |
| inputFormat = format; | |
| break; | |
| } | |
| } | |
| if (decoder == null) { | |
| throw new IllegalArgumentException("No decoder for file format"); | |
| } | |
| decoder.start(); | |
| inputBuffers = decoder.getInputBuffers(); | |
| outputBuffers = decoder.getOutputBuffers(); | |
| end_of_input_file = false; | |
| } | |
| // Read the raw data from MediaCodec. | |
| // The caller should copy the data out of the ByteBuffer before calling this again | |
| // or else it may get overwritten. | |
| private ByteBuffer readData(BufferInfo info) { | |
| if (decoder == null) | |
| return null; | |
| for (;;) { | |
| // Read data from the file into the codec. | |
| if (!end_of_input_file) { | |
| int inputBufferIndex = decoder.dequeueInputBuffer(10000); | |
| if (inputBufferIndex >= 0) { | |
| int size = extractor.readSampleData(inputBuffers[inputBufferIndex], 0); | |
| if (size < 0) { | |
| // End Of File | |
| decoder.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); | |
| end_of_input_file = true; | |
| } else { | |
| decoder.queueInputBuffer(inputBufferIndex, 0, size, extractor.getSampleTime(), 0); | |
| extractor.advance(); | |
| } | |
| } | |
| } | |
| // Read the output from the codec. | |
| if (outputBufferIndex >= 0) | |
| // Ensure that the data is placed at the start of the buffer | |
| outputBuffers[outputBufferIndex].position(0); | |
| outputBufferIndex = decoder.dequeueOutputBuffer(info, 10000); | |
| if (outputBufferIndex >= 0) { | |
| // Handle EOF | |
| if (info.flags != 0) { | |
| decoder.stop(); | |
| decoder.release(); | |
| decoder = null; | |
| return null; | |
| } | |
| // Release the buffer so MediaCodec can use it again. | |
| // The data should stay there until the next time we are called. | |
| decoder.releaseOutputBuffer(outputBufferIndex, false); | |
| return outputBuffers[outputBufferIndex]; | |
| } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { | |
| // This usually happens once at the start of the file. | |
| outputBuffers = decoder.getOutputBuffers(); | |
| } | |
| } | |
| } | |
| // Return the Audio sample rate, in samples/sec. | |
| public int getSampleRate() { | |
| return inputFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE); | |
| } | |
| // Read the raw audio data in 16-bit format | |
| // Returns null on EOF | |
| public short[] readShortData() { | |
| BufferInfo info = new BufferInfo(); | |
| ByteBuffer data = readData(info); | |
| if (data == null) | |
| return null; | |
| int samplesRead = info.size/2; | |
| short[] returnData = new short[samplesRead]; | |
| // Converting the ByteBuffer to an array doesn't actually make a copy | |
| // so we must do so or it will be overwritten later. | |
| System.arraycopy(data.asShortBuffer().array(), 0, returnData, 0, samplesRead); | |
| return returnData; | |
| } | |
| } |
I love your example, but there are some errors.
IllegalStateException and UnsupportedOperationException on Line 132 "System.arraycopy(data.asShortBuffer().array(), 0, returnData, 0, samplesRead);"
The IllegalStateException occurs because access to "ByteBuffer data" which has been released on Line 102 "decoder.releaseOutputBuffer(outputBufferIndex, false);"
The UnsupportedOperationException occurs because the "ShortBuffer" from "ByteBuffer.asShortBuffer" cannot use "array" function.
So I changed this line to "outputBuffers[outputBufferIndex].order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(returnData);" and it works like a charm!
Thank you for example code!
Is there any other way? There is an array error
I did what Riaxter said, but I could not solve it.
Is there any other way? There is an array error
I did what Riaxter said, but I could not solve it.
Me too. Another issue:
java.lang.IllegalStateException: buffer is inaccessible
at java.nio.DirectByteBuffer.getUnchecked(DirectByteBuffer.java:475)
at java.nio.ByteBufferAsShortBuffer.get(ByteBufferAsShortBuffer.java:102)
at java.nio.ShortBuffer.get(ShortBuffer.java:417)
at org.peace.allinone.ui.MediaDecoder.readShortData(MediaDecoder.java:138)
How can I save the audio track to a playable audio file?