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
を使うことが推奨されている。
Note
The nvoverlaysink plugin is deprecated in Jetson Linux Driver Package Release 32.1. Use nvdrmvideosink and nv3dsink instead for render pipelines with gst-v4l2 decoder.
そのため,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
の方が性能が高いことだ。
This video sink element works with NVMM buffers and renders using the 3D graphics rendering API. It performs better than nveglglessink with NVMM buffers.
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週間ほどの試行錯誤の成果をここに整理して,次回意向に役立てたい。