【问题标题】:Android MediaCodec eglSwapBuffer blocking GPU in asynchronous modeAndroid MediaCodec eglSwapBuffer 在异步模式下阻塞GPU
【发布时间】:2017-01-03 11:02:28
【问题描述】:

我有一个视频效果应用程序,我使用 OpenGL 绘制到帧缓冲区对象,然后将生成的纹理绘制到显示器,然后如果应用程序正在编码,则绘制 MediaCodec 输入表面。

我最初是在同步模式下为 API 18 编写编码器(基于大片示例)。我最近将它切换到 API 21 和异步模式。

它可以很好地录制视频,而且我相信我已经正确设置了所有内容。但是,似乎调用 eglSwapBuffers 会导致帧速率显着下降。

如果我删除所有其他 OpenGL 调用,它会运行得更好,但我渲染的内容并不那么昂贵(它可以每帧多次渲染)。更改编码器设置(即从 640x360 @ 2Mbps 到 1920x1080 @ 16Mbps)几乎没有区别。

唯一让它运行得更快的是删除对 eglSwapBuffers 的调用(它将缓冲区数据发送到编码器)。

我的理解是输出缓冲区不会像以前那样阻塞异步模式下的调用。我错了吗?有没有首选的调用渲染器的方法,或者在单独的线程上异步渲染的方法?

我们将不胜感激任何帮助或从哪里开始的想法,谢谢!

【问题讨论】:

  • 最后的解决方案是什么?

标签: android android-mediacodec


【解决方案1】:

即使在异步模式下,输出缓冲区仍然会阻塞编码器 - 您需要快速处理输出,并在调用异步编码器输出回调后将输出缓冲区返回给编码器,否则您最终会阻塞输入,就像之前。

同步和异步模式的唯一区别是您不需要轮询这些事件,而是获得回调。

【讨论】:

  • 非常感谢!这肯定回答了我的一个问题。在那种情况下,异步编码视频是否有意义?即使我在回调时立即释放缓冲区,并且不对数据做任何其他事情,渲染线程仍然被 eglSwapBuffers 阻塞。回到同步模式并通过释放任何输出缓冲区“耗尽”编码器,我得到了同样的减速。
  • 一般来说,是的,异步模式绝对有意义。例如,考虑一个不使用表面输入模式,而是使用普通缓冲区的编码器。在任何给定点,您都需要等待使用新的空闲输入缓冲区或填充输出缓冲区。如果您以零超时检查它们,您将获得最佳吞吐量,但您基本上最终会忙于循环。如果您等待非零超时,您将避免忙循环,但例如如果您已填满所有输入缓冲区,则在等待输出缓冲区并将其返回之前,您将不会获得任何新的输入缓冲区。
  • 也就是说,在同步模式下,您总是需要权衡等待输入和输出的时间,以平衡吞吐量与繁忙循环。使用异步模式,只需尽可能多地输入输入,并在输出可用时耗尽输出。你看到的可能是 eglSwapBuffers 等待编码器提供一个空闲的输入缓冲区来绘制,即它被 GL 管道和视频编码器能够编码的速度所阻止。交换本身可能不会花费太多时间,但如果没有更多可用的输入缓冲区,则需要等待一个。
  • 好吧,酷。因此,在同步模式下将超时归零没有影响。同步与异步模式没有影响。更改编码器的质量没有影响,更改编解码器类型也没有影响。所以问题是我为硬件渲染太多以有效地运行编码器?我想我唯一能做的就是减少渲染(无论如何对于这个设备)。感谢您提供的所有帮助,您在回答每个人的 MediaCodec 问题方面做得很好!
猜你喜欢
  • 2017-02-21
  • 2018-04-06
  • 2016-07-14
  • 1970-01-01
  • 1970-01-01
  • 2014-01-11
  • 2020-10-28
  • 2016-02-15
相关资源
最近更新 更多