河本の実験室

河本が作ったものを紹介するブログです。こっち(https://kawalabo.blogspot.com/)から移転してきました。ポートフォリオ: http://俺.jp

「いま撮ってればよかった!」を無くす、さかのぼり屋内カメラを作った

子供と遊んでいると、予測不可能なタイミングで面白い事を言ったり、可愛い顔したり、初めて歩いたりします。そんなとき「カメラ回してればよかった!」と嘆いたことのある親は私だけではないはず。

f:id:kenkawakenkenke:20191106020510p:plain
そこで、事後にGoogle Homeに向かって「OK Google、いまの残しといて」と言うだけで過去に遡って動画を残しておけるカメラを作りました。

 

構成

f:id:kenkawakenkenke:20191106000323p:plain

素数が多く見えますが、一つ一つの要素は沢山の先人たちに踏み固められた技術です。今回の特徴はその繋ぎ方だけなので、要素の詳細説明は省きます。

動画の常時録画

まずUSBウェブカメラをラズパイにつなげて、常時録画し続けます。

  • ウェブカメラ: 僕はこういう制作には大体Logicool C920を使ってます。安くて画質いいので。
  • ラズパイ:僕が使ったのはRaspberry Pi 3Bですが、もっと新しいのあると思います。

常時録画といっても実は過去30秒だけを1秒ごとに区切って動画(TS)ファイルとして書き出し、古いファイルはどんどん捨てていってます。古いファイルを消していったほうがラズパイの容量が節約できるし、「ずっと撮られてる感」が減らせるので。

実際の録画には、ffmpegを使ってHLSで保存しています。ffmpegの設定は黒魔術感があって、正直あまり理解していません。沢山ググって色々な例を合成していった結果できたのが以下の呪文です:

ffmpeg \                   
-f alsa -thread_queue_size 1024 -i hw:1,0 \            
-f v4l2 -thread_queue_size 256 -s 640x480 -framerate 24 -i /dev/video0 \
-b:v 8000k -c:v h264_omx -bufsize 500k -r 30 -vsync cfr -g 24 \                                               
-c:a aac -b:a 256k -ar 44100 -bufsize 256k \
-flags +cgop+loop+global_header   -bsf:v h264_mp4toannexb \
-f hls -hls_list_size 120 -hls_time 1 -hls_flags delete_segments stream.m3u8

これをラズパイで走らせると、実行ディレクトリ内に「stream.m3u8」というインデックスファイルと「stream*.ts」という動画ファイル群が作られ続けます。

f:id:kenkawakenkenke:20191106003931p:plain

このtsファイル一つ一つが、撮られた1秒毎の動画ファイルです。

Google Homeから呼び出す

Google Homeから発声を受け取って、ラズパイで任意のコードを実行させる方法は、沢山ネットに載っています。「ラズパイ google home」とかでググりましょう。

僕は「OK Google、リビングの動画を残して」というと、ラズパイで実行しているPythonプログラムが通知を受け取れるようにしました。

動画を結合する

Google Homeから通知を受け取ったら、ffmpegを使って出力用の動画ファイルを作ります。

RUN_ID=`date +%Y%m%d_%H%M%S`
OUTPUT=/tmp/output_$RUN_ID.mov
MYLIST=/tmp/$RUN_ID.txt

echo "" > $MYLIST 
for file in `ls -v /var/www/html/livecam/stream*.ts|tail -n $((DURATION+1))|head -n $DURATION`;do                                        
 echo "file $file" >> $MYLIST                  
done                       

ffmpeg -safe 0 -f concat -i /tmp/mylist.txt -acodec copy -vcodec copy -y -f mov $OUTPUT

まず、録画したtsファイルを新しい順に並べ、最新の30個(=30秒ぶん)のファイル名を書き出したテキストファイルを作ります。

f:id:kenkawakenkenke:20191106011128p:plain

これをffmpegに投げて、結合しつつひとまとめのmovファイルに書き出します。これで、過去30秒を映した動画ファイルができました。

ちなみにmp4に書き出したら何故かGoogle Photosへのアップがうまくいかなかったので、movを使っています。

Google Photosにアップする

Google Photosへのアップにはrcloneを使います。rcloneとは色々なクラウドサービスのファイル操作を担ってくれる便利なツールです。

公式ページがとても親切に書かれているので、設定に迷うことはないと思います。

rclone copy $OUTPUT gphoto:upload -P

先程作った動画ファイルをアップしましょう。(gphotoのところに自分が設定したGoogle Photoのターゲット名を入れる)

やってみた

こんなふうにクロマグロのぬいぐるみで遊んでいるときに、ふと今までの出来事を撮っておきたいと思ったとしましょう。「OK Google、リビングの動画残して」とつぶやきます。

www.youtube.com

一分後ほど待つと、遊んでいるときの動画がGoogle Photosにアップされます。

f:id:kenkawakenkenke:20191106014030p:plain

こんな動画が撮られます:

www.youtube.com

さいごに・・・

  • カメラを持ち歩かずに言葉だけで「撮れる」のは本当に便利です。特に、「撮りたい瞬間にカメラを構えていなくても大丈夫」という安心感のおかげで、子供との遊びに集中できるのが嬉しいです。
  • ただし、たまに音声入力がミスって「申し訳ございません、お役に立てそうにありません」とか言われてしまいます。過去30秒しか撮れないので、これは焦ります。「OK Google、いまのを『長めに』残しといて』と言えば5分ぐらい録画を残すようにすればいいと思います。
  • 僕はカメラの未来は「ずっと録画してAIが良いシーンを選別」だと信じてますが、それができるまでの間はこういうハックでQOLをあげていきましょう。
  • 関係ないですが、上の子が初めて立つ瞬間はたまたまカメラを回していたおかげで撮れました。月イチぐらいでリピート再生する宝物です。こういうツールを使って、もっと宝物が増えたら嬉しいですね。