動画の再生速度をJavaScriptで制御しよう

Webサイトのメインビジュアルに動画を再生する機会も多くなってきました。

そうなると、困った事態になることも増えてきます。
最近あったのが、「動画(の再生)をもっとゆっくりにして欲しい」という依頼。…ゆっくりですか。

今回の場合は、動画を撮影・編集してくれた人にお願いして、通常の速度より緩やかな動きになるように動画を作成していただくことになりました。
問題は「ゆっくり」というのがどの程度の早さなのか、ということ。

「ゆっくり」が通常の再生速度の半分なのか、4分の1なのか、4分の3なのか…。数値化されていない指示なので、そのまま動画を作ってくれる人に伝えられません。

動画編集は時間のかかる作業なので、「ごめん、半分の速度だと遅すぎたから 4分の3の速度にして作り直して」なんて気軽に言ってはいけません。

とはいえ、クライアントに「どれぐらいの速度ですか?」と聞いてもちゃんとした答えが返ってくるとは限りません。
クライアントも伝えたいと思っても、どう表現していいのか分からないこともあるでしょうし、修正された動画を見たら「思ったより早かった」なんてこともあるでしょう。

そこで、JavaScriptの出番です

JavaScriptで動画の再生速度を制御して、実際にクライアントでどれぐらいの速度がイメージされている「ゆっくり」であるか見てもらい、その速度を基準にして動画を作る、という流れでこの「ゆっくり問題」を解決しました。

今回は、このとき使用した「動画をJavaScriptで制御する」実装を解説します。

目次

処理の流れ

STEP
video要素とbutton要素を取得する

動画のvideo要素と、動画の速度をコントロールするbutton要素を取得します。

STEP
video要素にイベントリスナーを設定する

動画のメタデータが読み込まれたタイミングでloadedmetadataイベントが発生します。

これを検知するようにaddEventListener()メソッドを設定します。

STEP
button要素にイベントリスナーを設定する

取得したbutton要素がクリックされたら処理を実行できるように、clickイベントを検知するaddEventListener()メソッドを設定します。

STEP
クリックされたbutton要素から、変更したい再生速度を取得する

クリックされたボタン要素に設定しているdata属性から、変更したい再生速度を取得します。

STEP
取得した再生速度をvideo要素に反映する

取得した変更したい再生速度を、video要素の playbackRateプロパティに設定して、再生速度を変更します。

HTMLについて

今回、動画とコントロールのHTMLは以下のようにしました。

<div class="video-wrap">
  <video id="targetVideo" width="640" height="360" muted autoplay playsinline autoplay controls>
    <source src="assets/video/video01.mp4" type="video/mp4">
  </video>
</div>
<ul class="video-nav">
  <li><button data-speed="0.25" class="video-speed">0.25倍</button></li>
  <li><button data-speed="0.5" class="video-speed">0.5倍</button></li>
  <li><button data-speed="0.75" class="video-speed">0.75倍</button></li>
  <li><button data-speed="1" class="video-speed">等倍</button></li>
</ul>

それぞれの要素について、簡単に説明します。

video要素

<div class="video-wrap">
  <video id="targetVideo" width="640" height="480" muted autoplay playsinline controls>
    <source src="assets/video/video01.mp4" type="video/mp4">
  </video>
</div>

今回は動画の再生速度の確認だけなので、video要素には消音を指定するmuted属性、自動で再生を開始する指定のautoplay属性を設定しています。

また、短い動画なので繰り返し再生して確認できるようにするため、ブラウザ標準のコントロールを表示するcontrols属性も設定しています。

video要素を囲むdiv要素はレイアウト目的の要素なので、動画の再生には影響しません。

button要素

<ul class="video-nav">
  <li><button data-speed="0.25" class="video-speed">1/4の速度</button></li>
  <li><button data-speed="0.5" class="video-speed">半分の速度</button></li>
  <li><button data-speed="0.75" class="video-speed">3/4の速度</button></li>
  <li><button data-speed="1" class="video-speed">通常の速度</button></li>
</ul>

動画の速度を指定するために、button要素を使います。

ここではdata属性にdata-speedを設定しており、それぞれに動画の再生速度を以下のようにを指定しています。

  • data-speed="0.25":1/4の速度
  • data-speed="0.5":半分の速度
  • data-speed="0.75"0.75:3/4の速度
  • data-speed="1":通常の速度

また、JavaScriptでbutton要素を取得しやすいようにclass属性video-speedも設定しています。

処理の説明

STEP1 video要素とbutton要素を取得する

まずは、テーブルを変化させる関数をHTMLの読み込みと解析が完了した後で実行するように、イベントリスナーを設定します。

今回は関数名をvideoPlayRateController()とします。

document.addEventListener('DOMContentLoaded', videoPlayRateController);

