C++言語

【C++】gstreamerを使ってRTSP(Video+Audio)を再生するサンプル

2024年2月15日

はじめに

gstreamer をコマンドベースで利用する場合の記事はいくつかあるのですが、
C++ でライブラリとして利用する場合のサンプルが少なく、どのようなものなのかと使ってみた記録です。

今回は以下のようなことができる実現案を、サンプルコードと共にご紹介いたします。

  • Windows で動作するアプリケーション
  • MPEG2-TTS に対応できるようにしておきたい
  • デコードした映像は、OpenCV の Mat 形式でアプリ側で使用したい
  • デコードした音声は、gstreamer に任せて再生したい
SANACHAN
SANACHAN
本サンプルでは、デコードした映像をブラウザで表示します。

 

開発環境は以下を使用しています。

OS Windows10 Pro
CPU Intel Core i5 11400
GPU NVIDIA GTX 1650
IDE Visual Studio 2022
CMake v3.28.3
gstreamer v1.22.9
OpenCV v4.9.0
boost v1.84.0
websocketpp v0.8.2

 

環境構築

先ずは、gstreamer を利用できる環境を作ります。

インストール

gstreamer の公式ページから、インストーラーをダウンロードします。
以下、2つのファイルをダウンロードしてインストールします。

  • Runtime Installer
  • Development Installer

注意ポイント①

インストールする際、下図のように全てのプラグインをインストールしましょう。
多くのコーデックに対応するためのプラグイン gst-plugins-good などが含まれています。

注意ポイント②

インストールは、Runtime → Development の順で行いましょう。

gstreamer インストール画面

 

環境変数の設定

gstreamer をインストールしたパスに合わせて、システム環境変数を以下のように設定します。

SANACHAN
SANACHAN
設定後、再起動しないと反映されませんでした。
変数
GST_PLUGIN_SYSTEM_PATH [インストールしたパス]\1.0\msvc_x86_64\lib\gstreamer-1.0
GSTREAMER_1_0_ROOT_MSVC_X86_64 [インストールしたパス]\1.0\msvc_x86_64

システム環境変数の設定

 

Visual Studio プロジェクト

C++ で記述するため、コンパイラへ「追加のインクルードディレクトリ」、
リンカーへ「追加のライブラリディレクトリ」と「依存ファイル」の設定が必要です。

gstreamer をインストールしたパスに合わせて、以下のように設定します。

設定項目 設定内容
C/C++>全般
>追加のインクルードディレクトリ
[インストールしたパス]\opencv-4.9.0\build\include;
[インストールしたパス]\1.0\msvc_x86_64\lib\glib-2.0\include;
[インストールしたパス]\1.0\msvc_x86_64\include\gstreamer-1.0;
[インストールしたパス]\1.0\msvc_x86_64\include\glib-2.0;
[インストールしたパス]\1.0\msvc_x86_64\include\glib-2.0\glib;
リンカー>全般
>追加のライブラリディレクトリ
[インストールしたパス]\opencv-4.9.0\build\x64\vc16\lib;
[インストールしたパス]\1.0\msvc_x86_64\lib
リンカー>入力
>追加の依存ファイル
gobject-2.0.lib;
glib-2.0.lib;
gstreamer-1.0.lib;
gstaudio-1.0.lib;
gstpbutils-1.0.lib;
gstvideo-1.0.lib;
gstapp-1.0.lib;
opencv_world490.lib; (Debug 構成の場合は opencv_world490d.lib;)

追加のインクルードディレクトリ

追加のライブラリディレクトリ

追加の依存ファイル

SANACHAN
SANACHAN
これで環境構築、及び空のVisual Studioプロジェクト作成完了です。

 

gstreamer pipeline の検討

今回は gstreamer を使って、少し特殊なことを行います。
順に説明、解説していきます。

 

アプリで映像を取得

gstreamer でデコードした映像を、gstreamer が備えている DirectX で表示するのではなく、
アプリ側で独自に画像処理を行って表示することを条件としてプログラミングします。

この場合、gstreamer へ指定する pipeline を以下のように記述します。

 gstreamer pipeline
"rtspsrc location=rtsp://127.0.0.1:554/stream"
" ! rtph264depay"
" ! h264parse"
" ! avdec_h264"
" ! videoconvert"
" ! appsink name = sink"

RTSP を入力とするため、rtspsrc を使用します。
また、アプリ側でデコード結果を取得したいので、末端は appsink を利用し名前を付けます。

SANACHAN
SANACHAN
これで、アプリ側でデコード結果の画素データを取得できるようになります。

 

音声の出力

