简体   繁体   English

如何使用HTML5 canvas标签显示视频

[英]How do I display a video using HTML5 canvas tag

I want to display a video using the canvas including a play pause function that allows the user to toggle play by clicking on the canvas, I would also like an overlay drawn on top of the video when it is pause. 我想使用包含播放暂停功能的画布显示视频,该功能允许用户通过单击画布来切换播放,我还想在视频暂停时在视频上方绘制一个叠加层。 how is this done in javascript? 如何在javascript中完成?

The canvas can be used to display video from a variety of sources. 画布可用于显示来自各种来源的视频。 This example shows how to load a video as a file resource, display it and add a simple click on screen play/pause toggle. 本示例说明如何将视频加载为文件资源,显示它并在屏幕播放/暂停切换上添加简单的单击。

Just an image 只是一张图片

A video is just an image as far as the canvas is concerned. 就画布而言,视频只是图像。 You can draw it like any image. 您可以像绘制任何图像一样绘制它。 The difference being the video can play and has sound. 区别在于视频可以播放并具有声音。

Get canvas and basic setup 获取画布和基本设置

// It is assumed you know how to add a canvas and correctly size it.
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

Creating and loading the video 创建和加载视频

var video = document.createElement("video"); // create a video element
video.src = "urlOffVideo.webm"; 
// 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.
videoContainer = {  // we will add properties as needed
     video : video,
     ready : false,   
};

Unlike images elements videos don't have to be fully loaded to be displayed on the canvas. 与图像元素不同,视频不必完全加载即可在画布上显示。 Videos also provide a host of extra events that can be used to monitor status of the video. 视频还提供了许多额外的事件,可用于监视视频的状态。

In this case we wish to know when the video is ready to play. 在这种情况下,我们希望知道何时可以播放视频。 oncanplay means that enough of the video has loaded to play some of it, but there may not be enough to play to the end. oncanplay意味着已经加载了足够的视频以播放其中的一些视频,但可能还不足以播放到最后。

video.oncanplay = readyToPlayVideo; // set the event to the play function that 
                                  // can be found below

Alternatively you can use oncanplaythrough which will fire when enough of the video has loaded so that it can be played to the end. 另外,您可以使用oncanplaythrough ,当加载了足够多的视频时,它将触发,从而可以播放到最后。

video.oncanplaythrough = readyToPlayVideo; // set the event to the play function that
                                         // can be found below

Only use one of the canPlay events not both. 只能使用canPlay事件之一,不能同时使用两者。

The can play event (equivalent to image onload) 可以播放事件(相当于图片加载)

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(undateCanvas);
}

Displaying 显示中

The video will not play itself on the canvas. 视频将不会在画布上播放。 You need to draw it for every new frame. 您需要为每个新框架绘制它。 As it is difficult to know the exact frame rate and when they occur the best approch is to display the video as if running at 60fps. 由于很难知道确切的帧速率以及何时发生帧速率,最好的办法是将视频显示为以60fps的速度运行。 If the frame rate is lower then w just render the same frame twice. 如果帧速率较低,则w将同一帧渲染两次。 If the frame rate is higher then there is nothing that can be don to see the extra frames so we just ignore them. 如果帧速率较高,则看不到多余的帧,因此我们将其忽略。

The video element is just a image element and can be draw like any image, you can scale, rotate, pan the video, mirror it, fade it, clip it and display only parts, draw it twice the second time with a global composite mode to add FX like lighten, screen, etc.. video元素只是一个图像元素,可以像绘制任何图像一样进行绘制,您可以缩放,旋转,平移视频,对其进行镜像,淡入淡出,对其进行裁剪和仅显示部分,并使用全局合成模式第二次绘制两次添加效果,如变亮,屏幕等。

function updateCanvas(){
    ctx.clearRect(0,0,canvas.width,canvas.height); // Though not always needed 
                                                     // you may get bad pixels from 
                                                     // previous videos so clear to be
                                                     // safe
    // only draw if loaded and ready
    if(videoContainer !== undefined && videoContainer.ready){ 
        // find the top left of the video on the canvas
        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);

} }

Basic play pause control 基本播放暂停控制

Now we have the video loaded and displayed all we need is the play control. 现在,我们已经加载并显示了视频,我们需要的只是播放控件。 We will make it as a click toggle play on the screen. 我们将其作为单击切换在屏幕上播放。 When the video is playing and the user clicks the video is paused. 当视频正在播放并且用户单击时,视频暂停。 When paused the click resumes play. 暂停后,点击继续播放。 We will add a function to darken the video and draw an play icon (triangle) 我们将添加使视频变暗并绘制播放图标(三角形)的功能

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
}    

Now the play pause event 现在播放暂停事件

function playPauseClick(){
     if(videoContainer !== undefined && videoContainer.ready){
          if(videoContainer.video.paused){                                 
                videoContainer.video.play();
          }else{
                videoContainer.video.pause();
          }
     }
}
// register the event
canvas.addEventListener("click",playPauseClick);

Summary 摘要

Playing a video is very easy using the canvas, adding effect in real time is also easy. 使用画布播放视频非常容易,实时添加效果也很容易。 There are however some limitations on formats, how you can play and seek. 但是,格式,播放和搜索方式存在一些限制。 MDN HTMLMediaElement is the place to get the full referance to the video object. MDN HTMLMediaElement是获得对视频对象的完整引用的地方。

Once the image has been drawn on the canvas you can use ctx.getImageData to access the pixels it contains. 在画布上绘制图像后,您可以使用ctx.getImageData访问其中包含的像素。 Or you can use canvas.toDataURL to snap a still and download it. 或者,您可以使用canvas.toDataURL捕捉静止图像并下载。 (Only if the video is from a trusted source and does not taint the canvas). (仅当视频来自受信任的来源并且没有污染画布时)。


Note if the video has sound then playing it will also play the sound. 请注意,如果视频有声音,则播放时也会播放声音。

Happy videoing. 祝您拍摄愉快。

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. 较小的差异与onload事件有关,而事实是您需要每帧渲染视频,否则您只会看到一个帧而不是动画帧。

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. 静音功能(在视频下,单击静音/打开声音以切换声音),并进行一些错误检查以捕获IE9 +和Edge(如果它们没有正确的驱动程序)。 I would have used another format that IE supports but could not find one that was public domain. 我本来会使用IE支持的另一种格式,但找不到属于公共领域的格式。

Note users of IE9+ and Edge. 注意IE9 +和Edge的用户。 You may not be able to play the video format WebM as it needs additional drivers to play the videos. 您可能无法播放视频格式WebM,因为它需要其他驱动程序来播放视频。 They can be found at tools.google.com Download IE9+ WebM support 可以在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 incase the media load fails and a link to fix IE9+ and Edge suport. // Code by Blindman67. var mediaSource = "http://video.webmfiles.org/big-buck-bunny_trailer.webm"; 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> 

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

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