【问题标题】:How to take a snapshot of HTML5-JavaScript-based video player?如何拍摄基于 HTML5-JavaScript 的视频播放器的快照?
【发布时间】:2012-12-07 10:00:43
【问题描述】:

实际上,我有一个带有 JavaScript 功能的 HTML5 页面,可以让我播放 wmv 视频文件。 我需要在视频播放时拍摄快照(无论是否暂停)并以任何图像格式 JPG 或 BMP 保存。 任何帮助将不胜感激。 谢谢。

<!DOCTYPE HTML>

    <html>
        <head>
            <title>HTML5 video</title>        
    <script type="text/javascript">
        function checkPlay() {
            var myVideo = document.getElementById("myVid");
            var ytStr = '<iframe width="500" height="500" src="C:\XA0002.wmv" frameborder="0" allowfullscreen></iframe>';
            try {
                var canPlay = document.getElementsByTagName('video')[0].canPlayType("video/wmv");
                if ((canPlay == "no") || (canPlay == "")) {
                    myVideo.innerHTML = ytStr;
                }
                new MediaElement(v, { success: function (media) { media.play(); } });
            } catch (err) {
                myVideo.innerHTML = ytStr;
            }
        }
    </script>
        </head>
        <body onload="checkPlay()">
          <div id="myVid"/>

      </body>
    </html>

【问题讨论】:

  • 您想要视频播放器中特定时刻的快照,还是想要完整尺寸的屏幕截图?如果您要视频播放器的屏幕截图,这可能有点挑战性,但您可以查看屏幕截图stackoverflow.com/questions/4912092/…

标签: javascript html web html5-video snapshot


【解决方案1】:

要将视频帧复制到图像文件中,需要正确加载视频、将图像复制到画布并将其导出到文件中。这是完全可能的,但有几个地方可能会遇到麻烦,所以让我们一步一步来。

1) 加载视频

要捕获像素,您需要将视频加载到&lt;video&gt; 标记中,而不是iframeobjectembed。并且该文件需要来自网络服务器,该服务器与网页本身所在的服务器相同(除非您使用cross-origin headers,这很复杂,可能无法在您的浏览器中运行。出于安全原因,这受到浏览器的限制. 您的代码从本地文件系统加载视频,这不起作用。

您还需要加载正确的文件格式。 IE9+ 可以播放 WMV,但其他浏览器不太可能。如果可以,请使用 webm、mp4 和理想的 ogg/theora 加载 multiple sources

var container = document.getElementById("myVid"),
    video = document.createElement('video'),
    canCapture = true;
if (!video.canPlayType('video/wmv')) {
    /* If you don't have multiple sources, you can load up a Flash fallback here
       (like jPlayer), but you won't be able to capture frames */
    canCapture = false;
    return;
}
video.src = 'myvideo.wmv';
container.appendChild(video);
video.play(); //or put this in a button click handler if you want your own controls

2) 接下来,创建画布和绘图上下文。实际上,您甚至不需要将其附加到 DOM,但您确实需要将其设置为您想要保存结果图像的大小。对于此示例,我们假设您有一个固定尺寸,但如果您愿意,您可以将其设置为视频尺寸的倍数。只需确保在视频的“已加载元数据”事件中运行它,因为视频尺寸不会立即可用。

var canvas = document.createElement('canvas');
canvas.width = 640;
canvas.height = 480;
var ctx = canvas.getContext('2d');
// if you want to preview the captured image,
// attach the canvas to the DOM somewhere you can see it.

3) 将图像捕获到画布并将其保存到文件中。将此代码放在按钮上的 onclick 事件中或计时器内 - 但是您想决定何时捕获图像。使用 drawImage 方法。 ([这篇文章]提供了很好的解释,包括安全问题。视频和图像一样。)

//draw image to canvas. scale to target dimensions
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

//convert to desired file format
var dataURI = canvas.toDataURL('image/jpeg'); // can also use 'image/png'

4) 导出图片文件

jpg 文件现在保存为 Data URI,这是一个长的 javascript 字符串,表示完整二进制文件的编码版本。由你决定如何处理它。您可以将其直接放入 img 元素中,只需将其设置为 src:myImage.src = dataUri;

如果您想将其保存到文件中,您几乎需要将其上传到服务器。这是一个good tutorial,告诉你如何做到这一点。

像往常一样,以上所有内容都仅限于支持它的浏览器。如果您要坚持使用 wmv 视频,那么您几乎只能使用 Internet Explorer 9+。 6-8 不支持视频标签或画布。如果您可以添加更多视频格式,您可以使用 Firefox (3.5+) 和 Chrome。

