GStreamer on macOS ではじめる動画処理【video編】
よく訓練されたアップル信者、都元です。
動画は YouTube で見たり携帯で撮ったりはすれども、あまり技術的に「処理」したことがありませんでした。 そのため、CODEC (encoder + decoder) やファイルフォーマット、フレームレートの話などの話は 正直詳くはわからないままではあるのですが、GStreamer というソフトウェアを使って簡単に遊べる、ということを知り、触ってみました。
ちなみに「動画」というと、純粋な video (映像) のことなのか、audio (音声) とセットにして扱ったものなのか、 という解釈に曖昧さがあるような気がします。一応本エントリーでは用語を次のように整理しておきます。 (これが一般的なのかはわかりません…)
- video (映像) → 動く絵だけ
- audio (音声) → 音だけ
- movie (動画) → video と audio が同期した組み合わせ
- media (メディア) → video や audio、これらの抽象概念
前提
ソフトウェア
- macOS High Sierra v10.13.5
- GStreamer 及び標準プラグイン 1.14.1
Homebrew は導入済みである前提です。
ハードウェア
- MacBook Pro (13-inch, 2017, Four Thunderbolt 3 Ports): FaceTime HD Camera 内蔵
- Apple Thunderbolt Display: FaceTime HD Camera 内蔵
結果的に、マシンにはカメラとマイクが各 2 台ずつ接続してあることになります。
メディア処理は様々なデバイスに依存します。以降に書いてある処理は、 皆さんの環境で同じように動かないことも多いかもしれません。
GStreamer 概要
GStreamer は、エレメント (element) という部品を組み合わせて動作します。 エレメントにはパッド (pad) というデータの入出力のための口がついています。 データを取り出すためのパッドを source pad、データを取り込むためのパッドを sink pad と呼びます。
どのうようなパッドをいくつ備えているかによってエレメントには何種類かあるのですが、 取っ掛かりとして特に重要なものは次の 3 つです。
- データの入力エレメント (source element): source pad のみが付いている
- データの加工エレメント (filter element): source pad と sink pad 両方がついている
- データの出力エレメント (sink element): sink pad のみが付いている
これらのエレメントをつなぎあわせて、動画の処理を実行します。
ちょうど次のような「パイプ」を使ってテキスト処理をするのと同じようなノリです。
$ echo foobarbazqux | cut -c 4-6 | tee result.txt $ cat result.txt bar
echo
や cat
などでデータを作り出し、cut
, tr
, sed
などで加工、tee
でファイルへの書き込みができます。
ちなみに、GStreamer の主な役割はプログラミング用のライブラリ (主に C++) です。 しかし、本エントリーではコマンドラインツールのみをつかって、その概要を追いかけていきます。
インストール
必要なものは brew
コマンドで導入できます。
$ brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad $ brew install gst-plugins-ugly --with-x264 $ gst-launch-1.0 --version gst-launch-1.0 version 1.14.1 GStreamer 1.14.1 Unknown package origin
GStreamer 本体に加えて、前述の各種エレメントはプラグインという形で導入できるようになっています。
base, good, bad, ugly という、なんだかモヤっとするパッケージ名ではありますが、 これらを導入しておけば一通りのことがだいたいできるようになります。
ちなみにこれらのパッケージの意味合いは GStreamer Plug-ins splitup に記述があります。 ざっくり言えば、きちんとコアの変化に追従し、コード品質が高く、きちんとレビューやテストがされていて、 配布ライセンスも LGPL またはその互換ライセンスであり、ドキュメントもあり、アクティブなメンテナーもいて、 広く使われているのかどうか、などの幅広い評価軸で分類しているようです。
雑ですがとりあえず全部入れておけば、まずは用が足りると思います。
今回使うエレメント
source element
- videotestsrc - テスト用の映像を出力する。
- avfvideosrc - macOS のカメラ映像や画面のキャプチャ映像を読み出す。
- autovideosrc - 自動検出 (だいたいカメラ)
- filesrc - ファイルからメディアを読み出す。
filter element
- videobalance - コントラスト・明度・彩度などを調整する
- videoflip - 映像を回転・反転させる
- zebrastripe - 映像の白い部分を縞模様にする
- decodebin - デコーダー
- x264enc - H.264 エンコーダー
- qtmux - QuickTime Muxer
- textoverlay - 映像に任意のテキストを重ねる
- timeoverlay - 映像の頭からの経過時間テキストを重ねる
- clockoverlay - 映像に日付や時刻のテキストを重ねる
- capsfilter - ケイパビリティフィルター(?)
- videoconvert - 映像変換(?)
sink element
- autovideosink - 自動検出(だいたい画面上のウィンドウ)
- filesink - ファイルに書き出す。
さっそく、いろいろ試していく
テスト動画を画面に表示してみる
手始めに、カラーバーを画面上のウィンドウに表示してみましょう。
$ gst-launch-1.0 videotestsrc ! autovideosink
このコマンドを実行すると、新たなウィンドウが開き、カラーバーが表示されます。|
ではなく !
を使ってエレメントをつないで行くわけです。
右下の砂嵐はランダムに動くので、実際にやってみるとこれが動画であることが確認できると思います。
カメラからの画像を画面に表示してみる
$ gst-launch-1.0 avfvideosrc ! autovideosink $ gst-launch-1.0 avfvideosrc ! videobalance brightness=1.9 ! autovideosink
こんな感じです。右の絵は、明るさを調整してみました。パイプのノリで編集できることがわかると思います。 (違いは分かりづらいですね…。動画としてみると感じ取れる気がします。)
様々な入力にいろいろな加工をして表示してみる
これもちょっと分かりづらいかもしれませんが、スクリーンキャプチャを左右反転させています。
$ gst-launch-1.0 avfvideosrc capture-screen=true \ ! videoflip method=horizontal-flip \ ! autovideosink
そして、動画中の白っぽいところを縞模様に変えるフィルターを掛けてみました。
$ gst-launch-1.0 autovideosrc ! zebrastripe ! autovideosink
だんだん説明要らなくなってきましたね?
動画ファイルから、映像を画面に表示してみる
動画ファイルは大抵なんかしらのエンコードがされているはずですので、 いい感じにデコードしてくれるフィルターをはさみます。
$ gst-launch-1.0 filesrc location=classmethod_FULL_MIX.mov \ ! decodebin \ ! autovideosink
デコード後であれば、このようにフィルターを突っ込むこともできます。
$ gst-launch-1.0 filesrc location=classmethod_FULL_MIX.mov \ ! decodebin \ ! zebrastripe \ ! autovideosink
編集結果をファイルに書き込む
さて、結果を表示するのではなくファイルに出力してみます。このコマンドの実行は、少々時間がかかります。
$ gst-launch-1.0 filesrc location=classmethod_FULL_MIX.mov \ ! decodebin \ ! zebrastripe \ ! x264enc \ ! qtmux \ ! filesink location=out.mov
だいぶややこしくなってきましたが。
- ファイルから読み込み
- 自動デコード
- 縞模様加工
- H.264 エンコード
- QuickTime マルチプレクサ ※
- ファイルに書き込み
※ 要するに video を QuickTime 形式の movie にする処理です。が、今回は音声について扱っていませんので、出力ファイルには音声が無い状態になります。
動画になにか文字列を重ねてみる
各 overlay のフィルターを試してみる例です。
$ gst-launch-1.0 filesrc location=classmethod_FULL_MIX.mov \ ! decodebin \ ! textoverlay text="Hello, GStreamer!!" font-desc="Sans 36" \ ! capsfilter caps="video/x-raw" \ ! videoconvert \ ! autovideosink
$ gst-launch-1.0 filesrc location=classmethod_FULL_MIX.mov \ ! decodebin \ ! timeoverlay font-desc="Sans 36" \ ! capsfilter caps="video/x-raw" \ ! videoconvert \ ! autovideosink
$ gst-launch-1.0 filesrc location=classmethod_FULL_MIX.mov \ ! decodebin \ ! clockoverlay time-format="%Y-%m-%d %H:%M:%S" font-desc="Sans 36" draw-outline=false \ ! capsfilter caps="video/x-raw" \ ! videoconvert \ ! autovideosink
まとめ
まだまだ個人的に勉強しなければならないことは多いですが、これをとっかかりに、各種メディアに対する処理を実装できるようになっていきたいと思っています。