1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

GStreamerで映像のストリーミングをしながら静止画を保存する

Last updated at Posted at 2023-03-14

はじめに

仕事でGStreamerを使うことがあったんですが、私は全然ド素人。

ストリーミングする部分は他の人が書いたものをそのままコピペして使ったわけですが、ストリーミングと同時にストリーミングしてる映像を切り出して静止画として使いたい処理があり、GStreamerに入れる前に静止画にすることも考えたんですけど、GStreamerの処理としてできるなら楽かなぁ、と思って調べてみました。

色々試してみたこと

まずは基本の形

gst-launch-1.0 を使って /dev/video0 から映像を取得して、fakesink に入れて捨てるサンプル。

$ gst-launch-1.0 -e v4l2src device=/dev/video0 ! video/x-raw, width=1920, height=1080, framerate=60/1 ! queue ! videoconvert ! fakesink

tee でパイプラインをふたつに分けてみる

取得した映像を tee でふたつにわけで、ふたつとも fakesink に入れて捨てるサンプル(サンプルでもひどい気がする)

$ gst-launch-1.0 -e v4l2src device=/dev/video0 ! video/x-raw, width=1920, height=1080, framerate=60/1 ! tee name=t \
    t. ! queue ! videoconvert ! fakesink \
    t. ! queue ! videoconvert ! fakesink

これで、上の fakesink は普通にストリーミングに使用する想定でこのままにしておいて、下の fakesink を静止画保存用に使っていきます。

multifilesink で保存

色々調べてみて、「なるほどね。こうすればいいんだろ(よく分からない)」で、こうなった。

$ gst-launch-1.0 -e v4l2src device=/dev/video0 ! video/x-raw, width=1920, height=1080, framerate=60/1 ! tee name=t \
    t. ! queue ! videoconvert ! fakesink \
    t. ! queue ! videoconvert ! videoscale ! video/x-raw,width=720,height=480 ! jpegenc ! multifilesink location=capture_%05d.jpg max-files=10 next-file=max-duration max-file-duration=300000000000

videoscale でリサイズして、jpegenc でJPEGファイルにして、multifilesink で保存する。
location=capture_%05d.jpg でファイル名指定して、max-files=10 で保存されるファイルの最大数指定。next-file=max-duration max-file-duration=300000000000 の指定で、300秒毎にファイル保存。
ちなみに、capture_%05d.jpg でファイルが勝手に連番で保存されていくけど、max-files でファイル数を指定している場合、capture_00010.jpg が保存されると capture_00000.jpg が消える。capture_00000.jpg が新たに保存されるみたいに番号が戻るのかと思ったけど、そうはならないらしい。

一見できてるように見えたけど

上のスクリプトでうまくいってるように見えるんですよ。
「これでできたな GStreamer チョロいぜ」とか思ったんですけど、このスクリプト、非常に重い。最初に framerate=60 を指定してるのに、上の fakesink でフレームレートを確認すると、18フレーム/秒くらい。これは使えない。
たぶん、この指定方法だと、全フレームの画像サイズ変換して、JPEG変換して、そのうち5分に1度静止画保存してるんでしょうね。それは重いか。。

というわけで改良版。

$ gst-launch-1.0 -e v4l2src device=/dev/video0 ! video/x-raw, width=1920, height=1080, framerate=60/1 ! tee name=t \
    t. ! queue ! videoconvert ! fakesink \
    t. ! queue ! videoconvert ! videorate ! video/x-raw, framerate=1/300 ! videoscale ! video/x-raw, width=720, height=480 ! jpegenc ! multifilesink location=capture_%05d.jpg max-files=10

videorate でフレームレートを 1/300 に下げてから、videoscale 以降の処理をするように修正。multifilesink に来るのはフレームレート 1/300 で 5分に1回だから、next-file=max-duration max-file-duration=300000000000 の指定は不要になった。

もうちょっと短く書ける

videoratevideoscale はまとめてこんな感じで書いてもいいらしい。

$ gst-launch-1.0 -e v4l2src device=/dev/video0 ! video/x-raw, width=1920, height=1080, framerate=60/1 ! tee name=t \
    t. ! queue ! videoconvert ! fakesink \
    t. ! queue ! videoconvert ! videorate ! videoscale ! video/x-raw, width=720, height=480, framerate=1/300 ! jpegenc ! multifilesink location=capture_%05d.jpg max-files=10

ただし、これだとダメ

上の videoratevideoscale の順序を入れ替えただけだけど、これをやるとフレームレートが 20フレーム/秒くらいまで下がった。
このような順序にしてしまうと、全フレームに対してサイズ変更だけはやってしまうということかな。

$ gst-launch-1.0 -e v4l2src device=/dev/video0 ! video/x-raw, width=1920, height=1080, framerate=60/1 ! tee name=t \
    t. ! queue ! videoconvert ! fakesink \
    t. ! queue ! videoconvert ! videoscale ! videorate ! video/x-raw, width=720, height=480, framerate=1/300 ! jpegenc ! multifilesink location=capture_%05d.jpg max-files=10

まとめ

簡単にできるかなと思った、ストリーミングしながら静止画保存ですが、なかなか手強かったのでメモ的に試してみたスクリプトとその結果を書いてみました。

マシンパワーが強くて全フレームに対してガリガリ処理を入れても問題ない処理速度であれば色々考えなくていいのかもしれませんが、今回は非力なマシンでやる必要があったので色々試してみました。

ちょっと特殊な用途かもしれませんが、こんなこともできたよって感じで読んでいただけたら幸いです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?