android - 使用 MediaCodec 创建 AAC 编码器时出错

标签 android encode aac android-mediacodec

问题很简单,但是我没有任何解决的线索:

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

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

保存在“codec”中的返回值不为null,但我在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 @胡贝尔。看来他已经成功了。我做了同样的事情:(1)设置媒体解码器并输入 PCM 数据以获得编码帧。为此,我阅读了 cts 中的代码.每个编码帧长度约为 371-379。 (2)在frame中添加adts header,然后保存到文件中。我一点一点地检查了头部,是正确的。但该文件仍然无法播放。所以我认为错误日志可能是问题所在。

以下是我的全部代码,供引用:

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;
}

最佳答案

我想通了。

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

关于android - 使用 MediaCodec 创建 AAC 编码器时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22526714/

相关文章:

PHP 类实例转 JSON

android - Android SwitchCompat 的垂直对齐方式?

android - 在 Sqlite 中插入行很慢

java - 在 Java 中以 Base64 编码来自 URL 的图像

iphone - 使用 AQ 和音频文件流动态检测和流式传输 AAC

使用 AAC 的 FFMpeg 编码提供 1509 比特率

java - 使用java编程在android中将.mp3文件格式更改为.aac文件格式

android - Facebook SDK v4 LoginButton 忽略 XML 自定义

android - 从 Android 使用 Youtube 进行身份验证

php - 编码数据的最佳方式