我正在开发一个WebGL应用程序,它使用HLS.js从HTML5视频中获取纹理流。它在桌面上运行良好,它适用于移动Android上的1920 * 1080视频,但不适用于3840 * 2160.
我已经在几款高端设备(Xperia X Performance,三星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:为3840x2160设置nativeWindow 0xc9ef2008,颜色为0x7fa30c04,旋转0,用法0x20002900
chromium:[INFO:CONSOLE(11818)]“WebGL:INVALID_VALUE:texImage2D: 宽度或高度超出范围“
从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纹理无法渲染?
TL; DR
<video>
标记谢谢!
答案 0 :(得分:0)
经过一周的努力来理解这个问题后,现在很清楚错误就在我们的最后。
该视频确实创建为3840 x 2160,但是是从分辨率为3840 x 4320的源视频创建的。当将视频转换为3840 x 2160时,ffmpeg将宽高比设置为(3840/4320),领先的Android将视频扩展回那个尺寸。膨胀尺寸的高度> 4096,这就是无法创建纹理的原因。
我们在其他平台(本机应用)上没有看到此问题,因此可能是Android媒体播放器的一些怪癖。
我们已经通过手动将(3840/2160)的“正确”宽高比设置为ffmpeg参数来解决问题。
我学到了什么:
不要认为VLC或QuickTime等应用程序报告的分辨率将正确反映每个其他平台上会发生的情况。在实现检查HTML视频元素分辨率所需的代码之后,很明显Android上与其他平台相比发生了不同的事情。