OpenCV Video I/Oのバックエンドとライセンス

# はじめに

OpenCVのvideoioモジュールを使って普段から動画の読み込み・書き込みをしていますが、裏でどんなライブラリがエンコード・デコードしているのかなんとなくは知っていたものの、他にどんな選択肢があるのかなどを網羅的に調べたことはなかったので、興味を持って調べた結果をまとめます。

# Video I/Oとは

OpenCVのvideoioモジュールは、ビデオキャプチャデバイス（カメラ）やビデオファイルからフレームを読み込むため、またビデオファイルにフレームを書き込むためのAPIを提供するモジュールです。このモジュールを使用することで、ビデオの入力と出力を簡単に扱うことができます。

主な機能は、カメラデバイスやビデオファイルからフレームを読み込むビデオキャプチャ（読み込み）機能と、ビデオファイルにフレームを書き込むビデオライティング（書き込み）機能の2つです。どちらも複数のコーデックをサポートしており、さまざまなビデオフォーマットに対応できます。

以下は、ビデオキャプチャ機能を利用する例です。

```python
import cv2

# 動画ファイルのパス
video_path = "path_to_your_video.mp4"

# 動画ファイルのキャプチャを作成
cap = cv2.VideoCapture(video_path)

# キャプチャが正しく開かれているか確認
if not cap.isOpened():
    print("Error opening video file")

# フレームを1つずつ読み込んで表示
while cap.isOpened():
    ret, frame = cap.read()  # フレームの読み込み
    if not ret:
        break  # フレームが読み込めなかった場合ループを抜ける

    cv2.imshow("Frame", frame)  # フレームの表示

    # 'q'キーが押されたら終了
    if cv2.waitKey(25) & 0xFF == ord("q"):
        break

# リソースを解放
cap.release()
cv2.destroyAllWindows()
```

これだけ見るとOpenCVが読み込みとデコードを両方やっているように見えますが、実はOpenCVはインタフェースを提供しているだけで、実際の読み込みやデコード処理はバックエンドと呼ばれる別のライブラリが実行しています。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302427/2289f6c1-fb65-5654-2d22-154b0ff096fb.png)|
|:--|
出典：https://docs.opencv.org/4.x/d0/da7/videoio_overview.html

これはOpenCVのリファレンスにあるVideo I/Oの構成図です。OpenCV Video I/Oの下にOpenCV Video I/O API Backendsという層がありますが、これがバックエンドです。バックエンドはOpenCVのビルド時どのライブラリを取り込んだかと、実行時にどのバックエンドを選択したかで決まります。

# バックエンド

全てではありませんが、いくつかのバックエンドとその特徴を示します。

|名称|特徴|用途|サポートプラットフォーム|
|:--|:--|:--|:--|
|FFmpeg|幅広いビデオおよびオーディオフォーマットをサポートする強力なマルチメディアフレームワーク|ほぼすべての一般的なビデオフォーマットの読み書き|Windows, macOS, Linux|
|GStreamer|マルチメディア処理のためのパイプラインベースのフレームワーク|複雑なメディアパイプラインの作成やカスタマイズが可能|Windows, macOS, Linux|
|DirectShow|Windowsプラットフォームのためのメディアストリーミングアーキテクチャ|Windowsでのビデオキャプチャデバイスやファイルの読み込み|Windows|
|Media Foundation|Windows用のマルチメディアプラットフォーム|新しいWindowsプラットフォームでのビデオキャプチャやエンコード|Windows|
|V4L/V4L2 (Video for Linux)|LinuxプラットフォームのビデオキャプチャAPI|Linux上のカメラデバイスからのビデオキャプチャ|Linux|
|OpenCV Image Sequence (Images)|連続した画像ファイルをビデオフレームとして扱うことができる|画像シーケンスをビデオとして読み込み・書き込み|Windows, macOS, Linux|
|Intel Media SDK|Intelのハードウェアアクセラレーションを利用したマルチメディア処理フレームワーク|IntelのCPUおよびGPUを使用した高速ビデオ処理|Windows, Linux|
|NVIDIA Video Codec SDK (NVDEC/NVENC)|NVIDIAのGPUを利用したハードウェアアクセラレーションビデオデコードおよびエンコード|高速なビデオデコードおよびエンコード|Windows, Linux|
|AVFoundation|Appleのマルチメディアフレームワーク|macOSおよびiOSでのビデオキャプチャおよび再生|macOS, iOS|
|Xine|Linux用のマルチメディアプレーヤーライブラリ|マルチメディアファイルの再生|Linux|

