LoginSignup
17
19

More than 3 years have passed since last update.

GStreamerで動画ファイルの映像と音声の両方をRTSPで配信する方法

Last updated at Posted at 2019-07-07

はじめに

Jetson NanoからGStreamerを使ってリモートのMacにRTSPで動画を配信したい。GStreamerは古くからあるソフトウェアなので情報は非常に多いが、映像と音声を同時にRTSPで配信するサンプルがなかなか見つからなかった。そのためここではある動画ファイルの映像と音声を同時にRTSPで送信することを試みる。

実験環境

マシン 用途 動作
Jetson Nano サーバ GStreamerで動画をRTSPで送信
MacBook Air クライアント VLCにより動画をRTSPで受信

GStreamerパイプラインの書き方

パイプライン記法については別の記事として分離した(下記URL)。

gst-launch-1.0の典型的なパイプライン記法

処理概要

やりたいことは「ファイルから動画を読み込みRTSPで送信」である。図にすると下記のようになる。

gstreamer_rtp_graph.png

動画をまず「映像(video)」と「音声(audio)」に分け多重化を解く(いわゆるdemux)。それぞれRTPに変換して、最後にまた多重化して合わせ込む(mux)。後で分かったことだが、RTPの場合には合わせ込むmuxの部分は不要だった。すなわち下記の図が正しい。

gstreamer_rtp_graph2.png

動画ファイルを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を用いている。

file2rtsp.sh
#!/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"

最初に実行権限を与える。

JetsonNanoで実施
chmod +x file2rtsp.sh

あとはファイル名を指定するだけ。

JetsonNanoで実施
./file2rtsp.sh ファイル名

説明

先のスクリプトは下記のコマンドを実行することに等しい。demux.video_0demux.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アドレスの部分をサーバのアドレスにすれば接続できる。

Macで実施
open -a vlc rtsp://IPアドレス:8554/test

結果1
rtsp_vlc_client.png

まとめ

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を含めるのは間違いである。

file2rtsp.sh.old
#!/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"
17
19
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
19