【讨论】:

  • 谢谢。我刚刚制作了一个书签脚本来拍摄 Youtube 视频的快照:youtube-screenshot
  • 这太棒了,我想知道如何在视频中的某个时间点拍摄快照?我的意思是例如第 10 秒。
  • 对于任何遇到 CORS 问题和安全错误的人:overengineer.net/…(将 crossOrigin="anonymous" 添加到视频中)
  • @TomaszMularczyk 在video.play() 之前调用video.currentTime = 10000
  • 如果您需要以当前分辨率捕获视频,您可以使用videoElement.videoHeightvideoElement.videoWidth
【解决方案2】:
<html>
<body>

  <video controls>
    <source src="C:/Users/ganesha/Desktop/Aararum.mp4" type="video/mp4"></source>
  </video>
  <canvas id="canvas" width="640" height="480"></canvas>
  <button id="snap" onclick="snap()">Snap Photo</button>

  <!-- start the script ... within that declare variables as follows... -->
  <script>
  var video=document.querySelector('video');
  var canvas=document.querySelector('canvas');
  var context=canvas.getContext('2d');
  var w,h,ratio;

  //add loadedmetadata which will helps to identify video attributes

  video.addEventListener('loadedmetadata', function() {
    ratio = video.videoWidth/video.videoHeight;
    w = video.videoWidth-100;
    h = parseInt(w/ratio,10);
    canvas.width = w;
    canvas.height = h;
  },false);

  function snap() {
    context.fillRect(0,0,w,h);
    context.drawImage(video,0,0,w,h);
  }
  </script>

</body>
</html>

【讨论】:

  • 效果很好!但它仅在视频源托管在同一服务器上而不是跨源时才有效。但是感谢您的解决方案!
  • 那么你如何解决这个问题? @JonathanMarzullo
  • @Martian2029 因为它是一个跨源问题,这意味着视频必须位于相同的域、端口和协议上。有关跨源策略的更多信息,请参阅此内容。developer.mozilla.org/en-US/docs/Web/Security/…跨度>
  • 谢谢,2020 年也能完美运行!结合这种缩放,捕获的照片可以很好地适合响应式页面:stackoverflow.com/a/3422425/1838044
  • 如何在拍摄快照之前隐藏画布?
【解决方案3】:

您可以使用drawImage() 函数获取当前视频的副本并将其存储在画布元素中。

我有一个完整的示例,您可以在 Video/canvas screenshot 查看它的代码,这应该会让您走上正轨。

【讨论】:

  • 但是,这将要求 OP 摆脱他的 iframe,并改用 video 标签。倒不是说有什么不对,只是指出来而已。
【解决方案4】:
Sample code:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"> 
</script>

</head>
<body>
<h2>Upload,Save and Download video </h2>
<form method="POST" action="" enctype="multipart/form-data">
<input type="file" name="video" id="upload"/>
</...>

<script>
var input = document.getElementById('upload');

input.addEventListener('change', function(event){
var file = this.files[0];
var url = URL.createObjectURL(file);

var video = document.createElement('video');
video.src = url;

var snapshot = function(){
    var canvas = document.createElement('canvas');
    var ctx = canvas.getContext('2d');

    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
    var img_data = canvas.toDataURL('image/jpg');
    var filename = file.name;
    var filename = filename.split('.').slice(0, -1).join('.');



    document.getElementById("thumb").value = filename;
    $.post("thumb-saver.php", { 
        base:img_data, 
        output:"thumbnails/"+ filename +  '.jpg'
    }, function( data ) {
            //alert(data);
    });

    video.removeEventListener('canplay', snapshot);
 };

video.addEventListener('canplay', snapshot);
});
</script>

【讨论】:

    【解决方案5】:

    首先包含在画布标签中的视频糊状物。

    这样;

    <canvas id="target-canvas">
        <video id="video-for-thumbs" autoplay src="http://.....></video> 
    </canvas>
    

    还有这样的js

    setTimeout(function(){
        var canvas=$('#target-canvas')[0];
        canvas.getContext('2d').drawImage($('#video-for-thumbs')[0],0,0,1000,300);
        var f=canvas.toDataURL();
        console.log(f);
    
    },200);
    

    数据将以base64呈现

    如果你想在视频中间得到帧,你可以增加延迟时间来运行js。

    补充

    您可以添加播放速率以提高视频的速度,以缩短仅用于缩略图的屏幕截图的等待时间

    $('#video-for-thumbs')[0].playbackRate=9;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-05
      相关资源
      最近更新 更多