html5:在画布内显示视频

发布于 2024-10-07 12:08:55 字数 126 浏览 2 评论 0 原文

是否可以将 html5 视频显示为画布的一部分?

基本上与在画布上绘制图像的方式相同。

context.drawVideo(vid, 0, 0);

谢谢!

is it possible to display a html5-video as part of the canvas?

basically the same way as you draw an Image in the canvas.

context.drawVideo(vid, 0, 0);

thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

浅黛梨妆こ 2024-10-14 12:08:55
var canvas = document.getElementById('canvas');
var ctx    = canvas.getContext('2d');
var video  = document.getElementById('video');

video.addEventListener('play', function () {
    var $this = this; //cache
    (function loop() {
        if (!$this.paused && !$this.ended) {
            ctx.drawImage($this, 0, 0);
            setTimeout(loop, 1000 / 30); // drawing at 30fps
        }
    })();
}, 0);

我想上面的代码是不言自明的,如果不在下面发表评论,我会尝试解释上面几行代码

编辑
这是一个专门为您准备的在线示例:)
演示

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var video = document.getElementById('video');

// set canvas size = video size when known
video.addEventListener('loadedmetadata', function() {
  canvas.width = video.videoWidth;
  canvas.height = video.videoHeight;
});

video.addEventListener('play', function() {
  var $this = this; //cache
  (function loop() {
    if (!$this.paused && !$this.ended) {
      ctx.drawImage($this, 0, 0);
      setTimeout(loop, 1000 / 30); // drawing at 30fps
    }
  })();
}, 0);
<div id="theater">
  <video id="video" src="http://upload.wikimedia.org/wikipedia/commons/7/79/Big_Buck_Bunny_small.ogv" controls></video>
  <canvas id="canvas"></canvas>
  <label>
    <br />Try to play me :)</label>
  <br />
</div>

var canvas = document.getElementById('canvas');
var ctx    = canvas.getContext('2d');
var video  = document.getElementById('video');

video.addEventListener('play', function () {
    var $this = this; //cache
    (function loop() {
        if (!$this.paused && !$this.ended) {
            ctx.drawImage($this, 0, 0);
            setTimeout(loop, 1000 / 30); // drawing at 30fps
        }
    })();
}, 0);

I guess the above code is self Explanatory, If not drop a comment below, I will try to explain the above few lines of code

Edit :
here's an online example, just for you :)
Demo

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var video = document.getElementById('video');

// set canvas size = video size when known
video.addEventListener('loadedmetadata', function() {
  canvas.width = video.videoWidth;
  canvas.height = video.videoHeight;
});

video.addEventListener('play', function() {
  var $this = this; //cache
  (function loop() {
    if (!$this.paused && !$this.ended) {
      ctx.drawImage($this, 0, 0);
      setTimeout(loop, 1000 / 30); // drawing at 30fps
    }
  })();
}, 0);
<div id="theater">
  <video id="video" src="http://upload.wikimedia.org/wikipedia/commons/7/79/Big_Buck_Bunny_small.ogv" controls></video>
  <canvas id="canvas"></canvas>
  <label>
    <br />Try to play me :)</label>
  <br />
</div>

橘虞初梦 2024-10-14 12:08:55

这是一个使用更现代语法的解决方案,并且比已经提供的解决方案更简洁:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const video = document.querySelector("video");

video.addEventListener("play", () => {
  function step() {
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
    requestAnimationFrame(step);
  }
  requestAnimationFrame(step);
});

一些有用的链接:

Here's a solution that uses more modern syntax and is less verbose than the ones already provided:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const video = document.querySelector("video");

video.addEventListener("play", () => {
  function step() {
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
    requestAnimationFrame(step);
  }
  requestAnimationFrame(step);
});

Some useful links:

流云如水 2024-10-14 12:08:55

使用画布显示视频

显示视频与显示图像非常相似。细微的差别与 onload 事件有关,并且您需要渲染每一帧视频,否则您只会看到一帧而不是动画帧。

下面的演示与示例有一些细微的差别。静音功能(在视频下单击静音/声音打开以切换声音)和一些错误检查,以捕获 IE9+ 和 Edge(如果它们没有正确的驱动程序)。

Keeping answers current.

user372551 之前的答案已经过时(2010 年 12 月),并且所使用的渲染技术存在缺陷。它使用 setTimeout 和 33.333..ms 的速率,setTimeout 将向下舍入到 33ms,这将导致每两秒丢帧一次,如果视频帧速率更高,可能会丢更多帧超过 30。使用 setTimeout 还会引入由于 setTimeout 无法同步到显示硬件而创建的视频剪切。

