canvasタグを使って動画のスクリーンショットを撮る方法

はじめまして。エンジニアブログ初投稿の南です。
広告代理店であるアドウェイズではさまざまな動画広告を媒体に配信しています。
ある日、「動画からサムネイルを手軽に作る機能がほしい」と要望がありました。
用件としては、

  • 動画広告はサムネイルによって効果が変わる場合があるので、一つの動画から複数のサムネイルを作成する場合がある
  • 毎回スクリーンショットを撮るのは面倒
  • 再生しながらボタン一つで作成したい

以上のようなものでした。
今回はhtml5で新たに追加されたcanvasタグとjavascriptを用いて実装してみようと思います。

html用意

動画を描画するhtmlを用意します。

<html>
  <head>
    <meta charset="utf-8">
    <script src="http://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
  </head>
  <body>
    <video id="video" src="test.mp4" controls></video>
    <button id="capture">キャプチャー</button>
    <a href="" id="download" download="test.png">ダウンロード</a>
    <canvas id="canvas"></canvas>
  </body>
</html>

javascriptでcanvasに描画

ボタンがクリックされた際の動画の状態をcanvasに描画します

$('#capture').on('click', function(){
  var video = document.getElementById('video');
  var $canvas = $('#canvas');
  
  $canvas.attr('width', video.videoWidth);
  $canvas.attr('height', video.videoHeight);
  $canvas[0].getContext('2d').drawImage(video, 0, 0, $canvas.width(), $canvas.height());
});

canvasにはwidthとheightをvideoタグと同じ大きさで設定しています。
canvasのサイズはデフォルトでは300px×150pxが設定されており、cssを用いてwidthなどを変更してしまうと、デフォルトサイズが適用され思うように描画することができません。

後はaタグのhref属性にcanvasのバイナリを埋め込む処理をon click処理内に追記すればダウンロードまで完成です。

$('#download').attr('href', $canvas[0].toDataURL('image/png'));

デモ

f:id:AdwaysEngineerBlog:20170224130140g:plain

よさげですね。

感想

それほど複雑なコードを書くことなく作成できたので、「canvasすげー」ってなりました。
業務ではRailsを利用しているので、バイナリをサーバに送信し、RMagickを使ってごにょごにょやってます。
そこら辺も機会があれば書きたいと思います。