【问题标题】:Error when create AAC encoder with MediaCodec使用 MediaCodec 创建 AAC 编码器时出错
【发布时间】:2014-04-26 22:17:29
【问题描述】:

这个问题很简单,但我没有任何线索可以解决它:

我编写了一行代码来在我的 Nexus 4 (Android 4.4.2) 上创建一个 AAC 编码器

MediaCodec codec = MediaCodec.createEncoderByType("audio/mp4a-latm");

“编解码器”中保存的返回值不为空,但在Logcat中得到红色错误信息:

03-20 15:25:08.985: E/OMXMaster(24517): A component of name 'OMX.qcom.audio.decoder.aac' already exists, ignoring this one.

我也试过另一行:

MediaCodec codec = MediaCodec.createByCodecName("OMX.google.aac.encoder");

并得到相同的错误结果。

我在使用 MediaCodec 之前是否遗漏了任何初始化步骤?我在官方文档中没有找到这方面的任何信息。

有人遇到过这个问题吗?

实际上我正在尝试将 PCM 编码为 AAC 文件。我读过这个post@hubeir。看来他已经成功了。我做了同样的事情:(1)设置媒体编解码器并输入 PCM 数据以获取编码帧。为此,我阅读了来自 cts 的代码。每个编码帧长度约为 371-379。 (2)将adts头添加到框架中,然后保存到文件中。我一点一点地检查了头部,它是正确的。但该文件仍然无法播放。所以我认为错误日志可能是问题所在。

以下是我的全部代码,供参考:

MediaCodec codec = MediaCodec.createByCodecName("OMX.google.aac.encoder");      
MediaFormat format = new MediaFormat();
    format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
    format.setInteger(MediaFormat.KEY_AAC_PROFILE, 
                      MediaCodecInfo.CodecProfileLevel.AACObjectELD);
    format.setInteger(MediaFormat.KEY_SAMPLE_RATE, nSamplerate);
    format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
    format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, nChannels);

    codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
    codec.start();

    ByteBuffer[] inputBuffers = codec.getInputBuffers();
    ByteBuffer[] outputBuffers = codec.getOutputBuffers();

    boolean bEndInput = false;
    boolean bEndOutput = false;

while(true)
{
    if (!bEndInput)
    {
        int inputBufferIndex = codec.dequeueInputBuffer(0);
        if (inputBufferIndex >= 0)
        {
            int nLen = app.readPCM(nHandle,inputBuffers[inputBufferIndex]);//This line read PCM, return 0 if end of data.
            int nBufLen = inputBuffers[inputBufferIndex].capacity(); 
            if (nLen == nBufLen)
                codec.queueInputBuffer(inputBufferIndex, 0, nLen, 0,  MediaCodec.BUFFER_FLAG_SYNC_FRAME);
            else if (nLen < nBufLen)
            {
                codec.queueInputBuffer(inputBufferIndex, 0, nLen, 0,  MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                bEndInput = true;
                break;
            }   
        }
    }

    MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
    if (!bEndOutput)
    {
            int outputBufferIndex = codec.dequeueOutputBuffer(info, 0);
            if (outputBufferIndex  >= 0)
            {
                int outBitsSize   = info.size;
                Log.d("test", "Offset:"+info.offset);
                Log.d("test", "Size:"+info.size);
                Log.d("test", "Time:"+info.presentationTimeUs);
                Log.d("test", "Flags:"+info.flags);
                if (outBitsSize <= 10)
                {
                    codec.releaseOutputBuffer(outputBufferIndex, false /* render */);
                    continue;
                }

                int outPacketSize = outBitsSize + 7;    // 7 is ADTS size
                ByteBuffer outBuf = outputBuffers[outputBufferIndex];

                outBuf.position(info.offset);
                outBuf.limit(info.offset + outBitsSize);
                try {
                    byte[] data = new byte[outPacketSize];  //space for ADTS header included
                    addADTStoPacket(data, outPacketSize);
                    outBuf.get(data, 7, outBitsSize);
                    outBuf.position(info.offset);
                    outputStream.write(data, 0, outPacketSize);  //open FileOutputStream beforehand
                } catch (IOException e) {
                    Log.e("test", "failed writing bitstream data to file");
                    e.printStackTrace();
                }

                outBuf.clear();
                codec.releaseOutputBuffer(outputBufferIndex, false /* render */);
                Log.d("test", "  dequeued " + outBitsSize + " bytes of output data.");
                Log.d("test", "  wrote " + outPacketSize + " bytes into output file.");

                if (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM)
                {
                    bEndOutput = true;
                    //break;
                }   
            }
            else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) 
            {
                 outputBuffers = codec.getOutputBuffers();
            } 
            else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) 
            {

            }
    }

    if (bEndInput && bEndOutput)
        break;
}

【问题讨论】:

  • 一些驱动程序以“错误”级别记录所有内容,即使它只是一个轻微的警告。使用 MediaCodec 时,即使一切正常,也会看到一大堆“错误”。您是否对应用的运行方式有疑问,或者您只是想知道这些消息的全部内容是什么?
  • 实际上我正在尝试将 PCM 编码为 AAC 文件。我读过这个post。看来他已经成功了。我做了同样的事情:(1)设置媒体编解码器并输入 PCM 数据以获取编码帧。为此,我阅读了来自 cst 的代码。每个编码帧长度约为 371-379。
  • (2)在框架中添加adts头,然后保存到文件中。我已经一点一点地检查了添加的adts头,它是正确的。但该文件仍然无法播放。所以我认为错误日志可能是问题所在。 @hubeir

标签: android encode aac android-mediacodec


