みなさん、こんにちは。
Raspberry Pi で mjpg-streamer や qstreamer などを使って監視カメラシステムを構築した場合、後で見返すために録画したいことがありますよね。
「毎日同じ時間帯の映像を記録しておきたい」「特定イベント発生時ではなく、決まった時間の映像を保存しておきたい」といった場合、映像がリアルタイムから大きく遅れていてガッカリ、なんて経験はありませんか?
そこで今回は、Raspberry Piで配信しているMJPEG映像を、最小限の遅延で、決まった時間の映像としてきれいに保存する方法をご紹介します。ポイントは、Raspberry PiのCPUに負担をかけず、古いフレームをどんどん捨てて常に最新の映像に追従することです。
遅延を最小化する基本方針
今回の方法のキモは、ffmpegというコマンドラインツールを使います。そして、以下の3つのポイントを守ることで、遅延を最小限に抑えます。
- 再エンコードはしない!
- Raspberry Pi側で映像を再エンコードすると、CPUに大きな負荷がかかってしまいます。今回は
-c copy
オプションを使い、MJPEGストリームをそのままコピーして保存します。これならCPUの負荷はほぼゼロです。
- Raspberry Pi側で映像を再エンコードすると、CPUに大きな負荷がかかってしまいます。今回は
- 古いフレームは捨てる!
- 遅延が蓄積しないように、受信が遅れた古いフレームは容赦なく捨てて、常に最新の映像に追従させます。
- バッファを使わない!
- 入力や書き込みのバッファを最小化し、受け取ったデータをすぐに処理します。
これらのポイントを踏まえた、具体的なffmpegコマンドを見ていきましょう。
ffmpegのバージョン別コマンド例
Raspberry Pi OSやインストール方法によって、ffmpegのバージョンが異なります。お使いのバージョンに合わせて、以下のコマンドを試してみてください。
ffmpeg 4系の場合
ffmpeg \
-fflags nobuffer+genpts+discardcorrupt \
-flags low_delay \
-framedrop \
-avoid_negative_ts make_zero \
-i http://localhost:8080/?action=stream \
-c copy \
-f segment -segment_time 600 \
/home/pi/videos/%Y-%m-%d_%H-%M-%S.avi
このコマンドを、例えばcron
などを使って、毎日10時に実行するように設定することで、毎日10時から10分間の映像を保存できます。
ffmpeg 5系の場合
ffmpeg \
-fflags nobuffer+genpts+discardcorrupt \
-flags low_delay \
-framedrop \
-use_wallclock_as_timestamps 1 \
-avoid_negative_ts make_zero \
-i http://localhost:8080/?action=stream \
-c copy \
-f segment -segment_time 600 \
/home/pi/videos/%Y-%m-%d_%H-%M-%S.avi
ffmpeg 6系の場合
ffmpeg \
-fflags nobuffer+genpts+discardcorrupt \
-flags low_delay \
-framedrop \
-use_wallclock_as_timestamps 1 \
-avoid_negative_ts make_zero \
-thread_queue_size 128 \
-i http://localhost:8080/?action=stream \
-c copy \
-f segment -segment_time 600 \
/home/pi/videos/%Y-%m-%d_%H-%M-%S.avi
各オプションの役割をチェック!
コマンドに出てくるオプションの意味を簡単に解説します。特に、遅延をなくすための重要なオプションに注目してみてください。
-fflags nobuffer
- 入力バッファを使わずに、すぐに処理を始めます。
-flags low_delay
- 低遅延モードを有効にします。
-framedrop
- 遅れて到着したフレームを破棄し、常に最新のフレームに追従します。
-c copy
- 再エンコードせず、そのままコピー保存します。CPU負荷を最小限に抑える一番のポイントです。
-use_wallclock_as_timestamps 1
- 受信した時刻をそのままタイムスタンプとして利用します(ffmpeg 5系以降で推奨)。
-f segment -segment_time 600
600
秒(10分)ごとにファイルを分割して保存します。これにより、必要な時間の映像だけを効率的に保存できます。
/home/pi/videos/%Y-%m-%d_%H-%M-%S.avi
- 録画ファイル名に日時を自動で付与します。
実運用でのヒント
- 保存先は?
- 保存先がmicroSDカードだと、書き込みの負荷で寿命が短くなる可能性があります。USBメモリや外付けSSDを保存先にするのがおすすめです。
- ネットワーク経由でもOK
- このコマンドは、同じネットワーク上の別のPCなどからMJPEGストリームを取得して録画する場合にも使えます。
まとめ
いかがでしたか?
今回の設定の鍵は、再エンコードせずにmjpeg
をそのまま保存すること、そして、-fflags nobuffer
、-flags low_delay
、-framedrop
の3つのオプションで遅延を溜めないことです。
この方法なら、Raspberry Piでも軽快かつリアルタイムに近い録画が実現できますよ!
みなさんも、ぜひ試してみてください。
本日も最後までお読みいただきありがとうございました。
それでは、よいRaspberry Piライフを!