【问题标题】:Z-order issue with MediaCodec and TextureViewMediaCodec 和 TextureView 的 Z 顺序问题
【发布时间】:2014-04-29 10:34:50
【问题描述】:

在我的 Android 应用中,我需要使用以下 Z 顺序渲染三个视图:

  1. 在底部,覆盖整个屏幕的MediaCodec 解码器的输出表面。我的要求是我必须转换MediaCodec 生成的图像(例如缩放它)
  2. 在中间,GLSurfaceView(或我定义的其他运行 GL 着色器的表面/视图),覆盖整个屏幕。显然,这一层中的一些像素将是透明的,以便看到下方的MediaCodec 输出。
  3. 在顶部,任何其他视图 - 比如说ImageView。不确定我是否需要这些最顶层视图的透明度,也许完全不透明的矩形视图是可以的 - 它们不会覆盖整个屏幕并且会四处移动。

看起来这是不可能的,但也许我遗漏了一些东西,或者有一种方法可以在较低级别上付出更多的努力(例如 EGL 上下文或类似的东西......我目前不明白) .

我无法让它工作并担心这是不可能的原因是:

  • 对于底部MediaCodec 输出层(1),我必须能够转换图像。所以,我给 MediaCodec 渲染的表面必须来自 TextureView
  • 为了能看穿中间的透明像素GLSurfaceView(2),我不得不调用GLSurfaceView.setZOrderOnTop(true)。否则 GLSurfaceView 是不透明的。
  • 但调用GLSurfaceView.setZOrderOnTop(true) 意味着在GLSurfaceView 之上没有呈现其他视图(3)。例如。 ImageView 将始终出现在 GLSurfaceView 的不透明像素后面。

看起来调用 GLSurfaceView.setZOrderMediaOverlay(true) 而不是 GLSurfaceView.setZOrderOnTop(true) 旨在解决这个问题并促进这种类型的 Z 排序。如果最底部的MediaCodec 输出层是SurfaceView,它也会这样做。但我需要它是TextureView,这样我才能对其进行改造。当TextureView 下方有TextureView 时,GLSurfaceView.setZOrderMediaOverlay(true) 似乎不起作用:TextureView 被中间的GLSurfaceView 层完全遮挡,而不是透过透明像素显示。

这种 Z 排序是不可能的,对吗?还是可以通过搞乱 EGL 和上下文等来完成?

【问题讨论】:

    标签: android surfaceview android-mediacodec textureview


    【解决方案1】:

    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的surface层在后面,app UI层在上面,系统状态+导航条在上面。

    应用视图层次结构中的所有内容都呈现在单个层上。这包括TextureView。您无法控制其相对于其他硬件合成层的 Z 顺序。

    SurfaceView的奇特之处在于 View 部分只是一个透明的占位符,而真正的动作发生在单独的层上,您可以控制其 Z 顺序(一点点)。你可以把它分为三个不同的层次:

    • “媒体”(默认)
    • “媒体覆盖”
    • (应用界面在这里)
    • “面板”(ZOrderOnTop)

    因此,您要做的就是将您的MediaCodec 输出放在默认层,并将您的 GLES 输出放在“媒体覆盖”层。您需要使用SurfaceView 完成这两项操作。

    很难从这里提供更好的建议,因为您描述了您尝试解决方案时遇到的问题,而不是您尝试解决的问题(即您正在构建什么?),但我可以提供几个建议。

    首先,您可以缩放 SurfaceView。如果您查看上面的 dumpsys 输出,您会注意到“SurfaceView”行的源裁剪矩形为 320x240(视频大小),目标矩形为 984x738。这来自Grafika's“播放视频(SurfaceView)”,它调整了 SurfaceView 的大小以保持视频的 4:3 纵横比。 SurfaceFlinger 负责缩放内容以匹配视图。

    其次,如果您不显示受 DRM 保护的视频内容,您可以将其发送到 SurfaceTexture,然后在渲染其他所有内容时使用 GLES 进行渲染。 (这正是TextureView 所做的,这就是它需要硬件加速的原因。)参见例如Grafika 中的“连续捕获”。

    更新:可以在Android System-Level Graphics doc 中找到更长的描述。

    【讨论】:

    • SurfaceView里面有一个api setZOrderOnTop,但是TexutureView里面没有这个api,如果我用textureView又想做setZOrderOnTop做的事情,怎么做?现在我受了很多苦。 SurfaceHolder中有一个api setFormat。如果我使用 TextureView 怎么做 setFormat 做的事情?
    • @dragonfly:TextureView 中的任何一个都不需要。 TextureView 输出被写入 View UI 层,就像任何其他 UI 小部件一样。您可以使用布局调用或 XML 定位 Z 顺序。颜色格式是 View UI 的颜色格式,在现代设备上将是 RGBA8888。
    猜你喜欢
    • 2016-12-14
    • 1970-01-01
    • 1970-01-01
    • 2011-01-18
    • 2012-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多