macOS上のPodmanでGStreamerを使って動画・音声・RTP通信を扱うまで

# 概要

macOS上の[Podman](https://podman.io/)を使用して、[GStreamer](https://gstreamer.freedesktop.org/)を動作させることができました。

本記事は、その記録です。以下について説明します。

* コンテナイメージのビルド
* テスト用動画・音声のストリーミング
* ファイル出力
* RTP通信

なお、以下の内容は、本記事では扱いません。

* Podmanの使い方
* GStreamerの詳細な使い方
* HomebrewやMacPortsの使い方

また、本記事のコマンドの実行例は、Podmanの仮想マシンは起動済みであることを前提にしています。

# 使用したバージョン

本記事では、以下のバージョンを使用しました。

* macOS
  * macOS 12.6.1 （Intel Mac版）
* Podman
  * 4.2.0
* GStreamer
  * 1.20.3
* XQuartz（動画を再生する場合）
  * 2.8.2
* PulseAudio（音声を再生する場合）
  * 14.2

# Podmanを使用する理由

Podmanを使用せずとも、macOS上でGStremerを扱う方法はあります。

* 公式からパッケージをダウンロードしてインストールする
* HomebrewやMacPortsなどのパッケージマネージャからインストールする

Podmanを使用する利点は、以下の2点です。

* 環境をできる限り隔離できる
* 不要になったら簡単に削除できる

いっぽうで、ストレージの消費量が大きいという欠点もあります。

上記の利点・欠点について説明します。

## 利点：環境をできる限り隔離できる

コンテナ上でGStremerを扱うことで、macOSの環境をできる限り汚さずに使用できます。

[公式サイト](https://gstreamer.freedesktop.org/download/)にあるインストーラは、/Library/Frameworks/以下にGStremerをインストールします。

また、[Homebrew](https://brew.sh/index_ja)や[MacPorts](https://www.macports.org/)などのパッケージマネージャを用いてインストールした場合、様々な依存パッケージがインストールされます。動画・音声のエンコーダやデコーダ関係のライブラリ、表示のためのGUIライブラリなどです。

ただし、コンテナ上で扱ったとしても、環境を完全に汚さずにGStremerを使用することはできません。コンテナエンジンのインストールは必要不可欠です。また、動画の再生を行う場合はXQuartzを、音声の場合はPulseAudioのインストールが必要になります。

## 利点：不要になったら簡単に削除できる

コンテナ上でGStreamerを扱う場合、不要になった際には簡単に丸ごと削除できます。

## 欠点：ストレージの消費量が大きい

コンテナ上でGStreamerを扱う場合、ストレージの消費量が大きくなります。

本記事で作成したコンテナイメージのサイズは、約1.5GBありました。

ストレージの空き容量が気になる場合は、GStremerを直接macOSにインストールしたほうが良いでしょう。

# コンテナイメージのビルド

GStreamerを扱うためのコンテナイメージは、以下のようにビルドします。このコンテナイメージは、Ubuntu 22.04 LTSに、GStreamerのパッケージをインストールします。

```docker:Containerfile
FROM ubuntu:22.04

RUN apt update && \
    DEBIAN_FRONTEND=noninteractive apt install -y \
    libgstreamer1.0-dev \
    libgstreamer-plugins-base1.0-dev \
    libgstreamer-plugins-bad1.0-dev \
    gstreamer1.0-plugins-base \
    gstreamer1.0-plugins-good \
    gstreamer1.0-plugins-bad \
    gstreamer1.0-plugins-ugly \
    gstreamer1.0-libav \
    gstreamer1.0-tools \
    gstreamer1.0-x \
    gstreamer1.0-alsa \
    gstreamer1.0-gl \
    gstreamer1.0-gtk3 \
    gstreamer1.0-qt5 \
    gstreamer1.0-pulseaudio
```

```shell
#!/bin/bash

script_dir=$(cd $(dirname $0); pwd)

podman build -t gstreamer $script_dir
```

apt実行時に「DEBIAN_FRONTEND=noninteractive」を指定しているのは、この指定がないとtzdataのインストール時にビルドが停止してしまうためです。

# テスト用動画・音声のストリーミング

本章では、テスト用の動画や音声をコンテナ内で生成し、Mac上で再生する方法を説明します。

## テスト用動画の再生

### XQuartzの設定

Mac上でコンテナ内のウィンドウを表示するには、Xサーバのインストールが必要です。本記事では、[XQuartz](https://www.xquartz.org/)を使用します。XQuartzは、macOS用のXサーバです。

XQuartzをインストール後、以下のページを参考に設定してください。

https://qiita.com/kawaz/items/6cf04f923ebfac45a997

少なくとも、次の設定は必ず行ってください。

* 「環境設定→ セキュリティ→ 接続を認証」 をチェック
* 「環境設定→ セキュリティ→ ネットワーク・クライアントからの接続を許可する」 をチェック
* OpenGL が使えるようにする

### 実行用スクリプト

テスト用動画を再生するためのスクリプトは以下の通りです。

```shell:run_container_displaysink.sh
#!/bin/bash

script_dir=$(cd $(dirname $0); pwd)

xhost +localhost
podman run \
    --net=host \
    -e DISPLAY="host.containers.internal:0" \
    -e XDG_RUNTIME_DIR=/tmp \
    -e LIBGL_ALWAYS_INDIRECT=1 \
    -v ~/.Xauthority:/root/.Xauthority \
    -i \
    -t gstreamer \
    $*
xhost -localhost
```

コンテナの実行の前後で、Xサーバにアクセス可能なホストとしてMacを設定・設定解除しています。

「host.containers.internal」を指定することで、コンテナを実行中のMacにコンテナからアクセスできます。

XDG_RUNTIME_DIRとLIBGL_ALWAYS_INDIRECTは、指定しないとエラーメッセージが出力されるため、設定しています。

### 実行例

```shell
./run_container_displaysink.sh gst-launch-1.0 videotestsrc ! fpsdisplaysink
```

上記を実行すると、以下のようにテスト用動画が表示されます。

![XQuarz上で再生されているテスト用動画](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30639/d14fe878-db30-ddb2-ca32-eee2ac13de11.png "テスト用動画が再生される様子")

## テスト用音声の再生

### PulseAudioのインストール

コンテナ内の音声をMac上で再生するには、[PulseAudio](https://www.freedesktop.org/wiki/Software/PulseAudio/)のインストールが必要です。

MacPortsでもHomebrewでもインストールできます。

### 実行用スクリプト

テスト用音声を再生するためのスクリプトは以下の通りです。

スピーカーやヘッドホンから音声が流れますので、音量に注意してください。

```shell:run_container_audiosink.sh
#!/bin/bash

script_dir=$(cd $(dirname $0); pwd)

pulseaudio --load=module-native-protocol-tcp --exit-idle-time=-1 --daemon
podman run \
    --net=host \
    -e PULSE_SERVER="host.containers.internal" \
    -v ~/.config/pulse:/root/.config/pulse \
    -i \
    -t gstreamer \
    $*
pulseaudio -k
```

コンテナを実行する前後で、PulseAudioデーモンを起動・終了しています。

「host.containers.internal」を指定することで、コンテナを実行中のMacにコンテナからアクセスできます。

### 実行例

```shell
./run_container.sh gst-launch-1.0 audiotestsrc ! autoaudiosink
```

# ファイル出力

ファイル出力を行うには、Mac上のフォルダをコンテナ内にマウントする必要があります。事前にMac上に出力先のディレクトリを作成してください。以下の例では、カレントフォルダにdataフォルダがあることを前提としています。

実行例は以下の通りです。この例では、AV1形式のテスト用動画を格納した1秒間のWebMファイルを作成しています。Macの性能によっては、実行完了までに数分かかります。

```shell
./run_container_file.sh gst-launch-1.0 videotestsrc num-buffers=30 ! video/x-raw,width=640,height=480,framerate=30/1 ! av1enc ! webmmux ! filesink location=/data/av1.webm
```

# RTP通信

コンテナ間でRTP通信を行い、H.264形式の動画をストリーミング再生する方法を説明します。

## 送信側

### 実行用スクリプト

RTP通信の送信側のスクリプトは以下の通りです。

```shell:run_container_send.sh
#!/bin/bash

script_dir=$(cd $(dirname $0); pwd)

podman run \
    --net=host \
    -i \
    -t gstreamer \
    $*
```

コンテナのネットワークとしてMac上のネットワークを使用しています。localhostを指定することで、Mac上の他のコンテナと通信できます。

### 実行例

```shell
./run_container_send.sh gst-launch-1.0 videotestsrc ! openh264enc ! rtph264pay ! udpsink port=5004 host=localhost
```

この実行例では、localhostの5004番ポートに対して、RTPパケットをUDPで送信しています。

## 受信側

### 実行用スクリプト

```shell:run_container_receive_rtp_video.sh
#!/bin/bash

script_dir=$(cd $(dirname $0); pwd)

xhost +localhost
podman run \
    --net=host \
    -e DISPLAY="host.containers.internal:0" \
    -e XDG_RUNTIME_DIR=/tmp \
    -e LIBGL_ALWAYS_INDIRECT=1 \
    -v ~/.Xauthority:/root/.Xauthority \
    -i \
    -t gstreamer \
    $*
xhost -localhost
```

コンテナのネットワークとしてMac上のネットワークを使用する以外は、「テスト用動画の再生」と同じです。コンテナのオプションについては、「テスト用動画の再生」を参照してください。

### 実行例

```shell
./run_container_receive_rtp_video.sh gst-launch-1.0 udpsrc port=5004 address=localhost caps='application/x-rtp,media=video,clock-rate=90000,encoding-name=H264' ! decodebin3 ! videoconvert ! queue ! fpsdisplaysink
```

この実行例では、localhostの5004番ポートからRTPパケットをUDPで受信しています。

# まとめ

本記事では、macOS上のPodmanを使用して、GStreamerを動作させました。

コンテナを使用することで、複雑な依存関係を持つGStreamerの環境を、できる限り隔離することができます。

XQuartzやPluseAudioを使用すれば、動画・音声の再生ができます。また、ファイル作成やRTP通信も可能です。