目前没有可靠的方法可以确定视频帧速率,除非您提前知道视频帧速率,否则您应该以浏览器上可能的最大显示刷新率显示它。 60fps

给出的最佳答案是当时(6年前)最好的解决方案,因为 requestAnimationFrame 没有得到广泛支持(如果有的话),但 requestAnimationFrame 现在是跨主要的标准浏览器中,应该使用 setTimeout 来减少或删除丢帧,并防止剪切。

示例演示。

加载视频并将其设置为循环播放。在您点击视频之前,该视频不会播放。再次点击将暂停。视频下方有一个静音/声音按钮。视频默认静音。

请注意 IE9+ 和 Edge 的用户。您可能无法播放视频格式 WebM,因为它需要额外的驱动程序才能播放视频。您可以在 tools.google.com 找到它们下载 IE9+ WebM 支持

// This code is from the example document on stackoverflow documentation. See HTML for link to the example.
// This code is almost identical to the example. Mute has been added and a media source. Also added some error handling in case the media load fails and a link to fix IE9+ and Edge support.
// Code by Blindman67.


// Original source has returns 404
// var mediaSource = "http://video.webmfiles.org/big-buck-bunny_trailer.webm";
// New source from wiki commons. Attribution in the leading credits.
var mediaSource = "http://upload.wikimedia.org/wikipedia/commons/7/79/Big_Buck_Bunny_small.ogv"

var muted = true;
var canvas = document.getElementById("myCanvas"); // get the canvas from the page
var ctx = canvas.getContext("2d");
var videoContainer; // object to hold video and associated info
var video = document.createElement("video"); // create a video element
video.src = mediaSource;
// the video will now begin to load.
// As some additional info is needed we will place the video in a
// containing object for convenience
video.autoPlay = false; // ensure that the video does not auto play
video.loop = true; // set the video to loop.
video.muted = muted;
videoContainer = {  // we will add properties as needed
     video : video,
     ready : false,   
};
// To handle errors. This is not part of the example at the moment. Just fixing for Edge that did not like the ogv format video
video.onerror = function(e){
    document.body.removeChild(canvas);
    document.body.innerHTML += "<h2>There is a problem loading the video</h2><br>";
    document.body.innerHTML += "Users of IE9+ , the browser does not support WebM videos used by this demo";
    document.body.innerHTML += "<br><a href='https://tools.google.com/dlpage/webmmf/'> Download IE9+ WebM support</a> from tools.google.com<br> this includes Edge and Windows 10";
    
 }
video.oncanplay = readyToPlayVideo; // set the event to the play function that 
                                  // can be found below
function readyToPlayVideo(event){ // this is a referance to the video
    // the video may not match the canvas size so find a scale to fit
    videoContainer.scale = Math.min(
                         canvas.width / this.videoWidth, 
                         canvas.height / this.videoHeight); 
    videoContainer.ready = true;
    // the video can be played so hand it off to the display function
    requestAnimationFrame(updateCanvas);
    // add instruction
    document.getElementById("playPause").textContent = "Click video to play/pause.";
    document.querySelector(".mute").textContent = "Mute";
}

function updateCanvas(){
    ctx.clearRect(0,0,canvas.width,canvas.height); 
    // only draw if loaded and ready
    if(videoContainer !== undefined && videoContainer.ready){ 
        // find the top left of the video on the canvas
        video.muted = muted;
        var scale = videoContainer.scale;
        var vidH = videoContainer.video.videoHeight;
        var vidW = videoContainer.video.videoWidth;
        var top = canvas.height / 2 - (vidH /2 ) * scale;
        var left = canvas.width / 2 - (vidW /2 ) * scale;
        // now just draw the video the correct size
        ctx.drawImage(videoContainer.video, left, top, vidW * scale, vidH * scale);
        if(videoContainer.video.paused){ // if not playing show the paused screen 
            drawPayIcon();
        }
    }
    // all done for display 
    // request the next frame in 1/60th of a second
    requestAnimationFrame(updateCanvas);
}

function drawPayIcon(){
     ctx.fillStyle = "black";  // darken display
     ctx.globalAlpha = 0.5;
     ctx.fillRect(0,0,canvas.width,canvas.height);
     ctx.fillStyle = "#DDD"; // colour of play icon
     ctx.globalAlpha = 0.75; // partly transparent
     ctx.beginPath(); // create the path for the icon
     var size = (canvas.height / 2) * 0.5;  // the size of the icon
     ctx.moveTo(canvas.width/2 + size/2, canvas.height / 2); // start at the pointy end
     ctx.lineTo(canvas.width/2 - size/2, canvas.height / 2 + size);
     ctx.lineTo(canvas.width/2 - size/2, canvas.height / 2 - size);
     ctx.closePath();
     ctx.fill();
     ctx.globalAlpha = 1; // restore alpha
}    

