音声と動画の加工

ウェブのよいところは、複数の技術をまとめて新しいものを作ることができる点です。ネイティブの音声や動画をブラウザー上で利用できるということは、これらのデータストリームを <canvas>WebGLWeb Audio API を利用して操作することで、音声や動画に直接変更を加えることができることを意味します。例えば音声にリバーブやコンプレッション効果をかけたり、動画にグレイスケールやセピアのフィルターをかけたりすることができます。この記事では、必要なことを説明するためのリファレンスを提供します。

動画の加工

動画の各フレームからピクセルの値を読むことができることは、とても有用です。

動画と Canvas

<canvas> はウェブページ上で描画を行うための有用な方法です。これは強力で、動画の処理にも有用です。

一般的なテクニックは次のようになります。

  1. <video> 要素から取得される動画の各フレームを、<canvas>要素に直接描画します。
  2. <canvas> 要素から間接的にデータを取得し、それを操作します。
  3. 操作したデータを「画面の」 <canvas> を通じて描画します。
  4. これを繰り返します。

動画プレーヤーと、 <canvas> 要素は次のように記述します。

<video id="my-video" controls="true" width="480" height="270" crossorigin="anonymous">
  <source src="http://jplayer.org/video/webm/Big_Buck_Bunny_Trailer.webm" type="video/webm">
  <source src="http://jplayer.org/video/m4v/Big_Buck_Bunny_Trailer.m4v" type="video/mp4">
</video>

<canvas id="my-canvas" width="480" height="270"></canvas>

操作は以下のように行います。この例では動画を白黒に変換しています。

var processor = {  
  timerCallback: function() {  
    if (this.video.paused || this.video.ended) {  
      return;  
    }  
    this.computeFrame();  
    var self = this;  
    setTimeout(function () {  
      self.timerCallback();  
    }, 16); // roughly 60 frames per second  
  },

  doLoad: function() {
    this.video = document.getElementById("my-video");
    this.c1 = document.getElementById("my-canvas");
    this.ctx1 = this.c1.getContext("2d");
    var self = this;  

    this.video.addEventListener("play", function() {
      self.width = self.video.width;  
      self.height = self.video.height;  
      self.timerCallback();
    }, false);
  },  

  computeFrame: function() {
    this.ctx1.drawImage(this.video, 0, 0, this.width, this.height);
    var frame = this.ctx1.getImageData(0, 0, this.width, this.height);
    var l = frame.data.length / 4;  

    for (var i = 0; i < l; i++) {
      var grey = (frame.data[i * 4 + 0] + frame.data[i * 4 + 1] + frame.data[i * 4 + 2]) / 3;

      frame.data[i * 4 + 0] = grey;
      frame.data[i * 4 + 1] = grey;
      frame.data[i * 4 + 2] = grey;
    }
    this.ctx1.putImageData(frame, 0, 0);

    return;
  }
};  

ページロード後に、次の関数を呼び出します。

processor.doLoad()

メモ: 潜在的なセキュリティ上の問題により、動画がコードと異なるドメインより配信されている場合、動画を配信しているサーバーで CORS (Cross Origin Resource Sharing) を有効にする必要があります。

メモ: 上記の例は、動画を canvas で操作するためだけのものです。対応しているブラウザーであれば、 setTimeout の代わりに requestAnimationFrame を利用することを効率のために検討したほうがよいでしょう。

動画と WebGL

WebGL は canvas に三次元画像を描画できる強力な API です。 <video> 要素と組み合わせることで、動画をテクチャとして利用できます。つまり三次元空間上に動画を配置し、再生できます。

例:

再生レート

音声や動画の再生レートは <audio> もしくは <video> 要素の playbackRate 属性で指定できます (HTMLMediaElement を参照のこと)。playbackRate には再生スピードの倍率を指定します。例えば 0.5 を指定すると半分のスピードで、 2 を指定すると倍速で再生されます。

HTML:

<video id="my-video" controls src="http://jplayer.org/video/m4v/Big_Buck_Bunny_Trailer.m4v"></video>

JavaScript:

var myVideo = document.getElementById('my-video');
myVideo.playbackRate = 2;

