【问题标题】:What is the best way to draw YUV data to Surface in Android?在 Android 中将 YUV 数据绘制到 Surface 的最佳方法是什么?
【发布时间】:2019-11-14 11:13:32
【问题描述】:

我需要以特定方式播放视频。这就是为什么我需要“预解码”一些帧并将其保留并稍后显示。我使用 MediaCodec 来解码视频帧。输出缓冲区是 YUV(420) 格式,问题是,稍后在屏幕上显示它们的最佳方式是什么?

  1. 是复制编解码器的输出更好。GetOutputBuffer() 还是保留代码。GetOutputImage()?
  2. 是否有一种硬件加速方式可以将 YUV 转换为 RGB 以作为 Java 函数使用?
  3. 如何有效地将数据绘制到表面?
  4. 是否有必要进行转换?使用较新 (>=8.0) 的 Android 版本是否可以直接将 YUV 数据(以 ByteBuffer 或 Image 等任何形式)绘制到 Surface?
  5. 不能指示 mp4 编解码器生成 RGB 输出而不是 YUV,对吧?

我浏览了许多类似(或相同)的问题,但大多数都是旧的,我只是看到了一些手动 YUV 到 RGB 的转换,这对我来说似乎太慢了。我希望使用较新的 Android 版本时情况会好一些;)

感谢您的任何想法。

【问题讨论】:

  • 使用 opengl 将其绘制到表面怎么样?我之前在之前的项目中做过类似的事情,我将视频解码为表面,将其转换为 yuv 并将其缓存在 opengl 纹理中,并在将其显示到屏幕时重新转换回 rgb。所有这些都可以使用片段着色器完成。
  • 我没有使用opengl的经验,但这听起来是个好主意!有没有这种解决方案的例子?我是否理解可以通过硬件(着色器)以某种方式完成色彩空间转换?

标签: android yuv hardware-acceleration


【解决方案1】:

从 rgb 转换为 yuv 并将其转换回 rgb 的着色器示例。 为了简单起见,我将 2 个相邻的 rgba 像素转换为 yuv 并将其保存为(y1y2uv)格式的 1 个像素。这不是一个有效的例子,但我希望它可以让你进入正确的方向。

// From rgb to yuv
companion object {
    val FRAGMENT_SHADER = "" +
        "precision highp float;\n" +
        "varying vec2 textureCoordinate;\n" +
        " \n" +
        "uniform sampler2D inputImageTexture;\n" +
        "uniform float step;\n" +
        "const vec3 multiplier = vec3(0.299, 0.587, 0.114);\n" +
        " \n" +
        "void main()\n" +
        "{\n" +
        "     vec4 first= texture2D(inputImageTexture, textureCoordinate);\n" +
        "     float y1 = clamp(dot(multiplier, first.rgb), 0.0, 1.0);\n" +
        "     vec2 secondCoord = textureCoordinate;\n" +
        "     secondCoord.x = secondCoord.x + step;\n" +
        "     vec4 second= texture2D(inputImageTexture, secondCoord);\n" +
        "     float y2 = clamp(dot(multiplier, second.rgb), 0.0, 1.0);\n" +
        "     vec3 rgbAve = mix(first.rgb, second.rgb, 0.5);\n" +
        "     float yAve = 0.5 * (y1 + y2);\n" +
        "     float u = clamp((rgbAve.b - yAve) * 0.565 + 0.5, 0.0, 1.0);\n" +
        "     float v = clamp((rgbAve.r - yAve) * 0.713 + 0.5, 0.0, 1.0);\n" +
        "     gl_FragColor.r = y1;\n" +
        "     gl_FragColor.g = y2;\n" +
        "     gl_FragColor.b = u;\n" +
        "     gl_FragColor.a = v;\n" +
        "}"
}

// From yuv to rgb
companion object {
    val FRAGMENT_SHADER = "" +
        "precision highp float;\n" +
        "varying vec2 textureCoordinate;\n" +
        " \n" +
        "uniform sampler2D inputImageTexture;\n" +
        "uniform float step;\n" +
        " \n" +
        "void main()\n" +
        "{\n" +
        "     vec2 secondCoord = textureCoordinate;\n" +
        "     float correction = secondCoord.x - 2.0 * step * floor(secondCoord.x / (2.0 * step));\n" +
        "     correction = clamp((correction - (step/2.0))/ (step/2.0), 0.0, 1.0);\n" +
        "     secondCoord.x = secondCoord.x - (correction * step);\n" +
        "     vec4 yuv = texture2D(inputImageTexture, secondCoord);\n" +
        "     yuv.r = (1.0 - correction) * yuv.r + correction * yuv.g;\n" +
        "     yuv.g = yuv.b - 0.5;\n" +
        "     yuv.b = yuv.a - 0.5;\n" +
        "     gl_FragColor.r = clamp(yuv.r + 1.403 * yuv.b, 0.0, 1.0);\n" +
        "     gl_FragColor.g = clamp(yuv.r - 0.344 * yuv.g - 0.714 * yuv.b, 0.0, 1.0);\n" +
        "     gl_FragColor.b = clamp(yuv.r + 1.770 * yuv.g, 0.0, 1.0);\n" +
        "     gl_FragColor.a = 1.0;\n" +
        "}"
}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多