動画編集ソフトを作り始めた

Rustを使い始めて1ヶ月だぜ体験記みたいなのを書こうとしたけどせっかくなので今やってることも全部まとめて1本の記事にすることにした。

最近日本語をかくのがめんどくさい以外の発言をしていない気がする。

1ヶ月ほど前に動画編集ソフトを作りたくなって、言語はRust メディアフレームワークにGstreamer GUIにGTK+を使うのだけどこの3つをどれも触ったことがない状態で作り始めるという完全に勢いだけのアレというのが前置き。

Rust

前回の記事でも色々言ってたけどその後分かったことなんかを記しておく(本当はWHAT I WISH I KNEW WHEN LEARNING RUSTみたいにしてまとめると良いのだろうなぁ)

  • とりあえずメモリモデルとしてはスタックとヒープがあるということだけ分かっておけば大丈夫そう

  • structのフィールドに参照をもたせるとlifetime parameterにコードがまみれるのでやめたほうが良さそう

  • Rc<RefCell<T>> が便利(これは主にGTKを使う時に必要になったというのもある)

  • Rc<RefCell<T>> は確かに便利だけど hoge.borrow_mut().call(hoge.borrow()) みたいなことをするとBorrowMutError: already borrowedで実行時エラーになって死ぬので気をつけよう

  • 参照が欲しいときはBorrow, BorrowMut, AsRef, AsMutトレイトの実装があるかを見よう

  • Derefトレイトは神

  • Fn, FnMut, FnOnceの意味がようやく分かってきた FnOnce系はちょっと気をつけたほうがいい(Option::unwrapがselfを消費するのとか)

  • trait, implは飽くまでインターフェイスの提供だけなのでデータの扱いはstructで行う

  • OOPっぽくコード書きたいときはtrait objectと動的ディスパッチの仕組みを上手く使う(果たしてこれが正しいアレなのかはよく分からん)

  • マクロは便利

  • 別言語でtrailing commaで怒られると厳しい気持ちになる

  • if letが意外と便利

  • 言語拡張が結構カジュアルに欲しくなるのでこのままだとnightlyしか使わなくなりそう

  • 文字列リテラルが常に&strなのは意外とパターンマッチの時にめんどくさい マジでViewPatterns拡張が欲しい マジで

  • 大抵の他の言語でもそうなんだけどasって書くのめんどくさい

  • あと as (i32,i32) って書けないの割と不便

  • 前は「ブロックをclosureや関数として切り出してくると怒られるの理不尽💢」みたいなことを思っていたのだけれど、closureや関数は複数回呼ばれる可能性がある上に呼ばれるタイミングが不明なので所有権をちゃんと考えないといけないということが分かりスッキリした

最近Derefは神だなと思うことがあり、今まで(なんでこれ型が合うんだろう〜)って思ってたところは大体Derefのおかげであることが分かったりした。

例えば hoge: Rc<RefCell<T>> に対して hoge.borrow(): &T で一発でTへの参照が得られるんだけど、これは (*hoge).borrow() が勝手に補われており、更にRcのDerefの実装は中身への参照を取り出すようになってるからいい感じに出来るというのがある。

他にも、Rustは基本的にexplicitな言語であるけれどDerefだけは暗黙に色々やってくれるのでこいつのおかげで知らぬ間に記述が楽になってるところがあったりした。便利っぽい。

思ったよりいいたいことがなかった。最近Rustの勉強と言うよりGTKとかの勉強に時間もコストも取られてる感あるからかなぁ。

GTK+

gtk-rsというプロジェクトがありGTK関係のライブラリを色々提供してくれているので使ってる。たまに対応してないAPIがあるのとドキュメントにfeatureの指定が書いてないのでたまにハマる。

  • gtk: gtkのガワ widgetとかを提供する

  • gdk: 中身? 内部実装のあれこれを提供する

  • cairo: 2Dグラフィックスライブラリ

  • pango: フォントレンダリングライブラリ

  • pixbuf: cairo等で扱えるpixel buffer

  • githubのイシューにもあるんだけど登録するcallbackがほぼ'staticを要求するのでコード内の状態をcallback越しに持っていけない それを解決するために Rc<RefCell<S>> が必要になる

  • widgetが色々あるようで実はそんなにない ちょっと凝ったことするなら自作するしかない

  • widgetは内部状態を持っていてそれ自体がMVCみたいな感じになっているのでデータの持ち方を中央集権的にしようとすると結構めんどくさい

  • Elmの人も言っていたが何でもコンポーネントは(ライブラリは作りやすいけど)あんまりいい設計ではない気がする ViewはModelからの単なる関数にしたほうが素直

  • ドキュメントが豊富なので頑張って読めば意外となんとかなる(ただし本家以外は基本アテにならない)

Gstreamer

gstreamer-rsというライブラリがある。これもたまに対応してないAPIが(ry

そもそもgstreamerは設計が素直だけど結構独自概念も多くて複雑なので公式のドキュメントとかを頑張って読むしかない。

  • 基本的には用意されているElementを組み合わせていくだけ

  • とにかく対応している動画や音声のコーデックが豊富なのが強い 本当に強い

  • GdkPixbufSinkというのがありこれで動画をpixbufに吐いたり出来るのでGTKの連携は意外と簡単

  • やってきたデータをプログラム側で受け取ったり逆にプログラムからデータをgstreamerへ流したりするのはAppSrc, AppSink辺りを使う

関係ない話

早くリリースしたい。

今回は流石にプロジェクトマネジメントとかも割と真面目に頑張っている(の割に納期とか設定してないけど)しあとRustやGTKやらが初めてだけど意外となんとかなっているためにアプリケーションも形になってきているのでリリースはそのうち出来るんじゃないだろうか。

とはいえソフトウェア作るのって大変だなという感じ。動画編集ソフトなんて実装するべき機能が無限にあるしマジかという感じ。 某有名フリーソフトを倒せるように頑張りたい。

あとここまで書いた記事を読み返すといかに私が日本語を書きたくないかがよく分かると思う。

言語能力退化し過ぎでは…とちょっと不安になった。