在我的Android应用中,我需要使用以下Z顺序渲染三个视图:
MediaCodec
解码器的输出表面。我要求我必须转换MediaCodec
生成的图像(例如缩放它)GLSurfaceView
(或我运行的GL着色器的其他曲面/视图)覆盖整个屏幕。显然,此图层中的某些像素将是透明的,以便查看下方的MediaCodec
输出。ImageView
。我不确定这些最顶层的视图是否需要透明度,也许是完全不透明的矩形视图可以 - 它们只是不会覆盖整个屏幕并且会移动。看起来这是不可能的,但也许我错过了一些东西,或者有一种方法可以在较低的水平上做更多的努力(例如EGL上下文或类似的东西......我目前不明白。)
我无法让这个工作起来并且担心这是不可能的原因是:
MediaCodec
输出图层(1),我必须能够转换图像。因此,我给MediaCodec渲染的表面必须来自TextureView
GLSurfaceView
(2)的透明像素,我必须调用GLSurfaceView.setZOrderOnTop(true)
。否则GLSurfaceView是不透明的。GLSurfaceView.setZOrderOnTop(true)
意味着没有其他视图(3)呈现在GLSurfaceView
之上。例如。 ImageView
始终显示在GLSurfaceView
的不透明像素后面。看起来调用GLSurfaceView.setZOrderMediaOverlay(true)
而不是GLSurfaceView.setZOrderOnTop(true)
是为了解决这个问题并促进这种类型的Z排序。如果最底部的MediaCodec
输出图层是SurfaceView
,则会发生这种情况。但我需要它是TextureView
所以我可以改变它。如果GLSurfaceView.setZOrderMediaOverlay(true)
位于其下方TextureView
,则TextureView
似乎无效:GLSurfaceView
完全被中间{{1}}图层遮挡,而不是通过透明显示像素。
这种Z排序是不可能的吗?或者可以通过搞乱EGL和上下文等来完成它?
答案 0 :(得分:2)
EGL上下文在这里并不重要。你的斗争是使用SurfaceFlinger和视图系统。
如果您运行adb shell dumpsys SurfaceFlinger
,您可以看到系统合成器知道的所有图层的完整列表。如果您在SurfaceView
中播放320x240视频,它看起来像这样(为了简洁起见,删除了几列和其他许多内容):
type | source crop | frame name
------------+-----------------------------------+--------------------------------
HWC | [ 0.0, 0.0, 320.0, 240.0] | [ 48, 411, 1032, 1149] SurfaceView
HWC | [ 0.0, 75.0, 1080.0, 1776.0] | [ 0, 75, 1080, 1776] com.android.grafika/com.android.grafika.PlayMovieSurfaceActivity
HWC | [ 0.0, 0.0, 1080.0, 75.0] | [ 0, 0, 1080, 75] StatusBar
HWC | [ 0.0, 0.0, 1080.0, 144.0] | [ 0, 1776, 1080, 1920] NavigationBar
FB TARGET | [ 0.0, 0.0, 1080.0, 1920.0] | [ 0, 0, 1080, 1920] HWC_FRAMEBUFFER_TARGET
这些层从后到前呈Z顺序。 SurfaceView的表面层位于后面,app UI层位于其后面,系统状态+导航栏位于所有位置之上。
应用程序视图层次结构中的所有内容都在单个图层上呈现。这包括TextureView
。您无法控制其相对于其他硬件合成图层的Z顺序。
SurfaceView
很有意思,因为View部分只是一个透明的占位符,而真正的动作发生在那个单独的层上,你可以控制它的Z顺序(一点点)。你可以将它放在三个不同的层面上:
所以你要做的就是将你的MediaCodec
输出放在默认图层,将你的GLES输出放在"媒体覆盖"层。您需要使用SurfaceView
。
很难从这里提供更好的建议,因为您描述了您尝试使用解决方案时遇到的问题,而不是您尝试解决的问题(即您正在构建什么? ),但我可以提出一些建议。
首先,可以缩放SurfaceView。如果你看一下上面的dumpsys输出,你会注意到" SurfaceView" line的源裁剪矩形为320x240(视频大小),目标矩形为984x738。这来自Grafika's"播放视频(SurfaceView)",它调整SurfaceView的大小以保持视频的4:3宽高比。 SurfaceFlinger负责缩放内容以匹配视图。
其次,如果您没有显示受DRM保护的视频内容,您可以将其发送到SurfaceTexture
,并在您渲染其他内容时使用GLES进行渲染。 (这正是TextureView
所做的,这就是它需要硬件加速的原因。)参见例如"持续捕获"在格拉菲卡。
更新:Android System-Level Graphics doc可以找到更长的说明。