--- title: 音声と動画の加工 slug: Web/Guide/Audio_and_video_manipulation tags: - Audio - Canvas - Examples - Guide - HTML5 - Media - Video - Web Audio API - WebGL - developer recommendation translation_of: Web/Guide/Audio_and_video_manipulation ---
ウェブのよいところは、複数の技術をまとめて新しいものを作ることができる点です。ネイティブの音声や動画をブラウザー上で利用できるということは、これらのデータストリームを {{htmlelement("canvas")}}、WebGL、Web Audio API を利用して操作することで、音声や動画に直接変更を加えることができることを意味します。例えば音声にリバーブやコンプレッション効果をかけたり、動画にグレイスケールやセピアのフィルターをかけたりすることができます。この記事では、必要なことを説明するためのリファレンスを提供します。
動画の各フレームからピクセルの値を読むことができることは、とても有用です。
{{htmlelement("canvas")}} 要素はウェブページ上でグラフィックを描画するための平面を提供します。これは強力で、動画の処理にも有用です。
一般的なテクニックは次のようになります。
<canvas>
要素からデータを取得し、それを加工します。<canvas>
を通じて描画します。例えば、動画を処理してグレースケールで表示する場合を考えてみましょう。この場合、ソース動画と出力のグレースケールのフレームの両方を表示します。通常、「動画をグレースケールで再生」機能を実装する場合、 display: none
を <video>
要素のスタイルに追加して、ソース動画が画面に描画されず、変更されたフレームのみが表示されるキャンバスが表示されるようにします。
動画プレイヤーと、 <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()
{{EmbedLiveSample("Video_and_canvas", '100%', 580)}}
これは、キャンバスを使用して動画フレームを加工する方法を示すとてもシンプルな例です。効率をよくするために、対応しているブラウザーで実行する場合は {{domxref("Window.requestAnimationFrame", "requestAnimationFrame()")}} を setTimeout()
の代わりに使用することを検討したほうがいいでしょう。
注: 潜在的なセキュリティ上の問題により、動画がコードと異なるドメインより配信されている場合、動画を配信しているサーバーで CORS (オリジン間リソース共有) を有効にする必要があります。
WebGL はキャンバスを使用してハードウェアアクセラレーションによる三次元や二次元の描画を行う強力な API です。 {{htmlelement("video")}} 要素と組み合わせることで、動画をテクチャとして利用できます。つまり三次元空間上に動画を配置し、再生できます。
{{EmbedGHLiveSample('webgl-examples/tutorial/sample8/index.html', 670, 510) }}
注: このデモのソースコードは GitHub にあります (ライブで表示も)。
音声や動画の再生速度は {{htmlelement("audio")}} もしくは {{htmlelement("video")}} 要素の {{domxref("HTMLMediaElement.playbackRate", "playbackRate")}} と呼ばれる属性を使用して調整することができます。 playbackRate
には再生速度の倍率を指定します。例えば 0.5 を指定すると半分の速度で、 2 を指定すると倍速で再生されます。
なお、 playbackRate
プロパティは <audio>
と <video>
の両方で動作しますが、どちらの場合も、再生速度を変更するものの音程は変更しません。音声の高さを変更するには、 Web Audio API を使用する必要があります。 {{domxref("AudioBufferSourceNode.playbackRate")}} プロパティを参照してください。
<video id="my-video" controls src="http://jplayer.org/video/m4v/Big_Buck_Bunny_Trailer.m4v"> </video>
var myVideo = document.getElementById('my-video'); myVideo.playbackRate = 2;
<video id="my-video" controls="true" width="480" height="270"> <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> <div class="playable-buttons"> <input id="edit" type="button" value="Edit" /> <input id="reset" type="button" value="Reset" /> </div> <textarea id="code" class="playable-code"> var myVideo = document.getElementById('my-video'); myVideo.playbackRate = 2;</textarea>
var textarea = document.getElementById('code'); var reset = document.getElementById('reset'); var edit = document.getElementById('edit'); var code = textarea.value; function setPlaybackRate() { eval(textarea.value); } reset.addEventListener('click', function() { textarea.value = code; setPlaybackRate(); }); edit.addEventListener('click', function() { textarea.focus(); }) textarea.addEventListener('input', setPlaybackRate); window.addEventListener('load', setPlaybackRate);
{{ EmbedLiveSample('Playable_code', 700, 425) }}
注: playbackRate のデモを試してみてください。
playbackRate
の一方で、音声を加工するためには Web Audio API を利用することが一般的です。
Web Audio API は、様々なソースから音声を受け取り、それを処理してを受信し、それを処理して音を処理した後に送信する出力機器を表す {{domxref("AudioDestinationNode")}} に送り出すことができます。
この音声ソースの場合... | この Web Audio ノード型を使用してくださいnode type |
---|---|
HTML の {{HTMLElement("audio")}} または {{HTMLElement("video")}} 要素の音声トラック | {{domxref("MediaElementAudioSourceNode")}} |
メモリ内の生の音声データバッファー | {{domxref("AudioBufferSourceNode")}} |
サイン波やその他の合成波形を生成するオシレーター | {{domxref("OscillatorNode")}} |
WebRTC の音声トラック (例えば {{domxref("MediaDevices.getUserMedia", "getUserMedia()")}} を使用して取得できるマイク入力) | {{domxref("MediaStreamAudioSourceNode")}} |
Web Audio API では {{domxref("BiquadFilterNode")}} を利用することで様々なフィルターやエフェクトを利用できます。
<video id="my-video" controls src="myvideo.mp4" type="video/mp4"> </video>
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;
<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> <div class="playable-buttons"> <input id="edit" type="button" value="Edit" /> <input id="reset" type="button" value="Reset" /> </div> <textarea id="code" class="playable-code"> filter.type = "lowshelf"; filter.frequency.value = 1000; filter.gain.value = 25;</textarea>
var context = new AudioContext(), audioSource = context.createMediaElementSource(document.getElementById("my-video")), filter = context.createBiquadFilter(); audioSource.connect(filter); filter.connect(context.destination); var textarea = document.getElementById('code'); var reset = document.getElementById('reset'); var edit = document.getElementById('edit'); var code = textarea.value; function setFilter() { eval(textarea.value); } reset.addEventListener('click', function() { textarea.value = code; setFilter(); }); edit.addEventListener('click', function() { textarea.focus(); }) textarea.addEventListener('input', setFilter); window.addEventListener('load', setFilter);
{{ EmbedLiveSample('Playable_code_2', 700, 425) }}
注: CORS が有効になっていない環境では、動画はコードと同じドメイン上になければなりません。これはセキュリティ上の問題を避けるためです。
このノードでよく利用されるフィルターは以下の通りです。
注: 詳しくは {{domxref("BiquadFilterNode")}} を参照してください。
{{domxref("ConvolverNode")}} を利用することで、音声にインパルス応答を適用することができます。インパルス応答とはハンドクラップのような短い音のインパルスから作成された音のことです。インパルス応答はインパルスが作られた環境 (例えばトンネル内で手を叩くことで発生するエコー) を示します。
var convolver = context.createConvolver(); convolver.buffer = this.impulseResponseBuffer; // Connect the graph. source.connect(convolver); convolver.connect(context.destination);
適用例としてはこの Codepen をご覧ください (ただし、とても、とてもくだらないです。小さな子どもが喜ぶくらいでしょう)。
パンナーノードを使用することで、音源の位置を操作できます。パンナーノード—{{domxref("PannerNode")}}—は、ソースコーンの位置だけでなく、その方向も指定することができます。位置や方向は三次元空間上で指定します。
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 リポジトリに例があります (ライブ版も)。
JavasCript でより低レベルでの音声操作が可能です。これを利用することで、オーディオコーデックを自作することができます。
以下にフォーマットとそのコーデックのリストを示します。