使用没有 mediaextractor 的 mediacodec 的 MP3 解码失败

MP3 decoding failed using mediacodec without mediaextractor

我正在尝试使用 OMX.google.mp3.decoder 解码 android 中的 mp3 并使用 AudioTrack 播放它,但返回失败 I/OMXClient( 3506): Using client-side OMX mux. I/SW ( 3506): Codec ==== codec name:OMX.google.mp3.decoder I/SW ( 3506): type supported by codec:audio/mpeg I/SW ( 3506): is encoder:false E/OMXNodeInstance( 3506): OMX_GetExtensionIndex failed I/SWAudioPlayer( 3506): decoder ready: true E/SoftMP3 ( 3506): mp3 decoder returned error 2 E/ACodec ( 3506): [OMX.google.mp3.decoder] ERROR(0x80001001) E/MediaCodec( 3506): Codec reported an error. (omx error 0x80001001, internalError -2147483648) E/SWAudioPlayer( 3506): Exception in audio play java.lang.IllegalStateException

这是我的解码器设置代码(尝试使用从 4kb 到 64kb 的 playBufSize,但解码 mp3 失败)

    private static MediaCodecInfo getCodecInfo(String mimeType) {
    String info = "";
    int numCodecs = MediaCodecList.getCodecCount();
    for (int i = 0; i < numCodecs; i++) {
        MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
        String[] types = codecInfo.getSupportedTypes();
        for (int j = 0; j < types.length; j++) {
            if (types[j].equalsIgnoreCase(mimeType)) {
                info += "codec name:" + codecInfo.getName() + "\n";
                info += "type supported by codec:" + types[j] + "\n";
                info += "is encoder:" + codecInfo.isEncoder() + "\n";
                CodecCapabilities codecCapabilities = codecInfo.getCapabilitiesForType(types[j]);
                Log.i("SW","Codec ==== "+ info);
                for(final CodecProfileLevel codecProfileLevel : codecCapabilities.profileLevels) {
                    Log.i("SW","codec level "+codecProfileLevel.level);         
                    Log.i("SW","codec profile "+codecProfileLevel.profile);
                }
                return codecInfo;
            }
        }
    }
    return null;
}

private boolean setDecoder() throws IOException {
    String mimeType = "audio/mpeg";
    int rate = 48000;
    decoder = MediaCodec.createDecoderByType(mimeType);
    mCodecInfo = getCodecInfo(mimeType);
    if(mCodecInfo != null) {
        MediaFormat format = new MediaFormat();
        format.setString(MediaFormat.KEY_MIME, mimeType);
        format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2);
        format.setInteger(MediaFormat.KEY_SAMPLE_RATE, rate);
        format.setInteger(MediaFormat.KEY_BIT_RATE, 320 * 1024); /* 320 kbps */
        format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, playBufSize);

        decoder.configure(format, null, null, 0);
        return true;
    }
    return false;
}`

从服务器缓冲区接收到 Mp3 数据(将 mp3 数据从 android 流式传输到 android)

public void play_audio() {
    inputBuffers = decoder.getInputBuffers();
    outputBuffers = decoder.getOutputBuffers();
    inputBufferIndex = decoder.dequeueInputBuffer(-1);
    try {
        if (inputBufferIndex >= 0)
        {
            inputBuffer = inputBuffers[inputBufferIndex];
            inputBuffer.clear();
            inputBuffer.put(playData);
            decoder.queueInputBuffer(inputBufferIndex, 0, playData.length, 0, 0);
        }

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

        Log.i("SWA","outputBufferIndex "+outputBufferIndex);

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

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

            Log.i("SWA","bufferInfo.offset "+bufferInfo.offset);
            Log.i("SWA","bufferInfo.size "+bufferInfo.size);

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

            Log.i("SWA", outData.length + " bytes decoded");

            audioTrack.write(outData, 0, outData.length);

            decoder.releaseOutputBuffer(outputBufferIndex, false);
            outputBufferIndex = decoder.dequeueOutputBuffer(bufferInfo, 0);
        }
    }
    catch (Exception e)
    {
        Log.e("SWAudioPlayer","Exception in audio play "+e);
    }
}

我使用了从 4kb 到 64kb 的缓冲区大小(在 playData 字节数组中接收到的 mp3 数据的大小),但仍然出现 mp3 解码器 error.Getting 错误 decoder.queueInputBuffer(inputBufferIndex, 0, playData.length, 0, 0); 如何解决? 我们需要在解码之前跳过 Mp3 header 吗?

"mp3 decoder returned error 2"中的数字2好像是UNSUPPORTED_FREE_BITRATE的意思。从引用的 SoftMP3 源代码来看,mp3 似乎有 "free bit rate" and/or 保留频率,SoftMP3 不支持。

这应该很少见。我发现更有可能将错误数据输入解码器(特别是因为 "free bit rate" 恰好是 mp3 标准中的数字 0)。

我注意到 dequeInputBuffer() 只被调用了一次。我认为问题在于它应该在每一圈都被调用;参见 Synchronous Processing using Buffer Arrays