Fifo(named pipe)書き込み専用のgstreamerのエレメントを作った
Fifo(named pipe)に書き込む専用のgstreamerのエレメント(fifosink)を作ってみました。
Fifo専用
fifoに対して書き込むことは普通にfilesink
でできます。
あえてfifo専用のsinkを作ったのは、ひとつには自分の勉強のためですが、fifoに特化したので以下のようにしました。
pipeのバッファサイズを最大にセットする
pipeのバッファサイズは64KBですが、fcntl(2)のF_SETPIPE_SZ
でそれを変更できます。
一般ユーザーのセットできる最大値は /proc/sys/fs/pipe-max-size
でわかります。
このあたりの情報は man 7 pipe
で調べられます。
fifosink
では/proc/sys/fs/pipe-max-size
で得られた最大値をセットしています。
書き込みにwritev(2)でなくvmspice(2)を使用する
pipeのパフォーマンスについて以下の記事が興味深いです。
write
のかわりにvmsplice
のシステムコールを使用すると渡したメモリをそのままカーネル空間にマッピングするので、カーネル空間でのメモリの割り当てとコピーを省略できて高速化できたそうです。
それを参考にしてfifosink
では書き込むときにwritev
の代わりにvmsplice
を使用しています。
余談ですが、vmsplice
は対称性のためにパイプからの読み込みにも使えるようになっていますが、そのときにはカーネル空間のメモリからユーザ空間のメモリにコピーが発生するので、read
と本質的な差がないようです。このことはman 2 vmsplice
に書かれています。
fifo(named pipe)に特化しpipe(標準出力)をサポートしない
ここまで書いた内容はpipeに共通のことなのでfifo(named pipe)だけでなくpipe(標準出力)にも適用できます。しかしfifosink
ではあえてfifoのみのサポートにしました。
その理由は2つあります。
(1) gstreamerのエレメントに行儀悪く標準出力にログメッセージを出すのもがあり、それと混じってしまう。
gstreamerのログは標準エラー出力に出すのがルールで、そのためのマクロが用意されているのですが、それを守られていないものがありました。そういうものがあるため標準出力に書き込むのは実用的でないと判断しました。
(2) fifoに特化することで、start時に指定されたファイル名でオープンし、stop時にクローズすると単純化できました。標準エラー出力をサポートするとstop時にクローズせずにフラッシュすることを考えなくてはなりません。
使用例
先日作ったpipe_video_src
にfifosink
を使ってI420の映像データを流し込むとWebRTCで送信することができます。
#!/bin/sh -eux
SIGNALING_URL=wss://207-148-110-182.canary.sora.sora-labo.shiguredo.app/signaling
CHANNEL_ID=tetsu-koba@sora-devtools
SIGNALING_KEY=your_key_xxxyyy
WIDTH=1280
HEIGHT=720
FRAMERATE=20
AUDIO_OPT='--no-audio-device'
FIFO=$PWD/.fifo
rm -f $FIFO
mkfifo $FIFO
./pipe_video_src --log-level 1 $AUDIO_OPT --video-fifo $FIFO --resolution ${WIDTH}x${HEIGHT} --framerate $FRAMERATE \
--signaling-url $SIGNALING_URL --channel-id $CHANNEL_ID \
--multistream true --video-codec-type H264 \
--metadata "{\"signaling_key\": \"$SIGNALING_KEY\"}" > log1 2>&1 &
GST_DEBUG_NO_COLOR=1 GST_DEBUG=fifosink:6 gst-launch-1.0 -v v4l2src device="/dev/video0" ! \
"image/jpeg, width=$WIDTH, height=$HEIGHT, framerate=$FRAMERATE/1" ! \
nvv4l2decoder mjpeg=1 ! 'video/x-raw(memory:NVMM)' ! \
nvvidconv ! 'video/x-raw, format=(string)I420' ! \
fifosink location=$FIFO >log2 2>&1
関連
Discussion