0
0

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入力プラグイン入門(JPEG画像を表示する)

Posted at

🎯 はじめに

AviUtl2は非常に拡張性の高い動画編集ソフトですが、
すべてのファイル形式を直接読み込めるわけではありません。

たとえば、

  • Photoshop形式(PSD)
  • WebP / HEIC / 独自RGBA形式
  • AI生成画像やキャッシュ画像シーケンス

といった形式は、標準の input.aui2 では対応していません。

そこで登場するのが 入力プラグイン (Input Plugin) です。
入力プラグインを作成することで、AviUtl2が本来扱えない形式でも、
直接タイムラインに配置できるようになります。

本記事では、Delphiを使ってAviUtl2用入力プラグインを自作し、
JPEG画像を表示する最小サンプルを作成します。


🧩 開発環境

項目 内容
開発言語 Delphi (RAD Studio / Embarcadero Delphi 10以降)
対象バージョン AviUtl2 β17 SDK
プラグイン形式 .aui2 (Input Plugin)
動作環境 Windows 10 / 11

🔧 プラグインの概要

このサンプルは、AviUtl2にJPEG画像を1フレーム映像として読み込む
最小構成の入力プラグインです。

機能 内容
対応形式 .jpg, .jpeg
出力形式 RGBA 32bit (BGRA順)
フレーム数 1フレーム固定
フレームレート 30fps
音声 非対応
設定ダイアログ RGB色設定の簡易サンプルを実装

📂 プロジェクト構成

AviUtl2InputSample/
├─ AviUtl2InputSample.dpr      # メインソース(DLL本体)
├─ AviUtl2InputSample.dproj    # Delphi プロジェクトファイル
└─ README.md                   # GitHub用説明ファイル
AviUtl2InputSample.dpr
library AviUtl2InputSample;

uses
  Winapi.Windows,
  Winapi.MMSystem,
  System.SysUtils,
  Vcl.Graphics,
  Vcl.Imaging.jpeg;

type
  PWAVEFORMATEX = ^WAVEFORMATEX;
  WAVEFORMATEX = record
    wFormatTag: Word;
    nChannels: Word;
    nSamplesPerSec: Cardinal;
    nAvgBytesPerSec: Cardinal;
    nBlockAlign: Word;
    wBitsPerSample: Word;
    cbSize: Word;
  end;

type
  LPCWSTR = PWideChar;
  INPUT_HANDLE = Pointer;
  PBITMAPINFOHEADER = ^BITMAPINFOHEADER;

  TInputInfo = record
    flag: Integer;
    rate, scale: Integer;
    n: Integer;
    format: PBITMAPINFOHEADER;
    format_size: Integer;
    audio_n: Integer;
    audio_format: PWAVEFORMATEX;
    audio_format_size: Integer;
  end;
  PInputInfo = ^TInputInfo;

const
  INPUT_INFO_FLAG_VIDEO = 1;
  INPUT_PLUGIN_FLAG_VIDEO = 1;

type
  TInputPluginTable = record
    flag: Integer;
    name: LPCWSTR;
    filefilter: LPCWSTR;
    information: LPCWSTR;
    func_open: function(fileName: LPCWSTR): INPUT_HANDLE; cdecl;
    func_close: function(ih: INPUT_HANDLE): BOOL; cdecl;
    func_info_get: function(ih: INPUT_HANDLE; info: PInputInfo): BOOL; cdecl;
    func_read_video: function(ih: INPUT_HANDLE; frame: Integer; buf: Pointer): Integer; cdecl;
    func_read_audio: function(ih: INPUT_HANDLE; start, length: Integer; buf: Pointer): Integer; cdecl;
    func_config: function(hwnd: HWND; hinst: HINST): BOOL; cdecl;
    func_set_track: Pointer;
    func_time_to_frame: Pointer;
  end;
  PInputPluginTable = ^TInputPluginTable;

type
  PFileContext = ^TFileContext;
  TFileContext = record
    bitmap: TBitmap;
    info: BITMAPINFOHEADER;
  end;

function func_open(fileName: LPCWSTR): INPUT_HANDLE; cdecl;
var
  jpeg: TJPEGImage;
  bmp: TBitmap;
  ctx: PFileContext;
begin
  Result := nil;
  if not FileExists(fileName) then Exit;

  jpeg := TJPEGImage.Create;
  bmp := TBitmap.Create;
  try
    jpeg.LoadFromFile(fileName);
    bmp.Assign(jpeg);
    bmp.PixelFormat := pf32bit;

    New(ctx);
    ctx^.bitmap := bmp;

    FillChar(ctx^.info, SizeOf(ctx^.info), 0);
    ctx^.info.biSize := SizeOf(BITMAPINFOHEADER);
    ctx^.info.biWidth := bmp.Width;
    ctx^.info.biHeight := bmp.Height;
    ctx^.info.biPlanes := 1;
    ctx^.info.biBitCount := 32;
    ctx^.info.biCompression := BI_RGB;
    ctx^.info.biSizeImage := bmp.Width * bmp.Height * 4;

    Result := ctx;
  finally
    jpeg.Free;
  end;
