GstreamerでRTSPを使った動画の送受信と保存

# はじめに
Gstreamerを使えば、ラズパイを監視カメラ化したり、見守りカメラ化したりなど簡単にネットワークカメラを作ることができます。
今回、RTSPを用いた動画の送受信をやろうと思ったのですが、サクッと始められるような情報がまとまったページがなかなか見つかりませんでした。
そこで、動いたものを備忘録として以下にまとめておこうと思います。

# 環境構築
- OS: Ubuntu18.04/20.04
- Gstreamer本体
- Gstreamer plugin-base
- Gstreamer plugin-good
- Gstreamer plugin-bad
- Gstreamer plugin-ugly
- Gstreamer rtsp-server

のビルドを行います。
bashファイルとDockerファイルを作ったのですが非常に長いので、このページの[付録](https://qiita.com/bigface00/items/7c1f568dba96c34ec077#%E4%BB%98%E9%8C%B2)を参考にして下さい。

# Gstreamerを使う
ここからは上記に挙げた環境が整っていることを前提として進めていきます。
## RTSPサーバーを立ち上げる
Gstreamer rtsp-serverのディレクトリである`gst-rtsp-server`のbuildディレクトリ内にexamplesがあります。
その中の`test-launch`を使って配信を行います。まずは、そこへ移動しましょう。

```bash
cd <Gstreamerを格納したディレクトリ>/gst-rtsp-server/build/examples
```
以下のコマンドで配信することができます。
動画のサイズやフレームレートは適宜変えて下さい。
### H264で配信する
```bash
./test-launch '( v4l2src device=/dev/video0 ! video/x-h264, width=640, height=480, framerate=30/1 ! h264parse config-interval=1 ! rtph264pay name=pay0 pt=96 )'
``` 
### MJPGで配信する
```bash
./test-launch '( v4l2src device=/dev/video0 ! image/jpeg, width=640, height=480, framerate=30/1 ! jpegparse ! rtpjpegpay name=pay0 pt=96 )'
```

上記のコマンドを実行するとrtspのアドレスが表示されます。
但し、表示されたアドレスを入力しても何も取得することができません。
`127.0.0.1`の部分をサーバー側のIPアドレスに置き換えてください。
参考: [[Kinesis Video Streams] GStreamerを使用したRTSPサーバを構築し、Macから動画を送信してみました。](https://dev.classmethod.jp/articles/amazon-kinesis-vidseo-streams-gstreamer-rtsp-server/#:~:text=rtsp%3A//%7BRaspberry%20Pi%E3%81%AE%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%7D%3A8554/test)

## RTSPサーバーで配信している動画を取得する
ローカルネットワーク上で配信されている動画を取得します。
`location=`の`<your location>`の部分をサーバー側PC（ラズパイ）のIPアドレスへ変更して下さい。
もし、異なるネットワーク間で動画の受信を行いたい場合はサーバー側のルーターの設定でポートマッピング（ポートの開放）を行って下さい。
ルーター側でポートマッピングを行ったあとは、サーバー側PC（ラズパイ）もポートの開放を行って下さい。
IPアドレスも固定したほうが良いです。
参考：[ラズパイ(Raspbian)のIP固定とポートのルール設定](https://server.xn--minecrafter-k83ja61doa.com/introduction/ip-and-port/#toc5)

また、
`Could not receive any UDP packets for 5.0000 seconds, maybe your firewall is blocking it. Retrying using a tcp connection.`
というエラーが発生して動画を受信することができませんでした。
そのため、TCP通信を強制するように`do-rtcp=TRUE`と`location=rtspt://~`としています。
参考: [Unable to play RTSP stream on ec2 instance running Microsoft Windows Server 2016 Base](https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp/issues/397)

### H264で配信されている動画をFLVで保存する
```bash
gst-launch-1.0 -v rtspsrc do-rtcp=TRUE location=rtspt://<your location>:8554/test ntp-sync=true ! application/x-rtp, media=video, encoding-name=H264  ! queue ! rtph264depay ! h264parse ! flvmux ! filesink location=received_h264.flv
```

### MJPGで配信されている動画をAVIで保存する
```bash
gst-launch-1.0 -v rtspsrc do-rtcp=TRUE location=rtspt://<your location>:8554/test ntp-sync=true ! application/x-rtp, media=video ! queue ! rtpjpegdepay ! jpegparse ! avimux ! filesink location=received_mjpg.avi
```

### H264で配信されている動画を1フレームずつ画像で保存する
`<Your directory>`の部分は適宜変えて下さい。

```bash
gst-launch-1.0 -v rtspsrc do-rtcp=TRUE location=rtspt://<your location>:8554/test ntp-sync=true ! application/x-rtp ! queue ! rtph264depay ! h264parse ! multifilesink location="<Your directory>/frame%08d.jpg"
```

### MJPGで配信されている動画を1フレームずつ画像で保存する
```bash
gst-launch-1.0 -v rtspsrc do-rtcp=TRUE location=rtspt://<your location>:8554/test ntp-sync=true ! application/x-rtp ! queue ! rtpjpegdepay ! jpegparse ! multifilesink location="<Your directory>/frame%08d.jpg"
```

# 付録
## Gstreamerビルド用Dockerfile
インストールするフォルダや、バージョンは適宜変えて下さい。

### Ubuntu18.04

```Dockerfile
FROM ubuntu:18.04

USER root

# Set time zone
ENV TZ=Asia/Tokyo
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# Install Python
RUN apt update && apt -y --no-install-recommends install \
    sudo \
    python3 \
    python3-dev \
    python3-pip \
    wget
RUN sudo apt install -y python3.8
# Set Python3.8 as default python3
RUN sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 1
RUN sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 2
RUN sudo update-alternatives --auto python3
RUN sudo update-alternatives --config python3
# Install meson
RUN sudo python3.8 -m pip install -U pip && sudo python3.8 -m pip install meson
# Install cmake
RUN sudo apt install build-essential checkinstall zlib1g-dev libssl-dev -y
WORKDIR /home
RUN wget https://github.com/Kitware/CMake/releases/download/v3.25.1/cmake-3.25.1.tar.gz
RUN tar -zxvf cmake-3.25.1.tar.gz
RUN cd cmake-3.25.1 && sudo ./bootstrap && sudo make && sudo make install
WORKDIR /home
# Install dependent libraries
RUN sudo apt -y --no-install-recommends install \
    vim \
    wget \
    pkg-config \
    git \
    autoconf \
    automake \
    libtool \
    flex \
    bison \
    libglib2.0-dev \
    libjpeg-dev \
    libx264-dev \
    libgtk2.0-dev \
    libcanberra-gtk* \
    libgtk-3-dev \
    libasound2-dev \
    libegl1-mesa-dev \
    libglfw3-dev \
    libgles2-mesa-dev \
    libjpeg-dev \
    librtmp-dev \
    libvo-aacenc-dev \
    ca-certificates \
    ninja-build \
    libxml2-dev \
    libffi6 \
    libffi-dev
# Build and install latest wayland
RUN git clone https://gitlab.freedesktop.org/wayland/wayland.git
WORKDIR /home/wayland
RUN export WLD=/usr && meson build/ -Ddocumentation=false && meson build/ --prefix=$WLD && ninja -C build/ install
# Build and install latest wayland-protocols
WORKDIR /home
RUN git clone https://gitlab.freedesktop.org/wayland/wayland-protocols.git
WORKDIR /home/wayland-protocols
RUN export WLD=/usr && meson build/ --prefix=$WLD && ninja -C build/ install
# Create directory
WORKDIR /home
RUN mkdir gst
# Install gstreamer core
WORKDIR /home/gst
RUN wget https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.19.2.tar.xz && tar -xf gstreamer-1.19.2.tar.xz
WORKDIR /home/gst/gstreamer-1.19.2
RUN mkdir build && cd build && meson --prefix=/usr       \
                                    --wrap-mode=nofallback \
                                    -D gst_debug=true   \
                                    -D package-origin=https://gstreamer.freedesktop.org/src/gstreamer/ \
                                    -D package-name="GStreamer 1.19.2 BLFS" .. \
                                    && ninja -j4 && sudo ninja install && sudo ldconfig
# plugin-base
WORKDIR /home/gst
RUN wget https://gstreamer.freedesktop.org/src/gst-plugins-base/gst-plugins-base-1.19.2.tar.xz && tar -xf gst-plugins-base-1.19.2.tar.xz
WORKDIR /home/gst/gst-plugins-base-1.19.2
RUN mkdir build && cd build && meson --prefix=/usr \
                                -D gl_winsys=wayland \
                                -D package-origin=https://gstreamer.freedesktop.org/src/gstreamer/ .. \
                                && ninja -j4 && sudo ninja install && sudo ldconfig
# plugin-good
WORKDIR /home/gst
RUN wget https://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.19.2.tar.xz && tar -xf gst-plugins-good-1.19.2.tar.xz
WORKDIR /home/gst/gst-plugins-good-1.19.2
RUN mkdir build && cd build && meson --prefix=/usr       \
                                -D package-origin=https://gstreamer.freedesktop.org/src/gstreamer/ \
                                -D package-name="GStreamer 1.19.2 BLFS" .. \
                                && ninja -j4 && sudo ninja install && sudo ldconfig
# plugin-bad
WORKDIR /home/gst
RUN wget https://gstreamer.freedesktop.org/src/gst-plugins-bad/gst-plugins-bad-1.19.2.tar.xz && tar -xf gst-plugins-bad-1.19.2.tar.xz
WORKDIR /home/gst/gst-plugins-bad-1.19.2
RUN mkdir build && cd build && meson --prefix=/usr       \
                                -D package-origin=https://gstreamer.freedesktop.org/src/gstreamer/ \
                                -D package-name="GStreamer 1.19.2 BLFS" .. \
                                && ninja -j4 && sudo ninja install && sudo ldconfig
# plugin-ugly
WORKDIR /home/gst
RUN wget https://gstreamer.freedesktop.org/src/gst-plugins-ugly/gst-plugins-ugly-1.19.2.tar.xz && tar -xf gst-plugins-ugly-1.19.2.tar.xz
WORKDIR /home/gst/gst-plugins-ugly-1.19.2
RUN mkdir build && cd build && meson --prefix=/usr       \
                                -D package-origin=https://gstreamer.freedesktop.org/src/gstreamer/ \
                                -D package-name="GStreamer 1.19.2 BLFS" .. \
                                && ninja -j4 && sudo ninja install && sudo ldconfig
# RTSP-server
WORKDIR /home/gst
RUN wget https://gstreamer.freedesktop.org/src/gst-rtsp-server/gst-rtsp-server-1.19.2.tar.xz && tar -xf gst-rtsp-server-1.19.2.tar.xz
WORKDIR /home/gst/gst-rtsp-server-1.19.2
RUN mkdir build && cd build && meson --prefix=/usr       \
                                --wrap-mode=nofallback \
                                -D package-origin=https://gstreamer.freedesktop.org/src/gstreamer/ \
                                -D package-name="GStreamer 1.19.2 BLFS" .. \
                                && ninja -j4 && sudo ninja install && sudo ldconfig
```

### Ubuntu20.04

```Dockerfile
FROM ubuntu:20.04

USER root

# Set time zone
ENV TZ=Asia/Tokyo
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# Install dependent libraries
RUN apt update && apt -y --no-install-recommends install \
    sudo \
    vim \
    wget \
    build-essential \
    pkg-config \
    git \
    cmake \
    autoconf \
    automake \
    libtool \
    flex \
    bison \
    libglib2.0-dev \
    libjpeg-dev \
    libx264-dev \
    libgtk2.0-dev \
    libcanberra-gtk* \
    libgtk-3-dev \
    libasound2-dev \
    libegl1-mesa-dev \
    libglfw3-dev \
    libgles2-mesa-dev \
    libjpeg-dev \
    librtmp-dev \
    libvo-aacenc-dev \
    ca-certificates \
    python3 \
    python3-dev \
    python3-pip \
    ninja-build \
    libxml2-dev
# Install meson
RUN sudo pip3 install -U pip && sudo pip3 install meson
WORKDIR /home
# Install latest wayland-protocols
RUN git clone https://gitlab.freedesktop.org/wayland/wayland.git
WORKDIR /home/wayland
RUN export WLD=/usr && meson setup build/ -Ddocumentation=false && meson build/ --prefix=$WLD && ninja -C build/ install
# Create directory
WORKDIR /home
RUN mkdir gst
# Install gstreamer core
WORKDIR /home/gst
RUN wget https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.19.2.tar.xz && tar -xf gstreamer-1.19.2.tar.xz
WORKDIR /home/gst/gstreamer-1.19.2
RUN mkdir build && cd build && meson --prefix=/usr       \
                                    --wrap-mode=nofallback \
                                    -D gst_debug=true   \
                                    -D package-origin=https://gstreamer.freedesktop.org/src/gstreamer/ \
                                    -D package-name="GStreamer 1.19.2 BLFS" .. \
                                    && ninja -j4 && sudo ninja install && sudo ldconfig
# plugin-base
WORKDIR /home/gst
RUN wget https://gstreamer.freedesktop.org/src/gst-plugins-base/gst-plugins-base-1.19.2.tar.xz && tar -xf gst-plugins-base-1.19.2.tar.xz
WORKDIR /home/gst/gst-plugins-base-1.19.2
RUN mkdir build && cd build && meson --prefix=/usr \
                                -D gl_winsys=wayland \
                                -D package-origin=https://gstreamer.freedesktop.org/src/gstreamer/ .. \
                                && ninja -j4 && sudo ninja install && sudo ldconfig
# plugin-good
WORKDIR /home/gst
RUN wget https://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.19.2.tar.xz && tar -xf gst-plugins-good-1.19.2.tar.xz
WORKDIR /home/gst/gst-plugins-good-1.19.2
RUN mkdir build && cd build && meson --prefix=/usr       \
                                -D package-origin=https://gstreamer.freedesktop.org/src/gstreamer/ \
                                -D package-name="GStreamer 1.19.2 BLFS" .. \
                                && ninja -j4 && sudo ninja install && sudo ldconfig
# plugin-bad
WORKDIR /home/gst
RUN wget https://gstreamer.freedesktop.org/src/gst-plugins-bad/gst-plugins-bad-1.19.2.tar.xz && tar -xf gst-plugins-bad-1.19.2.tar.xz
WORKDIR /home/gst/gst-plugins-bad-1.19.2
RUN mkdir build && cd build && meson --prefix=/usr       \
                                -D package-origin=https://gstreamer.freedesktop.org/src/gstreamer/ \
                                -D package-name="GStreamer 1.19.2 BLFS" .. \
                                && ninja -j4 && sudo ninja install && sudo ldconfig
# plugin-ugly
WORKDIR /home/gst
RUN wget https://gstreamer.freedesktop.org/src/gst-plugins-ugly/gst-plugins-ugly-1.19.2.tar.xz && tar -xf gst-plugins-ugly-1.19.2.tar.xz
WORKDIR /home/gst/gst-plugins-ugly-1.19.2
RUN mkdir build && cd build && meson --prefix=/usr       \
                                -D package-origin=https://gstreamer.freedesktop.org/src/gstreamer/ \
                                -D package-name="GStreamer 1.19.2 BLFS" .. \
                                && ninja -j4 && sudo ninja install && sudo ldconfig
# RTSP-server
WORKDIR /home/gst
RUN wget https://gstreamer.freedesktop.org/src/gst-rtsp-server/gst-rtsp-server-1.19.2.tar.xz && tar -xf gst-rtsp-server-1.19.2.tar.xz
WORKDIR /home/gst/gst-rtsp-server-1.19.2
RUN mkdir build && cd build && meson --prefix=/usr       \
                                --wrap-mode=nofallback \
                                -D package-origin=https://gstreamer.freedesktop.org/src/gstreamer/ \
                                -D package-name="GStreamer 1.19.2 BLFS" .. \
                                && ninja -j4 && sudo ninja install && sudo ldconfig
```