【问题标题】:Android MediaCodec AMR-NB realtime decodingAndroid MediaCodec AMR-NB 实时解码
【发布时间】:2015-08-11 23:02:19
【问题描述】:

我正在通过 API 之类的套接字开发 VoIP。 (使用窄带连接)

我需要对每个语音帧(20ms)进行编码并通过所述api发送,然后在另一端解码。

我尝试通过 NDK 与 Opus 合作,但没有成功,因此我决定使用 MediaCodec 来使用 AMR-NB 进行编码/解码。

编码似乎工作,产生预期大小的缓冲区(160 个原始字节到 20 个编码字节 + 7.9Kbps 的标头)

但是当我处理编码缓冲区并尝试对其进行解码时,我会收到 INFO_OUTPUT_FORMAT_CHANGED 结果。

编码器:

// Set up recorder
    int recordBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
    arec = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, recordBufferSize);

    // Set Up codec
    try {
        encoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AMR_NB);
        MediaFormat format = new MediaFormat();
        format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AMR_NB);
        format.setInteger(MediaFormat.KEY_SAMPLE_RATE, SAMPLE_RATE);
        format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
        format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate.getVal());
        encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
    } catch (IOException e) {
        e.printStackTrace();
        return;
    }

    // Start Recording
    int read;
    byte[] buffer1 = new byte[bufferSize];

    ByteBuffer[] inputBuffers;
    ByteBuffer[] outputBuffers;

    ByteBuffer inputBuffer;
    ByteBuffer outputBuffer;

    MediaCodec.BufferInfo bufferInfo;
    int inputBufferIndex;
    int outputBufferIndex;

    byte[] outData;

    Frame frame;
    try {
        encoder.start();
        arec.startRecording();
        isRecording = true;
        while (isRecording) {
            read = arec.read(buffer1, 0, bufferSize);

            inputBuffers = encoder.getInputBuffers();
            outputBuffers = encoder.getOutputBuffers();
            inputBufferIndex = encoder.dequeueInputBuffer(-1);
            if (inputBufferIndex >= 0) {
                inputBuffer = inputBuffers[inputBufferIndex];
                inputBuffer.clear();

                inputBuffer.put(buffer1);

                encoder.queueInputBuffer(inputBufferIndex, 0, buffer1.length, 0, 0);
            }

            bufferInfo = new MediaCodec.BufferInfo();
            outputBufferIndex = encoder.dequeueOutputBuffer(bufferInfo, 0);


            while (outputBufferIndex >= 0) {
                outputBuffer = outputBuffers[outputBufferIndex];

                outputBuffer.position(bufferInfo.offset);
                outputBuffer.limit(bufferInfo.offset + bufferInfo.size);

                outData = new byte[bufferInfo.size];
                outputBuffer.get(outData);


                //-------------
                frame = new Frame(outData);
                handler.onFrameEncoded(frame);
                //------------

                encoder.releaseOutputBuffer(outputBufferIndex, false);
                outputBufferIndex = encoder.dequeueOutputBuffer(bufferInfo, 0);

            }
        }
        encoder.stop();
        arec.stop();
    } catch (Exception e) {
        e.printStackTrace();
    }

还有解码器:

@Override
        public void onFrameEncoded(Frame frame) {
            try {
                MediaCodec decoder = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_AUDIO_AMR_NB);
                MediaFormat format = new MediaFormat();
                format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AMR_NB);
                format.setInteger(MediaFormat.KEY_SAMPLE_RATE, SAMPLE_RATE);
                format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
                format.setInteger(MediaFormat.KEY_BIT_RATE, 7950);
                decoder.configure(format, null, null, 0);
                decoder.start();

                byte[] outData;

                ByteBuffer[] inputBuffers;
                ByteBuffer[] outputBuffers;

                ByteBuffer inputBuffer;
                ByteBuffer outputBuffer;

                MediaCodec.BufferInfo bufferInfo;
                int inputBufferIndex;
                int outputBufferIndex;
                inputBuffers = decoder.getInputBuffers();
                outputBuffers = decoder.getOutputBuffers();


                // Fill decoder input buffer
                inputBufferIndex = decoder.dequeueInputBuffer(-1);
                if (inputBufferIndex >= 0) {
                    inputBuffer = inputBuffers[inputBufferIndex];
                    inputBuffer.clear();

                    inputBuffer.put(frame.Buffer);

                    decoder.queueInputBuffer(inputBufferIndex, 0, frame.Buffer.length, 0, 0);
                }


                // Get Output
                bufferInfo = new MediaCodec.BufferInfo();
                outputBufferIndex = decoder.dequeueOutputBuffer(bufferInfo, -1);
                if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { // Just a check I threw in
                    MediaFormat format2 = decoder.getOutputFormat(); // Returns format RAW
                }

                while (outputBufferIndex >= 0) {
                    outputBuffer = outputBuffers[outputBufferIndex];

                    outputBuffer.position(bufferInfo.offset);
                    outputBuffer.limit(bufferInfo.offset + bufferInfo.size);

                    outData = new byte[bufferInfo.size];
                    outputBuffer.get(outData);


                    // Log.d("Decoder", outData.length + " bytes encoded");

                    decoder.releaseOutputBuffer(outputBufferIndex, false);
                    outputBufferIndex = decoder.dequeueOutputBuffer(bufferInfo, 0);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

我到处搜索INFO_OUTPUT_FORMAT_CHANGED,但找不到任何可以帮助我的东西..

【问题讨论】:

    标签: android decode android-mediacodec amr


    【解决方案1】:

    这是预期的行为。如果您使用的是 MediaMuxer,您会将该 MediaFormat 传递给 addTrack(),这需要一些必须来自 MediaCodec 的信息。引入 MediaMuxer 时,此行为为 added in API 18

    有关示例,请参阅 EncodeAndMuxTest

    如果您不使用 MediaMuxer,则可以忽略它。 (您可能想要记录它只是为了确认一切都还是应有的状态。)

    【讨论】:

    • 问题是我没有使用 MediaMuxer,因为我没有输出到文件,而是需要解码帧并将其提供给 AudioTrack。我不能忽略它,因为我应该收到输出缓冲区索引,而我收到的是INFO_OUTPUT_FORMAT_CHANGED。带有一个空的 BufferInfo。我需要一种逐帧解码数据的方法。
    • “输出格式改变”的结果不是instead数据,它除了数据,就在数据出现之前。如果在那之后您没有看到任何数据出现,那么就有问题了。您的代码似乎看到了一个结果,然后放弃了。它似乎还期望能够提交一个缓冲区并立即接收一个缓冲区,这可能是不明智的——这不适用于视频编解码器,它往往需要一些数据包在队列中,尽管它可能适用于音频.有关信息和示例,请参见 bigflake 网站。
    猜你喜欢
    • 2013-04-25
    • 1970-01-01
    • 2021-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多