end;

function func_close(ih: INPUT_HANDLE): BOOL; cdecl;
var
  ctx: PFileContext;
begin
  Result := False;
  if ih = nil then Exit;

  ctx := ih;
  ctx^.bitmap.Free;
  Dispose(ctx);
  Result := True;
end;

function func_info_get(ih: INPUT_HANDLE; info: PInputInfo): BOOL; cdecl;
var
  ctx: PFileContext;
begin
  Result := False;
  if (ih = nil) or (info = nil) then Exit;
  ctx := ih;

  FillChar(info^, SizeOf(TInputInfo), 0);
  info^.flag := INPUT_INFO_FLAG_VIDEO;
  info^.rate := 30;
  info^.scale := 1;
  info^.n := 1; // 静止画1フレーム
  info^.format := @ctx^.info;
  info^.format_size := SizeOf(BITMAPINFOHEADER);
  Result := True;
end;

function func_read_video(ih: INPUT_HANDLE; frame: Integer; buf: Pointer): Integer; cdecl;
var
  ctx: PFileContext;
  src, dst: PByte;
  y, x: Integer;
  lineSize: Integer;
  c: PRGBQuad;
begin
  Result := 0;
  if (ih = nil) or (buf = nil) then Exit;
  ctx := ih;

  lineSize := ctx^.bitmap.Width * 4;
  dst := buf;

  // biHeight は正(下→上コピー)
  for y := ctx^.bitmap.Height - 1 downto 0 do
  begin
    src := ctx^.bitmap.ScanLine[y];
    c := PRGBQuad(src);
    for x := 0 to ctx^.bitmap.Width - 1 do
    begin
      // BGRAのA=255に強制設定
      dst^ := c^.rgbBlue;  Inc(dst);
      dst^ := c^.rgbGreen; Inc(dst);
      dst^ := c^.rgbRed;   Inc(dst);
      dst^ := $FF;         Inc(dst); // αチャンネルを255
      Inc(c);
    end;
  end;

  Result := ctx^.info.biSizeImage;
end;

function func_read_audio(ih: INPUT_HANDLE; start, length: Integer; buf: Pointer): Integer; cdecl;
begin
  Result := 0; // 音声なし
end;

function func_config(hwnd: HWND; hinst: HINST): BOOL; cdecl;
begin
  MessageBox(hwnd, 'JPEG Input Plugin (Delphi)', 'AviUtl2InputSample', MB_OK);
  Result := True;
end;

var
  Plugin: TInputPluginTable = (
    flag: INPUT_PLUGIN_FLAG_VIDEO;
    name: 'AviUtl2 JPEG Input Sample';
    filefilter: 'JPEG File (*.jpg;*.jpeg)'#0'*.jpg;*.jpeg'#0;
    information: 'Delphi JPEG Reader for AviUtl2';
    func_open: func_open;
    func_close: func_close;
    func_info_get: func_info_get;
    func_read_video: func_read_video;
    func_read_audio: func_read_audio;
    func_config: func_config;
    func_set_track: nil;
    func_time_to_frame: nil
  );

function GetInputPluginTable: PInputPluginTable; cdecl;
begin
  Result := @Plugin;
end;

exports
  GetInputPluginTable name 'GetInputPluginTable';

begin
end.

⚙️ ビルド手順

  1. Delphiでプロジェクトを開く
  2. 出力フォルダをAviUtl2のPluginsフォルダに指定
  3. ビルド後、生成された AviUtl2InputSample.dll.aui2 にリネーム
AviUtl2InputSample.dll → AviUtl2InputSample.aui2
  1. AviUtl2を起動すると、プラグイン一覧に
    「AviUtl2 RGBA JPEG Input Plugin」が表示されます。

🖼️ 実行結果

JPEGファイルをAviUtl2にドラッグ&ドロップすると、
1フレームの静止画オブジェクトが自動生成されます。

image.png


💡 コード概要

主要な関数と役割:

関数 説明
func_open ファイルを開く(JPEGデコード処理)
func_info_get 画像サイズやフォーマット情報をAviUtlに渡す
func_read_video RGBAデータをAviUtlに転送
func_read_audio 非対応(0を返す)
func_config RGB値を変更できる設定ダイアログを表示
GetInputPluginTable プラグイン情報を登録

🚀 応用例

このサンプルを基礎に、以下のような拡張が可能です。

  • PSDファイル読み込み(レイヤー合成対応)
  • PNG / WebP 対応
  • 独自RGBA形式(AI生成画像など)の読み込み
  • 画像シーケンスによる動画生成
  • αチャンネル(透過)対応

🧑‍💻 開発者情報

Author: VRAMWiz
Language: Delphi
Platform: Windows 10 / 11
License: MIT License


🔗 関連リンク


📜 ライセンス

このプロジェクトは MIT License のもとで公開されています。
商用・非商用を問わず自由に利用・改変・再配布可能です。
著作権表記とライセンス条文の保持をお願いします。


🎓 DelphiでAviUtl2プラグインを開発できることを実証した、
実用的かつ教育的なサンプルです。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?