Bytebuffor操作使Android App从小型Amr文件中提取原始数据时崩溃

时间:2019-05-12 14:39:15

标签: java android mediacodec

当我使用mediaCodec解码AMR文件时,它会输出一个字节缓冲区,但是当我尝试将字节缓冲区转换为双精度数组时,应用程序将崩溃。

我尝试从字节缓冲区中取出一个字节,并且应用程序也崩溃了。字节缓冲区上的任何操作都会导致我的应用崩溃。

decoder.start();
        inputBuffers = decoder.getInputBuffers();
        outputBuffers = decoder.getOutputBuffers();
        end_of_input_file = false;

        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
        ByteBuffer data = readData(info);

        int samplesRead = info.size;

        byte[] bytesArray = new byte[data.remaining()];        
        bytesArray = getByteArrayFromByteBuffer(data);  

here the app crashes. 

这是readData方法:

 private ByteBuffer readData(MediaCodec.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 = mExtractor.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, mExtractor.getSampleTime(), 0);
                        mExtractor.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();
            }
        }
    }

这是getByteArrayFromByteBuffer方法:

private static byte[] getByteArrayFromByteBuffer(ByteBuffer byteBuffer) {
        byte[] bytesArray = new byte[byteBuffer.remaining()];
        byteBuffer.get(bytesArray, 0, bytesArray.length);
        return bytesArray;
    }
````


I would like to get the output of the decoder into a double array.

1 个答案:

答案 0 :(得分:0)

您的代码中有两个错误/误解。

第一期:

        // 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);

在调用dequeueOutputBuffer之前,您不知道它将返回什么输出缓冲区。即使那样,您也无法控制编解码器将其输出放置在缓冲区中的哪个位置。解码器将从可用的缓冲区中选择一个缓冲区,然后将输出数据放置在该缓冲区中的任何位置。 (实际上,它几乎总是在开始时。)

如果要以任何特定方式在输出缓冲区中设置位置/限制,请在dequeueOutputBuffer将其返回给您之后执行。

只需删除整个if语句和position()调用即可。

第二个错误,这是真正的主要问题:

            // 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];

dequeueOutputBuffer返回之前,仅允许您触摸并使用outputBuffers中的缓冲区,直到releaseOutputBuffer将其返回给解码器为止。如您的评论所述,在releaseOutputBuffers之后,MediaCodec可以再次使用它。您的ByteBuffer变量只是对编解码器可以将新输出写入其中的相同数据的引用-此处还不是副本。因此,在使用完ByteBuffer对象之前,您无法调用releaseOutputBuffer

奖励积分: 在使用ByteBuffer之前,最好为其设置位置/限制,如下所示:

outputBuffers[outputBufferIndex].position(info.offset);
outputBuffers[outputBufferIndex].limit(info.offset + info.size);

一些解码器隐式地执行此操作,但不一定全部执行该操作。