DeepStream プラグイン入門1 〜サンプルプラグインを実行してみる〜

DeepStream をきちんと使えるようになりたい!!
ということで、オリジナルのプラグインを作ってストリーム処理に組み込むことを最終目標に DeepStream の勉強をしてみました。
まず今回は手始めに配布されているサンプルのプラグインを実行し動作確認、さらにそこから『何もしない』サンプルプラグインを作ってみます。

DeepStreamとは?

NVIDIA DeepStream SDK

NVIDIA が提供する IVA (Intelligent Video Analytics) 向けのライブラリ。GPU を使って高速に映像の入出力、物体検出等を行うことができます。

マルチメディアフレームワーク「GStreamer」がベースとなっていて、GStreamer のプラグインと合わせて使用することも可能です。

環境

本シリーズ記事では、以下の環境で動作確認を行ってます。

  • Jetson Nano
    • JetPack 4.4.1
      • CUDA 8.0
      • OpenCV 4.3
    • DeepStream 5.0 インストール済み

サンプルプラグイン dsexample

DeepStream でオリジナルの処理を実装したい場合、 オリジナルのプラグインを作成し、それをストリームに組み込む必要があります。

DeepStream のパッケージにはサンプルプラグイン dsexample が含まれているので、オリジナルのプラグインを作るには、これを改造していくのが近道です。
( なお、dsexample は MIT ライセンスとのこと。)

まず初めに、この dsexample を呼び出してみます。
dsexample は映像と、nvinfer プラグインによる物体検出結果矩形を入力とし、 矩形の内部をぼかした映像を出力します。( blur-object オプション有効の場合 )

ストリームは C や Python でも書くことができるのですが、今回は gst-launch-1.0 を使って、そのまま実行してみます。
( なお、よく実行例としてみる deepstream-app では処理を追加ができないので、dsexample をそのまま使うことはできないようです。)

以下のコードで動画ファイルを読み込んで処理を行い、画面に出力します。

gst-launch-1.0 \
    -e \
    filesrc location = /opt/nvidia/deepstream/deepstream/samples/streams/sample_1080p_h264.mp4 ! \
    qtdemux ! h264parse ! nvv4l2decoder ! m.sink_0 nvstreammux name=m width=1280 height=720 batch_size=1 ! \
    nvinfer config-file-path=config_infer_primary.txt ! nvvideoconvert ! 'video/x-raw(memory:NVMM), format=RGBA' ! \
    dsexample full-frame=0 blur-objects=1 ! \
    nvdsosd ! nvegltransform ! nveglglessink sync=0

L2 … gst-launch のオプション。「-e」をつけることで Ctrl + C に対して EOS が発せられるようになります。
L3、L4 … 映像の入力と変換。
L5 … nvinfer により DeepLearning 検出処理。その後変換。
L6 … dsexample プラグイン処理。検出矩形に対してぼかしを入れます。
L7 … 矩形の描画 (nvdsosd)、Jetson 向け映像の出力 (nvegltransform)、表示 (nveglglessink)。

これを実行すると、検出した矩形すべてにぼかしが入るようになります。

01_01

dsexample を改造して『なにもしない』サンプル dspluginsample を作る

dsexample のコードは

/opt/nvidia/deepstream/deepstream-5.0/sources/gst-plugins/gst-dsexample

にあります ( 本環境の場合 ) 。

今後オリジナルプラグインを作るにあたり、まず『何もしない』サンプル dspluginsample を作ってみます。
任意の場所に dsexample のコードを丸々コピーしてきて、以下の変更を加えます。

・名前を一括変更  
  EXAMPLE => PLUGINSAMPLE
  Example => PluginSample
  example => pluginsample
・optimized は使わないので、設定を削除
・dsexample_lib の処理 ... C コードでさらなる処理 => 使わないので削除

その他、不要な部分を排除し、整理したコードは以下の通りです。

ISP-Kazuki-Nagasawa/deepstream_plugin_samples

この処理プラグインを環境にインストールします。
私が用いた環境では、

/opt/nvidia/deepstream/deepstream-$(NVDS_VERSION)/lib/gst-plugins/

はパスが通っていなかったようなので、Makefile を変更し、GStreamer プラグインのパス

/usr/lib/aarch64-linux-gnu/gstreamer-1.0/deepstream/

に変更したうえで

CUDA_VER=10.2 make
sudo CUDA_VER=10.2 make install

することで、ビルドしたプラグインが使えるようになります。

dspluginsample を動作させる

プラグインのインストールができたら、実際に実行してみます。
dsexample 実行スクリプトからプラグイン名だけ変えたものを実行すると、

gst-launch-1.0 \
    -e \
    filesrc location = /opt/nvidia/deepstream/deepstream/samples/streams/sample_1080p_h264.mp4 ! \
    qtdemux ! h264parse ! nvv4l2decoder ! m.sink_0 nvstreammux name=m width=1280 height=720 batch_size=1 ! \
    nvinfer config-file-path=config_infer_primary.txt ! nvvideoconvert ! 'video/x-raw(memory:NVMM), format=RGBA' ! \
    dspluginsample ! \
    nvdsosd ! nvegltransform ! nveglglessink sync=0

想定通り、プラグインが何もしない形の出力がされました。

01_02

これだと、逆に『本当にプラグインに処理が通っているの?』が気になるところ。
簡単に実装できるぼかし処理を入れてみます。

プラグインを構築する関数のうち、ストリームに対して処理をかけるのは「transform_ip」が担っています。
この処理に映像全体のぼかしを入れます。
詳しい説明は省略しますが、大まかには

  1. GPU メモリ上の映像を CPU 側に持ってくる。
  2. ストリームのメモリから OpenCV の画像として扱えるようにする。
  3. OpenCV の処理としてぼかしを入れる。
  4. GPU 側に映像を戻す。

ということをしています。

      ( 追記部分抜粋 )

      /* Cache the mapped data for CPU access */
      NvBufSurfaceSyncForCpu (surface, frame_meta->batch_id, 0);

      /*** OpenCV access ***/
      in_mat =
          cv::Mat (surface->surfaceList[frame_meta->batch_id].planeParams.height[0],
             surface->surfaceList[frame_meta->batch_id].planeParams.width[0], CV_8UC4,
             surface->surfaceList[frame_meta->batch_id].mappedAddr.addr[0],
             surface->surfaceList[frame_meta->batch_id].planeParams.pitch[0]);

      // Blur
      GaussianBlur(in_mat, in_mat, cv::Size(15, 15), 4);

      /* Cache the mapped data for device access */
      NvBufSurfaceSyncForDevice(surface, frame_meta->batch_id, 0);

make → make install 後、改めて実行すると、

01_03

のようになり、プラグインにストリームが通っていることが確認できました。

まとめ

DeepStream のプラグインの入門ということで、手始めにサンプルプラグインの実行、一番シンプルな形のプラグインの試行をしてみました。
ここから発展させ、オリジナルのプラグインを構築していきます。

シリーズ記事 :
DeepStreamプラグイン入門1 ~サンプルプラグインを実行してみる~ (本記事)
DeepStreamプラグイン入門2 ~独自のプラグインを構築する~
DeepStreamプラグイン入門3 ~GPU側で動作するプラグインを構築する~