WebGL 视频纹理大小限制 android - 如何使用 3840 * 2160?
WebGL video texture size limits on android - how to use 3840 * 2160?
我正在开发一个 WebGL 应用程序,它使用 HLS.js 从 HTML5 视频中获取纹理流。它在桌面上运行良好,在移动设备上运行 1920 * 1080 视频 Android,但不适用于 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
的文档说
source of type HTMLVideoElement
The width and height of the texture
are set to the width and height of the uploaded frame of the video in
pixels.
问题是:是否有规范可以解释为什么我的 3840 * 2160 纹理没有被渲染?
TL;DR
- 高端设备(Xperia X Performance、Galaxy S8)
- Android Chrome
- 我可以上传尺寸为 3840 * 2160 的自定义纹理并进行渲染
- 我可以使用
<video>
标签解码和播放大小为 3840 * 2160 的视频
- 我无法将 3840 * 2160 视频的帧上传到 WebGL
- 较低的分辨率效果很好
谢谢!
经过一周的努力来了解问题,现在很清楚错误出在我们这边。
该视频确实创建为 3840 x 2160,但它是根据分辨率为 3840 x 4320 的源视频创建的。将视频转换为 3840 x 2160 时,ffmpeg 将纵横比设置为 (3840/4320 ),导致 Android 将视频膨胀回该大小。膨胀尺寸的高度 > 4096,这就是无法创建纹理的原因。
我们没有在其他平台(本机应用程序)上看到这个问题,所以这可能是 Android 媒体播放器的一些怪癖。
我们已通过手动将 (3840/2160) 的 "correct" 宽高比设置为 ffmpeg 参数来解决我们这边的问题。
我学到了什么:
不要假设 VLC 或 QuickTime 等应用程序报告的分辨率将正确反映在所有其他平台上发生的情况。在实施检查 HTML 视频元素分辨率所需的代码后,很明显 Android 与其他平台相比发生了一些不同的事情。
我正在开发一个 WebGL 应用程序,它使用 HLS.js 从 HTML5 视频中获取纹理流。它在桌面上运行良好,在移动设备上运行 1920 * 1080 视频 Android,但不适用于 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
的文档说
source of type HTMLVideoElement
The width and height of the texture are set to the width and height of the uploaded frame of the video in pixels.
问题是:是否有规范可以解释为什么我的 3840 * 2160 纹理没有被渲染?
TL;DR
- 高端设备(Xperia X Performance、Galaxy S8)
- Android Chrome
- 我可以上传尺寸为 3840 * 2160 的自定义纹理并进行渲染
- 我可以使用
<video>
标签解码和播放大小为 3840 * 2160 的视频 - 我无法将 3840 * 2160 视频的帧上传到 WebGL
- 较低的分辨率效果很好
谢谢!
经过一周的努力来了解问题,现在很清楚错误出在我们这边。
该视频确实创建为 3840 x 2160,但它是根据分辨率为 3840 x 4320 的源视频创建的。将视频转换为 3840 x 2160 时,ffmpeg 将纵横比设置为 (3840/4320 ),导致 Android 将视频膨胀回该大小。膨胀尺寸的高度 > 4096,这就是无法创建纹理的原因。
我们没有在其他平台(本机应用程序)上看到这个问题,所以这可能是 Android 媒体播放器的一些怪癖。
我们已通过手动将 (3840/2160) 的 "correct" 宽高比设置为 ffmpeg 参数来解决我们这边的问题。
我学到了什么:
不要假设 VLC 或 QuickTime 等应用程序报告的分辨率将正确反映在所有其他平台上发生的情况。在实施检查 HTML 视频元素分辨率所需的代码后,很明显 Android 与其他平台相比发生了一些不同的事情。