function playPauseClick(){
     if(videoContainer !== undefined && videoContainer.ready){
          if(videoContainer.video.paused){                                 
                videoContainer.video.play();
          }else{
                videoContainer.video.pause();
          }
     }
}
function videoMute(){
    muted = !muted;
	if(muted){
         document.querySelector(".mute").textContent = "Mute";
    }else{
         document.querySelector(".mute").textContent= "Sound on";
    }


}
// register the event
canvas.addEventListener("click",playPauseClick);
document.querySelector(".mute").addEventListener("click",videoMute)
body {
    font :14px  arial;
    text-align : center;
    background : #36A;
}
h2 {
    color : white;
}
canvas {
    border : 10px white solid;
    cursor : pointer;
}
a {
  color : #F93;
}
.mute {
    cursor : pointer;
    display: initial;   
}
<h2>Basic Video & canvas example</h2>
<p>Code example from Stackoverflow Documentation HTML5-Canvas<br>
<a href="https://stackoverflow.com/documentation/html5-canvas/3689/media-types-and-the-canvas/14974/basic-loading-and-playing-a-video-on-the-canvas#t=201607271638099201116">Basic loading and playing a video on the canvas</a></p>
<canvas id="myCanvas" width = "532" height ="300" ></canvas><br>
<h3><div id = "playPause">Loading content.</div></h3>
<div class="mute"></div><br>
<div style="font-size:small">Attribution in the leading credits.</div><br>

画布附加功能

使用画布渲染视频为您提供了有关显示和混合效果的附加选项。下图显示了您可以使用画布获得的一些效果。使用 2D API 提供了广泛的创意可能性。

与答案相关的图片将画布视频从灰度淡化为彩色
视频过滤器

请参阅上面演示中的视频标题,了解上面图像中内容的归属。

Using canvas to display Videos

Displaying a video is much the same as displaying an image. The minor differences are to do with onload events and the fact that you need to render the video every frame or you will only see one frame not the animated frames.

The demo below has some minor differences to the example. A mute function (under the video click mute/sound on to toggle sound) and some error checking to catch IE9+ and Edge if they don't have the correct drivers.

Keeping answers current.

The previous answers by user372551 is out of date (December 2010) and has a flaw in the rendering technique used. It uses the setTimeout and a rate of 33.333..ms which setTimeout will round down to 33ms this will cause the frames to be dropped every two seconds and may drop many more if the video frame rate is any higher than 30. Using setTimeout will also introduce video shearing created because setTimeout can not be synced to the display hardware.

There is currently no reliable method that can determine a videos frame rate unless you know the video frame rate in advance you should display it at the maximum display refresh rate possible on browsers. 60fps

The given top answer was for the time (6 years ago) the best solution as requestAnimationFrame was not widely supported (if at all) but requestAnimationFrame is now standard across the Major browsers and should be used instead of setTimeout to reduce or remove dropped frames, and to prevent shearing.

The example demo.

Loads a video and set it to loop. The video will not play until the you click on it. Clicking again will pause. There is a mute/sound on button under the video. The video is muted by default.

Note users of IE9+ and Edge. You may not be able to play the video format WebM as it needs additional drivers to play the videos. They can be found at tools.google.com Download IE9+ WebM support

// This code is from the example document on stackoverflow documentation. See HTML for link to the example.
// This code is almost identical to the example. Mute has been added and a media source. Also added some error handling in case the media load fails and a link to fix IE9+ and Edge support.
// Code by Blindman67.


// Original source has returns 404
// var mediaSource = "http://video.webmfiles.org/big-buck-bunny_trailer.webm";
// New source from wiki commons. Attribution in the leading credits.
var mediaSource = "http://upload.wikimedia.org/wikipedia/commons/7/79/Big_Buck_Bunny_small.ogv"

