Search code examples
androidandroid-mediacodecpcm

NaN values in decoded audio data


I want to get pcm samples from audio file using MediaCodec. I successfully got them, but there are NaN values in decoded data.

What do those mean? How to eliminate them?

Here is my code:

public float[] getPCMSamples(String audioPath) throws IOException {
    MediaExtractor extractor = new MediaExtractor();
    MediaCodec decoder = null;

    int byte_num = 0;
    extractor.setDataSource(audioPath);
    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);

            int rate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
            int channels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
            long duration = format.getLong(MediaFormat.KEY_DURATION);
            duration = (duration / 1000000) + 1;
            int bitspersample = 16;
            //compute how much byte required for whole song
            byte_num = (rate * channels * (int) duration * bitspersample) / 8;
        }
    }

    //Decode
    decoder.start();
    ByteBuffer[] inputBuffers = decoder.getInputBuffers();
    ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
    //info for passing to the dequeueOutputBuffer
    MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
    //flag for the end of the stream
    boolean isEOS = false;
    //holding bytes obtained from each outputBuffer
    byte[] decodedBytes = new byte[byte_num];
    //index of decoded bytes so far
    int decodedIdx = 0;

    //Start decoding
    while (true) {
        //fill inputBuffer with audio encoded data
        if (!isEOS) {
            int inputBufferIndex = decoder.dequeueInputBuffer(10000);
            if (inputBufferIndex >= 0) {
                int sampleSize = extractor.readSampleData(inputBuffers[inputBufferIndex], 0);
                if (sampleSize < 0) {
                    decoder.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                    isEOS = true;
                } else {
                    decoder.queueInputBuffer(inputBufferIndex, 0, sampleSize, extractor.getSampleTime(), 0);
                    extractor.advance();
                }
            }
        }

        int outputBufIndex = decoder.dequeueOutputBuffer(info, 10000);
        if (outputBufIndex >= 0) {
            Log.d(TAG, "got frame, size " + info.size + "/" + info.presentationTimeUs);
            ByteBuffer buffer = outputBuffers[outputBufIndex];

            byte[] temp = new byte[buffer.remaining()];
            buffer.get(temp);
            System.arraycopy(temp, 0, decodedBytes, decodedIdx, temp.length);
            decodedIdx += temp.length;

            decoder.releaseOutputBuffer(outputBufIndex, false /* render */);
            if (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
                Log.d(TAG, "saw output EOS.");
                break;
            }
        } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
            outputBuffers = decoder.getOutputBuffers();

            Log.d(TAG, "output buffers have changed.");
        } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            MediaFormat oformat = decoder.getOutputFormat();

            Log.d(TAG, "output format has changed to " + oformat);
        } else {
            Log.d(TAG, "dequeueOutputBuffer returned " + outputBufIndex);
        }
    }
    decoder.stop();
    decoder.release();

    FloatBuffer floatBuffer = ByteBuffer.wrap(decodedBytes).asFloatBuffer();
    float[] decoded = new float[floatBuffer.remaining()];
    floatBuffer.get(decoded);

    return decoded;
}

Solution

  • Raw, decoded audio on android is normally 16 bit integers, not floats. So instead of FloatBuffer, use ShortBuffer.