メモ: playbackRate は <audio> 要素と <video> 要素で利用できます。ただし再生スピードを変更できますが、ピッチは変更できません。音声のピッチを変更は、Web Audio API を利用すると可能です。詳しくは AudioBufferSourceNode.playbackRate 属性をご覧ください。

音声の加工

音声を加工するためには、 Web Audio API を利用することが一般的です。

音源の選択

<audio> 要素、もしくは <video> 要素の音声トラックを Web Audio API で操作する音源として利用できます。またオーディオバッファ、サイン波のようなオシレータからの出力、 WebRTCgetUserMedia からの音声ストリームも音源とできます。具体的な方法については以下のページを参照してください。

音声フィルター

Web Audio API では BiquadFilterNode を利用することで様々なフィルターやエフェクトを利用できます。

HTML:

<video id="my-video" controls src="myvideo.mp4" type="video/mp4"></video>

JavaScript:

var context     = new AudioContext(),
    audioSource = context.createMediaElementSource(document.getElementById("my-video")),
    filter      = context.createBiquadFilter();
audioSource.connect(filter);
filter.connect(context.destination);

// Configure filter
filter.type = "lowshelf";
filter.frequency.value = 1000;
filter.gain.value = 25;

メモ: CORS が有効になっていない環境では、動画はコードと同じドメイン上になければなりません。これはセキュリティ上の問題を避けるためです。

このノードでよく利用されるフィルターは以下の通りです。

  • ローパス: 閾値に指定された周波数より低い音は通過させ、高いものは減衰させます。
  • ハイパス: 閾値に指定された周波数より高い音は通過させ、低いものは減衰させます。
  • バンドパス: 指定された周波数帯の音は通過させ、それ以外は減衰させます。
  • ローシェルフ: 周波数に関わらず全ての音を通過させますが、閾値より低いものは増幅 (もしくは減衰) されます
  • ハイシェルフ: 周波数に関わらず全ての音を通過させますが、閾値より高いものは増幅 (もしくは減衰) されます
  • ピーキング: 周波数に関わらず全ての音を通過させますが、指定された周波数帯のものは増幅 (もしくは減衰) されます
  • ノッチ: 指定された周波数帯を除き、全ての音を通過させます
  • オールパス: 周波数に関わらず全ての音を通過させますが、幾つかの周波数間の相関係を変更します

メモ: 詳しくは BiquadFilterNode を参照してください。

たたみ込みとインパルス

ConvolverNode を利用することで、音声にインパルス応答を適用できます。インパルス応答とはハンドクラッフのような短い音のインパルスから作成された音のことです。インパルス応答はインパルスが作られた環境、例えばトンネル内で手を叩くことでエコーが起きる、を示します。

例:

var convolver = context.createConvolver();
convolver.buffer = this.impulseResponseBuffer;
// Connect the graph.
source.connect(convolver);
convolver.connect(context.destination);

メモ: 詳しくは ConvolverNode を参照してください。

メモ: 詳しくは ConvolverNode を参照してください。

空間的な音

Panner ノードを利用することで、音源の位置を操作できます。ソースコーンの位置だけでなく、その方向も指定できます。位置や方向は三次元空間上で指定します。

例:

var panner = context.createPanner();
panner.coneOuterGain = 0.2;
panner.coneOuterAngle = 120;
panner.coneInnerAngle = 0;

panner.connect(context.destination);
source.connect(panner);
source.start(0);
 
// Position the listener at the origin.
context.listener.setPosition(0, 0, 0);

メモ: GitHub リポジトリに例があります (ライブ版も)。

メモ: 詳細は ConvolverNodeを参照してください。

JavaScript によるコーデック

JavasCript でより低レベルでの音声操作が可能です。これを利用することで、オーディオコーデックを自作できます。

以下にフォーマットとそのコーデックのリストを示します。

メモ: AudioCogs でいくつかのデモを試せます。 AudioCogs は JavaScript でのコーデック実装を行うためのフレームワークである Aurora.js を提供しています。

チュートリアル

リファレンス

ドキュメントのタグと貢献者

このページの貢献者: mfuji09, chikoski
最終更新者: mfuji09,