FFmpegで重ねた物にフリンジが出る場合はunpremultiplyフィルターで解決…なのか？

# 前提

コマンドラインで FFmpeg を使い、映像にフィルターをかけていく。

## 環境

- **FFmpeg 6.0**-essentials_build-www.gyan.dev（Chocolatey 1.3.1 により導入）
- GNU **bash** 5.2.15(1)-release（Git for Windows 2.24.0 により導入）
- **Windows 10** Home 64-bit 22H2

## 基本文法

映像にフィルターをかけるにはこうする。

```bash:単一入力の場合
ffmpeg -i "入力ファイル.avi" -filter:v "フィルター文字列" "出力ファイル.mp4"
```

```bash:複数入力の場合
# Qiita だと長いワンライナーは横スクロール必至で見にくいので、改行を挟んで書くことにする
ffmpeg -i "入力ファイル1.avi" -i "入力ファイル2.avi" \
       -filter_complex "フィルター文字列" \
       "出力ファイル.mp4"
```

## 単色映像ソースを呼び出す

入力指定オプション `-i` は普通、`-i "ファイル.avi"` のようにファイル名を指定する。
しかし、フォーマット強制オプション `-f` と特殊な仮想入力デバイス `lavfi` を用いて `-f lavfi -i "映像ソース系フィルター"` のように指定すると、何のファイルというわけでもない新規映像ソースを描画して入力とすることができる。

映像ソース系フィルターには例えば `color` があり、`-f lavfi -i "color=color=pink"` とするとピンク色（`#FFC0CB`）一色で塗り潰された映像ソースが生成される。
サイズ等の更なるパラメーターもあったりする。

```bash
ffmpeg `# デフォルトだとログ出力がやかましいので最低限のエラー報告に抑える` \
       -loglevel warning \
       `# 100×100 ピクセルのピンク色を描画` \
       -f lavfi -i "color = color=pink: size=100x100" \
       `# 静止画 1 枚として出力、既存ファイルを上書き` \
       -update 1 -frames:v 1 -y "pink.png"
```

![pink.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/cd877225-28fa-f703-d582-b1ace0b4a27f.png "pink.png")

また、映像ソース系フィルターは当然フィルターなので、その場（`-i` オプションの中）で更に色々な追いフィルターもかけられる。
そしてもちろん、その後段でも `-filter:v` や `-filter_complex` によってもっと好き放題にフィルターを重ねられる。


# 困り事：`overlay` で映像を重ねられるが、フリンジが出る

ではここで、2 個の映像ソースを新規描画してから、**`overlay` フィルター**で単純に重ねてみると…

```bash
ffmpeg -loglevel warning \
       `# 左側がピンク色、右側が透明の 100×100 ピクセルの背景を描画` \
       -f lavfi -i "color = color=pink: size=50x100,
                    format = rgba,
                    pad = w=in_w*2: color=black@0" \
       `# やや傾いた 65×65 ピクセルの水色の正方形を描画` \
       -f lavfi -i "color = color=cyan: size=65x65,
                    format = rgba,
                    pad = width=100: height=out_w: x=-1: y=-1: color=black@0,
                    rotate = angle=30*PI/180: fillcolor=none" \
       `# 水色側を前景にしてシンプルに重ねる` \
       -filter_complex "[0] [1] overlay = format=rgb" \
       -update 1 -frames:v 1 -y "out0-just-overlay.png"
```

![out0-just-overlay.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/d89a3ba5-eed4-ead6-2829-00f54705cc75.png "out0-just-overlay.png")

…ちょっと問題点がわかりづらいので拡大する。

```bash
ffmpeg -loglevel warning \
       `# さっき出力した画像を入力` \
       -i "out0-just-overlay.png" \
       `# 上部だけを切り出してニアレストネイバー法で拡大` \
       -filter:v "crop = y=0: h=40,
                  scale = width=in_w*6: height=-1: flags=neighbor" \
       -update 1 -frames:v 1 -y "out0-just-overlay-zoom.png"