var muted = true;
var canvas = document.getElementById("myCanvas"); // get the canvas from the page
var ctx = canvas.getContext("2d");
var videoContainer; // object to hold video and associated info
var video = document.createElement("video"); // create a video element
video.src = mediaSource;
// the video will now begin to load.
// As some additional info is needed we will place the video in a
// containing object for convenience
video.autoPlay = false; // ensure that the video does not auto play
video.loop = true; // set the video to loop.
video.muted = muted;
videoContainer = {  // we will add properties as needed
     video : video,
     ready : false,   
};
// To handle errors. This is not part of the example at the moment. Just fixing for Edge that did not like the ogv format video
video.onerror = function(e){
    document.body.removeChild(canvas);
    document.body.innerHTML += "<h2>There is a problem loading the video</h2><br>";
    document.body.innerHTML += "Users of IE9+ , the browser does not support WebM videos used by this demo";
    document.body.innerHTML += "<br><a href='https://tools.google.com/dlpage/webmmf/'> Download IE9+ WebM support</a> from tools.google.com<br> this includes Edge and Windows 10";
    
 }
video.oncanplay = readyToPlayVideo; // set the event to the play function that 
                                  // can be found below
function readyToPlayVideo(event){ // this is a referance to the video
    // the video may not match the canvas size so find a scale to fit
    videoContainer.scale = Math.min(
                         canvas.width / this.videoWidth, 
                         canvas.height / this.videoHeight); 
    videoContainer.ready = true;
    // the video can be played so hand it off to the display function
    requestAnimationFrame(updateCanvas);
    // add instruction
    document.getElementById("playPause").textContent = "Click video to play/pause.";
    document.querySelector(".mute").textContent = "Mute";
}

function updateCanvas(){
    ctx.clearRect(0,0,canvas.width,canvas.height); 
    // only draw if loaded and ready
    if(videoContainer !== undefined && videoContainer.ready){ 
        // find the top left of the video on the canvas
        video.muted = muted;
        var scale = videoContainer.scale;
        var vidH = videoContainer.video.videoHeight;
        var vidW = videoContainer.video.videoWidth;
        var top = canvas.height / 2 - (vidH /2 ) * scale;
        var left = canvas.width / 2 - (vidW /2 ) * scale;
        // now just draw the video the correct size
        ctx.drawImage(videoContainer.video, left, top, vidW * scale, vidH * scale);
        if(videoContainer.video.paused){ // if not playing show the paused screen 
            drawPayIcon();
        }
    }
    // all done for display 
    // request the next frame in 1/60th of a second
    requestAnimationFrame(updateCanvas);
}

function drawPayIcon(){
     ctx.fillStyle = "black";  // darken display
     ctx.globalAlpha = 0.5;
     ctx.fillRect(0,0,canvas.width,canvas.height);
     ctx.fillStyle = "#DDD"; // colour of play icon
     ctx.globalAlpha = 0.75; // partly transparent
     ctx.beginPath(); // create the path for the icon
     var size = (canvas.height / 2) * 0.5;  // the size of the icon
     ctx.moveTo(canvas.width/2 + size/2, canvas.height / 2); // start at the pointy end
     ctx.lineTo(canvas.width/2 - size/2, canvas.height / 2 + size);
     ctx.lineTo(canvas.width/2 - size/2, canvas.height / 2 - size);
     ctx.closePath();
     ctx.fill();
     ctx.globalAlpha = 1; // restore alpha
}    

function playPauseClick(){
     if(videoContainer !== undefined && videoContainer.ready){
          if(videoContainer.video.paused){                                 
                videoContainer.video.play();
          }else{
                videoContainer.video.pause();
          }
     }
}
function videoMute(){
    muted = !muted;
	if(muted){
         document.querySelector(".mute").textContent = "Mute";
    }else{
         document.querySelector(".mute").textContent= "Sound on";
    }


}
// register the event
canvas.addEventListener("click",playPauseClick);
document.querySelector(".mute").addEventListener("click",videoMute)
body {
    font :14px  arial;
    text-align : center;
    background : #36A;
}
h2 {
    color : white;
}
canvas {
    border : 10px white solid;
    cursor : pointer;
}
a {
  color : #F93;
}
.mute {
    cursor : pointer;
    display: initial;   
}
<h2>Basic Video & canvas example</h2>
<p>Code example from Stackoverflow Documentation HTML5-Canvas<br>
<a href="https://stackoverflow.com/documentation/html5-canvas/3689/media-types-and-the-canvas/14974/basic-loading-and-playing-a-video-on-the-canvas#t=201607271638099201116">Basic loading and playing a video on the canvas</a></p>
<canvas id="myCanvas" width = "532" height ="300" ></canvas><br>
<h3><div id = "playPause">Loading content.</div></h3>
<div class="mute"></div><br>
<div style="font-size:small">Attribution in the leading credits.</div><br>

Canvas extras

Using the canvas to render video gives you additional options in regard to displaying and mixing in fx. The following image shows some of the FX you can get using the canvas. Using the 2D API gives a huge range of creative possibilities.

