是否可以从android中的另一个线程获取GLSurfaceView的屏幕截图?

时间:2016-03-21 14:21:22

标签: android opengl-es-2.0 glsurfaceview

我试图从我的渲染器的onDrawFrame函数捕获我的android应用程序的屏幕截图。但它正在放弃框架并冻结应用程序,直到过程完成。我试图在不同的线程上做但没有成功。是否可以在不同的线程上拍摄屏幕。

2 个答案:

答案 0 :(得分:1)

您无法从另一个线程执行glReadPixels(),因为EGL上下文一次只能在一个线程中是最新的,并且您无法使用GLSurfaceView控制它。

然而,从GLES获取屏幕截图花费的95%以上用于PNG / JPEG压缩和磁盘I / O.因此,如果您从glReadPixels()进行onDrawFrame()调用,然后将数据移至新线程,则应该能够在后台处理屏幕截图时继续运行。

答案 1 :(得分:1)

如前所述,从另一个线程可能无法直接读取,但还有其他方法。

不是将场景直接绘制到曲面视图,而是将其绘制到带有附加纹理的帧缓冲对象(FBO),然后将纹理重绘到主缓冲区。这是一个非常标准的后处理程序,并且没有很高的性能影响。要实现这一点,您实际上只需要研究如何创建FBO,在绘图开始之前将其绑定,其余代码应保持原样。然后还添加代码以通过绑定主缓冲区重绘屏幕上的FBO纹理(索引0应该这样做)。

对于单独线程上的屏幕截图,您现在需要创建一个新线程和在该线程上设置的新上下文。必须与主要上下文共享新上下文(我相信有一个接受主要上下文的构造函数),因此您可以共享纹理。现在有趣的部分:当您想要截取屏幕时需要创建一个新纹理,将新纹理附加到FBO,分离旧纹理。通过这样做,你可以窃取内容被绘制的纹理,你可以用你想要的任何线程做你想做的任何事情。所以把它放到你的辅助线程中,在那个上下文中,你可以创建另一个FBO,绑定它并从该线程读取它的像素。不要忘记清理。

但建议谨慎行事。制作相对少量的屏幕截图时,这种程序可能会很好。如果一个屏幕截图在另一个屏幕截图开始之前没有完全完成,那么你的内存使用量会膨胀,你的应用很可能会崩溃。因此,请注意不要这样做,创建某种锁定机制或限制正在进行的屏幕截图处理的数量。这不仅仅适用于openGL,只需编码图像数据就可能出现同样的问题。

只是关于你原始想法的一个注释:即使你可以在一个单独的线程上使用表面视图并从其主缓冲区读取像素,你可能不会期望你会得到一个好的结果。在您阅读时可以绘制缓冲区,这样您就可以从不同的帧中获取数据块。这仍然只是在理论上,因为事实是缓冲区只是被锁定而你的应用程序在尝试访问它时会崩溃。所以这绝不可能,即使结果是不可预测的。