●ISPR (ISPR-V3.0) 出力プラグインのできるまで
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ AviUtl には、入力プラグイン、出力プラグイン、フィルタプラグインの 3種類のプラグインがあります。 今回の目的は ISD ファイルを作成することですので、出力プラグインを 作ることにしました。 ispr規格にも様々なフォーマットがありますが、ここは単純に、非圧縮で ADPCM の ISPR-V3.0 固定で行きます。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ●AviUtl plugin programing AviUtl の PluginSDK は C で記述されていますので、VC++ 6.0 程度の 開発環境が必要です。 まず、最初に行ったのはサンプルPlugin『連番BMP出力』の確認です。 ISPR-V3.0 は非圧縮なので、これが構成的に最も近いと考えたのです。 始める前は、画像や音声がどのように渡されてくるのか心配でしたが 嬉しいことに AviUtl は画像も音声も圧縮なしの展開済生イメージで 提供してくれます。 更に音声データに至っては、全範囲から指定した範囲だけを切り出して 渡してくれますし、詳細情報は oip で示される構造体に入ってくる等、 至れり尽くせり。 以下に、ソースの一部抜粋を示しますが、何となく簡単そうでしょ? // 処理するフレーム数だけループする for( i = 0; i < oip->n; i++ ) { // 中断検知 if( oip->func_is_abort() ) break; // 残り時間の表示 oip->func_rest_time_disp(i,oip->n); // DIB形式で24bitの画像を得る pixelp = (unsigned char *)oip->func_get_video_ex(i,NULL); // 音声データがある場合は WAVデータを読み出す if ( oip->flag & OUTPUT_INFO_FLAG_AUDIO ) { // short 配列として WAVデータを得る audiop = (short *)oip->func_get_audio( sp_fir, cnt_fir, &audio_readed ); // ***ここで、得た WAV データから ADPCM データを作成*** } // ***ここで、ISD 形式の変換と出力を行えば良い*** // プレビュー画面の表示 oip->func_update_preview(); } プラグイン側では、単に与えられたフレーム数だけの処理をループで 処理すれば良いので、特に面倒なことはありません。 雛形どおりに、キャンセル処理、画面表示の更新処理を呼び出せば、 それで良いのです。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ●ISD出力のための画像変換処理 画像については、1フレーム毎に 24bit DIB Bitmap から、X680x0 GVRAM 形式 2byte へ変換すれば良いだけなので、簡単な処理です。 isprヘッダの作成と出力は、フレーム処理ループの前に済ませて おけば OK ですね。 先に書いたように DIB 24bit 形式で画像が得られるので、これを どうにか処理して 1pixel = 2byte に変換するのですが…今時の Windows機で動かすのですから、メモリにも CPU速度にも十二分な 余裕がありますので、AVI2ISD.x ver.0.04 の持っていた 4種類に 加え、更に 2種類の誤差拡散処理を追加してみました。 (計算が速いと、アイディアを気楽に組み込めるから良いです) [組み込んだ減色処理の一覧] ○bit切捨 : 8bitデータの下位3bitを落とし5bitにします ○2x2ディザ : 2x2パターンのディザを適用します ○4x4ディザ : 4x4パターンのディザを適用します ●2x2時間軸ディザ : フレーム毎に異なる2x2ディザを適用します ○時間軸誤差拡散 : フレーム間でピクセル誤差を拡散します(砂嵐度高) ○平面誤差拡散 : フレーム内で誤差拡散を行います この他、AVI2ISD.x の時と同様にガンマ補正機能も組み込み、 行間を空ける/空けないの指定(ISDBLANK相当)、縦横独立の センタリング(SETPOS相当)も装備しました。 輝度bit の扱いについては最後まで悩みましたが、例えばモノクロ 動画だった場合には 32階調→64階調 と大幅に貢献できることから 全ての処理で輝度bit の利用可否を選択できるようにしています。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ●ISD出力のための音声変換処理 音声変換処理は AVI2ISD.x ではやってなかった部分なので全て 新規に起こしています。基本的には次の流れになります。 1. AviUtl のコールで必要な範囲の音声データを得る 2. ステレオならばモノラル化する 3. サンプリング周波数を 15.625 kHz に変換する 4. PCM -> ADPCM 変換を行う モノラル化は単純に (Left + Right) / 2 で処理すれば良いのですが、 厄介なのが 3. のサンプリング周波数変換と、4. の ADPCM 変換です。 通常、サンプリング周波数変換は、src と dst の最小公倍数となる 周波数までアップ・サンプリング(データの間に 0 を埋め込む)し、 そこから目的の周波数へとダウン・サンプリング(データ間引き)を 行います。 しかし・・・普通は 44.1kHz とか 48.0kHz のデータが主であって、 15.625kHz なんて中途半端なものはありません。 実際、これらのメジャーなサンプリング周波数と 15.625kHz の最小 公倍数を求めると、あまりにも大きくなりすぎて、計算量が膨大に なってしまいます。 そこで、アップ・サンプリングはせずに dst / src となるように、 ブレゼンハムアルゴリズムの手法でデータを間引くことにしました。 そのまま間引いたのでは、折り返しノイズもあって満足に聞ける 音にはなりません(ぶちぶち言って満足に聞けない音です)ので、 2. と 3. の間に、カットオフ周波数 15.625 kHz のローパス・ フィルタを挿入する事で、これを回避しています。 PCM -> ADPCM 変換については、OKI ADPCM の詳細情報が公開されて いない事から不明な部分が多々ありますが、実用上問題ない程度の 変換方法が NetBSD のソース (msm6258.c) にありますので、これを 参考にして実装しています。 こうして、最終的には次の流れで 44.1kHz, 48.0kHz の音声データを 15.625kHz の ADPCM データに変換できるようになりました。 1. AviUtl のコールで必要な範囲の音声データを得る 2. ステレオならばモノラル化する 3. ローパスフィルタをかける(FIRデジタルフィルタ) 3. サンプリング周波数を、間引きで 15.625 kHz に変換する 4. PCM -> ADPCM 変換を行う ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ●その他 画像と音声の処理ができてしまえば、あとは細かいところの微調整と、 減色方法やガンマ補正、センタリング指定等を自由に変更できるように ダイアログを作成すれば完了です。 AviUtl Plugin は、それぞれに独自の設定ダイアログを持てるように なっており、サンプルのダイアログもありますので、こちらも簡単に 作成できます。本当に、AviUtl は良く作られてますねぇ。 こうして、ISD出力プラグイン ispr_output.auo が完成しました。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ●参考文献など NetBSD ソース (msm6258.c) AviUtl PluginSDK AviUtlのお部屋 http://spring-fragrance.mints.ne.jp/aviutl/ (EOF) |