2022年5月31日火曜日

motion: いつの間にビルトインの動画出力と外部パイプ出力が同時に行われるようになったのだろう?

色々とソースを見ていて気付いた点があります。

基本動作としてmotionは、カメラで撮影した映像内の動体検知を行って記録すること。

ここから派生して記録する形式として、静止画と動画の大きく分けて2つがあり、動画は実際の映像と、動体検知を行っている処理の映像という2つの映像が存在します。

また実際の映像は、ビルトインのエンコーダで処理することもできるし、pipeを使って外部処理でエンコードすることもできます。

この機能は当初から存在してはいましたが、処理速度やビルド環境、実行環境に大きく左右される機能なのですが、体験記憶としては静止画と動画の同時出力はできていた記憶はあるのですが、実際の映像と検知処理の映像はどちらかしか出力できなかったと記憶していました。

現在のソースを見ていると実際の映像と検知処理の映像の同時出力を行うように作られており、さらにextpipe(外部パイプ)出力も同時に行う形になっていました。自分の中ではビルトインか外部パイプどちらかしか出力されないと思い込んでいて、外部パイプ出力の処理が予想以上に重たく感じられていたのです。なので微調整を行う過程で結局最後はビルトインエンコーダを使用する形で落ち着いていました。

motionの出力
┣静止画(全て/特定のフレーム)
┗動画
┣ビルトインエンコーダの出力 実際の映像
┣外部パイプへの出力 実際の映像
┗ビルトインエンコーダの出力 動作検知処理の映像

これらが同時に出力可能と言うことに今更気づいたのかよwとかいうレベルですが、ビルトインエンコーダと外部パイプ出力が同時に行われるという仕様をまったく想定していなかったので今まで理解できなかった不可解な現象がようやく理解できました。

不可解な現象を列記すると、

・ごくまれに出力された動画ファイルが壊れていることがあった。

・ビルトインの出力と外部パイプの出力で動体検知の癖が変わる。

・出力された動画をffmpegで処理すると、エンコーダを通していないのにファイルサイズが変わった。

・外部パイプを使用しているときにイベントスクリプト内(on_movie_end)で処理するときにまだ動画ファイルがクローズされていない。

・スクリプトの引数で%fを使用するときにファイルの拡張子がある場合とない場合があった。

などなど…まだあると思いますがこの辺が結構不可解だったポイントです。

仕様として、動体検知映像はファイルの末尾に"m"を強制的につけられるのですが、ビルトインエンコーダのファイル名と、外部パイプのファイル名は拡張子があるかないかの差しかありませんでした。(今まで、とりあえず外部スクリプトで拡張子がない場合は処理を行わないようにしていました。)

で、問題的な動作として、ビルトインエンコーダの出力と外部パイプの出力が同じファイル名になっていて、処理はビルトインエンコーダの出力→外部パイプの出力という順番で処理されるので、結果的にどうなるのかと言えば…

ビルトインエンコーダの出力が行われ、直後に外部パイプの出力が行われることにより上書きされてゆく結果に。

Windowsでそれなりの実装を行っていれば、おそらく外部パイプのファイル出力エラーとなるはずなのですが、Linux(Raspberry pi)では平気で処理が通ってしまい、ファイルサイズはどちらか大きいサイズ。出力内容は書き込みバッファサイズに依存してどうなることやらといった感じでしょうか。(ファイルの排他制御はファイルシステムに依存しているはずなので、ファイルシステムを変えると動作が変わるかも?)

大抵の場合、ビルトインエンコーダの出力は大きく、固定ビットレートなので外部パイプ出力を上書きしてしまうようなことがなかったために、動画が見れていた感じです。ファイルとしては映像の後に無駄なパディングが書き込まれている状態になったために、ffmpegで処理を行うと、その無駄なパディングが排除され、ファイルサイズが小さくなった、と。

なんか今まで不可解だった不安定な動作が一気にすっきりしました。

動体検知の癖の差はエンコード処理が単純に多くなるのでレスポンス低下による影響だと考えられます。

なぜこの辺のソースを追っかけたかと言えば、想定している機能とちょっとソースを見た感じ実装がずれていたので足りない部分を追加しようとしていたのですが、よくよく見てみると想定している仕様が違うということに気づきました…。

git上のソースを3.10ぐらいまでは遡れるのですが、そのくらいからは同時出力できる感じがしました。なので、おそらく当初からそういう仕様だったのかもw

0 件のコメント:

コメントを投稿