« デジタルトキワ荘とSNS | メイン | 吉里吉里2 + キャプチャープラグイン = 動画作成環境 »

2008年05月28日

吉里吉里 その他の開発日誌:: プレイ画面の動画書き出し

    

前々から動画の書き出し機能があると便利かなぁと思いつつも、需要があるのかどうかわからなかったので、特に手をつけていなかったんだけど、ある程度は使う人がいそうなのと、自分も使いそうなので作ることにした。

AVI で書き出すものはごうさんが既に作っていたけれど、AVI 2.0未対応で無圧縮で保存されるので、あっという間に2GB超え&HDDへの書き出しが間に合ってなさげで、扱いづらかった。
そこで、AVI 2.0 対応のために DirectShow を使用して書き出すことを考えていたが面倒くさい。
あれこれ考えていて、ふと、WMV で書き出すものなら、さくっと出来る気がした。
という事で、コーディング開始。
さくっと…… と思ったけど、4時間ぐらいコーディングにかかった。
動画系の API は手続きが多いので、いろいろと面倒だった。
改めて考えると、DirectShow を使っても大差なかった気がする。

で、動かすと IWMWriter::BeginWriting でエラーが返ってくる。
内容は、Video codec エラー ( An unexpected error occurred with the video codec ) 。
さっぱり理由がわからない。
サンプルのソースといろいろ見比べたり、サンプルをデバッガで動かして入っている値を見たりして修正するも改善せず。
もしかして、スレッドを分離しているのが原因? と思って、IWMWriter::BeginWriting を初期化側のスレッドとあわせるとエラーにならなくなった。
別スレッドにしたらだめだったのか。
でも、実際の書き出し部分はスレッドが分かれていても問題ない様子。
バッググラウンドでひたすらエンコードしてもらう必要があるので、書き出し部分は別スレッドに出来ないと少し面倒なので、そこは良かった。

という事で、吉里吉里でゲーム画面の動画を書き出すプラグインを作った (結局1日かかった)。
が、ここではまだ音に対応していない。
吉里吉里の本体から直接音を得る方法はない様子。
本体をいじるか、ループバックで録音するか。
結局、ループバックで録音する方法で行くことにした。
エラー音やクリック音などが鳴ると、一緒に録音されてしまうという難点があるが、まあそこは諦めるという事で。
音のキャプチャー自体は、DirectShow を用いて行った。
ここは特に問題なかったのだが、WMV 書き出しでまたうまく行かない。
エンコードしていたら途中で落ちてしまう。
エラーは The writer has received samples whose presentation times differ by an amount greater than the maximum synchronization tolerance. You can set the synchronization tolerance by calling IWMWriterAdvanced::SetSyncTolerance. とか。
IWMWriterAdvanced::SetSyncTolerance で時間を長くすると、どんどんメモリに溜めていってなかなかエンコードしない様子。
で、終わったものをみてもうまく撮れていない。
なんなんだろう? といろいろと調べていたら、書き出し時に指定するストリーム番号が設定されていなかった……
絵だけや音だけの場合、そこがおかしくても問題ないけど、絵と音のように2つ以上ストリームがある場合はまずいようだ。
というか、設定する部分を見逃していた。
これで音も撮れるようになった。
結局2日かかった。

ただ、これには問題がある。
WMV をリアルタイムでエンコードする関係上、すごくCPUパワーが必要。
640x480 30FPS では、Core 2 Duo E6750 (2.66GHz)、メモリ 4G、HDD RAID 0 でも間に合わない。
動きの少ないシーンでは大丈夫のようだが、動画を再生しながらとなるとだめ。
エンコードが間に合わない場合、メモリ上にひたすら画像を溜めていくのんだけど、どうも吉里吉里側の描画の方が処理落ちして、それであんまりメモリには溜まらずに進んでいく様子。
プライオリティーをいじれば解決するかもしれないけど、4Gあっても1分程度しか撮れないのであまり効果はない。
これはクアッドコア必須か。
ただ、Video Codec を Windows Media Video V7 や V8 にすると負荷が下がり撮れる。
というか、マルチスレッド化されておらず片方のコアをめいっぱい使っているだけのように見えるが、撮れることは撮れている様子。
まあ、これでいいかなぁと思ったが、もっと速い CPU が欲しいと自分も周りもつぶやいていて、少し考える。

連番 JPEG 書き出しバージョンを作ろう!
JPEG エンコードは、SIMD 拡張版 IJG JPEG library を使う。
で、組む。
1時間ぐらいで出来た。
WAV でもいいから音入らない? と言われる。
で、組む。
さらに1時間ぐらいで出来た。
いい感じ。
Core 2 Duo E6750 (2.66GHz) で CPU 負荷が 20 ~ 30% 程度。
比較的軽い。
WMV よりも容量が大きくなってしまうのは仕方ないが、バラバラのファイルになるので HDD 容量のみの問題だから、容量が大きくなるのはそれほど問題ではない。

実際のゲーム画面がキャプチャーされたものを見る。
普通に見れる。
というか、ゲームじゃなくてこっちでもいいとか思ったり。
それはどうか…… と言う話なんだけど、字幕付きのアニメを見ている感覚で楽。
これはちょっと考えさせられた。

このプラグインは少し使い方が厄介なので、マニュアルを少し書かないといけない。
その辺り書けたら公開するかも。



投稿者 Takenori : 2008年05月28日 13:31



コメント

キャプチャー画面って……DVD-PGみたいですね。

投稿者 ひろにー : 2008年05月28日 14:13

DVD-PG をプレイしたことはないのですが、たぶんそんな感じなんじゃないかと思います。
自分としてはニコニコ動画で時々見るようなものと言う印象が強いです。
ニコニコ動画の影響で、ムービーで十分と思ってしまうのかもしれません。
ネタ用に作ると楽しそうです。

投稿者 Takenori : 2008年05月28日 23:17

IWMWriter::BeginWritingエラーが帰ってくる件ですが、書き込もうとしたスレッドでCoIntialize()/CoInitializeEx()されてますか?

COMでスレッドまたいでちゃんとうごかないっつーとアパートメント関連のような気がします・・・

投稿者 rayfill : 2008年05月28日 23:31

CoIntialize を呼んでやったら別スレッドでも動きました。
エントリーにも書いてある通り、IWMWriter::BeginWriting は初期化側のスレッドに持って行って解決していました。
IWMWriter::BeginWriting と IWMWriter::EndWriting は初期化側のスレッドに持っていってもなんら問題ないので、これでいいかなと。
ただ、IWMWriter::AllocateSample と INSSBuffer::GetBufferAndLength、IWMWriter::WriteSample は別スレッドのままですが問題なく動作していました。
CoIntialize は全てのスレッドで必要だったのですね。

まあ、WMV 書き出しはまだまだマシンパワーが足りないのでお蔵入りなのですが。。。

投稿者 Takenori : 2008年05月29日 00:30


comments powered by Disqus
Total : Today : Yesterday : なかのひと