映像データはアプリで使用し、音声データは gstreamer に任せて再生することにしています。
この場合は、gstreamer へ指定する pipeline を以下のように記述します。

 gstreamer pipeline
"rtspsrc location=rtsp://127.0.0.1:554/stream name=src"
" src. ! queue"
" ! rtph264depay"
" ! h264parse"
" ! avdec_h264"
" ! videoconvert"
" ! appsink name=sink"
" src. ! queue leaky=1"
" ! decodebin"
" ! audioconvert"
" ! audioresample"
" ! autoaudiosink sync=false"

分かりやすくするため細かく改行していますが、rtspsrc の入力に名前を付け、
入力 src. から映像と音声、それぞれの pipeline を queue で繋げるイメージで記述します。

音声の末端は autoaudiosink としているため、gstreamer が自動で再生してくれます。

SANACHAN
SANACHAN
これで映像データはアプリ、音声データは自動で再生する条件を満たします。

 

MPEG2-TTS の対応

以下で紹介している方法で、rtph264depay を拡張し「rtpmp2tdepay tts=true」と指定、
更に「tsdemux」を追加すれば再生できるようになります。

こちらもCHECK

MPEG2-TTSをOSSでデコードする方法

はじめに MPEG-2(Moving Picture Experts Group)は、映像や音声を多重化する ISO/IEC の標準規格です。 DVD や放送で主に使用されており、ごく一部の公共インフ ...

続きを見る

SANACHAN
SANACHAN
pipeline の記述は、「gstreamerのpipeline集」を参照ください。

 

gstreamer 制御クラス

少し汎用的にプログラムを記述するため、gstreamer を制御するためのクラスを用意します。

前半は、gstreamer の初期化、pipeline の初期化や起動を記述しています。

 

また、デコードした画像データを取得できる ReadFrame() というメソッドを用意し、
OpenCV の VideoCapture.read() と同様に、フレームが到着するたびに読み出せるようにしています。

注意ポイント

gstreamer が確保するメモリ map.data を引数に cv::Mat を生成すると、
同じメモリアドレスを指す cv::Mat になるため、clone() してから解放します。

 

特に指定しなければ、取得できるのは YUV のカラーフォーマットなため、RGB へ変換して返します。
pipeline で、appsink の前に " ! video/x-raw, format=BGR " とすることで、
OpenCV に合わせた BGR フォーマットをデコード結果の色空間として指定することもできます。

SANACHAN
SANACHAN
動きを見ていると、フレームレートに応じて gst_app_sink_pull_sample から戻ってくるため、特に意識せずに表示してもフレームレートを制御できるようです。

 

ストリーミングした映像をブラウザで表示

デコードした映像のフレームデータを cv::Mat 形式で受け取れるようになったため、
ブラウザでRTSPストリーミング再生」で紹介している方法で、ブラウザに表示してみます。

今回は以下のような Bse64 変換関数と、

libwebsocketpp を使って WebSocket で通信するクラスを用意します。

SANACHAN
SANACHAN
websocketpp と boost のビルドが必要になります。また、Visual Studio のプロジェクトにインクルードディレクトリの追加も必要です。双方、ヘッダーだけで完結するため、インクルードディレクトリだけでOKです。

設定項目 設定内容
C/C++>全般
>追加のインクルードディレクトリ
[ビルドしたパス]\include\boost-1_84;
[ビルドしたパス]\websocketpp-0.8.2\install\include;

 

サンプルの Main.cpp

これまで準備してきたクラス達を使用し、以下のように記述することで、
所望の動作をするアプリケーションを作成できます。

検討した pipeline を使用すると、デコードした映像データはアプリ側で表示処理でき、
音声データは gstreamer で自動で再生されます。

SANACHAN
SANACHAN
映像と音声を別経路で再生しているため、処理系によってはリップシンクの制御が別途必要かもしれません。

 

おわりに

いかがでしたでしょうか。

gstreamer は、pipeline を構成するエレメントを組み替えることで、
きめ細やかな制御が簡単にできるようになっています。

pipeline の構成検討に障壁があるのか、あまり解説している記事が無いと感じており、
本記事が参考になれば幸いです。

 

こちらの記事もよく読まれています

  • この記事を書いた人
  • 最新記事
SANACHAN

SANACHAN

「生涯一エンジニア」を掲げ、大手グローバル企業でSE/PGとして8年勤め、キャリアアップ転職した現役のエンジニアです。世にあるメジャーな全プログラム言語(コボル除く)を自由に扱えます。一児の父。自分のため、家族のため、日々勉強してます。システムエンジニア、プログラミングに関する情報を蓄積している雑記帳です。

-C++言語
-, , , , ,