くまりゅう日記

もっと過去の日記
[.NET | BeOS | Blender | COLLADA | fossil | mono | monotone | NPR | OpenGL | PeerCastStation | Riko | Ruby | Silverlight | TRPG | XNA | ゲーム | ゲーム作り | プログラム | | 模型]

2012-08-06

日記

やっぱり何もやってないのに土日が終わってしまった。

と思ったが、イベントサイトの見た目修正してたり本読んだりアニメ見たりしてたので何もしてなかったわけでもないか。

平日にもうちょい時間作れればいいんだが。ちょっとだらだらしすぎである。

LOOX UのDC入力端子の接触が悪くなってしまった。以前から外部バッテリとの接触は悪かったんだが、純正ACアダプタのと接触もいまいちな感じに。端子綺麗にしてみればなんとかなるだろうか。

[PeerCastStation] FLV配信できるだろうか

FLV配信を以前実装したが、これちゃんと配信できるのか試してなかったのでやってみる。

と思ったんだが、FLVをライブストリーミングするのが意外に難しかった。 VLCで画面取り込みしてストリーム再生でFLV+H.264をhttp出力すればいいだろとやってみるが全然上手くいかん。というか見た目から上手くいってるかどうかすらわからんのでしばらくとても困ってた。

エラーメッセージを見るとなんかのキャッシュを増やしてみたらどうよ的なのが出てるので、ストリームアウトのキャッシュ設定を増やしてみたらいけた。が、2回目やったら駄目だったり。再生も怪しかったり。なんかVLCのストリーミング周りは送受信共に不安定な気がするぞ。

上手くいく場合はあるものの、エンコが全く間に合ってないとの警告が出まくってて確かに全くフレームが出力されてないようだ。x264重すぎるんだぜ。 でもVP6とか出力できないし、H.263指定してもエンコーダが開けないと言われてしまう。

x264じゃなくてffmpegでH.264エンコできないか調べたがやはりx264経由なようだ。そりゃそうか。だがよく見たらFlash Screen VideoとかFLV(H.263)とかのエンコに対応してるじゃないですか。これつかえるな。てかVLCではUIで対応してないのか。

ffmpegではhttpサーバになってくれないのでffserverを使おう。と思ったらWindows版のバイナリ無いじゃないですか。ケチだなー、ってcygwinならなんとかビルドできるかもしれない的なことが書いてあった。そか、Windowsネイティブではビルドできないなら仕方ない。

どうしようか悩んでいたが、ffmpegからパイプに出力して自前でHTTPで配信すればいいんじゃないかとアドバイスを貰った。うん、それは考えたんだけどめんどくせぇなって。しかし悩んでても何も解決しないのは確かなのでやってみる。ffmpegのコマンドを組み立てるのは後回しにして、とりあえず適当なファイルを要求されたら固定のコマンド起動してその出力をHTTP Responseのbodyとして出力するだけのサーバをRubyで書いた。超簡単だった。

あとはパイプに出力する方法を調べようとしたら、出力先に-を指定したらいけたと教えてもらったのでそれで。やってみたら無事上手くいった。めんどくせぇと悩んでるより手動かした方が早かったね。

ここまでで相当時間かかったんだが、ここからが本番だ。PeerCastStationでFLV配信して、パッチ当てたPeerCastIMでリレー&視聴できればOK。

やってみたらリレー接続はできても一瞬でエラーになっちゃうな。PeerCastIMの方を調べていったらパケットの書き込みが長すぎてエラー?!受信してる場所なんですけど。読み込んだパケットを一旦メモリにコピる際に1Atomのデータ超は最大16KBytes固定と決め打ってるが、それを越えてエラーになっていた。受信はできてるのにメモリ内のコピーでエラーかよ。う、うぜえ……。ネストするデータ構造でさらにビデオのパケットも入るのに最大16kてちょっと短いだろそれ。こういうところがあるからオリジナルPeerCastの出来はいまいちなんだよなぁ。いやまあPeerCastStationも他人のことは言ってられないか。

どう解決したものか悩んだが、そんな部分はそうそう変えるわけにいかないので送信側をなんとかするしかないんだよね。でも今はとりあえずその先が動けばいいので16kきめうちなところを160kにして受信できるようにした。さすがに1パケット160kはそう簡単に越えないし。