Image relating to answer Fade canvas video from greyscale to color
Video filters "Lighten", "Black & white", "Sepia", "Saturate", and "Negative"

See video title in above demo for attribution of content in above inmage.

歌枕肩 2024-10-14 12:08:55

我从 2018 年关于 requestAnimationFrame 的答案开始。然而,它存在三个问题。

  • 不必要的复杂
  • 有一种新的方法来处理此任务(大约从 2020 年开始)
  • 将事件侦听器附加到 play 事件会引发性能问题

首先,事件侦听器可以简单地连接到执行您所需的函数处理并安排下一次对其自身的调用。无需将其包装在匿名函数中并再次调用 requestAnimationFrame

其次,不要使用 requestAnimationFrame。该函数会以浏览器可以处理的速度(通常为 60Hz)安排下一次对回调的调用,这会导致大量的处理工作负载。 video.requestVideoFrameCallback 仅在视频进入下一帧时调用您的回调。当视频以低于 60 FPS 的速度运行时,这可以减少工作负载,并且在视频不播放时完全不需要进行任何处理,从而显着提高性能。

第三,每当您将视频告诉 video.play() 时,附加到 play 事件的事件侦听器就会触发,每次加载新视频时都会执行此操作进入视频元素并告诉它开始播放,以及在使用 video.pause() 后恢复播放时。因此,每次视频被告知 play() 时,视频都会在画布上绘制一次(加上您正在执行的任何其他处理),这会快速累积。

如果您确定只播放一个要暂停和恢复的视频,您可以通过更改播放速率来切换播放/暂停,例如 video.playbackRate = !video.playbackRate。如果您要将多个视频加载到此元素中,最好完全放弃 play 事件侦听器,并在加载第一个视频时插入对 step() 的手动调用开始吧。请注意,这在视频元素上有效,而不是在特定加载的视频上有效,因此您需要设置并检查标志以确保仅在加载第一个视频时调用 step(),或者在发出新请求之前取消任何活动视频帧请求(如下所示)。

let animation_handle;
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const video = document.querySelector("video");
video.addEventListener('loadeddata', video_load_callback, false);

function video_load_callback() {
    video.cancelVideoFrameCallback(animation_handle);
    step()
}
function step() { // update the canvas when a video proceeds to next frame
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
    animation_handle = video.requestVideoFrameCallback(step);
}

I started with the answer from 2018 about requestAnimationFrame. However, it has three problems.

  • unnecessarily complex
  • there is a new way to handle this task (since about 2020)
  • attaching an event listener to the play event invites performance issues

First, the event listener can simply be connected to the function that does your desired processing and schedules the next call to itself. There's no need to wrap it in an anonymous function with another call to requestAnimationFrame.

Second, don't use requestAnimationFrame. That function schedules the next call to your callback as quickly as the browser can handle (generally 60Hz), which results in a significant processing workload. video.requestVideoFrameCallback only calls your callback when the video proceeds to its next frame. This reduces the workload when a video runs at less than 60 FPS and obviates the need for any processing at all while the video isn't playing, significantly improving performance.

Third, an event listener attached to the play event will fire whenever you tell the video to video.play(), which you'll do every time you load a new video into the video element and tell it to start playing, and also when you resume playback after using video.pause(). Thus, the video is drawn on the canvas (plus whatever other processing you're doing) once for each time the video has been told to play(), which quickly accumulates.

If you're sure you'll only be playing one video which you'd like to pause and resume, you can toggle play/pause by changing the playback rate, e.g. video.playbackRate = !video.playbackRate. If you'll be loading multiple videos into this element, it's better to forego the play event listener entirely and insert a manual call to step() when you load your first video to get that started. Note that this is active on the video element, not on specific loaded videos, so you'll need to either set and check a flag to ensure that you only call step() when loading the first video, or cancel any active video frame request before making a new one (shown below).

let animation_handle;
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const video = document.querySelector("video");
video.addEventListener('loadeddata', video_load_callback, false);

function video_load_callback() {
    video.cancelVideoFrameCallback(animation_handle);
    step()
}
function step() { // update the canvas when a video proceeds to next frame
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
    animation_handle = video.requestVideoFrameCallback(step);
}
你的笑 2024-10-14 12:08:55

您需要更新 currentTime 视频元素,然后在画布中绘制帧。不要在视频上初始化 play() 事件。

您也可以使用 for ex。这个插件 https://github.com/tstabla/stVideo

You need to update currentTime video element and then draw the frame in canvas. Don't init play() event on the video.

You can also use for ex. this plugin https://github.com/tstabla/stVideo

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文