Rustで動画編集ソフトを作ろうとしている
モチベーション
AviUtlライクかつモダンかつマルチプラットフォームな無料動画編集ソフトがあるといいなと常々思っていたので作り始めました。
今の状況
矩形と円と文字列をレンダリングすることができます
技術要素
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バックエンドからどうにかしてウィンドウに描画できないかと模索したりもしました。詳しくはこの記事。
プラグイン拡張可能な設計
ゆくゆくは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
もう試されたかもしれませんが、Tauriで大量のストリームをフロントとやり取りする場合、ipc::channelを使うと良いかもしれません
ありがとうございます!試してみたいと思います🙏
久々に動画編集しようと思い立った時に今更 AviUtl 使うか?って悩むんですよね。
昔とてもお世話になったソフトで思い入れもあったりある程度慣れてて使い方もわかっているのですが、如何せん古くて更新も止まっているので。
誰か Rust で書き直してくれないかなーと思っていました。
応援してます。
ありがとうございます!励みになります!
AviUtlライクな動画編集ソフトいいですね。AviUtlは個人的にグラボ無しでも十分な開発ができることに魅力を感じているのですが、32bit版しかないため新しい代替ソフトを待ち望んでました。頑張って下さい。(自分も作ってみようと思ったけど断念した)
応援ありがとうございます、頑張ります!
AviUtlみたいな動画編集ソフトがLinux,macで動いたら嬉しい!!応援しています!!
応援ありがとうございます!どうにか完成まで持っていきたいです…
将来はGPUでの高速レンダリングできるようになってほしいです
頑張ってください
ぜひそうしたいと思っています!ありがとうございます🙏
夢の現代版 AviUtl …!! 応援しています!! (ぜひ Linux 版を…!!)
ありがとうございます!私はLinuxを普段遣いしているのでLinuxには必ず対応させます!