【JavaScript】WebRTC 関連と通常の video 要素を紐づけて動画に対してできることを増やす

 通常の video 要素は動画の見る分には十分な機能が備わっていますが。細かいことをするには不十分です。特にフレーム回りは標準機能が全くといいほどないです。この状況に対して Firefox と MicrosoftEdge は独自実装のメソッドを生やすことで対応しています。

HTMLVideoElement – Web API | MDN#gecko_固有のプロパティ
HTMLVideoElement – Web API | MDN#microsoft_拡張

 もう非推奨になってしまっていますが Firefox 限定のコマ送りメソッドもあります。

HTMLMediaElement.seekToNextFrame() – Web APIs | MDN

 microsoft拡張ですが、いくらか試したり調べたところ InternetExplorer からの遺産であり Microsoft Edge が Chromium ベースになったあたりで相当数が消えていそうです。
 Google Chrome について特に MDN に記述はなく Can I use 等の他でも見つけられませんでした。

 そんな感じで未だ機能が不足しつつ、何が使えるのかも微妙なブラウザの動画機能ですが昨今らしい対応策が二つあります。一つは WebAssembly です。

WebAssembly | MDN

 WebAssembly はブラウザ上で使えるバイナリ言語です。このバイナリ言語は C/C++、Rust、Go などの JavaScript 以外の言語からもコンパイルでき、その言語界隈で積み上げられたライブラリ等の成果物をブラウザ上で使用できるようになります。例えば、FFmpeg のコードを WebAssembly 形式に出力でき、ブラウザ上でこれまで読むのが困難だったローカル動画ファイルのフレームやメタ情報といった部分(File オブジェクトから得られるバイナリを直にどうこうする必要があった)を FFmpeg 形式で簡易に読むことができます。

ffmpegwasm/ffmpeg.wasm: FFmpeg for browser and node, powered by WebAssembly

 いい参考例がありませんが、本来ブラウザ上で再生不可能な形式の動画ファイルをそれ用の動画プレイヤーのコードを使った WebAssembly で再生することもできそうです。

 もう一つは WebRTC です。WebRTC は Web Real-Time Communications の略です。これはビデオ会議の様に各ユーザーがリアルタイムにそれぞれのユーザーと音声と動画を送受信するための仕組みです。Zoom もこの仕組みを部分的に使っています。

WebRTC API – Web API | MDN

 WebRTC はその目的上、動画と音声のストリーミングを操作する機能に長けています。この動画を操作する機能を video 要素につなげることによって本来の video 要素には備わっていない処理ができるようになります。

 JavaScript 上で WebRTC と video 要素をつなげるには次の様に HTMLMediaElement から継承した caputureStream メソッドを使います。例えば次で WebRTC のストリーミングから動画の現在のフレーム情報を取得する準備ができます。

/** video 要素 */
const videoEl = document.querySelector('video');
/** video 要素を WebRTC のストリーミングに変換 */
// @see https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/captureStream
// @see https://developer.mozilla.org/ja/docs/Web/API/MediaStream
const videoStream = videoEl.captureStream();
// WebRTC のストリーミングから動画要素だけを抜き取り
// @see https://developer.mozilla.org/ja/docs/Web/API/MediaStream/getVideoTracks
// @see https://developer.mozilla.org/ja/docs/Web/API/MediaStreamTrack
const videoTrack = videoStream.getVideoTracks()[0];
// WebRTC のストリーミングの動画要素から読み取り用のストリームオブジェクトを得る
// @see https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrackProcessor
// @see https://developer.mozilla.org/ja/docs/Web/API/ReadableStream
const videoReadableStream = new MediaStreamTrackProcessor(videoTrack).readable;
// 読み取り用ストリームオブジェクトから流れているデータを読み取るためのオブジェクトを取得
// @see https://developer.mozilla.org/ja/docs/Web/API/ReadableStream/getReader
// @see https://developer.mozilla.org/ja/docs/Web/API/ReadableStreamDefaultReader
const videoReader = videoReadableStream.getReader();

 チェーンが長いですが、これで準備が整います。この状態で次の様にすることで動画が現在参照しているフレームについての情報を得ることができる様になります。

// 先述の videoReader 変数の使いまわし
videoReader.read().then(e=>console.log(e))
/*
  done: false,
  value: VideoFrame
    codedHeight: 368
    codedRect: DOMRectReadOnly
      bottom: 368
      height: 368
      left: 0
      right: 640
      top: 0
      width: 640
      X: 0
      y: 0
      [[Prototype]]: DOMRectReadOnly
    codedWidth: 640
    colorSpace: VideoColorSpace
      fullRange: null
      matrix: null
      primaries: null
      transfer: null
      [[Prototype]]: VideoColorSpace
    displayHeight: 360
    displayWidth: 640
    duration: 33367
    format: "1420"
    timestamp: 753030358
    visibleRect: DOMRectReadOnly
      bottom: 360
      height: 360
      left: 0
      right: 640
      top: 0
      width: 640
      X: 0
      y: 0
      [[Prototype]]: DOMRectReadOnly
    [[Prototype]]: VideoFrame
  [[Prototype]]: Object
 */

 フレームの大きさやフレームの表示時刻が得られます。例ではフレームのために ReadableStreamDefaultReader まで進みましたが、途中で経由したオブジェクトからまた別の方向に分岐して別のメソッドやプロパティを使うことによってもっと別の様々なこともできそうです。

 注意点として WebRTC 関連技術の実装段階はブラウザによってまちまちな点があります。サービスの対象とするブラウザとの兼ね合いは必須です。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG