HTML5 Android Chrome 上的视频绘制成 canvas2D 问题

HTML5 video draw into canvas2D issue on Android Chrome

我正在 javascript(没有 jQuery 或其他框架)中开发 VR html5 页面,该页面使用 WebGL 渲染球体并具有流视频渲染到的纹理。

在 iPhone 6、6+ 上一切正常,但是在 Android 上我遇到了困难 - 简单地说,视频没有被传输到纹理 (gl.texSubImage2D)。纹理保持黑色。没有抛出 WebGL 错误。

所以我创建了一个没有 WebGL 的测试,它只是尝试播放视频并将其帧绘制成 canvas2D,因此我至少可以验证帧确实是从流视频中提取的。

视频在用户交互(触摸)时播放,当 canplay 事件被触发时,我开始帧循环(window.requestAnimationFrame)将视频绘制到 canvas (canvas.drawImage( 视频,​​ 0,0 ))

视频和 canvas 在文档正文中可见,彼此相邻。

结果:在桌面上它按预期工作,两个屏幕,左边是带有本机控件的视频,右边是 canvas。当我点击播放时,视频开始播放,canvas 同时刷新。在 Android Chrome 48.0.2564.106 上没有绘制像素 - canvas 完全是空的。

我已经安装了 Android Chrome Beta (50.0.2661.57) 并且它在那里工作,但是在 Android Chrome 48.0.2564.106 上它不工作。

设置视频的代码和canvas:

<!doctype html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="format-detection" content="telephone-no" />
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Video Canvas Test</title>
    <script>

    var video;
    var canvas;
    var ctx;
    var info;
    var pass = 0;

    window.onload = function()
    {
        video = document.createElement("video");
        video.oncanplay = function(){ initializeCanvas(); }
        video.onerror = function(e){ console.error("video problem"); }
        video.loop = true;
        video.controls = "true";
        video.src = "video/big-buck-bunny_trailer.webm";
        video.style.width = "400px";
        video.style.height = "300px";
        video.style.position = "absolute";
        video.style.left = "20px";
        video.style.top = "20px";
        video.style.backgroundColor = "#8080FF";

        canvas = document.createElement("canvas");
        canvas.style.backgroundColor = "#8080FF";
        canvas.style.width = "400px";
        canvas.style.height = "300px";
        canvas.style.position = "absolute";
        canvas.style.left = "420px";
        canvas.style.top = "20px";

        ctx = canvas.getContext("2d");

        info = document.createElement("p");
        info.innerHTML = window.navigator.userAgent;
        info.style.position = "absolute";
        info.style.width = "200px";
        info.style.height = "auto";
        info.style.position = "absolute";
        info.style.left = "20px";
        info.style.top = "320px";

        document.body.appendChild(video);
        document.body.appendChild(canvas);
        document.body.appendChild(info);
    }

    function initializeCanvas()
    {
        console.log("Video ready to play. Init canvas.");
        ctx.canvas.width = 640; // I am 100% sure this is correct video size.
        ctx.canvas.height = 360;
        console.log("Video size: " + video.videoWidth + "x" + video.videoHeight);
        ctx.font = "30px Arial";
        updateCanvas();
    }

    function updateCanvas()
    {
        pass ++;

        ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
        ctx.drawImage(video,0,0);
        ctx.fillText("Pass: " + pass,30,120);

        window.requestAnimationFrame( updateCanvas );
    }
    </script>
</head>
<body>
</body>
</html>

谁能确认canvas.drawImage Chrome 48 岁及以上是否不能接受视频作为绘图源?考虑到 WebGL 已经支持 Chrome 多年,并且有大量的视频纹理实验,这对我来说似乎是不可能的。

我已经尝试过将视频复制到 WebGL 纹理或 Canvas2D 中的其他示例,但效果不佳。

这里有什么我遗漏的吗?

经过深入研究后发现:

  1. Canvas2D.drawImage( video, 0,0 ) 自 2015 年 7 月起在 Android [=33= 中被破坏(至少我发现了那个日期的错误报告) ] 并且有点固定-不固定-固定-再次固定-但我可以确认它在 Android Chrome 49 和 Android Chrome 50(测试版)。将视频中的解码像素绘制到 Canvas2D 中的相同问题影响了将视频绘制到 WebGL 纹理中。

  2. 唯一的解决方法是:a) 在 JavaScript 中使用 Websocket + JPG sequence streamer 的定制视频流服务器(通过打开的 websocket 连接接收的图像)或 b) JPG JavaScript 中的序列流媒体(一张一张地下载图像并负责加载新的 - 删除旧的)。

我选择了 2.b 选项,并启用了 CDN,它非常适合 1024x512 视频大小,这是一个足够好的解决方案。

我会先使用 http 请求预加载 mp3 文件,然后将其加载到 Audio 对象中。完成后,JPG 流媒体将启动,然后使用声音 currentTime 值开始播放。与声音100%同步!

但是,问题已在 Chrome 49 和 Chrome 50(测试版)中修复,因此这可能会在 2-3 个月内过时。