NVIDIA JetsonのGStreamerでの4画面表示
概要
業務でJetson nanoのGStreamerでの映像表示を行っている。その際に,映像の4画面表示が必要になった。あまり情報がなく,手間取ったので情報を記す。
Jetson Nano R32.4.3で確認した。
cat /etc/nv_tegra_release
# R32 (release), REVISION: 4.3, GCID: 21589087, BOARD: t210ref, EABI: aarch64, DATE: Fri Jun 26 04:38:25 UTC 2020
公式ガイドの「NVIDIA Jetson Linux Developer Guide : Multimedia | NVIDIA Docs」を参考にした。
結論としては,性能面から以下のコマンドがベストだろうと判断した。
DISPLAY=:0 \
gst-launch-1.0 \
nvcompositor name=comp \
sink_0::xpos=000 sink_0::ypos=000 sink_0::width=640 sink_0::height=480 \
sink_1::xpos=640 sink_1::ypos=000 sink_1::width=640 sink_1::height=480 \
sink_2::xpos=000 sink_2::ypos=480 sink_2::width=640 sink_2::height=480 \
sink_3::xpos=640 sink_3::ypos=480 sink_3::width=640 sink_3::height=480 \
! nv3dsink \
videotestsrc ! decodebin ! nvvidconv ! comp. \
videotestsrc ! decodebin ! nvvidconv ! comp. \
videotestsrc ! decodebin ! nvvidconv ! comp. \
videotestsrc ! decodebin ! nvvidconv ! comp. \
Jetsonでは以下の4種類のvideo sinkを使える。
nvoverlaysink
nvdrmvideosink
nveglglessink
nv3dsink
しかし,それぞれ特徴や注意点があるので,まずそれらを説明する。
nvoverlaysink
は非推奨
nvoverlaysink
は以下の記載の通り,Jetson Linux Driver package Release 32.1で廃止されているため,nvdrmvideosink
かnv3dsink
を使うことが推奨されている。
そのため,nvoverlaysink
の使用は控えたほうがいいだろう。
nvoverlaysink
とnvdrmvideosink
は3画面まで
また,Jetson nanoのnvoverlaysink
とnvdrmvideosink
はデフォルトでは最大3画面までしか一度に表示できない (参考: nvoverlaysink rendering – Jetson & Embedded Systems / Jetson TX2 – NVIDIA Developer Forums)。
nvoverlaysink
で4以上の画面を表示させようとするとエラーが出る。例えば,nvoverlaysink
のoverlay
プロパティは0-2までであれば問題ないが,3以上に指定すると以下のエラーが出る。
gst-launch-1.0 videotestsrc ! decodebin ! nvoverlaysink overlay=3
NvxBaseWorkerFunction[2575] comp OMX.Nvidia.std.iv_renderer.overlay.yuv420 Error -2147479552
0:00:00.954405729 15152 0x7f18001470 ERROR omx gstomx.c:496:EventHandler:<nvoverlaysink-nvoverlaysink2> yuv420 got error: Insufficient resources (0x80001000)
このことは,「nvoverlaysink reports “got error: Insufficient resources” if overlay is 4 or 5 – Jetson & Embedded Systems / Jetson Nano – NVIDIA Developer Forums」でも報告されている。
nvoverlaysink
だとリソースの制限でできないので,nveglglessink
を使えとのことだ。
ただし,Jetson TX2であれば,以下の設定で最大6画面まで増やすことができるらしい (参考: NVIDIA Jetson Linux Developer Guide : Multimedia | NVIDIA Docs)。
sudo -s
cd /sys/class/graphics/fb0
echo 4 > blank // Blanks monitor for changing
// display setting.
echo 0x0 > device/win_mask
// Clears current window setting.
// window setting.
echo 0x3f > device/win_mask
// Assigns all 6 overlay windows
// in display controller to
// display 0 (fb0).
echo 0 > blank // Unblank display.
## Stop X11
sudo systemctl stop gdm
sudo loginctl terminate-seat seat0
しかし,こちらはあくまでJetson TX2向けの内容である (参考: two nvoverlaysink problem on jetson nano – Jetson & Embedded Systems / Jetson Nano – NVIDIA Developer Forums)。
Jetson nanoではdevice/win_maskの書き込み時に以下のエラーがでて設定を変更できなかった。
echo 0x0 >device/win_mask
bash: echo: write error: Invalid argument
従って,nvoverlaysink
とnvdrmvideosink
で4画面以上表示させる場合,nvcompositor
を併用する必要がある。
nvcompositor
を用いた4画面表示
nvoverlaysink
とnvdrmvideosink
で4画面以上表示させる場合,nvcompositor
を併用する。そのパイプラインの例が「NVIDIA Jetson Linux Developer Guide : Multimedia | NVIDIA Docs」に記されている。
簡略化すると以下のようになる。
gst-launch-1.0 \
nvcompositor name=comp \
sink_0::xpos=0 sink_0::ypos=0 sink_0::width=1920 sink_0::height=1080 \
sink_1::xpos=0 sink_1::ypos=0 sink_1::width=1600 sink_1::height=1024 \
sink_2::xpos=0 sink_2::ypos=0 sink_2::width=1366 sink_2::height=768 \
sink_3::xpos=0 sink_3::ypos=0 sink_3::width=1024 sink_3::height=576 \
! nvoverlaysink \
videotestsrc ! decodebin ! comp. \
videotestsrc ! decodebin ! comp. \
videotestsrc ! decodebin ! comp. \
videotestsrc ! decodebin ! comp. \
この方法はどのvideo sinkでも通用する。nvoverlaysink
とnvdrmvideosink
に関しては単独で3画面までしか表示できないので,4画面以上の表示にはnvcompositor
を併用するしかない。
なお,nvoverlaysink
を使う場合,なぜかxpos
とypos
が反映されず,勝手に中央揃えになってしまう。元々,nvoverlaysink
はnvidiaとしても非推奨扱いなので,使わないほうが無難だろう。
nvdrmvideosink
はCUI専用
nvdrmvideosink
で映像表示させるには,「NVIDIA Jetson Linux Developer Guide : Multimedia | NVIDIA Docs」の「DRM Videos Sink (Video playback using DRM) にある通り,以下のコマンドを実行して,ディスプレイマネージャーを停止させる必要がある。
sudo systemctl stop gdm
sudo loginctl terminate-seat seat0
そうしないと,以下のエラーが出る。
Failed to set plane Failed to display frame buffer
その他,nvdrmvideosink
のみプロパティで映像のサイズを指定できないので,直前にcapsfilter
でサイズを指定して変換する。
capsfilter caps="video/x-raw, width=640, height=480"
nveglglessink
とnv3dsink
の違い
nveglglessink
とnv3dsink
はEGL画像を用いたvideo sinkとなっている。どちらもX11のGUI環境でのみ動作する。実行時には,DISPLAY
環境変数が必須となる。
違いは,NVMMバッファーを使う場合にnv3dsink
の方が性能が高いことだ。
GStreamerのパイプライン図をデバッグで出力させると,capsにvideo/x-raw(memory:NVMM)
の指定があり,NVMMバッファーを使おうとしているように見えた。そのため,nveglglessink
よりもnv3dsink
のほうが良いように思った。
コマンド例
これらを踏まえた4画面表示のコマンド例を以下に記す。優先度順に並べている。
## 1. nv3dsink
## X11 GUI環境が必要
DISPLAY=:0 \
gst-launch-1.0 \
nvcompositor name=comp \
sink_0::xpos=000 sink_0::ypos=000 sink_0::width=640 sink_0::height=480 \
sink_1::xpos=640 sink_1::ypos=000 sink_1::width=640 sink_1::height=480 \
sink_2::xpos=000 sink_2::ypos=480 sink_2::width=640 sink_2::height=480 \
sink_3::xpos=640 sink_3::ypos=480 sink_3::width=640 sink_3::height=480 \
! nv3dsink \
videotestsrc ! decodebin ! nvvidconv ! comp. \
videotestsrc ! decodebin ! nvvidconv ! comp. \
videotestsrc ! decodebin ! nvvidconv ! comp. \
videotestsrc ! decodebin ! nvvidconv ! comp. \
## 2. nveglglessink
## X11 GUI環境が必要
## capsのエラーがでてうまくいかない。
## ERROR nvcompositor gstnvcompositor.c:1050:gst_nvcompositor_decide_allocation: not supported out caps
# DISPLAY=:0 \
# gst-launch-1.0 \
# nvcompositor name=comp \
# sink_0::xpos=000 sink_0::ypos=000 sink_0::width=640 sink_0::height=480 \
# sink_1::xpos=640 sink_1::ypos=000 sink_1::width=640 sink_1::height=480 \
# sink_2::xpos=000 sink_2::ypos=480 sink_2::width=640 sink_2::height=480 \
# sink_3::xpos=640 sink_3::ypos=480 sink_3::width=640 sink_3::height=480 \
# ! nveglglessink \
# videotestsrc ! decodebin ! comp. \
# videotestsrc ! decodebin ! comp. \
# videotestsrc ! decodebin ! comp. \
# videotestsrc ! decodebin ! comp. \
## 3. nv3dsink
## X11 GUI環境が必要
DISPLAY=:0 \
gst-launch-1.0 \
videotestsrc ! decodebin ! nvvidconv ! nv3dsink window-x=000 window-y=000 window-width=640 window-height=480 \
videotestsrc ! decodebin ! nvvidconv ! nv3dsink window-x=640 window-y=000 window-width=640 window-height=480 \
videotestsrc ! decodebin ! nvvidconv ! nv3dsink window-x=000 window-y=480 window-width=640 window-height=480 \
videotestsrc ! decodebin ! nvvidconv ! nv3dsink window-x=640 window-y=480 window-width=640 window-height=480 \
## 4. nveglglessink
## X11 GUI環境が必要。nvvidconvが必須。
DISPLAY=:0 \
gst-launch-1.0 \
videotestsrc ! decodebin ! nveglglessink window-x=000 window-y=000 window-width=640 window-height=480 \
videotestsrc ! decodebin ! nveglglessink window-x=640 window-y=000 window-width=640 window-height=480 \
videotestsrc ! decodebin ! nveglglessink window-x=000 window-y=480 window-width=640 window-height=480 \
videotestsrc ! decodebin ! nveglglessink window-x=640 window-y=480 window-width=640 window-height=480 \
## 5. nvdrmvideosink + nvcompositor
## xpos, yposも反映。無難。以下のコマンドでCUI化が必要
## ```
## sudo systemctl stop gdm
## sudo loginctl terminate-seat seat0
## ```
gst-launch-1.0 \
nvcompositor name=comp \
sink_0::xpos=000 sink_0::ypos=000 sink_0::width=640 sink_0::height=480 \
sink_1::xpos=640 sink_1::ypos=000 sink_1::width=640 sink_1::height=480 \
sink_2::xpos=000 sink_2::ypos=480 sink_2::width=640 sink_2::height=480 \
sink_3::xpos=640 sink_3::ypos=480 sink_3::width=640 sink_3::height=480 \
! nvdrmvideosink \
videotestsrc ! decodebin ! comp. \
videotestsrc ! decodebin ! comp. \
videotestsrc ! decodebin ! comp. \
videotestsrc ! decodebin ! comp. \
## 6. nvcompositor+nvoverlaysink
## xpos, yposが反映されない,nvoverlaysinkがnvidiaで非推奨。
gst-launch-1.0 \
nvcompositor name=comp \
sink_0::xpos=000 sink_0::ypos=000 sink_0::width=640 sink_0::height=480 \
sink_1::xpos=640 sink_1::ypos=000 sink_1::width=640 sink_1::height=480 \
sink_2::xpos=000 sink_2::ypos=480 sink_2::width=640 sink_2::height=480 \
sink_3::xpos=640 sink_3::ypos=480 sink_3::width=640 sink_3::height=480 \
! nvoverlaysink \
videotestsrc ! decodebin ! comp. \
videotestsrc ! decodebin ! comp. \
videotestsrc ! decodebin ! comp. \
videotestsrc ! decodebin ! comp. \
## 7. nvoverlaysink
# 3画面までしか表示できない。
gst-launch-1.0 \
videotestsrc ! decodebin ! nvoverlaysink overlay=0 overlay-x=000 overlay-y=000 overlay-w=640 overlay-h=480 \
videotestsrc ! decodebin ! nvoverlaysink overlay=1 overlay-x=640 overlay-y=000 overlay-w=640 overlay-h=480 \
videotestsrc ! decodebin ! nvoverlaysink overlay=2 overlay-x=000 overlay-y=480 overlay-w=640 overlay-h=480 \
# videotestsrc ! decodebin ! nvoverlaysink overlay=3 overlay-x=640 overlay-y=480 overlay-w=640 overlay-h=480 \
## 8. nvdrmvideosink
## 3画面までしか表示できない。nvvidconvが必須。2個目のcapsfilterで画面サイズを調整。
gst-launch-1.0 \
videotestsrc ! capsfilter caps="video/x-raw, width=640, height=480" ! decodebin ! capsfilter caps="video/x-raw, width=640, height=480" ! nvdrmvideosink plane-id=0 offset-x=000 offset-y=000 \
videotestsrc ! capsfilter caps="video/x-raw, width=640, height=480" ! decodebin ! capsfilter caps="video/x-raw, width=640, height=480" ! nvdrmvideosink plane-id=1 offset-x=640 offset-y=000 \
videotestsrc ! capsfilter caps="video/x-raw, width=640, height=480" ! decodebin ! capsfilter caps="video/x-raw, width=640, height=480" ! nvdrmvideosink plane-id=2 offset-x=000 offset-y=480 \
videotestsrc ! capsfilter caps="video/x-raw, width=640, height=480" ! decodebin ! capsfilter caps="video/x-raw, width=640, height=480" ! nvdrmvideosink plane-id=3 offset-x=640 offset-y=480 \
capsの調整でnvvideconv
を挟んだりしている。ただ,nveglglessink+nvcompositor
の組み合わせが,capsの問題でうまく再生できなかった。これとnv3dsink+nvcompositor
の組み合わせが,最も順当な方法と思う。
性能
JetsonでのGPU使用率を含めた性能はtegrastats
コマンド (参考: NVIDIA Jetson Linux Developer Guide : Applications and Tools | NVIDIA Docs) で確認できる。
試しに1分ずつ実行して集計したところ,nvcompositor
を使ったコマンドのGPU使用率が使わない場合よりも-10 %ほど低かった。
負荷が大きいと思われるvideo sinkの数が少ないので順当な結果だろう。
結論
Jetson nanoのGStreamerでの4画面表示の方法を検討した。
結論としては,nv3dsink+nvcompositor
の以下のパイプラインが妥当に思った。
DISPLAY=:0 \
gst-launch-1.0 \
nvcompositor name=comp \
sink_0::xpos=000 sink_0::ypos=000 sink_0::width=640 sink_0::height=480 \
sink_1::xpos=640 sink_1::ypos=000 sink_1::width=640 sink_1::height=480 \
sink_2::xpos=000 sink_2::ypos=480 sink_2::width=640 sink_2::height=480 \
sink_3::xpos=640 sink_3::ypos=480 sink_3::width=640 sink_3::height=480 \
! nv3dsink \
videotestsrc ! decodebin ! nvvidconv ! comp. \
videotestsrc ! decodebin ! nvvidconv ! comp. \
videotestsrc ! decodebin ! nvvidconv ! comp. \
videotestsrc ! decodebin ! nvvidconv ! comp. \
実製品では実際のvideo srcに合わせて若干の調整が必要になる。後は,nveglglessink+nvcompositor
の組み合わせとも性能比較が必要になる。
いろいろとエラーがあり,整理に時間がかかった。ひとまず1-2週間ほどの試行錯誤の成果をここに整理して,次回意向に役立てたい。