```

![out0-just-overlay-zoom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/e3ceafca-588a-ffd0-99f3-c0b822babf2a.png "out0-just-overlay-zoom.png")

なんか…**前景のフチが黒い**んだよね……。

こいつを解決したい。


# 解決策

## `pad` の色埋めを工夫する…のは汎用性が無い

既に使っているが、`色@不透明度` という記法は色に不透明度を追加できる。
`black@0` なら `rgba(0, 0, 0, 0)`、`blue@0.4` なら `rgba(0, 0, 255, 0.4)` という感じになる。

今回の例では前景が水色一色とわかりきっているので、`pad` フィルターが前景に与える透明部分の色を `black@0` ではなく `cyan@0` にしてやれば、一応は解決する。

```bash
ffmpeg -loglevel warning -y `# -y は全ての出力に効くので手前に移動` \
       -f lavfi -i "color = color=pink: size=50x100,
                    format = rgba,
                    pad = w=in_w*2: color=black@0" \
       `# 余白に透明な水色を用いる` \
       -f lavfi -i "color = color=cyan: size=65x65,
                    format = rgba,
                    pad = width=100: height=out_w: x=-1: y=-1: color=cyan@0,
                    rotate = angle=30*PI/180: fillcolor=none" \
       `# 拡大した映像も同時に作っちゃう` \
       -filter_complex "[0] [1] overlay = format=rgb,
                                split [normal] [tmp];
                        [tmp] crop = y=0: h=40,
                              scale = width=in_w*6: height=-1: flags=neighbor [zoom]" \
       `# 普通のと拡大したのをそれぞれ別ファイルに出力` \
       -map "[normal]" -update 1 -frames:v 1 "out1-alpha-cyan.png" \
       -map "[zoom]"   -update 1 -frames:v 1 "out1-alpha-cyan-zoom.png"
```

![out1-alpha-cyan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/7d6be876-7c2f-de86-6801-ea2b4eae8fec.png "out1-alpha-cyan.png")
![out1-alpha-cyan-zoom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/b63c742f-9ec2-0a03-a44b-9a470d5f8582.png "out1-alpha-cyan-zoom.png")

しかし当然ながら、この方法は前景の色を完全に掌握していないと使えない。

もっと汎用性の高い方法があるはず。

## `alpha=premultiplied` で解決…するのは不透明背景の上だけ

そもそもなんでこんなフリンジ（縁、輪郭線、境界線）が発生しているのかというと。いわゆる**プリマルチプライ**（premultiply）で事故っているため。

解決法として、`overlay` フィルターに `alpha=premultiplied` パラメーターを渡して「もうプリマルチプライしてあるよ！」と教えてあげる手法が知られているっぽい。

```bash
ffmpeg -loglevel warning -y \
       -f lavfi -i "color = color=pink: size=50x100,
                    format = rgba,
                    pad = w=in_w*2: color=black@0" \
       -f lavfi -i "color = color=cyan: size=65x65,
                    format = rgba,
                    pad = width=100: height=out_w: x=-1: y=-1: color=black@0,
                    rotate = angle=30*PI/180: fillcolor=none" \
       `# alpha=premultiplied で重ねる` \
       -filter_complex "[0] [1] overlay = format=rgb: alpha=premultiplied,
                                split [normal] [tmp];
                        [tmp] crop = y=0: h=40,
                              scale = width=in_w*6: height=-1: flags=neighbor [zoom]" \
       -map "[normal]" -update 1 -frames:v 1 "out2-pre.png" \
       -map "[zoom]"   -update 1 -frames:v 1 "out2-pre-zoom.png"
```

![out2-pre.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/ff0fbdd8-a74c-6650-ea30-39bce203cce9.png "out2-pre.png")
![out2-pre-zoom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/20d12a2b-d942-de84-c01d-ba488fc09e2e.png "out2-pre-zoom.png")

うんうん、確かにピンク色の背景との間にあったフリンジが消えて…
**透明背景の方にはフリンジ残ってるじゃん！！**

## `unpremultiply` で（ほぼ）解決

**`unpremultiply` フィルター**を `inplace=1` パラメーターでかけてやれば、映像のアルファチャンネルがプリマルチプライドからストレートに変換される。
その際、逆に `overlay` フィルターの `alpha=premultiplied` パラメーターは指定しないでおくこと。

```bash
ffmpeg -loglevel warning -y \
       -f lavfi -i "color = color=pink: size=50x100,
                    format = rgba,
                    pad = w=in_w*2: color=black@0" \
       `# unpremultiply を噛ませる` \
       -f lavfi -i "color = color=cyan: size=65x65,
                    format = rgba,
                    pad = width=100: height=out_w: x=-1: y=-1: color=black@0,
                    rotate = angle=30*PI/180: fillcolor=none,
                    unpremultiply = inplace=1" \
       `# alpha=premultiplied は使わない` \
       -filter_complex "[0] [1] overlay = format=rgb,
                                split [normal] [tmp];
                        [tmp] crop = y=0: h=40,
                              scale = width=in_w*6: height=-1: flags=neighbor [zoom]" \
       -map "[normal]" -update 1 -frames:v 1 "out3-unpre.png" \
       -map "[zoom]"   -update 1 -frames:v 1 "out3-unpre-zoom.png"
```

![out3-unpre.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/2adc2608-e90e-a017-2c92-ab45ecec2e4e.png "out3-unpre.png")
![out3-unpre-zoom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/41e6aa68-39d0-7c8d-c23d-82c6012d1f03.png "out3-unpre-zoom.png")

**背景の透明度によらず、前景のフリンジが消えた！**

このシンプルな解決法が、調べても意外と全然見つからなくて苦労した。
シンプルすぎるからだろうか。

なお、もし `alpha=premultiplied` パラメーターを消さずに残しておくと…

```bash
ffmpeg -loglevel warning -y \
       -f lavfi -i "color = color=pink: size=50x100,
                    format = rgba,
                    pad = w=in_w*2: color=black@0" \
       -f lavfi -i "color = color=cyan: size=65x65,
                    format = rgba,
                    pad = width=100: height=out_w: x=-1: y=-1: color=black@0,
                    rotate = angle=30*PI/180: fillcolor=none,
                    unpremultiply = inplace=1" \
       `# alpha=premultiplied も指定してみる` \
       -filter_complex "[0] [1] overlay = format=rgb: alpha=premultiplied,
                                split [normal] [tmp];
                        [tmp] crop = y=0: h=40,
                              scale = width=in_w*6: height=-1: flags=neighbor [zoom]" \
       -map "[normal]" -update 1 -frames:v 1 "out4-unpre-pre.png" \
       -map "[zoom]"   -update 1 -frames:v 1 "out4-unpre-pre-zoom.png"
```

![out4-unpre-pre.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/84b89062-4a7c-d45a-b2e3-30ba62faeba3.png "out4-unpre-pre.png")
![out4-unpre-pre-zoom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/aa64d4ee-861b-3c98-728c-43ac885734b9.png "out4-unpre-pre-zoom.png")

今度は逆に**不透明背景の方に白いフリンジが発生**してしまう。
何事もやり過ぎは良くない。

### しかし実は完全解決ではない

`unpremultiply` フィルターがおおよそ今回求めていたものであることはわかった。
でも、もうちょっと確認しておきたい。

背景の右側の透明化をやめて全てピンク色だけにし、更に前景の正方形をピンク色にして重ねてみる。
`unpremultiply` フィルターのおかげでフリンジも出ないんだから、当然**ピンク色一色だけの画像が出力されるはず**。

```bash
ffmpeg -loglevel warning -y \
       `# ピンク色の 100×100 ピクセルの背景を描画` \
       -f lavfi -i "color = color=pink: size=100x100,
                    format = rgba" \
       `# やや傾いた 65×65 ピクセルのピンク色の正方形を描画して unpremultiply` \
       -f lavfi -i "color = color=pink: size=65x65,
                    format = rgba,
                    pad = width=100: height=out_w: x=-1: y=-1: color=black@0,
                    rotate = angle=30*PI/180: fillcolor=none,
                    unpremultiply = inplace=1" \
       `# 重ねて、拡大した映像も同時作成` \
       -filter_complex "[0] [1] overlay = format=rgb,
                                split [normal] [tmp];
                        [tmp] crop = y=0: h=40,
                              scale = width=in_w*6: height=-1: flags=neighbor [zoom]" \
       `# ピンク色一色になる？` \
       -map "[normal]" -update 1 -frames:v 1 "out5-one-color.png" \
       -map "[zoom]"   -update 1 -frames:v 1 "out5-one-color-zoom.png"
```

![out5-one-color.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/1929b293-4435-7911-9574-85f2b64ccdf4.png "out5-one-color.png")
![out5-one-color-zoom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/3b17fc13-6e9e-5545-d365-74547bf3e22b.png "out5-one-color-zoom.png")

…良さそう。
**本当に？**

じゃあちょっと**色数**を数えてもらおうか。

<!--
`-loglevel` の詳細度がデフォルトかそれ以上なら、`palettegen` フィルターを使うとログに色数が報告される。
ただしログは標準エラー出力なので、後の `grep` コマンドで絞り込むには `2>&1` で標準出力にリダイレクトする。
また、FFmpeg としてファイル出力は不要なので、`-f null "-"` で握り潰す。
-->

```bash
$ ffmpeg -i "out5-one-color.png" -filter:v "palettegen" -f null "-" 2>&1 | grep "palettegen"
[Parsed_palettegen_0 @ 00000221d9f78b80] 12(+1) colors generated out of 12 colors; ratio=1.000000
```

> 12(+1) colors generated out of 12 colors

**12 色もあるんですけど！！！！**

ただ、そう言われても見た目にはほとんどわからない。
そこで、`normalize` フィルターでコントラストをガッと引き伸ばして可視化してみる。

```bash
ffmpeg -loglevel warning -y \
       -i "out5-one-color.png" \
       -filter_complex "normalize,
                        split [normal] [tmp];
                        [tmp] crop = y=0: h=40,
                              scale = width=in_w*6: height=-1: flags=neighbor [zoom]" \
       -map "[normal]" -update 1 -frames:v 1 "out6-one-color-normalize.png" \
       -map "[zoom]"   -update 1 -frames:v 1 "out6-one-color-normalize-zoom.png"
```

![out6-one-color-normalize.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/d5b975e1-b854-dbb2-3193-d42674c0d684.png "out6-one-color-normalize.png")
![out6-one-color-normalize-zoom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/f55f9f1a-a3c2-f7aa-715d-54ee3a614590.png "out6-one-color-normalize-zoom.png")

へ～そうなんだ。
**じゃあダメだねぇ**。

…ということで、`unpremultiply` フィルターを使っても、フリンジが**完璧な汎用性で解消されるわけではない**っぽい。
しかし、私が見つけられた方法の中では現状最もマシでもある。

FFmpeg ともあろうものがこの程度の合成もできないとは到底思えないので、何か真の解決策がありそうな気がする。
募集中。


# 余談：同色フリンジを肉眼で見る

ピンク色一色の出力を期待した際に観測された**同色フリンジ（仮）**<wbr>は、肉眼では到底認識できないレベルの微妙～な色の差だったので、`normalize` フィルターのお力を借りてようやく可視化できた。

しかしこの同色フリンジ、場合によっては肉眼で見えることもある。
具体的には、

- 前景に描くものをもっと複雑な形状にする
- 適当にアニメーションさせる
- 拡大する

という感じで頑張れば、ようやく肉眼でも若干見えるようになったり…ならなかったりする。

実際に、ピンク色の背景にピンク色の「あ」という文字が回転している映像を作ってみる。
また、比較用として文字色の方を白にしたものも作成する。

```bash
#!/usr/bin/env bash

