Raspberry Pi 3につないだUSBカメラの映像と音声をFFmpegで録画する

Raspberry 3 Model BにUSBカメラをつなぎFFmpegのh264_omxで録画をしてみます。
LinuxのFFmpegでUSBカメラの扱い方を確かめてみます。





前回はFFmpegをビルドしてh264_omxが使えるようにしました。
Rapberry Pi 3 のハードウエアエンコーダh264_omxが使えるFFmpegをビルドする

今回はUSBカメラの映像をファイルに録画してみます。

FFmpegのハードウエアエンコードh264_omxでUSBカメラの映像を録画する

LinuxでUSBカメラを扱うにはWindowsとは異なった流儀が必要です。
コンパイルの時に追加したALSAライブラリは音声を扱うものです。FFmpegで音声入力を扱う場合にalsaのお世話になります。
映像はVideo4Linuxというドライバを使います。

まずはFFmpegで動かしてみた方が判りやすいでしょう。
USBカメラをRaspberry Piにつなぎましょう。今回使うカメラはこちら。

販売終了 新製品

iBuffaleの広角レンズが特徴のUSBカメラです。

さっそくFFmpegで動かしてみたいです。が、その前に準備。
USBカメラの映像と音声を入力するために必要なパラメータを知らなくてはなりません。

まずは音声の方を見てみます。
arecord -l
と入れます。すると使える音声入力デバイスの一覧が表示されます。
pi@raspberrypi:~ $ arecord -l
**** ハードウェアデバイス CAPTURE のリスト ****
カード 1: USBCamera [USB_Camera], デバイス 0: USB Audio [USB Audio]
  サブデバイス: 1/1
  サブデバイス #0: subdevice #0
私の場合はこのように出ました。一つしかありませんが、USBカメラのマイクを認識している事が判ります。この中のカード番号とデバイス番号を控えておいてください。この番号でどの音声入力を使うか指定します。

次に映像の方です。
v4l2-ctl --list-device
と入れます。するとビデオデバイスの一覧が表示されます。
pi@raspberrypi:~ $ v4l2-ctl --list-device
USB_Camera (usb-3f980000.usb-1.5):
        /dev/video0
一つだけですが /dev/Video0 というのを映像入力の指定で使います。

これで入力の準備ができました。FFmpegでカメラの映像と音声を録画してみましょう。
コマンドは次のとおり。
ffmpeg -f v4l2 -i /dev/video0 -f alsa  -i hw:1,0  -c:v h264_omx   -c:a aac  -f matroska  out.mkv
先ほどのビデオファイルの指定の代わりに映像と音声の入力元を指定しました。映像の入力フォーマットにv4l2、音声にはalsaを指定します。音声の入力指定はhw:1,0です。この数字は先ほどのカード番号とデバイス番号です。

エラーが表示されなければ録画を続けています。適当なところでCtrl+Cを押して中断します。
出来上がったout.mkvをパソコンへコピーして再生してみてください。
ちゃんと映って音が聞こえれば成功ですね。

ここまで動けば基本的な動作の確認はできた事になります。画質を調整したり、配信するオプションに替えてみたりできますね。

カメラの解像度を変える

カメラの録画はうまくできましたでしょうか?録画ができて終わりでも良いのですが少し気になる点が残っています。

俺の買ったUSBカメラはもっと高解像度だ!  と。

USBカメラには何種類かの解像度とフレームレートを選択できるようになっています。さて、どうやって指定すればよいのでしょうか?やり方は全く知りませんでした。

最初に試したのは先ほども使ったv4l2-ctlを使う事です。
まずはUSBカメラで扱えるビデオ形式を表示させます。
v4l2-ctl -d /dev/video0 --list-formats-ext
これで映像フォーマット、解像度、フレームレートの組み合わせが判ります。
次にその組み合わせの指定を試してみます。
例えば
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720

v4l2-ctl -d 0 --set-fmt-video=width=1280,height=720,pixelformat='MJPG'
とかやってみました。
結果としては、解像度は変わったが思った映像フォーマットにもフレームレートにもなりませんでした。何かオプション指定に間違えがあるのでしょうね。
v4l2-ctl の使い方は良くわからないので、違う方向で調べ直します。だってこんな命令使ったらFFmpegだけで完結できないじゃないですか。何かがおかしい。

もう一度FFmpegの使い方に戻り調べ直します。
基本はFFmpegのドキュメントです。ドキュメントの豊富さと親切さにはいつも感心します。
そして、見るべき場所はここ。

27.19 video4linux2, v4l2 /  ffmpeg Documentation

先ほどの使える映像フォーマットの一覧は次のオプション指定でFFmpegから得られます。
ffmpeg -f v4l2 -list_formats all -i /dev/video0
でもフレームレートとの関係が表示されていないですね。この確認にはv4l2-ctlを使いましょう。

入力デバイスの条件もオプションでいろいろ指定できます。カメラの対応した組み合わせで条件を全部指定してみます。例えば
ffmpeg -f v4l2 -input_format mjpeg -framerate 30 -video_size 800x600 -i /dev/video0 -f alsa -i hw:1 -c:v h264_omx  -b:v 3000k -c:a aac -b:a 32k -f matroska  out.mkv
変換速度は約10fpsになってしまいます。
本当にハードウエアエンコードしているのか不安になります。まだまだ使い方を把握できません。

"ALSA buffer xrun" のエラーをなくす

とりあえず動いたことに満足してFFmpegを動かしていましたが、さっきから何か出てるんですよね。
エンコード中のテキストに
"ALSA buffer xrun"
と出てます。バッファですからオーバー?アンダー?と思うところにXですか。
いったい何でしょう。録音された音声はところどころぶつ切りな感じです。

ちょっとググります。するとRaspberry PiでFFmpegを試した方、皆さん出てますね。少し安心。では解決方法は?

これがなかなか見つかりません。alsaソースコードのバッファのパラメータをいじれみたいなのが出てきます。でも私の環境に言われているファイルが存在しません。

alsaライブラリのバグなら更新を待つしかありません。これは放置か・・・とあきらめかけましたが、

Past duration too large - messing with ALSA recording / reddit
evilsaltine 1ポイント 11ヶ月前
"You could try adding -thread_queue_size 1024 in your audio input options."
-thread_queue_size オプション? そんなの使ったことがない。今回のFFmpegで動くのかな?
早速試しましょう。コマンドはこちら
ffmpeg -f v4l2 -input_format mjpeg -framerate 30 -video_size 800x600  -i /dev/video0 -f alsa -thread_queue_size 1024 -i hw:1 -c:v h264_omx -b:v 1000k -c:a aac -b:a 32k -f matroska out.mkv
おぉー! エラーが消えた!
evilsaltineさん、ありがとう!

今回は放置かと思いましたがオプション指定で回避できました。
キューサイズは、1024ではまだ警告がでる事があります。2048にしてもまだ出ます。4096にするとほぼ出なくなりましたが解像度が高いと出てきます。場合によってはもっと大きな値にしなくてはならないでしょう。

エンコード中の負荷を見てみる

どのくらいCPUを使っているか見てみます。
Tera Termで2つターミナルを開きます。一つはコマンド操作用に、もう一つはhtopを動かして負荷を見ます。

まずは何もしていない時です。



CPU平均は1%前後をうろうろしてます。

ffmpegを動かしてみます。コマンドはこれ。

ffmpeg -f v4l2 -input_format yuyv422 -framerate 30 -video_size 640x480 -i /dev/video0 -f alsa -thread_queue_size 8192 -i hw:1 -c:v h264_omx -b:v 10000k -c:a aac -b:a 128k -vsync 0 -f matroska out.mkv

ビットレートは10Mです。
録画中"Past duration 0.xxxx too large"と警告が出てしまいます。

この時のCPUの状態は



CPU平均で12%前後でした。

エンコーダをmpeg4にしてみます。

ffmpeg -f v4l2 -input_format yuyv422 -framerate 30 -video_size 640x480 -i /dev/video0 -f alsa -thread_queue_size 8192 -i hw:1 -c:v mpeg4 -b:v 10M -c:a aac -b:a 128k -vsync 0 -f matroska out.mkv


CPU平均は30%前後になりました。
mpeg2videoでは35%ほどでした。

CPUを使ってくれませんね。mpeg2videoでフルHDとか試しますが40%ほどしか使いません。fpsは3fpsも出ないくらい。

Raspberry Piの消費電力

エンコード中のRPiの電流をモニタしていました。
おおむね0.5Aで動いています。2.5Wしか電力を消費していません。当然USBカメラの電力込みの値です。

ちょっとモバイルバッテリーで使う事を考えてみましょう。
例えば2000mAのモバイルバッテリーを使うとします。モバイルバッテリーの容量は搭載されたリチウム電池の容量を単純に足し算したものでしょう。基準の電圧は3.7V(3.6V)です。

電力比では単純に2.8時間になります。変換効率を0.6とすると1.7時間ほどになります。90分は動かせそうです。

まとめ

FFmpegでUSBカメラの映像と音声を保存してみました。LinuxのUSBカメラの扱い方をやっと理解しだしました。
これをやろうと思ったのはOctoPrintでUSBカメラの音声を配信したいというところにあります。どうしても音声を取得できないんですよ。素のRaspbianで録音できたので改めてOctoPiのOS部分を見直しをしてみます。

USBカメラの変換速度が思ったほど出ません。USBカメラの出力は30fpsのはずですが入力フレームレートが少ない気がします。変換速度は1倍に届かない事が多いです。USBカメラではなくファイルから変換させるとそこそこの速さで動きますのでFFmpegのエンコードが遅いわけではないと思います。Video4Linuxが遅いのでしょうか?使い方が違うのでしょうか?

h264_omxのエンコードはもっときれいかな?と期待してしまいました。Rapberry Piでh.264のハードウエアエンコードができる、という言葉だけで少し夢を持ち過ぎたところがあります。
h.264なのに品質指定ができないのが残念です。配信用途というならビットレート指定の方が設計しやすいですけどね。
いろいろ疑問や不満もありますが、消費電力が2.5Wというのを考えれば、やはりすごい!

さて、次はffmpegでカメラ映像のストリーミングを試してみます。

コメント

最近のコメント

Threaded Recent Comments will be here.