Ошибка при создании кодировщика AAC с помощью MediaCodec

Вопрос простой, но я понятия не имею, как его решить:

Я пишу однострочный код для создания кодировщика AAC на своем Nexus 4 (Android 4.4.2)

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. И я прочитал этот сообщение @хубер. Кажется, у него это получилось. Я сделал то же самое: (1) настроил медиакодек и ввел данные PCM, чтобы получить закодированный кадр. Для этого я прочитал код из cts . Длина каждого закодированного кадра составляет около 371-379. (2) Добавьте заголовок объявления в кадр, затем сохраните в файл. Я проверил голову по крупицам, она правильная. Но файл все равно не воспроизводится. Поэтому я думаю, что, возможно, проблема в журнале ошибок.

Ниже приведен весь мой код для справки:

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

person Matt    schedule 20.03.2014    source источник
comment
Некоторые драйверы регистрируют все на уровне ошибки, даже если это просто легкое предупреждение. При работе с MediaCodec нередко можно увидеть большую кучу ошибок, даже когда все работает нормально. У вас возникли проблемы с тем, как работает ваше приложение, или вам просто интересно, о чем эти сообщения?   -  person fadden    schedule 20.03.2014
comment
На самом деле я пытаюсь кодировать PCM в файл AAC. И я прочитал этот пост . Кажется, у него это получилось. Я сделал то же самое: (1) настроил медиакодек и ввел данные PCM, чтобы получить закодированный кадр. Для этого я прочитал код из cst . Длина каждого закодированного кадра составляет около 371-379.   -  person Matt    schedule 21.03.2014
comment
(2) Добавьте заголовок объявления в кадр, затем сохраните в файл. Я проверил заголовок добавленной рекламы по крупицам, он правильный. Но файл все равно не воспроизводится. Поэтому я думаю, что, возможно, проблема в журнале ошибок. @hubeir   -  person Matt    schedule 21.03.2014


Ответы (3)


Я понял это.

(1) Установка ошибки в формате носителя:

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

должно быть

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

(2) Закодированный кадр мог быть записан в файл с файлом объявлений только тогда, когда (info.flags == 0)

(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;
}
person Matt    schedule 21.03.2014

Не могли бы вы проверить media_codecs_xxxx.xml, который находится в папке устройства (примечание: xxxx обычно зависит от вашей аппаратной платформы).

Здесь у вас могут быть OMX.qcom.audio.decoder.aac и OMX.google.aac.encoder. Пожалуйста, используйте любой из них и прокомментируйте другой

См. https://source.android.com/devices/media.html (разоблачение кодеки в фреймворк), это поможет вам

person AravindMS    schedule 20.03.2014

Интересно, некоторое время назад я столкнулся с похожей проблемой на каком-то устройстве: вместо кодировщика создается AAC-декодер, если используется MediaCodec.createEncoderByType(). Чтобы обойти это, я использовал:

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

что-то такое

person Marlon    schedule 20.03.2014
comment
Спасибо за ответ. Я попробовал код, но все равно получаю ошибку. - person Matt; 21.03.2014