当前位置: 首页 > 知识库问答 >
问题:

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

子车成和
2023-03-14

我正在尝试将来自麦克风的音频流编码为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数据似乎是正确的(存储到文件中,使用Audacy监听)

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

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文档并不出色,在输出缓冲区上下文中使用ByteBuffer.clear()的尝试和错误太多。

向你问好,阿蒂。

共有1个答案

卓瀚
2023-03-14

给所有的患者,回答我自己的问题。

真正的问题实际上是将原始PCM数据提供给编码器输入。Android文档在如何准确地将数据输入到输入缓冲区上含糊不清(好吧,老实说,它实际上更多地与字节缓冲行为有关):

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, ...);

上面的代码缺少一点:翻转字节缓冲区的位置!

inputBuffers[inputBufferIndex].flip();

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

 类似资料:
  • 这似乎真的很疯狂,但在我的IntelliJ想法的控制台中,我不能用中断的编码做任何事情。 我为克服这一点所做的事情: 在

  • 我正在Linux上编写一个C应用程序。我的应用程序有一个 UDP 服务器,它在某些事件上向客户端发送数据。UDP 服务器还会收到来自客户端的一些反馈/确认。 为了实现这个应用程序,我使用了一个UDP套接字(例如< code>int fdSocket)来发送和接收来自所有客户端的数据。我将这个socked绑定到端口8080,并将套接字设置为非阻塞模式。 我创建了两个线程。在一个线程中,我等待某个事件

  • 我正在使用Google Protocol Buffers向服务器发送消息。我对如何发送图像与如何接收图像感到困惑。有关详细信息,请参阅下面的代码,但我的问题是: 我需要base64_decode从未经过base64编码的返回字符串吗,因为它是使用char*和size发送的?也许Google Protocol Buffers处理了这个问题,但我在生成的类中找不到任何证据。 我可能在这里找到了答案,但

  • 缓冲区溢出的漏洞随着冯·诺依曼 1 构架的出 现就已经开始出现了。 在1988年随着莫里斯互联网蠕虫的广泛传播他们开始声名狼藉。不幸的是, 同样的这种攻击一直持续到今天。 到目前为止,大部分的缓冲区溢出的攻击都是基于摧毁栈的方式。 大部分现代计算机系统使用栈来给进程传递参数并且存储局部变量。 栈是一种在进程映象内存的高地址内的后进先出(LIFO)的缓冲区。 当程序调用一个函数时一个新的“栈帧”会被

  • 背景: 我已经将Android的MediaCodec连接到FFmpeg,以对MediaMuxer不支持的各种格式进行多路复用,包括通过集装箱。这种流媒体多路复用器需要对MediaCodec的输出缓冲区拥有更长、不可预测的所有权,因为它们可能在任何数据包处理步骤上执行网络I/O。对于我的视频流,我使用为Surface输入配置的MediaCodec。为了将多路复用与编码分离,我通过处理程序将Media

  • 问题内容: 我有一个Java程序,它将一些文本输出到控制台。它使用,和其他一些方法来执行此操作。 在程序的最后,我想读取控制台中的所有文本并将其复制到String缓冲区中。我该如何用Java做到这一点?我需要阅读和独立。 问题答案: 好的,这是一个有趣的问题。似乎不是一种同时解决所有方法的优雅方法。(不幸的是没有。) 我确实写了一个丑陋的基于反射的解决方法(我想不要在生产代码中使用它:) …可以像