呪いのビデオをGStreamerで作る

GStreamerというマルチメディアフレームワークを使って、呪いのビデオを作ってみたいと思います。

# 準備その1: GStreamer

brewやaptなどでインストールできます。

```
$ brew install \
    gstreamer \
    gst-plugins-base \
    gst-plugins-good \
    gst-plugins-bad \
    gst-plugins-ugly
```

# 準備その2: 怖そうなフォント
![2020-11-26 at 16.12.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587625/06b0f9f2-1ad8-656d-b46b-698453354214.jpeg)

今回は`VDL テラG`というフォントを使いました
https://www.vdl.co.jp/font/terag.html
https://fonts.adobe.com/fonts/vdl-terag

# ベース映像を作る

まずベースとなる砂嵐動画を、480p(640x480)30fpsで10秒分=300フレーム生成して表示してみます。

```
$ gst-launch-1.0 -e \
  videotestsrc pattern=snow num-buffers=300 ! \
  video/x-raw,width=640,height=480,framerate=30/1 ! \
  autovideosink
```

![output1_base.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587625/5f55e426-8c10-05ed-30cf-f8296841c59b.jpeg)

このような動画が生成できました。`videotestsrc` で砂嵐を生成して `autovideosink` で画面に表示しています。
コマンドのパイプに似ていますが、 `|` ではなく `!` で繋ぐ事に注意してください。


# 文字を乗せる

先程の砂嵐動画に文字を乗せてみます。

```
$ gst-launch-1.0 -e \
  videotestsrc pattern=snow num-buffers=300 ! \
  video/x-raw,width=640,height=480,framerate=30/1 ! \
  textoverlay text="おわかりいただけただろうか...？" font-desc="VDL-TeraG, 30" ! \
  autovideosink 
```
![output2_text_simple.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587625/7383da68-0d47-7ac2-b2e7-e648cf8443d5.jpeg)

https://twitter.com/alarky1/status/1331853711501475840

このような動画が生成できました。
`videotestsrc` に `textoverlay` で文字を乗せて `autovideosink` で画面に表示しています。
`font-desc` の部分で今回使用するフォントと大きさを指定しています。

# 文字を不穏な赤色にする

先程の`textoverlay`に指定するテキストをマークアップして色指定してみます。

```
$ gst-launch-1.0 -e \
  videotestsrc pattern=snow num-buffers=300 ! \
  video/x-raw,width=640,height=480,framerate=30/1 ! \
  textoverlay text="<span foreground='#0000BB'>おわかりいただけただろうか...？</span>" font-desc="VDL-TeraG, 30" ! \
  autovideosink
```

![output3_text_red.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587625/f1066773-4e25-f50b-f4da-6ef79d0f20a8.jpeg)

このような動画が生成できました。

`<span foreground='#0000BB'>` とHTMLのような感じでマークアップしていますが、これは`pango markup`という、GTKで多言語を描画するライブラリのマークアップ形式です。
参考: https://developer.gnome.org/pygtk/stable/pango-markup-language.html

また、環境によって色指定の順序が違います。
brewでgstreamerをインストールしたMac環境の場合、画面表示ではBGR、書き出しではRGBで指定しないと正しい色になりませんでした。

# 字幕ファイルで、再生フレームに応じて文字を表示する

`{開始フレーム番号}{終了フレーム番号}字幕テキスト`
のような形式(MicroDVD形式)で字幕ファイルを用意します。

```subtitles.txt
{10}{20}お
{20}{30}おわ
{30}{40}おわか
{40}{50}おわかり
{50}{60}おわかりい
{60}{70}おわかりいた
{70}{80}おわかりいただ
{80}{90}おわかりいただけ
{90}{100}おわかりいただけた
{100}{110}おわかりいただけただ
{110}{120}おわかりいただけただろ
{120}{130}おわかりいただけただろう
{130}{140}おわかりいただけただろうか
{140}{150}おわかりいただけただろうか.
{150}{160}おわかりいただけただろうか..
{160}{170}おわかりいただけただろうか...
{170}{300}おわかりいただけただろうか...？
```

動画に合わせて表示します。

```
$ gst-launch-1.0 -e \
  filesrc location=subtitles.txt ! \
  subparse ! \
  text. \
  \
  videotestsrc pattern=snow num-buffers=300 ! \
  video/x-raw,width=640,height=480,framerate=30/1 ! \
  textoverlay name=text font-desc="VDL-TeraG, 30" ! \
  autovideosink 
```

![output4_subtitle.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587625/f477dcd1-2406-6dc5-37c5-1a7621d1dc34.jpeg)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">qiita貼り付け用 <a href="https://t.co/aHagNjHeKy">pic.twitter.com/aHagNjHeKy</a></p>&mdash; alarky (@alarky1) <a href="https://twitter.com/alarky1/status/1331870891140022273?ref_src=twsrc%5Etfw">November 26, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

今回のコマンドには2つのストリームがあります。

1つめは `filesrc location=subtitles.txt ! subparse` の字幕ファイルから字幕データをパースするストリームで、 `! text.` の部分でストリームに`text`という名前を付けています。

2つめは `videotestsrc` から始まる動画ストリームです。`textoverlay name=text`の部分で、先程の字幕ストリームを参照しています。

また、字幕ファイルはMicroDVD形式以外にも、

- SubRip
- MPSub
- SAMI
- TMPlayer
- MPL2
- SubViewer
- DKS
- WebVTT
- QTtext
- LRC

形式の字幕ファイルにも対応しているようです。

ただMicroDVD、SubRipで試した限り、字幕ファイルではpango markupが使えないようでした...

# 書き出す

今までは `autovideosink` で画面に表示しているだけでしたが、h264でエンコードしてMP4ファイルに保存してみます。

```
$ gst-launch-1.0 -e \
  filesrc location=subtitles.txt ! \
  subparse ! \
  text. \
  \
  videotestsrc pattern=snow num-buffers=300 ! \
  video/x-raw,width=640,height=480,framerate=30/1 ! \
  textoverlay name=text font-desc="VDL-TeraG, 30" ! \
  vtenc_h264 ! \
  mp4mux ! \
  filesink location=output.mp4 
```

`vtenc_h264` でh264にエンコードして `mp4mux` でMPEGコンテナに格納、`filesink` でファイルに書き出しています。

※ エンコーダ部分は環境によって使える物が違います。
CPUエンコードの`x264enc`や`avenc_h264`は幅広い環境でも使えるかと思います。
Mac環境では`vtenc_h264` `vtenc_h264_hw`
IntelCPU Linux環境なら `vaapih264enc`
NVIDIAのNVENCが扱える環境なら `nvv4l2h264enc` `nvenc`
Raspberry Piだと `avenc_h264_omx`
などなど...エンコーダを明示的に指定できます。

# 免責事項

当記事内容や映像によって生じたあらゆる損害、呪いについて、当方は一切責任を負いません。