Android MediaCodec mais lento no modo assíncrono do que no modo síncrono?

novamente uma pergunta minha sobre a classe MediaCodec de andróides. Consegui decodificar com sucesso o conteúdo bruto do h264 e exibir o resultado em dois TextureViews. O fluxo h264 vem de um servidor que está executando uma cena openGL. A cena tem uma câmera e, portanto, responde à entrada dos usuários. Para reduzir ainda mais a latência entre uma entrada no servidor e o resultado real no smartphone, pensei em usar o modo Async do MediaCodecs. Aqui está como eu configuro as duas variantes, síncrona e assíncrona:

Assíncrono:

//decoderCodec is "video/avc"
MediaFormat fmt = MediaFormat.createVideoFormat(decoderCodec, 1280,720);
codec.setCallback(new MediaCodec.Callback() {

    @Override
    public void onInputBufferAvailable(MediaCodec codec, int index) {
        byte[] frameData;
        try {
            frameData = frameQueue.take(); //this call is blocking
        } catch (InterruptedException e) {
            return;
        }

        ByteBuffer inputData = codec.getInputBuffer(index);
        inputData.clear();
        inputData.put(frameData);

        codec.queueInputBuffer(index, 0, frameData.length, 0, 0);
    }

    @Override
    public void onOutputBufferAvailable(MediaCodec codec, int index, MediaCodec.BufferInfo info) {
        codec.releaseOutputBuffer(index, true);
    }

     //The two other methods are left blank at the moment.

});


codec.configure(fmt, surface, null, 0);
codec.start();

Sincronizar: (é configurado como Async, exceto ocodec.setCallback(...) parte. A classe em que ambas as variantes residem é Runnable.

public void run() {

    while(!Thread.interrupted())
    {
        if(!IS_ASYNC) {
            byte[] frameData;
            try {
                frameData = frameQueue.take(); //this call is blocking
            } catch (InterruptedException e) {
                break;
            }

            int inIndex = codec.dequeueInputBuffer(BUFFER_TIMEOUT);

            if (inIndex >= 0) {
                ByteBuffer input = codec.getInputBuffer(inIndex);
                input.clear();
                input.put(frameData);
                codec.queueInputBuffer(inIndex, 0, frameData.length, 0, 0);
            }

            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
            int outIndex = codec.dequeueOutputBuffer(bufferInfo, BUFFER_TIMEOUT);

            if(outIndex >= 0)
                codec.releaseOutputBuffer(outIndex, true);
        }
        else sleep(3000); //Just for testing, if we are in Async, this thread has nothing to do actually...
    }
}

Ambas as abordagens funcionam, mas estou observando que os vídeos reproduzidos no modo síncrono são muito mais suaves e a latência também é menor.

Eu tive a ideia de usar o modo assíncrono porqueframeQueue é umLinkedBlockingDeque e pensei que, se o decodificador síncrono estiver aguardando demais para que novos dados do quadro cheguem, a saída decodificada já estará disponível, mas não será exibida devido à natureza de bloqueio da fila. Por outro lado, eu não queria fazer algo como ocupado esperando e pesquisando a fila, os inputBuffers e outputBuffers o tempo todo.

Então, tentei o AsyncMode usando os retornos de chamada, mas o resultado obtido é pior do que no modo síncrono. A pergunta para vocês agora é: Por quê? Uso mal o modo assíncrono ou é outra coisa?

Obrigado por qualquer feedback!

Christoph

questionAnswers(1)

yourAnswerToTheQuestion