在 canvas 中播放部分视频

Play part of a video in a canvas

我想在 canvas 上只播放视频的一半,但在对角线上被截断了。 目前,我可以使用 javascript:

在 canvas easyli 中播放我的完整视频
var video = document.getElementById('video');
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

var drawFrame = function drawFrame() {
    context.drawImage(video, 0, 0, canvas.width, canvas.height);
    requestAnimationFrame(drawFrame);
};

requestAnimationFrame(drawFrame);

最后,我希望能够同时播放 2 个视频(我只需要在每个视频上调用 drawImage),但每个视频都会沿对角线切割,以呈现如下内容:

然后我想根据鼠标位置移动分隔符。

您可以使用合成来实现。

Compositions 使用 alpha 通道以各种方式组合非 alpha 数据,例如“source-in”将在存在像素的地方绘制源 image/video,而“destination-over”将保留现有像素在有非 alpha 的地方,只在有 alpha 的地方绘制新的(这些也称为 Porter-Duff or alpha composition。混合属于同一保护伞,但与合成具有不同的目的)。

有很多模式,但上面提到的模式允许我们将它们组合起来,只需定义一个用作两者遮罩的 alpha 区域,即可获得我们想要的部分。我将包括一个概述,以展示操作员如何为每种模式工作,以更好地理解他们的工作(来自 Wikipedia):


(A = 来源,B = 目的地)

在这种情况下需要的步骤是:

  • 使用组合模式“source-over”初始化,因为我们在循环中使用它
  • 清除 canvas 以确保我们有一个 alpha 通道可以使用
  • 绘制相对于鼠标位置的对角线一半
  • 使用“source-in”在顶部绘制视频源 2(将其放在左侧)
  • 使用“destination-over”在顶部绘制视频源 1“

工作示例

这将加载两个不同的视频(从 here 借用的链接)并且在加载时如上所述设置循环(只需给视频几秒钟加载时间):

var ctx = c.getContext("2d"), pos = c.width * 0.5, count = 2;
ctx.fillText("Please wait while videos are loading...", 20, 20);
video1.oncanplay = video2.oncanplay = function() {if (!--count) renderFrame()};

function renderFrame() {
  ctx.globalCompositeOperation = "source-over";
  ctx.clearRect(0, 0, c.width, c.height);     // makes sure we have an alpha channel

  ctx.beginPath();                            // draw diagonal half
  ctx.moveTo(0, 0);
  ctx.lineTo(pos - 50, 0);
  ctx.lineTo(pos + 50, c.height);
  ctx.lineTo(0, c.height);
  ctx.fill();

  // video source 2
  ctx.globalCompositeOperation = "source-in";        // comp in source 2
  ctx.drawImage(video2, 0, 0, c.width, c.height);
  
  // video source 1
  ctx.globalCompositeOperation = "destination-atop"; // comp in source 1
  ctx.drawImage(video1, 0, 0, c.width, c.height);

  requestAnimationFrame(renderFrame)
}

c.onmousemove = function(e) {
  pos = e.clientX - c.getBoundingClientRect().left;
}
video {display:none}
<canvas id=c width=640 height=400></canvas>
<video id=video1 muted autoplay loop src="http://media.w3.org/2010/05/sintel/trailer.mp4"></video>
<video id=video2 muted autoplay loop src="http://media.w3.org/2010/05/video/movie_300.webm"></video>