【ffmpeg】Unknown decoder 'libx265' エラー

> [ffmpeg](https://ja.wikipedia.org/wiki/FFmpeg) を使いエンコードしようとすると、`Unknown decoder 'libx265'`エラーがでます。しかし、x265 のコーデック `libx256` はインストール済みです。

```shell-session
$ ffmpeg -loop 1 -vcodec libx265 -crf 30 -i background.png -i overlay.mp4 -filter_complex "[1]scale=680:-1[inner];[0][inner]overlay=66:218:shortest=1[out]" -map "[out]" -map 1:a -
c:a copy -y output.mp4
ffmpeg version 6.0 Copyright (c) 2000-2023 the FFmpeg developers
  built with gcc 12.2.1 (Alpine 12.2.1_git20220924-r10) 20220924
  configuration: --prefix=/usr --disable-librtmp --disable-lzma --disable-static --disable-stripping --enable-avfilter --enable-gnutls --enable-gpl --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libmp3lame --enable-libopenmpt --enable-libopus --enable-libplacebo --enable-libpulse --enable-librist --enable-libsoxr --enable-libsrt --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-libzimg --enable-libzmq --enable-lto --enable-pic --enable-postproc --enable-pthreads --enable-shared --enable-vaapi --enable-vdpau --enable-vulkan --optflags=-O3 --enable-libjxl --enable-libsvtav1 --enable-libvpl
  libavutil      58.  2.100 / 58.  2.100
  libavcodec     60.  3.100 / 60.  3.100
  libavformat    60.  3.100 / 60.  3.100
  libavdevice    60.  1.100 / 60.  1.100
  libavfilter     9.  3.100 /  9.  3.100
  libswscale      7.  1.100 /  7.  1.100
  libswresample   5.  0.100 /  5.  0.100
  libpostproc    57.  1.100 / 57.  1.100
Unknown decoder 'libx265' # 👈　これ

$ # インストールはされている
$ apk list --installed *265*
x265-libs-3.5-r4 x86_64 {x265} (GPL-2.0-or-later) [installed]
```

## TL; DR <sub><sup>（今北産業）</sup></sub>

1. 引数のオプションの並びが間違っています
1. 一般的なコマンドと違い、<font color=darkorange>`ffmpeg` の引数はオプションであっても記載する順番に意味がある</font>ので注意します
1. 出力のコーデック指定（`-vcodec libx265 -crf 30`）は出力直前に記載するのが吉です

```diff
ffmpeg \
    -loop 1 \
-   -vcodec libx265 -crf 30 \
    -i background.png \
    -i overlay.mp4 \
    -filter_complex "[1]scale=680:-1[inner];[0][inner]overlay=66:218:shortest=1[out]" \
    -map "[out]" \
    -map 1:a \
    -c:a copy -y \
+   -vcodec libx265 -crf 30 \
    output.mp4
```

## TS; DR <sub><sup>（静止画に縮小した動画を載せる例）</sup></sub>

以下は、表題とは関係がないのですが、何をしているのか自分でも把握しておきたかったので、各々の引数（オプション）の意味を調べてみました。また、どうせ忘れるので自分のググラビリティとして。

Linux 環境（docker+alpine）で [ffmpeg](https://ja.wikipedia.org/wiki/FFmpeg) を使い、静止画の上に小さくリサイズした動画を載せたオーバーレイ動画を作りました。動画にテロップを載せる[スーパーインポーズ](https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%BC%E3%83%91%E3%83%BC%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%82%BA_(%E6%98%A0%E5%83%8F%E7%B7%A8%E9%9B%86))の逆、つまりテレビでいう「d ボタン」を押した時のような感じの動画です。

無事作成できたものの、動画サイズを小さくしようと[コーデック](https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%BC%E3%83%87%E3%83%83%E3%82%AF#%E5%8B%95%E7%94%BB%E5%9C%A7%E7%B8%AE%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%87%E3%83%83%E3%82%AF)に [x256](https://en.wikipedia.org/wiki/X265) を使ったら `Unknown decoder 'libx265'` が出ました。しかし、x265 のコーデック `libx256` はインストール済みです。

Youtube 向けに、サイズより画質優先で変換に時間がかかっていいのであれば H265 (x265) より [AV1](https://ja.wikipedia.org/wiki/AV1)（`svt-av1-libs`）の方が、何かと良い気がします。しかし、自分の場合は、Raspberry Pi で作ったサイネージ向けなので x256 で落ち着きました。

```shell
ffmpeg -loop 1 -i background.png -i overlay.mp4 -filter_complex "[1]scale=680:-1[inner];[0][inner]overlay=66:218:shortest=1[out]" -map "[out]" -map 1:a -c:a copy -y -vcodec libx265 -crf 30 output.mp4
```

```shell:オプションの詳細
ffmpeg \
    # ループ動画ではないので 1 回に指定
    -loop 1 \
    # 背景となる画像 （input[0])
    -i background.png \
    # オーバーレイさせる（上に載せる）動画 (input[1])
    -i overlay.mp4 \
    # フィルター（加工方法）の設定で、オーバーレイの詳細を定義する
    #   [1]scale=680:-1[inner]
    #     --> 2 番目の入力ソースを横幅 680px、高さは -1 で自動調整（アスペクト比の維持）で縮小・拡大
    #   overlay=66:218:shortest=1
    #     --> 設置先座標 x=66px, y=218px
    #   shortest=1[out]
    #     --> 出力の終了を動画の短い方に合わせる（画像はフレーム数が決まっていないので、動画に方に合わせる）
    -filter_complex "[1]scale=680:-1[inner];[0][inner]overlay=66:218:shortest=1[out]" \
    # 続く map 設定が出力ファイルが対象であることを指定
    -map "[out]" \
    # 入力ソース 2 （input[1]） のオーディオを利用する
    -map 1:a \
    # コンテナ（動画と音声のアーカイブ）のオーディオは、そのままコピー
    -c:a copy \
    # ファイルを上書き
    -y \
    # 出力動画のビデオ・コーデックを x265 を指定し、画質を 30 （範囲は 0-51、小さいほど高画質）
    -vcodec libx265 -crf 30 \
    # 出力先
    output.mp4
```

```dockerfile:Dockerfile
FROM python:alpine

# Install dependencies
RUN apk --no-cache add \
    ffmpeg \
    ffmpeg-libs \
    x265-libs \
    gcc \
    musl-dev

RUN pip3 install yt-dlp --no-dependencies

WORKDIR /data
```

- 検証環境

    ```shell-session
    $ sw_vers
    ProductName:	macOS
    ProductVersion:	12.6.9
    BuildVersion:	21G726

    $ docker -v
    Docker version 24.0.5, build ced0996

    $ docker run --rm python:alpine cat /etc/os-release | grep PRETTY_NAME
    PRETTY_NAME="Alpine Linux v3.18"
    
    $ docker run --rm python:alpine python --version
    Python 3.11.5
    
    $ docker run --rm python:alpine pip --version
    pip 23.2.1 from /usr/local/lib/python3.11/site-packages/pip (python 3.11)
    ```

### 参考文献

- [ffmpeg のフィールターオプション](https://ffmpeg.org/ffmpeg-filters.html) @ ffmpeg.org （公式）
- [ffmpegのmapを解説する](https://qiita.com/cabbage_lettuce/items/21348358ba46f4110d75) @ Qiita
- [H.264でエンコード](https://tech.ckme.co.jp/ffmpeg_h264.shtml) @ tech.ckme.co.jp
- [最新ffmpegのオプションまとめ](http://mobilehackerz.jp/archive/wiki/index.php?%BA%C7%BF%B7ffmpeg%A4%CE%A5%AA%A5%D7%A5%B7%A5%E7%A5%F3%A4%DE%A4%C8%A4%E1) | Wiki @ MobileHackerz
- [FFmpegで動画編集をするガイド](https://moriyoshi.hatenablog.com/entry/2015/12/17/224127) @ moriyoshiの日記
- [ffmpeg](https://nico-lab.net/about-ffmpeg/) @ ニコラボ
- [AV1](https://trac.ffmpeg.org/wiki/Encode/AV1) @ trac.ffmpeg.org