RubyIZUMIはどう作られたか

年度末の怒濤の納品ラッシュでつぶれていましたが、ようやく書く時間がとれました。技術的な詳細よりはやや概略みたいなところをまず書いてみました。本当に細かいところもこのエントリに追記するかもです。あと自分的にはかつて無い長文です。。

RubyIZUMIとは

Rubyだけで書かれたオープンソースのMP4ビデオ/オーディオストリーミング専用のRTMPサーバーです。(ダウンロード等はこちらを参照RTMPは、Real Time Messaging Protocolの略で、Adobe Flash Playerでサポートしている、ビデオ/オーディオをストリーミングで再生可能な唯一のプロトコルです。このRTMPAdobe社の独自の規格で、仕様等はオープンになっていませんが、ほぼコンパチブルな仕様で製品化、またオープンソース化もされています。

なぜ作ったか

弊社ではvixy.tvというサービスを行っていて、いわばustream.tvのようなライブストリーミングのコミュニティサイトを運営しています。特徴としては、クライアントアプリ(vixy.tv broadcasterと呼んでいます)を配布していて、それがエンコーダー兼(RTMP)サーバになっているという点です。このRTMPサーバー(IZUMIと呼んでいます)については自社開発を行っています。現在は、H.263(正確にはSorenson Spark互換)のエンコーダーを使っていますが、これが画質的な面でそこそこなレベルなのですが、あまり満足できるものではありません。これはビデオコーデックとしては2世代位古い規格なためです。

そこで、その画質向上のために、ビデオコーデックとしては最新のH.264対応を行おうとしています。しかしH.264のストリーミング配信できる実装は、(開発を始めた当初は)FMS3しか無く、まずFMS3を買い取って配布するというのは不可能な話です。という訳で、FMS3の解析を始め、その過程で実際に動くものとしてまずRubyIZUMIを作りました。

MP4(H.264/AAC)対応の意味

Adobe社は昨年、FlashPlayer9の新バージョンのβ版(Moviestarというコードネーム)を公開しました。現在は、これは9,0,115,0というバージョンで正式版になっています。このMoviestarは何がトピックだったかというと、MP4(H.264/AAC)再生に対応したというものです。それまでのFlashPlayerのビデオのFLVは、フォーマット/コーデックともISO標準規格のものではなく、Adobe独自のものでしたが、Moviestarは、MP4というISO標準フォーマットにも対応をしたのです。さらに、ビデオはH.264、オーディオはAACという、これも両方ともISO標準になっているコーデックです。H.264は、Blue-rayやワンセグ放送などでも使われているように、非常に高品質な圧縮が出来ます。AACiTunes Storeが採用しているように、mp3よりも高品質な圧縮が出来ます。

ではなぜ標準が良いのか。一言でいうと、「(規格を理解できれば)誰でも参入できて、そこに競争が起こるから」ではないかと思います。ISO標準の面白いところは、再生する側のデコーダーの規格が決められていて、じつは圧縮する側のエンコーダーの規格が決められていないことです。つまり同じ圧縮ストリームで、別々のデコーダーを使っても、すべて同じように再生できることは保証するけど、その圧縮ストリームの作り方はデコーダーがデコードできれば何でも良いよ、ということです。デコーダー同士での競争は(この規格の精神だと)出来ないですが、エンコーダーメーカーには自由な裁量が与えられています。実際にDVDで使われているMPEG2の圧縮技術もDVDという大きなアプリケーションがあったため、エンコーダーメーカーはそれをいかに早く安く奇麗にできるかを競争した結果、現在のような品質が出来上がった、ということのようです。このDVDというアプリケーションと同様なことが、モバイルからHDまでをカバーしているH.264にも起きることが期待されています。

また、このH.264AACをMP4という組み合わせは、現在でも、iPodPSPや一部の携帯電話でも採用しているように、モバイルデバイスでも今後標準的な組み合わせなってくると予想されます。つまり、mp3がこれだけ普及しているのと同様に、MP4(H.264/AAC)は映像におけるmp3的なポジションになるのではないかと思っています。

なぜRuby

Rubyというと最近はRubyOnRailsでしょうか。僕も最近Railsを触ってその素晴らしさと、Rubyの持つパワーがようやく理解できました。(しかし、まだ十分使いこなせてないと思いますが..)Railsを触ってみて驚いたことの1つが、Webrickというサーバー機能までRubyで実装されているということでした。Rubyはもともとソケットプログラミングも結構簡単に書けるようになっているので、もっとネットワーク系の実装が増えてもいいと思います。というわけで、単にRubyで書きたかったとかそんな理由がまずありました。

で、まともなビデオストリーミングが出来る実装が知る限りなかったというのがもう一つです。じつはRTMPRuby実装は、RTMPオープンソース実装が出始めたころの初期から存在します。Yannickさんという方が作られたもので、今でもここからダウンロードできますRTMPを用いてチャットなどのテストが出来る実験実装です。基本的な仕組みはほとんどできているのではないかと思いますが、残念ながら映像ストリーミングは出来ません。*1それと、このYannickさん実装は、Javaの実装で有名なRed5の元になったものではないか(となると結構重要な仕事)と勝手に想像しています。ZIP中のファイルの日付を見ると、2005年の9月のようです。また、このRubyIZUMIでもYannickさんのコードが結構重要なところ(具体的にはAMFオブジェクトの生成/パーズ)で生きています。

どうやって作ったか(概要)

まず事前情報として、FMS3のデベロッパー版が配布された2008年1月末には、MP4での配信は、RTMPの仕様的にはそれほど変化がなさそうだ、という情報がありました。結果からするとこの情報はそれほど間違ってはいませんでしたが、全然変わっていない訳ではありませんでした。

まず、Yannickさんの実装を元に、サーバではなく、クライアントを作ってみました。これはいきなりサーバを作るよりは、クライアントから作った方が色々感じがつかめるんじゃないかとか思ったからです。ところが、これが結構大変でした。後から考えるとやり方がまずいのですが、これでちょっと無駄な時間を2週間位を消費してしまいました。(でも試験用のクライアントは副産物で出来ました)

そのあと、考えを変えて、サーバーを作ろうと思ったのですが、ともかく既存のosflash.orgなどにある情報はあまりあてにならない可能性もあったので、こういう場合どうしたら?とちょっと悩みました。ちょっと悩んだところ、サーバとクライアント間の全パケットをキャプチャしておいて、そのキャプチャしたものがリプレイできれば、そのままサーバーとして動くんではないか?という考えが浮かびました。非常に単純な考えなのですが、これがうまくいきました。

これは何が良かったかというと、そのリプレイ方式でクライアントで再生可能なものがが比較的短時間で出来たので、そこを足がかかりに解析や改変が出来たというのがありました。ちょっと変えて再生できないと、あ、これは削っちゃだめか、とか、このタイミングか、とかいうような。つまり基本的にほとんど最初から動く状態を保ったまま作業していた、というのが、精神衛生上非常に有利だったと思います。動くものと、動かないものの差分が常に少ない状態なので、バイナリ単位で比較すれば何がまずいのかもすぐ分かりました。

ビデオデータについてもこのキャプチャの中に入っていたのですが、ある程度リプレイ方式で全体が見えて来たあと、FMS3で送信したMP4ファイルと、ビデオ/オーディオのAMFパケットで送られるものとのバイナリの差分を取っていけば、何が変わっているのか、というのも分かります。結果的には、MP4から同様に切り出してビデオ/オーディオパケットを生成するのは比較的楽でした。MP4のもとになったQuickTime File Formatのパーサを8年位前にCで書いていたとかいうのもあります。

技術的差分

ハンドシェイク(あとで書く)
connect call(あとで書く)
H.264/AACのヘッダ(あとで書く)

*1:チャンクに対応していないので、大きいデータが送れない