简体   繁体   English

HTML5视频在Android Chrome上陷入canvas2D问题

[英]HTML5 video draw into canvas2D issue on Android Chrome

I am developing VR html5 page in javascript (no jQuery or other frameworks) that uses WebGL to render a sphere and has texture to which streamed video is rendered into. 我正在使用JavaScript(无jQuery或其他框架)开发使用JavaScript的VR html5页面,该页面使用WebGL渲染球体,并具有将流视频渲染到的纹理。

All that works fine on iPhone 6, 6+, however on Android I've hit the wall - simply, video is not being transferred into texture (gl.texSubImage2D). 所有这些在iPhone 6、6+上都可以正常工作,但是在Android上我遇到了麻烦-简而言之,视频没有被转换为纹理(gl.texSubImage2D)。 Texture remains black. 纹理保持黑色。 No WebGL errors thrown. 没有引发WebGL错误。

So I have created a test, without WebGL, that just tries to play a video and draw it's frames into canvas2D, so I can at least verify that frames are indeed extracted from streamed video. 因此,我创建了一个没有WebGL的测试,该测试只是尝试播放视频并将其帧绘制到canvas2D中,因此我至少可以验证是否确实从流视频中提取了帧。

Video is played on user interaction (touch) and when canplay event is triggered, I start frame loop (window.requestAnimationFrame) to draw video into canvas (canvas.drawImage( video, 0,0 )) 在用户交互(触摸)上播放视频,并且触发canplay事件时,我开始帧循环(window.requestAnimationFrame)将视频绘制到画布中(canvas.drawImage(video,0,0))

Both video and canvas are on the document body visible, next to each other. 视频和画布在文档主体上都可见,彼此相邻。

Result: On desktop it works as expected, two screens, left is video with native controls, right is canvas. 结果:在桌面上它按预期方式工作,有两个屏幕,左边是带有本机控件的视频,右边是画布。 When I click play, video starts, and canvas gets refreshed at the same time. 当我单击播放时,视频开始播放,并且画布同时刷新。 On Android Chrome 48.0.2564.106 no pixels drawn - canvas is totally empty. 在Android Chrome 48.0.2564.106上,未绘制像素-画布完全为空。

I have installed Android Chrome Beta (50.0.2661.57) and it works there, but on Android Chrome 48.0.2564.106 it does not. 我已经安装了Android Chrome Beta(50.0.2661.57),并且可以在其中运行,但在Android Chrome 48.0.2564.106上却无法运行。

Codes to setup video and 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>

Can anyone confirm if canvas.drawImage on Chrome 48 and older cannot accept video as drawing source? 任何人都可以确认Chrome 48及更高版本上的canvas.drawImage是否不能接受视频作为绘图源吗? This looks impossible to me considering WebGL has been in Chrome's support for ages and with plenty of experiments with video textures out there. 考虑到WebGL一直以来都是Chrome的支持者,并且对视频纹理进行了大量的实验,这对我来说似乎是不可能的。

I have tried other samples that copy video into WebGL texture or Canvas2D and they do not work as well. 我尝试了将视频复制到WebGL纹理或Canvas2D中的其他示例,但它们无法正常工作。

Is there anything I am missing here? 我在这里想念什么吗?

After thorough research it appears that: 经过深入研究,看来:

  1. Canvas2D.drawImage( video, 0,0 ) was broken since July 2015 (at least as I found bug reports that date from then) in Android Chrome and was kinda fixed-not-fixed-fixed-again-and-again-not-fixed - but I can confirm that it is fixed in Android Chrome 49 and in Android Chrome 50 (Beta). 自2015年7月以来,Canvas2D.drawImage(video,0,0)在Android Chrome中已损坏(至少因为我发现从那时起的错误报告),并且有点像是“固定”,“不固定”,“又是又不是”已修复-但我可以确认该问题已在Android Chrome 49和Android Chrome 50(测试版)中修复。 Same issue with decoding pixels from video to be drawn into Canvas2D has affected drawing video into WebGL texture. 从视频中解码像素以将其绘制到Canvas2D中的相同问题也影响了将视频绘制为WebGL纹理。

  2. The only workaround is to have either: a) custom-made video streaming server using Websocket + JPG sequence streamer in JavaScript (images received through opened websocket connection) or b) JPG sequence streamer in JavaScript (downloads images one by one and takes care of loading new - deleting old). 唯一的解决方法是:a)使用JavaScript中的Websocket + JPG序列流媒体(通过打开的websocket连接接收的图像)的定制视频流服务器,或b)JavaScript中的JPG序列流媒体(逐个下载图像并进行维护)正在加载新-删除旧)。

I went with option 2.b and with CDN kicked in it really works great for 1024x512 video size, which was good enough solution. 我选择了选项2.b,并插入了CDN,它对于1024x512视频尺寸确实非常有效,这是足够好的解决方案。

I would first preload mp3 file using http request, then load it into Audio object. 我将首先使用http请求预加载mp3文件,然后将其加载到Audio对象中。 Once that's done, JPG streamer would kick in and would then commence playback using sound currentTime value. 完成此操作后,JPG流将启动,然后将使用声音currentTime值开始播放。 It was 100% synchronised with sound! 它与声音100%同步!

However, issue is fixed in Chrome 49, and Chrome 50 (beta), so this likely will be obsolete in 2-3 months. 但是,Chrome 49和Chrome 50(测试版)中的问题已修复,因此这可能会在2-3个月内被淘汰。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM