2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Delphi】AviUtl2 用の汎用プラグイン(.aux2)を自作してみた

Posted at

🎯 はじめに

AviUtl2 beta17 SDKに含まれる plugin2.h を元に、
Delphi で動作する汎用プラグイン(拡張子 .aux2)を実装しました。

このサンプルでは、AviUtl2 上に独自ウィンドウを追加し、
ボタン操作でシーン情報(フレーム/レイヤーなど)を取得・表示する最小構成になっています。


🧠 背景と目的

AviUtl2 SDK では以下の 5 種類のプラグイン形式が定義されています。

種類 拡張子 役割
Input Plugin .aui2 ファイル入力(画像・動画など)
Output Plugin .auo2 ファイル出力
Filter Plugin .auf2 画像や音声の加工
Script Module .mod2 Luaスクリプト拡張
Generic Plugin .aux2 アプリ全体の拡張(ウィンドウ・メニューなど)

今回はその中の Generic Plugin (.aux2) を使用しています。
これは AviUtl2 にウィンドウやボタンなどの「機能拡張UI」を追加できる仕組みで、
入力/出力/フィルタとは独立して動作します。


💡 実装方針

  • Delphi で plugin2.h の構造体を再現
  • RegisterPlugin() から AviUtl2 にウィンドウを登録
  • CallEditSection() 経由で AviUtl2 の編集情報に安全にアクセス
  • 取得結果をウィンドウ上のラベルやメッセージボックスに表示

AviUtl2 側から呼び出されるため、DLL は通常の EXE とは異なり
AviUtl2 実行中にロードされる動的モジュールとして扱われます。


🧩 サンプルコード

Delphi での主要部分は以下の通りです。


library AviUtl2Plugin;

uses
  Windows, Messages, SysUtils, Classes;

const
  SampleWindowName = 'DelphiPSDControl';
  IDC_BUTTON_INFO  = 1001;
  IDC_LABEL_INFO   = 1002;

type
  TObjectHandle = Pointer;

  TObjectFrameInfo = record
    StartFrame: Integer;
    EndFrame: Integer;
  end;

  PEditInfo = ^TEditInfo;
  TEditInfo = record
    Width, Height: Integer;
    Rate, Scale: Integer;
    SampleRate: Integer;
    Frame, Layer: Integer;
    FrameMax, LayerMax: Integer;
  end;

  PEditSection = ^TEditSection;
  TEditSection = record
    Info: PEditInfo;
    CreateObjectFromAlias: function(Alias: PAnsiChar; Layer, Frame, Length: Integer): TObjectHandle; cdecl;
    FindObject: function(Layer, Frame: Integer): TObjectHandle; cdecl;
    GetObjectFrameInfo: function(Obj: TObjectHandle): TObjectFrameInfo; cdecl;
  end;

  TProcEditSection = procedure(Edit: PEditSection); cdecl;

  PEditHandle = ^TEditHandle;
  TEditHandle = record
    CallEditSection: function(FuncProcEdit: TProcEditSection): BOOL; cdecl;
  end;

  PInputPluginTable  = Pointer;
  POutputPluginTable = Pointer;
  PFilterPluginTable = Pointer;
  PScriptModuleTable = Pointer;

  PHOST_APP_TABLE = ^THostAppTable;
  THostAppTable = record
    SetPluginInformation: procedure(Info: PWideChar); cdecl;
    RegisterInputPlugin:  procedure(InputTable:  PInputPluginTable);  cdecl;
    RegisterOutputPlugin: procedure(OutputTable: POutputPluginTable); cdecl;
    RegisterFilterPlugin: procedure(FilterTable: PFilterPluginTable); cdecl;
    RegisterScriptModule: procedure(ScriptTable: PScriptModuleTable); cdecl;
    RegisterImportMenu:   procedure(Name: PWideChar; Func: TProcEditSection); cdecl;
    RegisterExportMenu:   procedure(Name: PWideChar; Func: TProcEditSection); cdecl;
    RegisterWindowClient: procedure(Name: PWideChar; HWnd: HWND); cdecl;
    CreateEditHandle:     function(): PEditHandle; cdecl;
  end;

var
  EditHandle: PEditHandle = nil;
  LabelWnd  : HWND = 0;

{-------------------------------------------------------------}
{ シーン情報取得とラベル更新                                 }
{-------------------------------------------------------------}
procedure ShowSceneInfo(Edit: PEditSection); cdecl;
var
  Info: PEditInfo;
  S: string;
begin
  if (Edit = nil) or (Edit^.Info = nil) then Exit;
  Info := Edit^.Info;

  S := Format('Scene Info:'#13#10 +
              'Size: %d x %d'#13#10 +
              'Rate/Scale: %d / %d'#13#10 +
              'Frame: %d / %d'#13#10 +
              'Layer: %d / %d',
              [Info^.Width, Info^.Height,
               Info^.Rate, Info^.Scale,
               Info^.Frame, Info^.FrameMax,
               Info^.Layer, Info^.LayerMax]);

  if LabelWnd <> 0 then
    SetWindowTextW(LabelWnd, PWideChar(WideString(S)));
end;

{-------------------------------------------------------------}
{ ウィンドウプロシージャ                                     }
{-------------------------------------------------------------}
function WndProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
  case uMsg of
    WM_COMMAND:
      if LOWORD(wParam) = IDC_BUTTON_INFO then
      begin
        if Assigned(EditHandle) then
          EditHandle^.CallEditSection(@ShowSceneInfo)
        else
          MessageBox(hWnd, 'EditHandleが無効です。', 'Error', MB_ICONERROR);
        Exit(0);
      end;
  end;
  Result := DefWindowProc(hWnd, uMsg, wParam, lParam);