これで上手くリレーできるようになったがVLCではうんともすんとも言わず再生されない。仕方ないのでFlashベースのプレイヤーで再生してみるか、とごにょごにょ作業してたらいつのまにかVLCで再生されてた。あれ、再生開始するまでに数分かかるようだ。なんかおかしいなこれは……。 VLCだけの問題かと思ったがFlashベースのプレイヤーも上手く再生されない。FlashベースのプレイヤーはPeerCastStation直だと上手くいくのでPeerCastIM介すと駄目かな。なんかskipがどうこうといったログが出てるのでリレー出力でパケットのPositionが上手くないのかもな。これってどうすりゃいいんだかよくわからんな。地道に調べるか。

そんなところで日曜の作業は終わり。

FLVでの配信自体はできそうだが、もうちょいバグ取りが必要そう。Atomの長さが16k越えちゃいけないのはきついなぁ。読み込んだビデオパケットが16k越えてたら分割しろってことでしょ。あ、何も考えずに分割するだけだから簡単か。

エンコード→ストリーミング自体はffmpeg+簡易ストリーミングサーバで大丈夫な気がする。設定が大変なのでフロントエンドは必要になるだろうな。コーデックとしてH.264はちょっと試した限りでは重すぎるが、もしかしたらちゃんと設定すればいけるのかもしれない。flv、というかH.263はそこまで重くなかった。プログラミング配信してるとFlashScreenVideoが気になるけどこれは実用になるのかな……?

プレイヤーが何気に難しい。普段みんなが使ってるのはWindowsMediaPlayerかDirectShowベースのプレイヤーだろう。これでFLV再生しようとしたらSplitterとCodecを別途入れないといけないよなぁ。Flashベースのプレイヤーを用意すればいいんだが、現状無いし。

とはいえすぐにFLV配信が流行るとは全く思ってないんでべつに良いと言えばいいんだけどね。選択肢増やして出来ることが増えてればそれでいいので。

[Ruby] IronRubyのat_exitブロックで割り込みが効かない

PeerCastStationのテストはIronRubyで書いてるんですけど、なんかtimeoutが使えなくて困るんすよ。

調べて最小ケースまで追い込んでみると、at_exitブロック内でのtimeoutが、もっと言うとat_exitブロック内でメインスレッドへのThread#raiseが動いてないようだ。

IronRubyのソースまで追い掛けてみると、Thread#raiseはCLRのThread.Abortで実現されていた。Thread.Abortは指定したスレッドでいきなりThreadAbortExceptionを発生させるやつ。投げる例外が固定だけどRubyのThread#raiseと似てるのでこれ使って実装するのはごく自然だね。

一方at_exitブロックがどこで実行されてるのか調べると、スクリプト実行後の(C#の)finallyブロック内だった。at_exitで登録したブロックは例外で終了した時も実行されるので、これまた自然ですね。

さてThread.Abortのドキュメントを見ると、スレッドが一部の保護された領域内を実行中は止まりません的なことが書いてある。保護された領域とはたとえば、catchブロック内やfinallyブロック内である。ぎゃー!at_exitブロックが実行されるのはfinally内なのでThread.Abortで止まらないじゃないですか!!

他にThreadAbortExceptionを発生させるものとしてキーボードからの割り込み、つまりCtrl+Cがあるようだ。これもat_exitブロック内では割り込めない。 なんか以前からテストをCtrl+Cで止めらんないなーと思ってたんですけどこれが原因か。

解決方法だけど……上手いこと思いつかなかった。上で書いたようにThread#raiseをThread.Abortで実現するのも、at_exitブロックをfinally内で実行するのも、ごく真っ当な作りなので回避しようとすると、おそらくとても面倒な作りをしないといけなさそう。簡単にやるなら、スクリプト本体実行中の例外を一旦catchして保存しておいて、at_exitブロック実行してから保存されていた例外があれば投げなおすようにConsoleHostクラスを直すくらいか。これの問題点は一旦例外を受け取って投げ直すので、例外を一段ラップしないといけないこと。いまいちよろしくない。 あとIronRuby固有ならともかく、Microsoft.Scripting.dllのクラスなのでIronPythonとかにも影響でるんで、これはパッチ作っても通しづらいだろうなぁ。

Rubyレベルで回避するならテストの実行をat_exitブロックで行なわなければいい。標準のtest/unit使うとMiniTestになるのでちょっと綺麗にはいかないがまあ出来なくもないし、最新のtest-unit入れて使えばなおよし。俺はこの方法で回避するか。RakeならTestTaskでrunner指定すればいいようだ。

というわけでIronRubyではat_exitに注意な。at_exitで時間かかることやらせるとtimeoutとかCtrl+Cとか動かなくてめんどくなるよ。


ページのトップへ | トップ «前の日記(2012-07-31) 最新 次の日記(2012-08-13)» | 編集 | kumaryu.net by kumaryu