はじめに
Linux環境でWebカメラの映像を仮想ビデオデバイスに出力し、その映像をFFmpegを使って録画する方法について説明します。仮想ビデオデバイスを使うことにより、1つのWebカメラ映像を、複数のアプリケーションで利用可能になります
作業環境
・Ubuntu 24.04.1 LTS \n \l
・PC:x86_64 ガレリア NvidiaのGPU搭載
・入力映像:Webカメラ 640x360
30fps
・GStreamer Core Library version 1.24.2
~$ which gst-launch-1.0
/usr/bin/gst-launch-1.0
・ffmpeg version 6.1.1-3ubuntu5
~$ which ffmpeg
/usr/bin/ffmpeg
手順の全体像
-
仮想ビデオデバイスの設定:
v4l2loopback
モジュールを使って仮想ビデオデバイスを作成し、設定を確認します - GStreamerで映像転送:Webカメラ映像を仮想ビデオデバイスに転送します
- FFmpegで映像の録画:仮想ビデオデバイスに流れた映像をFFmpegで録画します
1. 仮想ビデオデバイスの設定
まず、v4l2loopback
モジュールを利用して仮想ビデオデバイスを作成します
シェルスクリプト
以下のシェルスクリプトで、v4l2loopback
モジュールのインストールと仮想ビデオデバイスの設定を行います。仮想ビデオデバイスはなんぼあっても良いので、今回は4つ作成します
#!/bin/bash
# If you have older version, purge it
sudo modprobe -r v4l2loopback
# Install required packages
sudo apt update
sudo apt install -y git build-essential dkms linux-headers-$(uname -r) v4l2loopback-dkms
# Clone v4l2loopback from GitHub
git clone https://github.com/umlaeute/v4l2loopback.git
cd v4l2loopback
# Compile and install the module
make && sudo make install
# Load the v4l2loopback module with 4 devices
# "echo" for using also after reboot PC
echo "options v4l2loopback devices=4 video_nr=0,1,2,3 exclusive_caps=1" | sudo tee -a /etc/modprobe.d/v4l2loopback.conf
echo v4l2loopback | sudo tee -a /etc/modules-load.d/modules.conf
以下で、仮想ビデオデバイス(video0~video3)がインストールされたことを確認します
$ v4l2-ctl --list-devices
Dummy video device (0x0000) (platform:v4l2loopback-000):
/dev/video0
Dummy video device (0x0001) (platform:v4l2loopback-001):
/dev/video1
Dummy video device (0x0002) (platform:v4l2loopback-002):
/dev/video2
Dummy video device (0x0003) (platform:v4l2loopback-003):
/dev/video3
USB 2.0 Camera: USB 2.0 Camera (usb-0000:01:00.0-2):
/dev/video4
/dev/video5
/dev/media0
ここで確認できたデバイスを使って、次の手順に進みます
2. GStreamerで仮想ビデオデバイスに映像を転送
次に、GStreamerを使ってWebカメラ(/dev/video4)から取得した映像を、仮想ビデオデバイス(/dev/video0)に転送します
gst-launch-1.0 -e -v v4l2src device=/dev/video4 ! videorate ! video/x-raw,framerate=30/1 ! videoconvert ! v4l2sink device=/dev/video0
・v4l2src device=/dev/video4:Webカメラから映像を取得します
・videorate:フレームレートを調整します
・video/x-raw,framerate=30/1:フレームレートを30fpsに設定します
・videoconvert:映像フォーマットを変換します
・v4l2sink device=/dev/video0:仮想ビデオデバイスに映像を転送します
3. FFmpegで映像をコピー
FFmpegを使って、仮想ビデオデバイス/dev/video0からの映像を/dev/video1にコピーします(本当はvideo0から直接保存したかったが……この理由は『ちなみに』にて記載)
ffmpeg -f v4l2 -r 30 -i /dev/video0 -f v4l2 -c:v copy /dev/video1
・-f v4l2:V4L2形式を使用します
・-r 30:フレームレートを30fpsに設定します
・-i /dev/video0:入力デバイスとして仮想ビデオデバイス/dev/video0を指定します
・-c:v copy:エンコードせずに映像をコピーします
・/dev/video1:出力デバイスとして仮想ビデオデバイス/dev/video1を指定します
4. FFmpegで映像を保存
映像を保存にもFFmpegを使います。以下のコマンドで映像をmp4ファイルに保存します
ffmpeg -f v4l2 -i /dev/video1 -c:v h264_nvenc -preset fast output.mp4
・-f v4l2:V4L2形式で映像を取得します
・-i /dev/video1:入力デバイスとして仮想ビデオデバイス/dev/video1を指定します
・-c:v h264_nvenc:NVIDIAのハードウェアエンコーダでH.264形式にエンコードします
・-preset fast:エンコード速度を優先する設定です
・output.mp4:出力ファイルの名前です
しかるべき映像が排出されれば完成です
おわりに
本記事では、Linux上でWebカメラ映像を仮想ビデオデバイスを通じて録画する手順について説明しました。仮想ビデオデバイスを活用することで、映像処理の幅が広がると思います
ちなみに
上記3.で/dev/video1を経由しない場合、エンコードが行われず(ずっとdrop)破損したmp4ファイルが排出される。rawvideo流れる仮想ビデオデバイス(v4l2loopback)直下での録画は難しそう。ffplayは見れるのに……謎です
追記_20241126
もうひとつの仮想ビデオデバイス経由せずとも録画できました
-f v4l2
ではなく-f rawvideo
が正解でした。それに合わせて保存部分のコマンド修正
ffmpeg -r 30 -f rawvideo -video_size 640x480 -pix_fmt yuyv422 -i /dev/video0 -c:v h264_nvenc -preset fast output.mp4
仮想ビデオデバイス(v4l2loopback)流入した時点で、v4l2系列の扱いになるとおもってた。ちがった。流入してなお、生データ扱いでした
~$ ffprobe /dev/video0
〜〜〜
Input #0, video4linux2,v4l2, from '/dev/video0':
Duration: N/A, start: 2178.241541, bitrate: 147456 kb/s
Stream #0:0: Video: rawvideo (YUY2 / 0x32595559), yuyv422, 640x480, 147456 kb/s, 30 fps, 30 tbr, 1000k tbn
参考