【aviutl】#3 プラグインの入り口
閉じる
閉じる

【aviutl】#3 プラグインの入り口

2017-09-09 23:30
    この記事の要約
    ・フィルタプラグインの情報構造体
    ・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のフィルタプラグインとして登録できます。


    次回はもう少しディスクリプタとイベント関数について書いていこうと思います。
    広告
    コメントを書く
    コメントをするには、
    ログインして下さい。