知恵の杜

「AviUtl2」のプラグインはC#でも作れる! Native AOTを使って実装してみよう

6年ぶりにアプデされた無料動画編集ツールのための開発テク

 「知恵の杜」では、役立つ実践的な技法の共有を目的に、技術ブログで見つけた「なるほど!」なテクニックをご紹介します。掲載にあたっては、公開前に著者様の許可を得た上で、編集部による補足・注釈を加え、より理解しやすい形でお届けします。

今回はいま話題の動画編集ツール「AviUtl2」向けのプラグインをC#で作成するテクニックを紹介

 無料でありながら、“できないことはほぼない”といってよい多機能ぶりが幅広い支持を集めている老舗動画編集ツール「AviUtl」。

 2025年7月に突如、約6年ぶりの更新が行われ、次期バージョンとなる「AviUtl ExEdit2」(「AviUtl」と拡張編集をまとめて新しくゼロから作り直したツールのテスト版)が公開されたことで、いま大きな話題となっています。

 「AviUtl」の魅力のひとつとして挙げられるのは、プラグインで自由に機能を拡張できること。「AviUtl ExEdit2」は現在のところ、基本的な編集のみが可能ですが、以前からあった拡張機能プラグイン「ExEdit」も一体化されているほか、「AviUtl ExEdit2 Plugin SDK」も公開されています。

 そこで今回の「知恵の杜」では、ちゅうこさんが公開している「C#でもaviutl2のプラグインが作れる!Native AOTを添えて」をご紹介します。「AviUtl ExEdit2」向けのプラグインを開発するきっかけとしておすすめしたいインフォメーションです。

[ここまで窓の杜編集部 補編、以下、原著]

C#でもaviutl2のプラグインが作れる!Native AOTを添えて

 突如として現れた「AviUtl ExEdit2」(通称:AviUtl2)、とても懐かしい気分でいっぱいですね! そんな「AviUtl2」はAviUtlと同様、プラグイン機構が備わっています。

 ちょうどよい機会なので、プラグイン実装に挑戦してみようと思いますが、サンプルとして提供されているのはC++。急にハードルが上がってしまいました。

 それでも作りたい、なにか方法はないかと頭を悩ませた結果、ひとつの結論にたどり着きました。

  C# で書けばよいのだと。

Native AOTという救世主

 「でもC#で書いたDLLをCのプラグインとして使えるの?」という疑問が浮かぶと思います。

 実は「.NET 7」以降で提供されている「Native AOT」という機能を使うことで、C#コードを直接ネイティブコードにコンパイルできるようになりました。

 これにより「.NET ランタイム」が不要で、Cで書いたプラグインと同じように動作するネイティブライブラリを作成できます。

【編集部注:Native AOT】

「Native AOT」(Native Ahead-Of-Time)とは、中間言語(IL)コードをインタープリターで実行するのではなく、事前にネイティブコードへコンパイルしてしまう手法のこと。起動時間が短縮され、メモリフットプリントが小さくなるという利点があります。

「Native AOT」詳細はこちらから

AviUtlプラグインの基本構造

 「AviUtl ExEdit2」のプラグインは、特定の関数をエクスポートするDLLとして実装されているようです。

 SDKの入力プラグインのサンプル実装である「AviReader.cpp」を確認してみたところ、「EXTERN_C」している「GetInputPluginTable」関数をエクスポートし、プラグインテーブルのポインターを返す必要があります。

 このプラグインテーブル構造体をC#で表現し、「GetInputPluginTable」関数を表現できればよさそうです。

C#でのNative AOTを使用したSharedライブラリ実装

 C#でNative AOTを使用してプラグインを実装するには、以下の手順が必要です。

  1. プロジェクト設定
    まず、.csprojファイルでNative AOTを有効にします。
    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFramework>net9.0</TargetFramework>
        <PublishAot>true</PublishAot> 
        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
      </PropertyGroup>
    </Project>
  2. UnmanagedCallersOnly属性の使用
    Native AOTでは「UnmanagedCallersOnly」属性を使用してC言語風の関数をエクスポートします。
    [UnmanagedCallersOnly(EntryPoint = "GetInputPluginTable",
                          CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
    public static IntPtr GetInputPluginTable()
    {
        return ~; // TODO: Impl
    }
  3. Native AOTを使用したビルド
    以下のようなコマンドを使用して、Sharedライブラリをpublishします。
    dotnet publish /p:NativeLib=Shared --use-current-runtime

実際の動作例

 前述したNative AOTを使用してサンプルプラグインを実装しました。

yamachu / play-aviutl-plugin-dotnet(GitHub)

 今回実装したサンプルプラグインは、画像を読み込んで1秒間で360度回転させる単純なものです。

 「SkiaSharp」を使用して画像処理を行い、AviUtlが期待するBGR24フォーマットで出力します。

【編集部注:SkiaSharp】

「SkiaSharp」は、Googleがオープンソースで提供している2D グラフィックスライブラリのこと。Chromiumなどで使用されているグラフィックスライブラリをC#から使えるようにします。

 今後もプラグインを作っていきたいなということで、今回のプロジェクトでは以下の2点を工夫してみました。

  1. 「AviUtlPluginNet.Abstractions」というパッケージと、プラグインのインターフェイスを作成し、最低限の実装で量産できるように
  2. CsWin32」パッケージを使用し、頑張らないWin32APIの型定義
【編集部注:CsWin32】

「CsWin32」は、Windows APIをC#で使用するときに書かなくてはいけない構文(C言語のAPI宣言をC#に翻訳)を肩代わりしてくれるライブラリのこと。

 突貫で作ったため、インターフェイスはまだまだ改善の余地ありですが、まずは動くものができて一安心です。

まとめ

 「Native AOT」を使用することで、C#でもネイティブレベルのパフォーマンスを持つ、AviUtlプラグインを開発できることがわかりました。

 従来のC++開発よりも生産性が高く(個人の感想です)、豊富な.NETエコシステムを活用できるのが大きな利点です(macOSでもWindowsのヘッダー不要で開発できるのは最高でした)。

 今回のサンプル実装では、画像処理に「SkiaSharp」を使用しましたが、同様にして他のNuGetパッケージも活用できます。ただし、Native AOTでは一部制限があるため、事前に互換性を確認することが重要です。

 「AviUtl ExEdit2」のみならず、より多くの開発者がC#でネイティブライブラリ開発を始めるきっかけになれば幸いです。

[原著はここまで、一部内容を編集部 編]

原著「C#でもaviutl2のプラグインが作れる!Native AOTを添えて」はこちらから

実際に窓の杜編集部で試してみました!

 それでは、今回のテクニックを実際に窓の杜編集部でも試してみたいと思います。

実際にプラグインを実装してみました

 上記の画像の通り、問題なく実装することができました。

 ひとつポイントとして挙げるなら、基本的に、サンプルプラグインのGitHubページに記載されている「Exampleのビルドおよび実行方法」の通りにビルドは可能でしたが、Native AOTのために「Visual StudioのC++によるデスクトップ開発」ワークロードをインストールしなければいけない点には、注意が必要かと感じました。

 まだまだテスト版の「AviUtl2」ではありますが、今回ご紹介したテクニックを参考に、思い思いのプラグインを先んじて開発してみてはいかがでしょうか。来たる正式版への期待を込めて盛り上げてまいりましょう。

ソフトウェア情報

「AviUtl ExEdit2」テスト版
【著作権者】
KENくん 氏
【対応OS】
64bit版のWindows 10以降
【ソフト種別】
フリーソフト
【バージョン】
2.00 beta5(25/08/03)