はじめに
Jetson NanoからGStreamerを使ってリモートのMacにRTSPで動画を配信したい。GStreamerは古くからあるソフトウェアなので情報は非常に多いが、映像と音声を同時にRTSPで配信するサンプルがなかなか見つからなかった。そのためここではある動画ファイルの映像と音声を同時にRTSPで送信することを試みる。
実験環境
マシン | 用途 | 動作 |
---|---|---|
Jetson Nano | サーバ | GStreamerで動画をRTSPで送信 |
MacBook Air | クライアント | VLCにより動画をRTSPで受信 |
GStreamerパイプラインの書き方
パイプライン記法については別の記事として分離した(下記URL)。
処理概要
やりたいことは「ファイルから動画を読み込みRTSPで送信」である。図にすると下記のようになる。
動画をまず「映像(video)」と「音声(audio)」に分け多重化を解く(いわゆるdemux)。それぞれRTPに変換して、最後にまた多重化して合わせ込む(mux)。後で分かったことだが、RTPの場合には合わせ込むmuxの部分は不要だった。すなわち下記の図が正しい。
動画ファイルをRTSPで配信する
準備
RTSPで配信するためにtest-launch
というプログラムを使用している。これは下記からダウンロードしてコンパイルする必要がある。
sudo apt install libgstrtspserver-1.0-dev
gcc -o test-launch test-launch.c `pkg-config --cflags --libs gstreamer-rtsp-server-1.0`
配信用スクリプトの作成
GStreamerの記法をそのまま書くと非常に分かりにくいので
- main ... 分岐前と分岐後を示すメインストリーム
- video ... 映像のみのストリーム
- audio ... 音声のみのストリーム
の3つを別々に用意し最後にスペースで結合することを考えた。また各ストリームの処理はビックリマークで結合するために配列を使用した。そのためシェルスクリプトにはbashを用いている。
#!/bin/bash
if [ $# -ne 1 ]; then
echo "usage $0 filename"
exit 1
fi
main=(
"filesrc location=$1"
"qtdemux name=demux"
)
video=(
"demux.video_0"
"queue"
"rtph264pay name=pay0 pt=96"
)
audio=(
"demux.audio_0"
"queue"
"decodebin"
"vorbisenc"
"rtpvorbispay name=pay1 pt=97"
)
pipeline_main="$(IFS=!; echo "${main[*]}" | sed 's/!/ ! /g')"
pipeline_video="$(IFS=!; echo "${video[*]}" | sed 's/!/ ! /g')"
pipeline_audio="$(IFS=!; echo "${audio[*]}" | sed 's/!/ ! /g')"
pipeline="$pipeline_main $pipeline_video $pipeline_audio"
echo "$pipeline"
./test-launch "$pipeline"
最初に実行権限を与える。
chmod +x file2rtsp.sh
あとはファイル名を指定するだけ。
./file2rtsp.sh ファイル名
説明
先のスクリプトは下記のコマンドを実行することに等しい。demux.video_0
やdemux.audio_0
などに気をつけてみると、どこで区切れているのかが分かる。
./test-launch "filesrc location=ファイル名 ! qtdemux name=demux demux.video_0 ! queue ! rtph264pay name=pay0 pt=96 demux.audio_0 ! queue ! decodebin ! vorbisenc ! rtpvorbispay name=pay1 pt=97"
VLCによる接続
接続するのはVLCを用いる。IPアドレス
の部分をサーバのアドレスにすれば接続できる。
open -a vlc rtsp://IPアドレス:8554/test
結果1
まとめ
GStreamerを使ってRTSPにより映像と音声の両方を送信することができた。GStreamerの奥が深すぎて学ぶのも一苦労だ。
おまけ「rtpmuxが不要な理由」
rtpmuxの説明
を読むと「The rtp muxer takes multiple RTP streams having the same clock-rate and muxes into a single stream with a single SSRC.」と書かれており、多重化の元となるソースは完全に同じクロックレートでなければならない。通常「映像」と「音声」のクロックレートが同じはずはないので、rtpmuxを使って多重化することはできない。従って下記(以前のシェルスクリプト)のようにrtpmuxを含めるのは間違いである。
#!/bin/bash
if [ $# -ne 1 ]; then
echo "usage $0 filename"
exit 1
fi
main=(
"rtpmux name=mux"
"filesrc location=$1"
"qtdemux name=demux"
)
video=(
"demux.video_0"
"queue"
"rtph264pay name=pay0 pt=96"
"mux.video_0"
)
audio=(
"demux.audio_0"
"queue"
"decodebin"
"vorbisenc"
"rtpvorbispay name=pay1 pt=97"
"mux.audio_0"
)
pipeline_main="$(IFS=!; echo "${main[*]}" | sed 's/!/ ! /g')"
pipeline_video="$(IFS=!; echo "${video[*]}" | sed 's/!/ ! /g')"
pipeline_audio="$(IFS=!; echo "${audio[*]}" | sed 's/!/ ! /g')"
pipeline="$pipeline_main $pipeline_video $pipeline_audio"
echo "$pipeline"
./test-launch "$pipeline"