-
【aviutl】#3 プラグインの入り口
この記事の要約
・フィルタプラグインの情報構造体
・aviutlにフィルタを認識させるには
・フィルタの情報構造体
まず、aviutlのフィルタプラグインは下記のような仕組みで実行されます。
起動時
1.aviutlからフィルタプラグインDLL(auf等)に対しFILTER_DLL構造体アドレスを要求
2.FILTER_DLL構造体アドレスを保持
3.返されたFILTER_DLL構造体のアドレスをたどって、フィルタ名や種類、パラメータを識別
4.種類に沿って決められたメニュー位置にフィルタタイトルを表示
パラメータ設定用のトラックバーなどを配置
「フィルタをロードした」ということでイベント時に関数をコール
フレーム再生中(編集時や出力時)
1.保持していたFILTER_DLL構造体アドレスから
「フレームデータ処理」の関数アドレスを取得
2.フレーム情報とパラメータの現在値(対象フレームにおける値)を引数に関数コール
3.拡張編集の場合は上のトラックに配置されたオブジェクトやフィルタから順に処理
プロジェクトの保存・呼び出し
1.保持していたFILTER_DLL構造体アドレスから
「プロジェクトの保存/呼出時処理」の関数アドレスを取得
2.設定パラメータのデータを引数に関数コール
といった具合にFILTER_DLL構造体を基点に処理が行われます。
FILTER_DLL構造体には、フィルタ処理で用いるパラメータや、
イベント毎の関数それぞれのアドレスを設定しておきます。
イベントとは、
・フィルタがロードされたタイミング(func_init)
・1フレーム分の再生データが必要な時(func_proc)
・aviutlのプロジェクトが保存される時(func_project_save)
・aviutlのメインウィンドウにメッセージが送られた時(func_WndProc)
などがあります。
これからの記事ではFILTER_DLL構造体のことをディスクリプタと呼ぶことにします。
ディスクリプタとは制御するシステム(フィルタプラグインの場合はaviutl本体)が
対象のオブジェクト(各フィルタプラグイン)を識別するための情報の集まりを指します。
識別のための情報は、それぞれ「ディスクリプタの先頭アドレスからnバイト目」という
感じで位置が決まっています。(位置は構造体の定義によって決められます)
→雰囲気を知るにはファイルディスクリプタ、ゲートディスクリプタなど参照
ここからはSDKに付属のfilter.hを見ながら読み進めることをお勧めします。
aviutlのフィルタプラグインのディスクリプタ(FILTER_DLL構造体)には
関数アドレス、プラグイン名情報、トラックバーやチェックボックス情報
が含まれます。
さて、ディスクリプタをaviutlに登録させるには次の関数をDLLに用意しておきます。
1.
EXTERN_C __declspec(dllexport) FILTER_DLL* __stdcall GetFilterTable(void);
2.
EXTERN_C __declspec(dllexport) FILTER_DLL** __stdcall GetFilterTableList(void);
1.はプラグインDLLが提供するフィルタが1つ(ディスクリプタが1つ)の時、
2.は複数のフィルタを提供する場合(複数のディスクリプタ)の時に呼ばれます。
aviutlからはどちらの関数があるかをチェックしますので
作成するフィルタプラグインに合う片方だけ定義すればOKです。
(大は小を兼ねるともいうので2.の方だけでもいい気がしますが…)
だいたいの意訳ですが
EXTERN_C すなわちextern "C"、(C++式ではなく)C言語の命名規則を用います
__declspec(dllexport) DLLからシンボルをエクスポートします
__stdcall Windowsの標準呼び出し規約でコールしてください
1.はFILTER_DLLのポインタなので定義した構造体変数のアドレスを返せばOKです。
2.はダブルポインタ、言い換えればポインタの配列のアドレスを返します。
FILTER_DLL filter1, filter2, filter3;
とある定義した場合(とても雑ですが)、1.であれば
return ( &filter1 );
でFILTER_DLL構造体のアドレスを返し、2.の場合では配列にして
FILTER_DLL *filtertable[] = { &filter1, &filter2, &filter3, NULL };
return (&filtertable);
でポインタ配列のアドレスを返します。
最後のNULLは必要です。
aviutlからは配列の先頭アドレスしかわからないので、
どこまでが有効なアドレスかが判らないためです。
NULLであれば有効なアドレスとしては取りえない値なので終端として識別できます。
ちなみに、FILTER構造体ですが、こちらはおもに呼ばれた側向けの構造体です。
FILTER_DLLと基本的には同じ構造体です。
多くのイベント用関数の引数には FILTER *fp というパラメータを取ります。
aviutlからフィルタの関数アドレスを参照して関数コールしたように、
逆にEXFUNC *exfuncメンバからaviutl側の処理関数のアドレスを参照します。
fp->exfunc->get_frame_n(editp);
ここで渡しているedhitpはエディットハンドルと呼ばれるポインタで、
引数に与えられる情報です。
void *型のため、指されているアドレス情報しかわからず、
先のメモリ領域の構造は知ることはできません。
(aviutl側で使うので知る必要もありません、ということですね)
最低限、FILTER_DLL構造体(ディスクリプタ)のアドレスを返せば
aviutlのフィルタプラグインとして登録できます。
次回はもう少しディスクリプタとイベント関数について書いていこうと思います。 -
【aviutl】#2 開発環境とコーディング方針
さて、今回は開発環境と設計方針についてメモしておきます。
開発環境はMicrosoft Visual Studio 2017 communityを使用しています。
githubのリポジトリアクセス機能も付いていますので外部アプリは使いません。
言語はc++で記述します。
Aviutlの動作確認は前回同様、AviUt 1.00 + 拡張編集プラグイン 0.92で進めます。
1つのアーカイブにパッケージされているものが配布されているのでそのまま使用します。
Myルール的なこと
・gitにコミットする際はマーカーくらいはつけよう
add ファイルの追加
del ファイル削除
update データの更新
upgrade バージョンアップなど上位版への更新
fix 不具合修正
今後これらのマーカーは増えるかもしれません。
・ドキュメンテーションはなるべく行う
doxygen向けのタグ付けをして、後で見てそれなりに読めるソースコードを目指します。
githubと連携してドキュメント生成できるサービスがあるのかは不明。
設計方針
・filter.hはこのプロジェクト用に書きなおす →完了
namespaceで囲って、多重インクルードガードも設定して、多少読みやすくした。
・クラス分けは再利用性よりは管理のしやすさを重視する
共通、またはベースとなるクラス群はcommonフォルダにまとめる。
派生したクラス類はその目的単位ごとにフォルダ分けして管理する。
・コミット回数やメモの書き方はあまり気にしない
本当はブランチ切ってある程度推敲してからmasterにマージかけるべきなのでしょうけれど
まずは作業フローを覚えるために気にせずに更新していく方向で。
・プルリクエストなど外部開発者からの協力/情報は目を通す
機能自体使ったことないけれど、取り入れられるか判断して改善していく。
・急がない。
ひとまず動くものは出してあるのだから急ぐ必要は無い。じっくりやろう。
ゆったりまったりやっていきたいと思います。
-
【aviutl】#1 フィルタプラグイン開発始めます
みなさん おはこんばんちは。ししです。
aviutl用の音声フィルタプラグイン
「VSTホストプラグイン+α」→ sm29926034
を公開してもう1年近く経ちました。
バイナリはこちら
https://github.com/Aios-Ciao/VSThost4aviutl
VSThost4aviutl.zip バイナリセット登録 ←これをダウンロード。
おかげさまで2525再生!!も達成できてとてもうれしく思っています。
広告や解説動画のおかげですね。感謝感謝です。
ところで、公開しているフィルタプラグインのソースですが、
全面的にリファインを始めました。
そこで久しぶりにこのブロマガの機能をつかって
設計方針のメモや技術的なところの相談を残していきたいなーと考えています。
機能提案や不具合報告はもちろん、雑談でも構いませんので
動画やブロマガ記事へコメント残していただけると励みになります。
とりあえず動く形になったものをずるずると公開し続けているのもちょっと恥ずかしいので、
もう少し丁寧に再設計してみようと思います。
リファインが完了したらソース公開は新しい方をメインにします。
フィルタプラグインの公開は継続しますのでご安心を。
ちょこちょこ更新していこうと思いますので
これからもどうぞよろしくお願いしますm(_ _)m
広告
1 / 10