これらのバックエンドは、それぞれ異なるプラットフォームや用途に特化しています。OpenCVを使用する際には、目的に応じて適切なバックエンドを選択することが重要です。特にFFmpegやGStreamerは、幅広いフォーマットのサポートや高度なメディア処理機能を提供するため、一般的に推奨されるバックエンドです。

今使用しているOpenCVがどのバックエンドを利用できるかは、以下のコマンドを実行することで確認可能です。

```python
import cv2
print(cv2.getBuildInformation())
```

出力例

```
  Video I/O:
    DC1394:                      NO
    FFMPEG:                      YES (prebuilt binaries)
      avcodec:                   YES (58.134.100)
      avformat:                  YES (58.76.100)
      avutil:                    YES (56.70.100)
      swscale:                   YES (5.9.100)
      avresample:                YES (4.0.0)
    GStreamer:                   NO
    DirectShow:                  YES
    Media Foundation:            YES
      DXVA:                      YES
```

# バックエンドとライセンス

どのバックエンドを使用するかを検討するとき、バックエンドのライセンスには注意を払う必要があります。例えば、FFmpegはどのエンコーダ・デコーダと動的リンクするかによって、GPLとLGPLとでライセンスが変化します。意識することなく使っていたら実はGPL版のFFmpegと動的リンクしていて、GPL汚染が発生していたということも有り得る話です。

また、H.264（MPEG-4 AVC）やH.265（HEVC）は非常に広く使われているビデオ圧縮規格ですが、その技術は多くの企業が所有する特許によって保護されています。このため、H.264/H.265技術を使用する製品やサービスを提供する場合、特許使用料（ロイヤリティ）の支払いが必要となることがあるため、そちらにも注意が必要です。

## 著名なH.264のエンコーダとデコーダ

|名前|エンコード|デコード|ライセンス|
|:--|:--|:--|:--|
|x264|○|×|GPLv2または商用ライセンス|
|libavcodec|○|○|LGPL|
|Intel Quick Sync Video (QSV)|○|○|プロプライエタリ（無料）|
|NVIDIA NVENC/NVDEC|○ (NVENC)|○ (NVDEC)|プロプライエタリ（NVIDIA GPU）|
|OpenH264|○|○|BSD（公式のビルド済みモジュールを利用する限り特許使用料の支払いが回避可能）|
|AMD Video Coding Engine (VCE)|○|○|プロプライエタリ（AMD GPU）|
|Apple VideoToolbox|○|○|プロプライエタリ（Appleデバイス）|

一番注意が必要と思われるのはx264です。デコード機能はないのでVideoCaptureを利用したいだけなら不要なモジュールですが、FFmpegのビルド時にデフォルトで入ってくるため、明示的にx264の使用を避ける必要があります。デコード機能を利用したいだけならオープンソースなOpenH264かlibavcodecの利用が無難かと思われます。pipでインストールした`opencv-python`はlibavcodecを利用しているため、GPL汚染などを気にせずH.264のエンコード・デコードが可能になっています。一方でC++を使っていて自前でビルドしたOpenCV+FFmpegを使う場合は、どのエンコーダ・デコーダを利用しているか注意が必要です。

## 著名なH.265のエンコーダとデコーダ

|名前|エンコード|デコード|ライセンス|
|:--|:--|:--|:--|
|x265|○|×|GPLv2または商用ライセンス|
|libde265|×|○|LGPLv3|
|libavcodec|○|○|LGPL|
|NVIDIA NVENC/NVDEC|○ (NVENC)|○ (NVDEC)|プロプライエタリ（NVIDIA GPU）|
|Intel Media SDK|○|○|プロプライエタリ（無料）|
|AMD VCE|○|○|プロプライエタリ（AMD GPU）|
|Apple VideoToolbox|○|○|プロプライエタリ（Appleデバイス）|

こちらもx265には注意が必要です。デコード機能を利用したいだけならオープンソースなlibde265かlibavcodecの利用が無難かと思われます。こちらもpipでインストールした`opencv-python`はlibavcodecを利用しているため、GPL汚染などを気にせずH.265のエンコード・デコードが可能になっています。一方でC++を使っていて自前でビルドしたOpenCV+FFmpegを使う場合は、どのエンコーダ・デコーダを利用しているか注意が必要です。

# OpenH264+FFmpeg+OpenCVのソースビルド

別の記事で作成しました。

https://qiita.com/JuvenileTalk9/items/e857b9a62b447cc725e3

# おわりに

libavcodecがH.264のデコードを担当していることは知っていましたが、H.265も動くことは知りませんでした。逆に言えば、同じソースでH.265のデコードが動いてしまう＝実はH.265のロイヤリティ支払い違反していた、という場合もあると感じます。企業でH.264デコードをしたくてOpenCV使っているところがどのような対策をしているのかは少し興味があります。