【问题标题】:Play part of a video in a canvas在画布中播放视频的一部分
【发布时间】:2016-09-29 13:57:49
【问题描述】:

我只想在画布上播放我的视频的一半,但在对角线上被截断。 目前我可以使用这个小javascript在画布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),但每个视频都会被切割成对角线,以呈现如下内容:

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

【问题讨论】:

  • 你想达到什么目的,为什么不在一些视频编辑软件上编辑视频蒙太奇并在你的页面上播放呢?或者您正在尝试创建在线视频编辑器? :)
  • 我忘记了一点,我希望能够根据鼠标位置移动对角线。我正在更新问题:)

标签: javascript html canvas html5-video


【解决方案1】:

您可以使用合成来实现此目的。

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

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


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

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

  • 在循环中使用组合模式“source-over”进行初始化
  • 清除画布以确保我们可以使用 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>

【讨论】:

  • 从来没有听说过作文,这有点棘手,即使在阅读了两次文档之后,我也不确定这里发生了什么 :D 但是使用这个解决方案,我只看到 1 个视频,并且我一移动鼠标,就没有视频了:(
  • @jbuiss0n 哎呀,忘了设置初始补偿。掩码的模式(源过)。当然也必须在每一帧调用 renderFrame()。
  • @jbuiss0n 也添加了实际视频源以显示它按预期工作(只需给视频一些时间来加载...)
  • 这太棒了,非常感谢!我仍然不完全了解如何使用组合,但我一定会研究它。
  • @jbuiss0n 没问题。我建议不要过多地陷入数学问题,而是查看这个图形概述,显示每个操作员对源(=正在绘制的新内容)与目标(现有内容)所做的事情 - this overview =透明 Alpha 通道。
猜你喜欢
  • 2013-03-08
  • 2021-01-13
  • 1970-01-01
  • 2013-01-26
  • 1970-01-01
  • 2015-10-10
  • 1970-01-01
  • 2012-09-30
相关资源
最近更新 更多