【解决方案1】:

您能否检查一下设备文件夹下的 media_codecs_xxxx.xml (注意:xxxx 通常取决于您的硬件平台)。

这里你可能有 OMX.qcom.audio.decoder.aac 和 OMX.google.aac.encoder。请使用其中任何一个并评论另一个

请参考https://source.android.com/devices/media.html(将编解码器暴露给框架), 这会帮助你

【讨论】:

    【解决方案2】:

    有趣的是,前一段时间我在某些设备上遇到了类似的问题:如果使用 MediaCodec.createEncoderByType(),则会创建 AAC 解码器而不是编码器。为了解决这个问题,我使用了:

      String codecName = selectEncoder(mime);
      mediaCodec = MediaCodec.createByCodecName(codecName);
    

      private String selectEncoder(String mime) {
        for (int index = 0; index < MediaCodecList.getCodecCount(); index++) {
            MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(index);
    
            if (!codecInfo.isEncoder()) {
                continue;
            }
    
            for (String type : codecInfo.getSupportedTypes()) {
                if (type.equalsIgnoreCase(mime)) {
                    return codecInfogetName();
                }
            }
        }
        return null;
     }
    

    类似的东西

    【讨论】:

    • 感谢您的回复。我尝试了代码,但仍然收到错误。
    【解决方案3】:

    我想通了。

    (1)媒体格式的错误设置:

    format.setInteger(MediaFormat.KEY_AAC_PROFILE, 
                          MediaCodecInfo.CodecProfileLevel.AACObjectELD);
    

    应该是

    format.setInteger(MediaFormat.KEY_AAC_PROFILE, 
                          MediaCodecInfo.CodecProfileLevel.AACObjectLC);
    

    (2) 只有在 (info.flags == 0) 时,编码帧才能写入带有 adts 文件的文件

    (3) 输出文件名后缀为“aac”。 “mp4”或“m4a”可能不适用于某些应用程序。

    MediaCodec codec = MediaCodec.createByCodecName("OMX.google.aac.encoder");      
    MediaFormat format = new MediaFormat();
        format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
        format.setInteger(MediaFormat.KEY_AAC_PROFILE, 
                          MediaCodecInfo.CodecProfileLevel.AACObjectLC); //fixed version
        format.setInteger(MediaFormat.KEY_SAMPLE_RATE, nSamplerate);
        format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
        format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, nChannels);
    
        codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        codec.start();
    
        ByteBuffer[] inputBuffers = codec.getInputBuffers();
        ByteBuffer[] outputBuffers = codec.getOutputBuffers();
    
        boolean bEndInput = false;
        boolean bEndOutput = false;
    
    while(true)
    {
        if (!bEndInput)
        {
            int inputBufferIndex = codec.dequeueInputBuffer(0);
            if (inputBufferIndex >= 0)
            {
                int nLen = app.readPCM(nHandle,inputBuffers[inputBufferIndex]);//This line read PCM, return 0 if end of data.
                int nBufLen = inputBuffers[inputBufferIndex].capacity(); 
                if (nLen == nBufLen)
                    codec.queueInputBuffer(inputBufferIndex, 0, nLen, 0,  MediaCodec.BUFFER_FLAG_SYNC_FRAME);
                else if (nLen < nBufLen)
                {
                    codec.queueInputBuffer(inputBufferIndex, 0, nLen, 0,  MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                    bEndInput = true;
                    break;
                }   
            }
        }
    
        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
        if (!bEndOutput)
        {
                int outputBufferIndex = codec.dequeueOutputBuffer(info, 0);
                if (outputBufferIndex  >= 0)
                {
                    int outBitsSize   = info.size;
                    Log.d("test", "Offset:"+info.offset);
                    Log.d("test", "Size:"+info.size);
                    Log.d("test", "Time:"+info.presentationTimeUs);
                    Log.d("test", "Flags:"+info.flags);
                    if (info.flags != 0) //fixed version
                    {
                        codec.releaseOutputBuffer(outputBufferIndex, false /* render */);
                        continue;
                    }
    
                    int outPacketSize = outBitsSize + 7;    // 7 is ADTS size
                    ByteBuffer outBuf = outputBuffers[outputBufferIndex];
    
                    outBuf.position(info.offset);
                    outBuf.limit(info.offset + outBitsSize);
                    try {
                        byte[] data = new byte[outPacketSize];  //space for ADTS header included
                        addADTStoPacket(data, outPacketSize);
                        outBuf.get(data, 7, outBitsSize);
                        outBuf.position(info.offset);
                        outputStream.write(data, 0, outPacketSize);  //open FileOutputStream beforehand
                    } catch (IOException e) {
                        Log.e("test", "failed writing bitstream data to file");
                        e.printStackTrace();
                    }
    
                    outBuf.clear();
                    codec.releaseOutputBuffer(outputBufferIndex, false /* render */);
                    Log.d("test", "  dequeued " + outBitsSize + " bytes of output data.");
                    Log.d("test", "  wrote " + outPacketSize + " bytes into output file.");
    
                    if (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM)
                    {
                        bEndOutput = true;
                        //break;
                    }   
                }
                else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) 
                {
                     outputBuffers = codec.getOutputBuffers();
                } 
                else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) 
                {
    
                }
        }
    
        if (bEndInput && bEndOutput)
            break;
    }
    

    【讨论】:

      猜你喜欢
      • 2013-02-22
      • 2021-12-01
      • 1970-01-01
      • 2013-11-18
      • 2021-08-02
      • 2012-10-08
      • 1970-01-01
      • 2015-10-28
      • 2016-02-21
      相关资源
      最近更新 更多