我需要使用HTML5在移动设备上播放具有透明背景的视频。在Windows Phone上,我可以捕获视频标签的当前帧并在画布中显示。但这不适用于Android和iOS设备(我认为出于安全原因?)
我的解决方案是使用FFMPEG分割.flv,然后将这些帧拼接成大图像,如精灵表。
问题是当我切换到新的相框时动画'挂起'。我只是通过视觉和控制台检查了这一点(当我更改当前的精灵表行时通过记录。)我通过查看当我更改精灵表时它是如何挂起来测试它,以及当我更改它时它是如何挂起的只是一遍又一遍地循环同一张纸。
我预先加载了所有图片:
var frameImages = [];
for(var i = 0; i < 35; i++)
{
frameImages.push(new Image());
frameImages[i].src = 'frame' + i + '.png';
console.log(frameImages[i].src);
frameImages[i].onload = function()
{
// Notify us that it's been loaded.
console.log("Image loaded");
}
}
然后像这样玩:
processFrame = function()
{
outputCanvas.width = outputCanvas.width;
output.drawImage(frameImages[currentFrame], (curCol*153), (curRow*448), 153, 448, 0, 0, 153, 448);
curCol += 1;
if(curCol >= maxCol)
{
curCol = 0;
curRow += 1;
if(curRow >= maxRow)
{
curRow = 0;
currentFrame++;
}
}
}
}
var mozstart = window.mozAnimationStartTime;
step = function(timestamp) {
var diff = (new Date().getTime() - start) - time;
if(diff >= frameDelay)
{
processFrame();
time += frameDelay;
}
}
我在使用Win 7计算机的Chrome v 23.0.1271.97 m和使用Chrome的Nexus 7上尝试过此操作。
在此见到它:
http://savedbythecode.com/spokes/mozanimation.php - 这是使用mozAnimationStartTime
和http://savedbythecode.com/spokes/newplayer.php - 这是使用每个步骤调整的常规JS计时器(来自http://www.sitepoint.com/creating-accurate-timers-in-javascript/)
有什么想法吗?问题是否足够明确?
谢谢, 凯文
答案 0 :(得分:2)
酷代码。为什么你不能只使用视频标签(参见选项6)?无论如何,我只会列出我能想到的问题并希望它能帮到你:
将++
更改为+= 1
:与您之前的代码保持一致,并且因为channeling Doug Crockford's benevolent ghost可能有助于消除您的JavaScript代码中的故障。
将一堆图像拼接成一张“精灵表”。当您想要下一张表时,代码会挂起。因此,因为您的代码还没有工作,作为测试,删除循环遍历每个帧中的子图像的所有循环,并直接将每个渲染中的frameImages数组中的每个帧输出到画布以查看它是否仍然挂起。结果将告诉您代码是否可以到达frameImages中的下一帧,或者它是否可以。这可能会使您更接近错误的来源。
currentFrame是用var声明的,并且在processFrame的范围内?如果没有,就放
var currentFrame = 0;
位于您定义function processFrame(...
当你说“然后我像这样播放”你是否使用了promise或在所有onloads被触发后等效地调用你的动画启动功能? 执行此操作的方法是:您可以使用每个启动的onload递增计数器一次,并且每次检查计数器是否等于所需的负载总数,然后再调用动画启动。 我的预感是这是一个缓存问题,因为由于内部不同,这些似乎是不同浏览器之间变化最大的。
尝试在drawImage调用和更新currentFrame之间清除画布,因为在更改图像时,它可能有助于重置画布的内部状态。
您可以使用HTML5视频代码执行Alpha和透明度。只需使用一些svg转换。这些很容易实现,如this SO answer
答案 1 :(得分:2)
这是另一种不那么正统的解决方案 - 使用视频作为画布输入,并使用getImageData在每个帧中绿屏。
基本上你已经有了视频标签和画布
<video id='source' style='display: none;'>
<source>whatever.mp4</source>
<source>whatever.ogg</source>
</video>
<canvas id='screen' width='videoWidth' height='videoHeight></canvas>
然后你设置绘制功能
var t = null;
document.getElementById('source').addEventListener('playing', function(){
var vid = this;
t = setInterval(function(){
if (vid.paused || vid.ended){
clearInterval(t);
return
} else {
drawFrame();
}
}, 20)
}, false)
并且您的并条机功能是
function drawFrame(){
var ctx = document.getElementById('screen').getContext('2d'),
vid = document.getElementById('source');
ctx.drawImage(vid, 0, 0);
var tolerance = 0.2,
bgColor = [0, 255, 0], //or whatever
imageData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height),
len = imageData.data.length;
for (var i=0; i<len; i+=4){
var r = imageData.data[i],
g = imageData.data[i+1],
b = imageData.data[i+2];
//There's lots of different color comparing methods, just check google
var dif = colorCompare([r, g, b], bgColor);
if (dif < tolerance){
imageData.data[i+3] = 255;
}
}
ctx.putImageData(imageData, 0, 0);
}
您可以使用它的不同部分来达到您想要的性能水平。对于相对较小(尺寸方面)的视频,您的表现应该不是问题。您可能必须使用缓冲画布来避免屏幕闪烁,但我对此表示怀疑。您可以调整公差变量以避免任何光环效应。
并不是说它是最好的解决方案,但它绝对是一个可行的解决方案,如果您只想更改输入视频而无需额外工作就可以更改视频,那么该解决方案就可以使用。
答案 2 :(得分:0)
不确定你是否看过这个......但你有没有想过利用jquery队列?当我把它加载到我的浏览器中时,我看到一些帧没有显示,或者空白,然后回来等等等。我之前用过队列做同步处理说ajax调用我想“链“在一个特定的顺序中......这可能是一个区域,您可以尝试以同步的方式加载每个”图像框架“,确保每个框架以正确的顺序加载?