Android MediaCodec在异步模式下比在同步模式下慢吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android MediaCodec在异步模式下比在同步模式下慢吗?相关的知识,希望对你有一定的参考价值。

关于orroids MediaCodec类的问题再次提出。我已成功设法解码原始h264内容并在两个TextureViews中显示结果。 h264流来自运行openGL场景的服务器。场景有一个摄像头,因此响应用户输入。为了进一步减少服务器上的输入和智能手机上的实际结果之间的延迟,我正在考虑使用MediaCodecs异步模式。以下是我如何设置同步和异步两种变体:

异步:

//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();

同步:(设置为Async,除了codec.setCallback(...)部分。两个变体所在的类都是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...
    }
}

这两种方法都有效,但我观察到以同步模式播放的视频更加流畅,延迟也更低。

我提出了使用异步模式的想法,因为frameQueue是一个LinkedBlockingDeque,我想,如果同步解码器等待新帧数据到达的时间太长,解码输出可能已经可用但由于阻塞性质而未显示的队列。另一方面,我不想做像忙等待和轮询队列,in​​putBuffers和outputBuffers一样的事情。

所以我尝试使用Callbacks的AsyncMode,但是我得到的结果比同步模式更差。你们现在的问题是:为什么?我是否滥用异步模式或者是其他什么?

感谢您的任何反馈!

克里斯托夫

答案

如果onInputBufferAvailable的拦截电话是罪魁祸首,我不会感到惊讶。感觉很可能在同一个线程中调用onInputBufferAvailableonOutputBufferAvailable,如果你阻塞一个,你就会阻止另一个运行。

我建议更改它,以便你在onInputBufferAvailable只是将缓冲区索引推送到某个队列,并发出一个不同的线程,表示现在有另一个缓冲区可用,然后让第二个线程等待队列中的缓冲区,并进行阻塞获取输入数据那里。

以上是关于Android MediaCodec在异步模式下比在同步模式下慢吗?的主要内容,如果未能解决你的问题,请参考以下文章

安卓执法仪编码器之同步/异步模式

安卓执法仪编码器之同步/异步模式

安卓执法仪编码器之同步/异步模式

给Android工程师的音视频教程之一文弄懂MediaCodec

Android 音视频编解码 -- 视频编码和H264格式原理讲解

Android 音视频编解码 -- 视频编码和H264格式原理讲解