HTML5 Videoの対話的実行ツールを作ってみた。
新しいことを覚えて自分のものにする最も確実な方法は、自分の手を動かして実際に確かめることと思っています。新しいプログラミング言語を覚えるときも、ただ単に本を読んでいるだけではなかなか身につきませんが、実際にキーボードを叩いて結果を確認するだけでも、すごく身近に感じられるようになります。恐らく、実行してすぐ結果を確認できるということが学習効果を高めるのでしょう。
今回、HTML5のビデオ要素について、対話的にJavaScriptコマンドを実行して結果を確認できるようなものを作ってみました。画面イメージは下のようなものです。左側にJavaScriptのコードを入力できるshellもどきの領域があり、右側にビデオとその下にいくつかのボタンがあります。
JavaScriptの入力領域はbashライクなコマンド編集機能をつけました。キーバインドはemacsと同じです。Control-A,B,D,E,F,H,J,K,L,N,P,T,U,W,Yが使えます。ブラウザによってはpreventDefault()してもControlキーがそちらに取られてしまうものもあるようです。例えば、ChromeではC-nで別ウィンドウが開いてしまいます。その場合には、代わりに方向キーのDownが使えます。
入力した文字はJavaScriptでeval()され、結果が表示されます。videoという変数に右側に表示しているvideoオブジェクトがバインドされています。videoをいちいち入力しなくても済むように with (video) { eval(input) } がトップレベルになります。
ビデオの再生中の実行例を示します。
js> currentTime // 現在の再生時刻 17.684701 js> pause() // 一時停止 undefined js> muted = true // 音声ミュート true js> currentTime = 30 // 30秒の位置へジャンプ 30 js> src = "http://server/video.ogg" // 指定したURLのビデオを再生 http://server/video.ogg
上記ではビデオ要素から投げられてくるイベントのログは省略しましたが、イベントも表示されます。
js> currentTime=20 20 Event(13:26:56.322): seeking Event(13:26:56.894): suspend Event(13:26:56.959): seeked js>
currentTimeを20に設定して、先頭から20秒の位置にシークしようとすると、シーク開始にseekingが、シーク終了後にseekedイベントが発行されます。Eventの右の括弧の中の文字はイベント発生のtimeStampです(Firefoxは値がちょっと変)。ネットワークが非常の遅かったりすると、途中にsuspendイベントが複数発行されるようです。
イベントはW3Cでは以下のものが定義されています。一応、これらのイベントは全部拾えるようにしています。
abort canplay canplaythrough cuechange durationchange emptied ended enter error exit load loadeddata loadedmetadata loadstart pause play playing progress ratechange seeked seeking stalled suspend timeupdate volumechange waiting
このうち、progressとtimeupdateは再生中に頻繁に発生するため、shell領域には表示しないで、右側の再生時刻表示と、Progressカウンタに表示しています。
ビデオのsrc属性にURLをセットすると、別のビデオを再生することができますが、そのときには以下のようなイベントが発生することがわかります。どのイベントがどのような順番で発生するかはブラウザやビデオのコンテナ/コーデックによって多少異なるようです。
js> src="http://some.server/any/video.webm" http://some.server/any/video.webm Event(23:56:02.238): abort Event(23:56:02.247): emptied Event(23:56:02.251): loadstart Event(23:56:02.372): durationchange Event(23:56:02.372): loadedmetadata Event(23:56:02.372): loadeddata Event(23:56:02.372): canplay Event(23:56:02.372): canplaythrough Event(23:56:02.372): play Event(23:56:02.372): playing js>
一方、load, enter, exit, cuechangeはTextTrack(字幕など)に関するイベントですが、実装しているブラウザはまだないようです。
右下のplay(), pause()などのボタンは、コマンド入力と同じことをしているだけのものです。step()はコマ送りに近い動作をするもので、以下の関数です。
function step(tm) { tm = tm || 0.3; video.pause() var curr = video.currentTime + tm; video.currentTime = curr; return curr; }
つまり、ポーズして引数のtm秒(デフォルトは0.3)だけ進めます。
Fast/Slow/Normalはそれぞれ、10倍速、0.3倍速、通常再生になります。playbackRate属性にそれぞれの値を代入することで実現できます。ただし、Chrome, Firefox, Operaで確認したところ、実際に再生速度が変わったのはChromeだけでした。
また、videoオブジェクトのプロパティの値を全て表示するdump()という関数も組み込んであります。この出力結果を見ると分かりますが、playedやseekableなどのTimeRangeが実装されているのもChromeだけでした。
どのフォーマットに対応しているかの確認も対話的にできるので便利です。以下はFirefoxの例です。
js> canPlayType("video/webm") probably // WebMは再生できる js> canPlayType("video/ogg") maybe // Oggは再生できるかも js> canPlayType("video/ogg;codecs=theora") probably // OggでコーデックがTheoraなら再生できる js> canPlayType("video/mp4") // MP4は再生できない js>
実際の動作とソースコードはこちらからどうぞ。
- http://dl.dropbox.com/u/1865210/mindcat/video_playground.html
- http://dl.dropbox.com/u/1865210/mindcat/video_playground.js
キャプチャなどセキュリティに関するAPIは使っていないので、HTMLファイルとJavaScriptファイルをローカルにダウンロードして適当にビデオファイルを用意すれば、サーバを使わなくてもfile://で利用できます。ボタン[Video 1]〜[Video 5]に対するビデオのURLはJavaScript中で_$video1〜_$video5の変数に代入しているので、そこを変更すればお好みのビデオで動作を確認することができます。