1

我正在尝试将来自 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 

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

最好的问候,阿赫蒂。

4

1 回答 1

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

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

于 2013-07-11T20:23:03.297 回答