次に、関数videoPlayRateController()を定義して、video要素とbutton要素を取得します。
取得した要素は、それぞれ変数videoElementspeedButtonsに格納します。

function videoPlayRateController() {
  // video要素を取得する
  const videoElement = document.getElementById('targetVideo');

  // button要素を取得する
  const speedButtons = document.querySelectorAll('.video-speed');
}

STEP2 video要素にイベントリスナーを設定する

動画はファイル容量が大きく、通常ダウンロードが完了するまで時間がかかります。そのため、addEventListener()メソッドでloadedmetadataイベントを監視して、メタデータが読み込まれたタイミングで処理が実行されるようにします。

// 動画のメタデータが読み込まれたら処理を実行する
videoElement.addEventListener('loadedmetadata', function() {

});

loadedmetadataイベントについては、MDNが参考になります。

button要素にイベントリスナーを設定する

動画のメタデータが読み込まれたら、button要素に addEventListener()メソッドでclickイベントを検知するようにします。

button要素はquerySelectorAll()メソッドを使って取得していますので、forEach()メソッドで取得したすべてのbutton要素にイベントリスナーを設定していきます。

// 動画のメタデータが読み込まれたら処理を実行する
videoElement.addEventListener('loadedmetadata', function() {

  // 取得したすべてのbutton要素をループ処理する
  speedButtons.forEach(item => {
    // button要素のclickイベントにイベントリスナーを設定する
    item.addEventListener('click', function () {

    });
  });

});

クリックされたbutton要素から、変更したい再生速度を取得する

次に、クリックされたbutton要素のdatasetプロパティを取得して、変数buttonへ格納します。

item.addEventListener('click', function () {
  // クリックされた要素のdatasetプロパティを取得して、変数buttonへ格納する
  const button = this.dataset;
});

thisはクリックされたbutton要素になりますので、this.datasetはクリックされたbutton要素の datasetプロパティを参照することになります。

datasetプロパティについてはMDNが参考になります。

取得したbuttonconsole.log()で出力すると、開発ツールのコンソールへ以下のようにカスタム属性のデータが出力されます。

出力されたカスタム属性のデータ

button要素にはカスタム属性でdata-speedが設定されています。
datasetプロパティで取得したデータは、接頭辞の data- を削除した名前がキーとなりますので、 button.speedでカスタム属性の値を参照できます。

例えば、console.log(button.speed)とすると、 コンソールへ以下のようにカスタム属性の値だけが出力されます。

カスタム属性の値だけが出力された

これで、変更したい変更速度を取得できますので、動画の再生速度を変える準備ができました。

取得した再生速度をvideo要素に反映する

動画の再生速度は、video要素の playbackRateプロパティに設定すると変更できます。

playbackRateプロパティはMDNが参考になります。

取得した再生速度を video要素のplaybackRateプロパティに設定します。

item.addEventListener('click', function () {
  const button = this.dataset;
  
  // video要素のplaybackRateプロパティに、指定された再生速度を設定する
  videoElement.playbackRate = button.speed;
});

これで一通り、機能を実装することができました。

完成したコード

完成したコードは以下のようになります。

function videoPlayRateController() {
  // video要素を取得する
  const videoElement = document.getElementById('targetVideo');

  // button要素を取得する
  const speedButtons = document.querySelectorAll('.video-speed');

  // 動画のメタデータが読み込まれたら処理を実行する
  videoElement.addEventListener('loadedmetadata', function() {

    // 取得したすべてのbutton要素をループ処理する
    speedButtons.forEach(item => {

      // button要素のclickイベントにイベントリスナーを設定する
      item.addEventListener('click', function () {

        // クリックされた要素のdatasetプロパティを取得して、変数buttonへ格納する
        let button = this.dataset;

        // video要素のplaybackRateプロパティに、指定された再生速度を設定する
        videoElement.playbackRate = button.speed;
      });
    });
  });
}

document.addEventListener('DOMContentLoaded', videoPlayRateController);

デモ

実際にどんな風に動作するのか、確認するためのデモページを用意しました。
以下のリンクから見ることができます。

https://tech-blog.tomono.jp/demo/changing-video-playback-speed/

まとめ

JavaScriptで再生速度を制御しましたが、あくまで簡易的に再生速度を変更しているため、場合によってはカクカクしてしまうことがあります。
クライアントとのすり合わせができたら、ちゃんと動画作った方が無難です。

今回は再生速度を「ゆっくり」に変更しましたが、指定を変えれば「倍速再生」なんてこともできますので、いろいろ試してみるのもいいですね。

よかったらシェアしてね!

この記事を書いた人

Webコーダーとして日々研鑽しています。
最近はJavaScriptで実現できるギミックが増えることに喜びながら、後方互換に悩むのが日課になっています。

目次
閉じる