🎬

Rustで動画編集ソフトを作ろうとしている

2025/03/02に公開
12

モチベーション

AviUtlライクかつモダンかつマルチプラットフォームな無料動画編集ソフトがあるといいなと常々思っていたので作り始めました。

今の状況

矩形と円と文字列をレンダリングすることができます
https://github.com/1Step621/iva

技術要素

Tauri(フロントにはVue)を使っています。プレピューレンダリングはWebAssemblyをVueから呼び出し、画像データを生成してcanvasに描くところまでやっています。なぜWasmを使ったのかは後述します。

なぜTauri + Vueを選んだのか

UI部分もRustで書きたいのはやまやまだったのですが、タイムラインUIなど高度なUIを作成するのは現状やはりVueなりReactのエコシステムを利用するのが早いと思ったからです。

現時点で難しかったところ

レンダリング

もともとは

  • アイテムの情報をTauriのバックエンドに送って、
  • バックエンドで画像を生成してバイト列Vec<u8>を返却し、
  • それをフロントで表示する

という風にしようと思っていたのですが、(これは自分のやり方が悪かったのかもしれませんが)JSに渡すときにStack limit exceededになってしまったので断念しました。

次に、バックエンドでbmpエンコード+Base64エンコードまで済ませて、Stringを返却するアプローチを考えました。エラーは出なかったものの、エンコードに計130ms程度かかっていたことと、Tauri IPCのオーバーヘッドからか、かなりカクカクになってしまいました。

最後に試したのが現在のWebAssemblyでレンダリングする方法で、これはかなり高速に動作しました。ただ、Wasmで画像生成をする際rayonによる並列化の恩恵を受けるにはJavaScriptのSharedArrayBufferを有効にする必要があり、TauriがLinuxで使用するlibwebkitgtkはこれをサポートしていないため、Linuxで重くなってしまいます。またWasmはネイティブバイナリほど速くないため、せっかくなら最速を目指したいなぁという感じもあります。

→Tauriにはバイト列を返すための構造体tauri::ipc::Responseがあると聞いたので、こんど試してみたいと思います。
↑やってみましたが単発だと100ms、スライダー入力などで連続してレンダリングすると300msくらいかかってしまい、引っかかりを感じました。やはりこの量のデータを頻繁にやり取りするのは無理がありそうです。

ほかにもTauriバックエンドからどうにかしてウィンドウに描画できないかと模索したりもしました。詳しくはこの記事
https://zenn.dev/yadokani389/articles/rendering-with-rust-in-tauri-20250305

プラグイン拡張可能な設計

ゆくゆくはWasmによるプラグインシステムを作りたいと考えているため、そういうふうに設計しようとしています。

現在タイムライン上でのオブジェクトを示す型Itemは以下のようになっています。

export type Item = {
  id: string;
  layer: number;
  kind: string;
  name: string;
  time: TimeRange;
  filters: Filter[];
  props: Record<string, any>;
};

レンダリング側はこんな感じです。

            match item.kind.as_str() {
                "rect" => render_rect(&mut img, item),
                "circle" => render_circle(&mut img, item),
                "text" => render_text(&mut img, item),
                "image" => {}
                "video" => {}
                "audio" => {}
                _ => {}
            }

このkindを拡張し、レンダリングする関数をプラグイン側から提供してもらうことでカスタムオブジェクトを表現できるだろうという算段です。

ここで問題になりそうなのが、プロパティ画面(座標、幅、高さ、色などを入力するところ)をどうやって拡張してもらうかです。
JSON上にプロパティ用DSL的なもの(?)を作成し、

export type PropDefinition = (
  {
    type: "slider",
    default?: number,
    min: number,
    max: number,
    step?: number,
  } | {
    type: "number",
    default?: number,
    min?: number,
    max?: number,
    step?: number,
  } | {
    type: "color",
  } | {
    type: "text",
    multiline?: boolean,
    default?: string,
  } | {
    type: "select",
    options: {
      value: string,
      label: string,
    }[],
    default?: string,
  } | {
    type: "file",
    default?: string,
  }
) & {
  label: string,
};

みたいなものを提供してもらえばいいかなと最初は思いましたが、入力欄を特定の条件でdisabledにしたかったり、ボタンを押して入力欄の数を増やせるようにしたかったり、いろいろ想定されるので、この方法だとニーズに対応しきれない可能性があるなぁと思っています。

おわり

思ったよりちゃんと動いて感動しています
飽きるまでぽちぽち開発していきたいです。

Discussion

ionohionoh

もう試されたかもしれませんが、Tauriで大量のストリームをフロントとやり取りする場合、ipc::channelを使うと良いかもしれません

1Step6211Step621

ありがとうございます!試してみたいと思います🙏

dog_cat_foxdog_cat_fox

久々に動画編集しようと思い立った時に今更 AviUtl 使うか?って悩むんですよね。
昔とてもお世話になったソフトで思い入れもあったりある程度慣れてて使い方もわかっているのですが、如何せん古くて更新も止まっているので。
誰か Rust で書き直してくれないかなーと思っていました。
応援してます。

Eishu KawaguchiEishu Kawaguchi

AviUtlライクな動画編集ソフトいいですね。AviUtlは個人的にグラボ無しでも十分な開発ができることに魅力を感じているのですが、32bit版しかないため新しい代替ソフトを待ち望んでました。頑張って下さい。(自分も作ってみようと思ったけど断念した)

bunmeibunmei

AviUtlみたいな動画編集ソフトがLinux,macで動いたら嬉しい!!応援しています!!

1Step6211Step621

応援ありがとうございます!どうにか完成まで持っていきたいです…

jijinbeijijinbei

将来はGPUでの高速レンダリングできるようになってほしいです
頑張ってください

1Step6211Step621

ぜひそうしたいと思っています!ありがとうございます🙏

Lemon73Lemon73

夢の現代版 AviUtl …!! 応援しています!! (ぜひ Linux 版を…!!)

1Step6211Step621

ありがとうございます!私はLinuxを普段遣いしているのでLinuxには必ず対応させます!