Android上的WebGL视频纹理大小限制 - 如何使用3840 * 2160?

3

我正在开发一个WebGL应用程序,从HTML5视频流中获取纹理,使用HLS.js。在桌面上运行良好,并且在移动Android上的1920 * 1080视频上也能正常工作,但无法处理3840 * 2160的视频。

我已经在一些高端设备(Xperia X Performance、Samsung Galaxy S8)上测试了该应用程序,但这两种设备都无法播放4K视频。

我知道这些设备可以播放视频,因为我还有一个调试模式,在该模式下,视频元素附加到DOM上,视频渲染完美。

我还在这些设备上使用了http://webglreport.com/,该页面显示我应该能够使用4096 * 4096的纹理。

我还手动使用JavaScript ArrayBuffer生成了一个3840 * 2160的纹理,而且该纹理被正确渲染了。

以下是我复制视频的方法

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, this.videoElement);

当在Chrome Android上执行大小为3840 * 2160的视频调用时,我会得到以下日志打印:
SurfaceUtils: set up nativeWindow 0xc9ef2008 for 3840x2160, color 0x7fa30c04, rotation 0, usage 0x20002900 chromium: [INFO:CONSOLE(11818)] "WebGL: INVALID_VALUE: texImage2D: width or height out of range"
这对应于gl.getError()的错误代码:
GL_INVALID_VALUE,0x0501
这些是我用于支持纹理的参数。
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

以下是我生成和上传测试纹理的方法

const width = 3840;
const height = 2160;

const generateTex = (w: number, h: number): number[] => {
    const res = [];
    for (let i = 0; i < w * h; i++) {
        res.push(0, 255, 0);
    }
    return res;
};

const image = new Uint8Array(generateTex(width, height));
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, width, height, 0, gl.RGB, gl.UNSIGNED_BYTE, image);

texImage2D的文档表示:

源类型为HTMLVideoElement

纹理的宽度和高度设置为上传的视频帧的宽度和高度(以像素为单位)。

问题是:是否有规范可以解释为什么我的3840 * 2160纹理无法被渲染?

简而言之:

  • 更高端的设备(Xperia X Performance,Galaxy S8)
  • Android Chrome
  • 我可以上传大小为3840 * 2160的自定义纹理并进行渲染
  • 我可以使用 <video> 标签解码和播放大小为3840 * 2160的视频
  • 我无法将3840 * 2160视频的帧上传到WebGL中
  • 低分辨率可以正常工作

谢谢!

1个回答

2
经过一周的努力研究问题,现在清楚地看到错误出在我们这边。
视频确实是以3840 x 2160的分辨率创建的,但是是从一个3840 x 4320的源视频创建的。在将视频转换为3840 x 2160时,ffmpeg将宽高比设置为(3840/4320),导致Android将视频放大回到那个尺寸。放大后的大小高度>4096,这就是纹理无法被创建的原因。
我们在其他平台(本地应用程序)上没有看到这个问题,所以可能是Android媒体播放器的某种怪癖。
我们通过手动设置"正确"的宽高比(3840/2160)作为ffmpeg参数来解决了这个问题。
我学到的东西:
不要假定像VLC或QuickTime这样的应用程序报告的分辨率会正确反映在每个其他平台上所发生的情况。在实施检查HTML视频元素分辨率所需的代码后,很明显在Android上与其他平台发生了不同的事情。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接