VCUを使った動画ストリーミング
1.はじめに
今回はZynq UltraScale+ MPSoC ZCU104 評価キットでMPSoCに統合されたVideoCodecUnit(VCU)
を使ってGstreamerで動画ストリーミングの動作を確認して行きたいと思います。
2.ハードウェアプラットフォームの確認
PetalinuxをBSPからインストールすると、<path-to-installed-PetaLinux>/hardware/xilinx-zcu104-2021.1
ディレクトリにハードウエアプラットフォームがインストールされます。
まずはその中身について確認していこうと思います。
Vivadoを使うので、セットアップファイルを読み込みます。
source <path-to-installed-Vitis>/Vitis/2021.1/settings64.sh
ハードウエアプラットフォームのフォルダに移動し、Vivadoを起動します。
cd <path-to-installed-PetaLinux>/hardware/xilinx-zcu104-2021.1
vivado &
Vivadoが起動したらFile -> Project -> Open
を選択します。
ファイルダイアログが開くので、Vivadoのプロジェクトファイルxilinx-zcu104-2021.1.xpr
を選択してOK
ボタンをクリックします。
そうすると、以下の図のようにVivadoプロジェクトが立ち上がります。
次に回路の構成図を参照していきます。
Vivado のFlow Navigator
からOpen Block Design
をクリックします。
以下のようなブロック図が表示されます。
ブロック図内から、今回調べたいVCUのIPを探します。
Block Design画面の検索ボタンをクリックして、検索画面にvcu
というワードを入力するとvcu_0
が表示されるので、これをクリックします。
Block Design画面の中央にVCUが拡大表示されます。
このハードウェアプラットフォームにはVCUが組み込まれている事がわかります。
Block Design画面上のVCUをダブルクリックするとIPのパラメータ画面が表示されます。
VCUエンコーダのパラメータには以下が指定されています。
- コーデック種別はHEVC(H.265)
- Intra/Interフレーム圧縮
- 解像度1920x1080、30fps
- カラーフォーマット4:2:2
- 画素ビット10bit
- 最大8本のストリームエンコード
ここでVCUパラメータの内容がわかったので一旦Vivadoは終了し、
次にZCU104でVCUを使ったGstreamerのストリーミングを試していこうと思います。
3.Gstreamerの送信側設定
ZCU104のスイッチSW1
をSDカードブートモードに設定します。
Petalinuxイメージを書き込んだSDカードをZCU104のSDカードスロットに差し込みます。
USBカメラをZCU104に接続し、シリアル通信用のUSBケーブルでZCU104と受信用PCを接続します。
受信用PCでTerminalソフトを起動します。通信のBAUDレートは115200
を設定します。
ZCU104の電源を投入します。起動に成功するとコンソールがTerminal画面に表示されます。
起動に成功したら、最初にIPアドレスを変更しておきます。
ZCU104に接続したTerminalから以下のコマンドを実行します。
ifconfig eth0 192.168.0.20
次に、ZCU104に接続したカメラの解像度パラメータを確認します。
ZCU104に接続したTerminalから以下のコマンドを実行します。
gst-device-monitor-1.0
コマンド実行結果が表示されるので、USBカメラの情報を確認する事ができます。
Device found:
name : See3CAM_CU30
class : Video/Source
caps : video/x-raw, format=(string)UYVY, width=(int)2304, height=(int)1536, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction){ 24/1, 12/1 };
video/x-raw, format=(string)UYVY, width=(int)2048, height=(int)1536, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction){ 42/1, 21/1 };
video/x-raw, format=(string)UYVY, width=(int)2304, height=(int)1296, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction){ 30/1, 15/1 };
video/x-raw, format=(string)UYVY, width=(int)1920, height=(int)1280, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction){ 50/1, 25/1 };
video/x-raw, format=(string)UYVY, width=(int)1920, height=(int)1080, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction){ 60/1, 30/1, 15/1 };
video/x-raw, format=(string)UYVY, width=(int)1280, height=(int)960, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction){ 58/1, 30/1 };
video/x-raw, format=(string)UYVY, width=(int)1280, height=(int)720, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction){ 60/1, 30/1 };
video/x-raw, format=(string)UYVY, width=(int)1152, height=(int)768, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction){ 60/1, 30/1 };
video/x-raw, format=(string)UYVY, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction){ 60/1, 30/1 };
image/jpeg, width=(int)2304, height=(int)1536, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)48/1;
image/jpeg, width=(int)2048, height=(int)1536, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)50/1;
image/jpeg, width=(int)2304, height=(int)1296, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)60/1;
image/jpeg, width=(int)1920, height=(int)1280, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)50/1;
image/jpeg, width=(int)1920, height=(int)1080, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)60/1;
image/jpeg, width=(int)1280, height=(int)960, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)58/1;
image/jpeg, width=(int)1280, height=(int)720, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)60/1;
image/jpeg, width=(int)1152, height=(int)768, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)60/1;
image/jpeg, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)60/1;
ZCU104でGstreamerコマンドを実行して動画配信します。
gst-device-monitor-1.0
コマンドで調べたUSBカメラパラメータを選択しますが、RAWデータからHEVCに圧縮して配信したいので、まずはサイズが小さいvideo/x-raw Width=640, Height=480, FrameRate=30
のパラメータを選択して試してみます。
送信側のGstreamerは以下を実行します。
gst-launch-1.0 v4l2src io-mode=4 device=/dev/video0 ! videoconvert ! video/x-raw, format=NV12, framerate=30/1, width=640, height=480 ! omxh265enc ! h265parse ! queue ! rtph265pay ! udpsink host=192.168.0.15 port=9000 buffer-size=20000000
ZCU104のVCUを使ったGstreamerコマンドの設定方法については、以下のマニュアルが参考になります。
4.Gstreamerの受信側設定
受信側PCでH.265のハードウェアデコードを実行したいので、ここではIntel UHD Graphic 630のGPUでコーデックができるようにIntelMediaSDKをインストールします。
以下のページにアクセスしてダウンロードします。
Windows版を選択してRegister and Download
をクリックします。
サインインが求められるので、必要な情報を入力してSUBMIT
ボタンをクリックします。
IntelMediaSDKのバージョンを指定してIntel Media SDK 2021
のボタンをクリックしてダウンロードを開始します。ここでは最新版の2021 R1
を選択しました。
ダウンロードされたファイルMSDK2021R1.exe
をダブルクリックしてインストーラを起動します。
インストーラが起動すると以下の画面が表示さるのでHEVC Decoder & Encoder
を選択してNext
ボタンをクリックします。
しばらくするとインストールが完了して以下の画面が表示されます。
Finish
ボタンをクリックして終了します。
今度は受信側PCのGstreamerコマンドを実行します。
受信PCのCMDプロンプトから以下を実行します。
gst-launch-1.0.exe --gst-debug-level=0 udpsrc name=video_src port=9000 caps="application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H265" ! rtph265depay ! queue ! h265parse ! queue ! d3d11h265dec ! videoconvert ! d3d11videosink
WindowsPC上に画面が立ち上がり、そこに動画が表示されますが、何もパラメータを指定していないので画質はかなり悪く、ブロックノイズが目立つことが見てわかると思います。
タスクマネージャーからイーサーネットのデータ受信量をチェックしてみると、100kbps程度の圧縮率でストリーミングされているようです。
5.HEVCの画質調整
GstreamerのHEVC(omxh265enc)では符号化パラメータが公開されています。
以下のコマンドを実行しomxh265encの仕様が確認できます。
gst-inspect-1.0 omxh265enc
デフォルトではブロックノイズが目立っていたので、量子化パラメータを変更してみたいと思います。上記コマンドでプラグイン仕様を確認するとmax-qp
というパラメータがあります。max-qp
のデフォルト値は51
と低画質向けの設定になっているので、これをmax-qp=20
くらいに変更して試してみます。送信側のGstreamerを以下に変更してストリーミングを実行してみます。
gst-launch-1.0 v4l2src io-mode=4 device=/dev/video0 ! videoconvert ! video/x-raw, format=NV12, framerate=30/1, width=640, height=480 ! omxh265enc max-qp=20 ! h265parse ! queue ! rtph265pay ! udpsink host=192.168.0.15 port=9000 buffer-size=20000000
パラメータ変更の結果、以下の動画が表示されます。
ブロックノイズはだいぶ改善されている事が分かります。
タスクマネージャーからイーサーネットのデータ受信量をチェックしてみると、約1Mbpsまで圧縮率が上がっている事が確認できると思います。
次回、高解像度のストリーミングを試していこうと思います。
Discussion