CreateRotatingText () {  # $1: 背景色, $2: 文字色
  ffmpeg -loglevel warning -y \
         -f lavfi -i "color = color=${1}: size=100x100,
                      format = rgba" \
         `# 透明（黒色透明）の映像ソース` \
         -f lavfi -i "nullsrc = size=100x100,
                      format = rgba" \
         `# 透明映像に「あ」を描画して 60°/s で回転させ続け、背景映像に重ね、拡大版も同時作成` \
         -filter_complex \
           "[1] drawtext = text='あ':
                           fontfile='C\:/Windows/fonts/NotoSansJP-ExtraBold.ttf':
                           fontcolor=${2}:
                           fontsize=90:
                           x=(main_w-text_w)/2:
                           y=(main_h-text_h)/2,
                rotate = angle=(t*60+30)*PI/180: fillcolor=none,
                unpremultiply = inplace=1 [text];
            [0] [text] overlay = format=rgb,
                       split [normal] [tmp];
            [tmp] crop = y=0: h=40,
                  scale = width=in_w*6: height=-1: flags=neighbor [zoom]" \
         `# 長さ 6 秒（1 回転分）で無限ループする APNG として出力` \
         -map "[normal]" -plays 0 -t 6 "out7-${2}-text-rotate.apng" \
         -map "[zoom]"   -plays 0 -t 6 "out7-${2}-text-rotate-zoom.apng"
}

CreateRotatingText pink pink   # ピンク背景にピンク文字（ほぼ一色だが同色フリンジがある）
CreateRotatingText pink white  # ピンク背景に白文字（比較用。普通に字が見える）
```

計 4 個の APNG ファイルが出力されるが、Qiita でそのまま 4 個の画像を縦に並べるのは見づらいので、1 個の映像に敷き詰めてみる。
また、そもそもだが APNG は Qiita での掲載に難があるし、恐らく元映像には 256 色も使われていない（= GIF アニメに変換しても劣化が無い）ので、GIF アニメにしてみる。
念のために色数も教えてもらう。

```bash
gap=10
ffmpeg -i "out7-pink-text-rotate.apng" \
       -i "out7-pink-text-rotate-zoom.apng" \
       -i "out7-white-text-rotate.apng" \
       -i "out7-white-text-rotate-zoom.apng" \
       `# 敷き詰めて GIF アニメにする` \
       -filter_complex \
         "[0] [1] [2] [3] xstack = inputs=4:
                                   layout=0_0|0_h0+${gap}|w0+${gap}_0|0_h0+${gap}+h1+${gap},
                          split [main] [tmp];
          [tmp] palettegen [palette];
          [main] [palette] paletteuse" \
       -loop 0 -t 6 -y "out7-all.gif" 2>&1 \
| grep "palettegen"  # "140(+1) colors generated out of 140 colors" と出る
```

![out7-all.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225134/588ac0b8-80c2-593b-8e76-b16fb0736f20.gif "out7-all.gif")

※「あ」の回転が再生されない場合は、画像をクリックして別タブで開いてみてください。

原寸の 2 個と大きい白文字の 1 個は単に比較用なので、**中央の大きいピンク色の映像に注目**。
この映像はピンク色一色のはずだが、よ～く見れば大きい白文字の方と同じ形の「あ」の**おぼろげな輪郭が見える**はず。

まぁ、そんだけ。

## 余談の余談：`drawtext` のフォント指定がややめんどい

文字を描画するフィルター `drawtext` のフォントパス指定パラメーター `fontfile` は、クォーテーションやエスケープが意外とめんどかった。
フォント指定を少しでもミスると **"Fontconfig error: Cannot load default config file: No such file: (null)"** のようなエラーで怒られ続けることになる。

こんな余計な所でハマりたくない人は、下記を全て守るのが無難そうに思う。

- フィルター文字列は全体をダブルクォート `""`
- フォントパスは全体をシングルクォート `''`
- フォントパスのコロン `:` はシングルエスケープ
- パス区切り文字はスラッシュ `/`

つまりこう。

```bash
"drawtext = fontfile='C\:/path/to/font.ttf':
            他のパラメーター,
 他のフィルター"
