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で廃止されているため,nvdrmvideosinknv3dsinkを使うことが推奨されている。

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.
NVIDIA Jetson Linux Developer Guide : Multimedia | NVIDIA Docs

そのため,nvoverlaysinkの使用は控えたほうがいいだろう。

nvoverlaysinknvdrmvideosinkは3画面まで

また,Jetson nanoのnvoverlaysinknvdrmvideosinkはデフォルトでは最大3画面までしか一度に表示できない (参考: nvoverlaysink rendering – Jetson & Embedded Systems / Jetson TX2 – NVIDIA Developer Forums)。

nvoverlaysinkで4以上の画面を表示させようとするとエラーが出る。例えば,nvoverlaysinkoverlayプロパティは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

従って,nvoverlaysinknvdrmvideosinkで4画面以上表示させる場合,nvcompositorを併用する必要がある。

nvcompositorを用いた4画面表示

nvoverlaysinknvdrmvideosinkで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でも通用する。nvoverlaysinknvdrmvideosinkに関しては単独で3画面までしか表示できないので,4画面以上の表示にはnvcompositorを併用するしかない。

なお,nvoverlaysinkを使う場合,なぜかxposyposが反映されず,勝手に中央揃えになってしまう。元々,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"

nveglglessinknv3dsinkの違い

nveglglessinknv3dsinkは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.
NVIDIA Jetson Linux Developer Guide : Multimedia | NVIDIA Docs

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週間ほどの試行錯誤の成果をここに整理して,次回意向に役立てたい。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です