Проблемы с MediaCodec Decoder при вызове dequeueOutputBuffer (H.264)

Вопрос: Почему я... Я имею в виду, что происходит с моим декодером? Он всегда возвращает тайм-аут (-1), когда я пытаюсь получить сочные выходные данные!

Позвольте мне начать с того, что я прочитал относительные темы, но все еще не могу решить проблему. Мне действительно нужно некоторое руководство и помощь здесь. Итак, что я делаю, так это передаю закодированные данные AVC в мой декодер. Кодер работает, вытягивая данные из предварительного просмотра камеры, где я делаю преобразование из NV21 в NV12, прежде чем перейти к кодеру.

Первые данные, доступные из кодировщика, имеют codec-specific-data, который я передаю ConfigureDecoder(ByteBuffer csd0, ByteBuffer csd1) Функция создания и настройки декодера, которая не выдает никаких ошибок.

public void ConfigureDecoder(ByteBuffer csd0, ByteBuffer csd1)
{
    try
    {
        decoder = MediaCodec.createDecoderByType(MIME_TYPE);
    }
    catch(IOException e)
    {
        Log.d(TAG, "Decoder codec creation failed: " + e.toString());
    }

    MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, 320, 240);
    format.setByteBuffer("csd-0", csd0);
    format.setByteBuffer("csd-1", csd1);
    decoder.configure(format, null, null, 0);

    try
    {
        decoder.start();
        Log.d(TAG, "Decoder configured");
    }
    catch(CodecException e)
    {
        Log.d(TAG, "Decoder config start failed: " + e.getDiagnosticInfo());
    }
}

Следующая функция вызывается, как только кодер уведомляет о наличии закодированных данных (после данных, специфичных для кодека). Сначала я получаю доступный входной буфер декодера, в случае успеха я заполняю его закодированными данными (проверено) и добавляю в очередь декодера. Тогда все идет к черту, я пытаюсь извлечь данные из декодера, используя dequeueOutputBuffer(bufferInfo, 0); который всегда возвращает -1.


public void offerDecoder(byte[] input, int offset, int size, long presentationTimeUs, int flags)
{   
    int inputBufIndex = decoder.dequeueInputBuffer(10000);
    Log.d(TAG, "Decoder dequeueInputBuffer = " + inputBufIndex);

    if(inputBufIndex >= 0)
    {
        try
        {
            // Get valid buffer and push into the decoder input buffer
            ByteBuffer inputBuf = decoder.getInputBuffer(inputBufIndex);
            inputBuf.clear();
            inputBuf = ByteBuffer.wrap(input);
            decoder.queueInputBuffer(inputBufIndex, 0, size, presentationTimeUs, flags);
        }
        catch(MediaCodec.CodecException ce)
        {
            Log.d(TAG, "Decoder adding data error: " + ce.getDiagnosticInfo());
        }
    }

    MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
    int outIndex = decoder.dequeueOutputBuffer(bufferInfo, 0);
    Log.d(TAG, "Decoder dequeueOutputBuffer = " + outIndex);

    switch(outIndex)
    {
        case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
            ByteBuffer outputBuffers = decoder.getOutputBuffer(outIndex);
            Log.d(TAG, "Decoder dequeueOutputBuffer = INFO_OUTPUT_BUFFERS_CHANGED");
            break;

        case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
            //MediaFormat bufferFormat = decoder.getOutputFormat(outIndex);
            Log.d(TAG, "Decoder dequeueOutputBuffer = INFO_OUTPUT_FORMAT_CHANGED");
            break;

        case MediaCodec.INFO_TRY_AGAIN_LATER:
            //Total fail, something is really wrong if you are always receiving -1 from dequeueOutputBuffer
            //Log.d(TAG, "Decoder dequeueOutputBuffer = INFO_TRY_AGAIN_LATER");
            break;

        default:
            Log.d(TAG, "Decoder out buffer info-->" + bufferInfo.offset + "--" + bufferInfo.size + "--" + bufferInfo.flags + "--" + bufferInfo.presentationTimeUs);
            ByteBuffer buffer = decoder.getOutputBuffer(outIndex); 
            decoder.releaseOutputBuffer(outIndex, false);
            break;
    }
}

Если вы достигли этой точки в посте, я действительно ценю ваше время:)

2 ответа

Кажется, проблема в том, что API дает вам иллюзию, что декодирование будет синхронным - это не так.

Когда вы дадите декодеру один входной пакет, он начнет декодировать его - теперь вы проверяете его только один раз сразу после этого, когда декодер возвращает -1, указывая, что у него больше нет выходных данных (пока).

Вы можете увеличить параметр timeoutUs, чтобы он немного подождал, чтобы увидеть, возвращает ли декодер что-то, или установите его в -1, чтобы ждать бесконечно.

Но если вы всегда будете ждать вывода сразу для каждого входного пакета, вы получите довольно плохую производительность (а в случае неправильного ввода вы можете вообще не получить никакого вывода); Вы должны дать декодеру столько данных, сколько у вас есть для декодирования (пока dequeueInputBuffer не покажет, что на данный момент нет входных буферов), и использовать любые выходные буферы, которые предоставляет декодер. Если вам нужен таргетинг только на Android 5.0 и выше, вам следует обратиться к API обратного вызова (MediaCodec.setCallback), что гораздо понятнее, не нужно опрашивать вывод.

Я также столкнулся с той же проблемой, решение состоит в том, чтобы просто удалить следующую строку из вашего кода,

format.setByteBuffer("csd-0", csd0);
format.setByteBuffer("csd-1", csd1);
Другие вопросы по тегам