🦧
jetson nanoのgstreamerでNVIDIAのハードウェアアクセラレーションと新しいlibsrtをdockerを使って共生させる
前回の記事でサーバ側ではdockerを使って新しいlibsrtを動かすことに成功しました。次にこの記事の送信側のjetson nanoでもやってみました。
2つのプロセスに分離させて、間をfifoでつなぐ
NVIDIAのハードウェアアクセラレーションを行うgstreamerのエレメントは現状のバージョンのgstreamerでしか提供されていません。これはこのまま使用します。
SRTで送信するところを別のプロセスに分離し、そちらをubuntu 22.04のdocker環境で動かすようにします。
両者の間はfifo(名前付きパイプ)でつなぐことにしました。
とりあえず録画はやめて送信するだけのスクリプト。
send_srt.sh
#!/bin/sh -xue
HOST=xx.yy.zz.ww
PORT=7001
gst-launch-1.0 -eq v4l2src device="/dev/video0" ! \
'image/jpeg, width=1280, height=720, framerate=30/1' ! \
nvv4l2decoder mjpeg=1 ! 'video/x-raw(memory:NVMM)' ! \
nvvidconv ! 'video/x-raw(memory:NVMM), format=(string)I420' ! \
nvv4l2h265enc insert-aud=1 insert-sps-pps=1 iframeinterval=60 bitrate=2000000 ! \
queue ! \
h265parse ! mpegtsmux alignment=7 ! srtclientsink uri="srt://$HOST:$PORT"
これをfifoをはさんで2つのプロセスに分離します。fifoを読み出す側のプロセスを先に起動します。
send_fifo.sh
#!/bin/sh -xue
HOST=xx.yy.zz.ww
PORT=7001
FIFO=$PWD/.fifo
rm -f $FIFO
mkfifo $FIFO
gst-launch-1.0 -eq filesrc location=$FIFO ! \
h265parse ! mpegtsmux alignment=7 ! \
srtclientsink uri="srt://$HOST:$PORT" &
gst-launch-1.0 -eq v4l2src device="/dev/video0" ! \
'image/jpeg, width=1280, height=720, framerate=30/1' ! \
nvv4l2decoder mjpeg=1 ! 'video/x-raw(memory:NVMM)' ! \
nvvidconv ! 'video/x-raw(memory:NVMM), format=(string)I420' ! \
nvv4l2h265enc insert-aud=1 insert-sps-pps=1 iframeinterval=60 bitrate=2000000 ! \
filesink location=$FIFO
これで動くことを確認しました。
dockerでubuntu 22.04の環境を準備
Dockerfile
FROM ubuntu:22.04
RUN apt-get update
RUN apt-get install -y gstreamer1.0-tools gstreamer1.0-plugins-bad
RUN gst-inspect-1.0 --version
EXPOSE 7001/udp 7002/udp
CMD /bin/bash
docker イメージをビルド。
$ docker build -t koba/srt .
できたdockerイメージの中でコマンドを動かす。
$ docker run --rm -v $PWD:$PWD -p 7001:7001/udp koba/srt /usr/bin/gst-inspect-1.0 --version
gst-inspect-1.0 version 1.20.1
GStreamer 1.20.1
https://launchpad.net/distros/ubuntu/+source/gstreamer1.0
いい感じです。
docker run --rm -v $PWD:$PWD -p 7001:7001/udp koba/srt
を頭につけてフルパスで実行すればubuntu 22.04環境の中でコマンドを実行できます。
後半部分をdocker環境の中で動かす
send_with_docker.sh
#!/bin/sh -xue
HOST=xx.yy.zz.ww
PORT=7001
FIFO=$PWD/.fifo
rm -f $FIFO
mkfifo $FIFO
docker run --rm -v $PWD:$PWD -p $PORT:$PORT/udp koba/srt \
/usr/bin/gst-launch-1.0 -eq filesrc location=$FIFO ! \
h265parse ! mpegtsmux alignment=7 ! \
srtclientsink uri="srt://$HOST:$PORT" &
gst-launch-1.0 -eq v4l2src device="/dev/video0" ! \
'image/jpeg, width=1280, height=720, framerate=30/1' ! \
nvv4l2decoder mjpeg=1 ! 'video/x-raw(memory:NVMM)' ! \
nvvidconv ! 'video/x-raw(memory:NVMM), format=(string)I420' ! \
nvv4l2h265enc insert-aud=1 insert-sps-pps=1 iframeinterval=60 bitrate=2000000 ! \
filesink location=$FIFO
みごと成功!
計算通り ----- !!
と思ったけど、やっぱりコマ落ちが発生してる。映像をfifo(名前付きパイプ)で渡すのは厳しいか。
** 2022/05/28 追記
fifoはボトルネックではありませんでした。この記事の最後の関連のところを見てください。
** 追記ここまで
録画機能を追加したバージョン
録画のほうはfifoを通さずに処理するように修正しました。
rec_send_with_docker.sh
#!/bin/sh -xue
HOST_IP=xx.yy.zz.ww
PORT=7001
RECDIR=$PWD/rec
MAX_FILE_SIZE=$((100 * 1024 * 1024))
MAX_FILES=20
filename="$RECDIR/d%04d.m2ts"
index_wrap=10000
last_index=`ls -t rec/d*.m2ts |head -1 |sed -n -e 's/\.m2ts$//' -e 's/[^0-9]//gp'`
if [ -z $last_index ] ; then
mkdir -p $RECDIR
next_index=0
else
next_index=`echo "($last_index + 1) % $index_wrap" |bc`
fi
FIFO=$PWD/.fifo
rm -f $FIFO
mkfifo $FIFO
touch $RECDIR/start_${next_index}_$(date +%Y%m%d%H%M%S)
docker run --rm -v $PWD:$PWD -p $PORT:$PORT/udp koba/srt \
/usr/bin/gst-launch-1.0 -eq filesrc location=$FIFO ! queue leaky=2 ! \
h265parse ! mpegtsmux alignment=7 ! srtclientsink uri="srt://$HOST_IP:$PORT" &
gst-launch-1.0 -eq v4l2src device="/dev/video0" ! \
'image/jpeg, width=1280, height=720, framerate=30/1' ! \
nvv4l2decoder mjpeg=1 ! 'video/x-raw(memory:NVMM)' ! \
nvvidconv ! 'video/x-raw(memory:NVMM), format=(string)I420' ! \
nvv4l2h265enc insert-aud=1 insert-sps-pps=1 iframeinterval=60 bitrate=2000000 ! \
tee name = t \
t. ! queue leaky=2 ! filesink location=$FIFO \
t. ! queue ! h265parse ! mpegtsmux ! multifilesink location=$filename index=$next_index \
next-file=4 max-file-size=$MAX_FILE_SIZE max-files=$MAX_FILES
関連
ffmpegを使ってコマ落ちを回避するのに成功しました。
gstreamerでもコマ落ちを解消できました。
Discussion