Android MediaCodec 3gpp编码器输出缓冲区包含不正确的字节

时间:2013-07-11 10:32:08

标签: android amr 3gp mediacodec

我正在尝试将来自MIC的音频流编码为3gpp(AMR-NB)。问题是输出缓冲区包含奇怪的数据。代码和输出如下:

创建媒体编码器:

MediaFormat format = MediaFormat.createAudioFormat("audio/3gpp", 8*1024, 1);
format.setInteger(MediaFormat.KEY_BIT_RATE, 8*1024);
format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, minBufSize);
MediaCodec encoder = MediaCodec.createEncoderByType("audio/3gpp");
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
encoder.start();

来自MIC的PCM数据似乎是正确的(存储到文件,用Audacity收听)

读取编码的字节(缓冲区,在线程中运行):

ByteBuffer[] outputBuffers = encoder.getOutputBuffers();
int outputBufferIndex = 0;
while( outputBufferIndex >= 0 )
{
    MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
    outputBufferIndex = encoder.dequeueOutputBuffer(bufferInfo, -1);
    if (outputBufferIndex >= 0)
    {
        ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
        byte[] outData = new byte[bufferInfo.size];
        outputBuffer.get(outData);
        outputBuffer.clear();
        encoder.releaseOutputBuffer(outputBufferIndex, false);
        Log.d(LOG_TAG_ENCODING, util.bytesToString(outData));
    }
    else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
    {
        outputBuffers = encoder.getOutputBuffers();
    }
}

输出是:

07-11 13:13:58.622: 34 6c 1e 08 27 80 05 28 56 40 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
07-11 13:13:58.632: 34 6c 1e 08 27 80 05 28 56 40 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
07-11 13:13:58.667: 34 ff d9 08 27 80 05 28 56 40 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
07-11 13:13:58.672: 34 6c 1e 08 27 80 05 28 56 40 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
07-11 13:13:58.677: 34 6c 1e 08 27 80 05 28 56 40 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

我用Google搜索并没有找到任何帮助。关于MediaCodec使用的Android文档也不是很好 - 很多在outputbuffer上下文中使用ByteBuffer.clear()的试验和错误。

最好的问候, 阿赫蒂。

1 个答案:

答案 0 :(得分:1)

对那里的所有患者,回答我自己的问题。

真正的问题实际上是将原始PCM数据输入编码器输入。关于如何将数据准确输入到输入缓冲区中的Android文档很模糊(好吧,实际上它更多地与ByteBuffer行为有关):

int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs);
if (inputBufferIndex >= 0) {
   // fill inputBuffers[inputBufferIndex] with valid data
   ...
   codec.queueInputBuffer(inputBufferIndex, ...);
}

我的解释是添加数据如下:

inputBuffers[inputBufferIndex].clear();
inputBuffers[inputBufferIndex].put(audioPCMbuffer);
codec.queueInputBuffer(inputBufferIndex, ...);

上面的代码有一点缺失:翻转ByteBuffer的位置!

inputBuffers[inputBufferIndex].flip();

保留它以供将来参考,因为很难找到简单的代码来查看实现。