end;

{-------------------------------------------------------------}
{ プラグイン登録関数(AviUtl2本体から呼び出される)        }
{-------------------------------------------------------------}
procedure RegisterPlugin(Host: PHOST_APP_TABLE); cdecl;
var
  WndClass: WNDCLASSEXW;
  MainWnd: HWND;
begin
  Host^.SetPluginInformation('Delphi AviUtl2 Scene Info Viewer');

  // ウィンドウクラス登録
  FillChar(WndClass, SizeOf(WndClass), 0);
  WndClass.cbSize := SizeOf(WndClass);
  WndClass.lpszClassName := SampleWindowName;
  WndClass.lpfnWndProc := @WndProc;
  WndClass.hInstance := HInstance;
  WndClass.hbrBackground := GetSysColorBrush(COLOR_WINDOW);
  WndClass.hCursor := LoadCursor(0, IDC_ARROW);
  RegisterClassExW(WndClass);

  // メインウィンドウ作成
  MainWnd := CreateWindowExW(
    0,                  // 拡張スタイル(0なら特に無し)
    SampleWindowName,   // クラス名
    'Scene Info Viewer',// ウィンドウタイトル(AviUtl内では使われない)
    WS_POPUP,           // スタイル(RegisterWindowClientで子ウィンドウ化される)
    CW_USEDEFAULT,      // X座標(AviUtlが配置を制御するので無視される)
    CW_USEDEFAULT,      // Y座標(同上)
    260,                // ★ 幅(Width)
    140,                // ★ 高さ(Height)
    0, 0, HInstance, nil
  );

  // ------------------------------------------------------
  // ボタンを作成
  // ------------------------------------------------------
  CreateWindowExW(
    0,                      // 拡張スタイル(特になし)
    'BUTTON',               // クラス名(ボタン)
    'シーン情報取得',       // ボタンに表示する文字列
    WS_VISIBLE or WS_CHILD or BS_PUSHBUTTON, // スタイル:子ウィンドウ+押しボタン
    30,                     // X座標(左から30px)
    15,                     // Y座標(上から15px)
    200,                    // 幅(260px全体のうち中央寄り)
    30,                     // 高さ(一般的なボタン高さ)
    MainWnd,                // 親ウィンドウハンドル
    IDC_BUTTON_INFO,        // コントロールID
    HInstance,              // インスタンスハンドル
    nil                     // 追加パラメータ(未使用)
  );

  // ------------------------------------------------------
  // ラベルを作成
  // ------------------------------------------------------
  LabelWnd := CreateWindowExW(
    0,                      // 拡張スタイル(特になし)
    'STATIC',               // クラス名(静的テキスト)
    '未取得',               // 初期テキスト
    WS_VISIBLE or WS_CHILD or SS_LEFT or SS_NOTIFY, // 左寄せ・クリック通知あり
    30,                     // X座標(左から30px)
    55,                     // Y座標(ボタンの下、約40px下げ)
    200,                    // 幅(ボタンと同じ200px)
    120,                    // 高さ(複数行テキストのため余裕を確保)
    MainWnd,                // 親ウィンドウハンドル
    IDC_LABEL_INFO,         // コントロールID
    HInstance,              // インスタンスハンドル
    nil                     // 追加パラメータ(未使用)
  );

  // AviUtl2本体へ登録
  Host^.RegisterWindowClient(SampleWindowName, MainWnd);

  // 編集ハンドルを取得
  EditHandle := Host^.CreateEditHandle;
end;

exports
  RegisterPlugin;

begin
end.

AviUtl2 でロードすると、
独自ウィンドウ内に「シーン情報取得」ボタンが追加されます。


🖥️ 実行結果

ボタンを押すと、AviUtl2 の現在シーン情報を取得して
メッセージボックスやラベルに表示します。
image.png


⚙️ ビルド手順

  1. AviUtl2Plugin.dpr を Delphi で開く
  2. Win32 DLL としてビルド
  3. 出力ファイルをリネーム:
    AviUtl2Plugin.dll → AviUtl2Plugin.aux2
    
  4. AviUtl2Plugin.aux2AviUtl2 フォルダに配置
  5. AviUtl2 起動後、「ウィンドウクライアント」に追加されていることを確認

🧱 応用可能性

この .aux2 形式は「アプリ全体の拡張」に相当するため、
複数のプラグインを統合する UI ハブとしても活用できます。

たとえば:

  • .aui2(入力プラグイン)で PSD ファイルを読み込み
  • .aux2(汎用プラグイン)でレイヤー表示/非表示設定を制御
  • .auf2(フィルタプラグイン)で描画調整を行う

という構成を取ることで、
PSD Toolkit のような複数モジュール連携が Delphi 側からも実現可能になります。


🧭 今後の展開

  • PSDファイルレイヤーの表示/非表示切替UIを追加
  • Base64化されたレイヤー設定をテキストボックスに保存
  • 入力プラグインとの連携によるリアルタイム更新

この仕組みを基礎にして、AviUtl2 上で
「PSDファイルを編集・制御できる完全な描画拡張」を構築していく予定です。


📦 GitHub リポジトリ

本サンプルは GitHub にて公開中です:

👉 https://github.com/vramwiz/AviUtl2PluginSample

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?