```

<!--
```bash:検証用テンプレ
ffmpeg -loglevel warning -f lavfi -i "color = color=white: size=100x100" \
       -filter:v "drawtext = text=Q:
                             fontfile='C\:/Windows/fonts/arial.ttf':
                             fontsize=90" \
       -update 1 -frames:v 1 -y "q.png"
```
-->

そんだけ。


# 参考リンク

## FFmpeg 公式

- ffmpeg Documentation https://ffmpeg.org/ffmpeg-all.html
  - 全部入りの膨大なドキュメント

<details><summary>本記事で使った全ての機能へのリンクを列挙しまくったら長くなったので、畳んでおく。</summary>

本記事の重要キャラっぽいやつは何となく太字。

- ffmpeg Documentation https://ffmpeg.org/ffmpeg.html
  - [3.1 Filtering](https://ffmpeg.org/ffmpeg.html#Filtering): フィルターの概説
  - [5.2 Generic options](https://ffmpeg.org/ffmpeg.html#Generic-options): `-loglevel warning`
  - [5.4 Main options](https://ffmpeg.org/ffmpeg.html#Main-options): **`-f`**（force format）、**`-i`**（input）、`-y`（yes）、`-t`（time）、`-frames:v`、`-filter:v`
  - [5.11 Advanced options](https://ffmpeg.org/ffmpeg.html#Advanced-options): **`-filter_complex`**、`-map`
- FFmpeg Utilities Documentation https://ffmpeg.org/ffmpeg-utils.html
  - [2.7 Color](https://ffmpeg.org/ffmpeg-utils.html#Color): **色書式**（`色@不透明度`）、色名
- FFmpeg Formats Documentation https://ffmpeg.org/ffmpeg-formats.html
  - [4.15 gif](https://ffmpeg.org/ffmpeg-formats.html#gif-2): `-loop`
  - [4.19 image2](https://ffmpeg.org/ffmpeg-formats.html#image2-2): `-update 1`
  - [4.26 null](https://ffmpeg.org/ffmpeg-formats.html#null): `-f null "-"`
- FFmpeg Devices Documentation https://ffmpeg.org/ffmpeg-devices.html
  - [3.12 lavfi](https://ffmpeg.org/ffmpeg-devices.html#lavfi): **`-f lavfi -i`**
- FFmpeg Filters Documentation https://ffmpeg.org/ffmpeg-filters.html
  - [11 Video Filters](https://ffmpeg.org/ffmpeg-filters.html#Video-Filters)
    - [11.48 crop](https://ffmpeg.org/ffmpeg-filters.html#crop): `crop`、[11.76 drawtext](https://ffmpeg.org/ffmpeg-filters.html#drawtext-1): `drawtext`、[11.98 format](https://ffmpeg.org/ffmpeg-filters.html#format-1): `format = rgba`、[11.175 normalize](https://ffmpeg.org/ffmpeg-filters.html#normalize): `normalize`、[11.180 overlay](https://ffmpeg.org/ffmpeg-filters.html#overlay-1): **`overlay`**、[11.183 pad](https://ffmpeg.org/ffmpeg-filters.html#pad-1): `pad`、[11.184 palettegen](https://ffmpeg.org/ffmpeg-filters.html#palettegen-1): `palettegen`、[11.185 paletteuse](https://ffmpeg.org/ffmpeg-filters.html#paletteuse): `paletteuse`、[11.210 rotate](https://ffmpeg.org/ffmpeg-filters.html#rotate): `rotate`、[11.212 scale](https://ffmpeg.org/ffmpeg-filters.html#scale-1): `scale`、[11.261 unpremultiply](https://ffmpeg.org/ffmpeg-filters.html#unpremultiply): **`unpremultiply = inplace=1`**、[11.285 xstack](https://ffmpeg.org/ffmpeg-filters.html#xstack-1): `xstack`
  - [15 Video Sources](https://ffmpeg.org/ffmpeg-filters.html#Video-Sources)
    - [15.10 allrgb, allyuv, color, colorchart, colorspectrum, haldclutsrc, nullsrc, pal75bars, pal100bars, rgbtestsrc, smptebars, smptehdbars, testsrc, testsrc2, yuvtestsrc](https://ffmpeg.org/ffmpeg-filters.html#allrgb_002c-allyuv_002c-color_002c-colorchart_002c-colorspectrum_002c-haldclutsrc_002c-nullsrc_002c-pal75bars_002c-pal100bars_002c-rgbtestsrc_002c-smptebars_002c-smptehdbars_002c-testsrc_002c-testsrc2_002c-yuvtestsrc): **`color`**、`nullsrc`
  - [17 Multimedia Filters](https://ffmpeg.org/ffmpeg-filters.html#Multimedia-Filters)
    - [17.33 split, asplit](https://ffmpeg.org/ffmpeg-filters.html#split_002c-asplit): `split`
- FFmpeg/libavformat/apngenc.c - GitHub
  https://github.com/FFmpeg/FFmpeg/blob/n6.0/libavformat/apngenc.c#L296
  - APNG の `-plays` オプションがまだドキュメントに無い！

</details>

## ニコラボ

FFmpeg の膨大な機能群を片っ端から日本語で解説してくださっているサイト。
大変参考になった。

- ニコラボ https://nico-lab.net/
  - [ffmpeg](https://nico-lab.net/about-ffmpeg/)
    - [フィルタの記述方法](https://nico-lab.net/about-ffmpeg/#i-2)
  - [ffmpeg で使える映像のテストソース](https://nico-lab.net/testsrc_with_ffmpeg/)
  - [フォーマット変換するformat、aformat](https://nico-lab.net/format_aformat_with_ffmpeg/)
  - [映像に余白を追加する pad](https://nico-lab.net/pad_with_ffmpeg/)
  - [映像を任意の角度に回転させる rotate](https://nico-lab.net/rotate_with_ffmpeg/)
  - [映像の上に映像をのせる overlay](https://nico-lab.net/overlay_with_ffmpeg/)
  - [映像を指定座標に切り取る crop](https://nico-lab.net/crop_with_ffmpeg/)
  - [リサイズする scale](https://nico-lab.net/scale_with_ffmpeg/)
  - [ffmpeg で 256色を最適化する palettegen, paletteuse](https://nico-lab.net/optimized_256_colors_with_ffmpeg/)
  - [APNG をループ出力する](https://nico-lab.net/infinity_loop_apng/)

## Stack Overflow

- FFmpeg transparent PNG black outline issue
  https://stackoverflow.com/questions/48144440
  - `alpha=premultiplied` 等が提案されているが、`unpremultiply` は無い。
- FFmpeg: Removing black outline on overlay after alphamerge
  https://stackoverflow.com/questions/71910384
  - この質問に[私が `unpremultiply` を絡めて回答した](https://stackoverflow.com/questions/71910384#76034851)のだが、その内容を日本語でまとめ直しておきたくて本記事を書いた。
- How to extract duration time from ffmpeg output? &gt; 採用済み回答
  https://stackoverflow.com/questions/6239350#6239379
  - FFmpeg のやかましいログは標準エラー出力なので、後の `grep` 等にパイプしたければ `2>&1` が要る、という話。

## 他

- コンポジターに必要なアルファチャンネルの知識（前編） - コンポジゴク
  http://compojigoku.blog.fc2.com/blog-entry-4.html
- コンポジターに必要なアルファチャンネルの知識（後編） - コンポジゴク
  http://compojigoku.blog.fc2.com/blog-entry-5.html
  - プリマルチプライについてのわかりやすい解説。

<!--->

- Qiita記事でAPNGの投稿と再生はできるのか、実際に上げてみた - Qiita
  https://qiita.com/Phroneris/items/ae8430b310b929ec34db
  - **それは私です！**

&ZeroWidthSpace;

おわり