WSL2でUSBカメラを使う – 後編

WSL2でUSBカメラを使う - 後編 WSL
スポンサーリンク

前回はUSBIPD-WINというツールを使って、WSL2のLinuxからWindows上のUSBデバイスを認識できるようにしました。

しかしまだWSL2でUSBカメラは使えません。今回はこの問題を解決したいと思います。

USBIPD-WINを導入していない場合は前編をご確認ください。

WSL2でUSBカメラを使う - 前編
今回はWSL2のUbuntuでUSBデバイスを認識できるようにしてみます。WSL2は仮想マシンのようなものなので物理的なUSBポートは有りませんが、USBIPD-WINというツールを使うことでWindowsに接続されたUSBデバイスを認識することができます。ただWSL2のLinux kernelにはUSBカメラのドライバが含まれていないため、USBカメラを使うにはもう一工夫必要です。
スポンサーリンク

LinuxとUSBカメラ

LinuxでUSBカメラを利用する場合は、一般的にVideo for Linux 2(Video4Linux 2, V4L2)という仕組みを利用します。

Linux Kernel Media Documentation — The Linux Kernel documentation

V4L2では、様々なビデオカメラのドライバをサポートしています。

最近のUSBカメラはUSB Video Class(UVC)に対応しているものが多く、V4L2とUVCドライバという組み合わせでUSBカメラが利用できるケースが多いようです。

この「V4L2」と「UVCドライバ」はいずれもLinux Kernel内の機能であり、Linux Kernelがこれらの機能を有効にする設定で作られている(コンパイルされている)必要があります。

私が使っているWSL2のkernelでどうなっているか調べてみましょう。ちなみにLinuxカーネルのバージョンは次のようになっています。

$ uname -r
5.10.102.1-microsoft-standard-WSL2

まずV4L2の状況です。

$ zgrep CONFIG_VIDEO_V4L2 /proc/config.gz

何も表示されません。つまりV4L2は有効になっていないと言うことです。

UVCの状況も確認してみます。

$ zgrep CONFIG_USB_VIDEO_CLASS /proc/config.gz

こちらも何も表示されません。

従って、WSL2で提供されているこのLinux KernelではUSBカメラが利用できないことがわかります。

スポンサーリンク

WSL2のLinux Kernelのコンパイル

WSL2のLinux KernelでV4L2とUVCを利用できるようにするためには、Linux Kernelの再コンパイルが必要です。

この作業はWSL2のLinux上で行います。

コンパイルのためのツールを入手

Linux kernelをコンパイルするためには様々なツールが必要です。

Ubuntuでは下記コマンドで必要なツール一式を導入することができます。

$ sudo apt-get update
$ sudo apt-get install build-essential flex bison dwarves libssl-dev libelf-dev git libncurses-dev

これでツールの入手は完了です。

ソースの取得

次にLinux kernelのソースコードを取得します。

WSL2のLinux kernelのソースは下記で公開されています。

GitHub - microsoft/WSL2-Linux-Kernel: The source for the Linux kernel used in Windows Subsystem for Linux 2 (WSL2)
The source for the Linux kernel used in Windows Subsystem for Linux 2 (WSL2) - microsoft/WSL2-Linux-Kernel

まずタグ名を調べましょう。

タグ名の調査

右上の①の部分を選択すると「Switch branches/tags」という欄が表示されるので、②のTagsを選択しましょう。

そして③のエリアに現在使用しているLinux Kernelのバージョン(数字の部分)を入力します。

するとそのカーネルに対応したタグが④に表示されます。このタグ名をメモしておきます。

次のWSL2上の適当なディレクトリでこのタグ名を指定してcloneをします。「-b」の次の「linux-msft-wsl-5.10.102.1」が今回取得するタグ名になります。

$ mkdir wsl-kernel
$ cd wsl-kernel
$ git clone https://github.com/microsoft/WSL2-Linux-Kernel.git -b linux-msft-wsl-5.10.102.1 --depth 1

これでWSL2-Linux-Kernelというディレクトリが作成され、その中に指定したバージョンのLinux Kernelのソースコードが展開されています。

設定(コンフィグレーション)

続いてLinux kernelの設定(コンフィグレーション)をしていきます。

これをゼロからやるのは大変なので、現状の設定をベースに行うのがオススメです。現状の設定はソースコードのMicrosoft/config-wslに記載されているのでこれを利用します。

/proc/config.gzを展開したものを利用しても構いません。

$ cd Microsoft/config-wsl
$ make menuconfig KCONFIG_CONFIG=Microsoft/config-wsl

これで次のようなLinux kernelの設定画面が表示されます。

Linux kernelの設定画面

この設定画面ではカーソルキー・スペースキー・リターンキー・Tabキーを駆使して操作します。

まずはV4L2を有効にしましょう。

  • 「Device Drivers」→「Multimedia support」→「Filter media drivers」を有効化
  • 「Device Drivers」→「Multimedia support」→「Media device types」→「Cameras and video grabbers」を有効化
  • 「Device Drivers」→「Multimedia support」→「Media core support」→「Video4Linux options」→「V4L2 sub-device userspace API」を有効化

を設定します。

有効化する際は、モジュール(<M>)でなくビルトイン(<*>)とする必要があります。

次はUVCを有効にしましょう。

  • 「Device Drivers」→「Multimedia support」→「Media core support」→「Media drivers」→「Media USB Adapters」→「USB Video Class (UVC)」と「UVC input events device support」を有効化

とします。ここでもモジュールではなくビルトインにします。

UVC以外のUSBカメラを使いたい場合は「Media USB Adapters」で表示されるドライバを有効化しておくと使えるかもしれません。

特に「GSPA based webcams」では多くのWebカメラに対応しているようです。

gspca devices - LinuxTVWiki

ここまでの設定を行うと、いくつか勝手に有効になってしまう設定があります。これは無効化しておきましょう。私が気づいたのは下記の1つです。

  • 「Device Drivers」→「Multimedia support」→「Media core support」→「Media drivers」→「Media USB Adapters」→「GSPCA based webcams」

これはそのままにして置いても問題ないですが、Linux kernelのサイズが無題に大きくなったり、コンパイル時間が延びたりするので、無効化するのがオススメです。

以上の設定が終わったらTabキーで<Exit>を選び続け、一番上の階層で<Exit>を選ぶと「Do you with to save your new configuration?」と聞かれるので<Yes>を選択して保存しましょう。

なお設定は「Microsoft/config-wsl」に上書き保存されます。

ビルド

先ほど保存した設定を使ってビルドします。

$ make -j $(nproc) KCONFIG_CONFIG=Microsoft/config-wsl

ビルドは結構時間がかかります。最終的に次のように「Kernel: arch/x86/boot/bzImage is ready」となればビルド成功です。

ビルドの完了

この最後の行に表示されたbzImageがビルドして生成されたLinux Kernelになります。

このファイルはWindows側にコピーする必要があります。

今回はWindowsのユーザディレクトリ(%UserProfile%)にwslというフォルダをつくってそこにコピーしておきます。

$ mkdir -p /mnt/c/Users/Windowsでのユーザ名/wsl
$ cp arch/x86/boot/bzImage /mnt/c/Users/Windowsでのユーザ名/wsl/bzImage-v4l2-uvc

今回は作成したLinux KernelをbzImage-v4l2-uvcというファイル名でコピーしました。

作成したLinux Kernelでの起動

自分で作成したLinux KernelをWSL2で使用するためには、「.wslconfig」というファイルをWindowsのユーザフォルダ(%UserProfile%)に作成する必要があります。

このフォルダは「Windowsアイコンを右クリック」→「ファイル名を指定して実行」→「. (ピリオドを入力してOK)」で開くことができます。

ユーザフォルダを開いたら「テキストドキュメント」を新規作成し、ファイル名を「.wslconfig」に変更します。

そしてこの.wslconfigの中身を次のようにします。

[wsl2]
kernel=C:\\Users\\Windowのユーザ名\\wsl\\bzImage-v4l2-uvc

つまりkernelというキーに先ほどコピーしたbzImageファイルを指定します。ただし、ファイルパスの「\」は「\\」とする必要があります。

.wslconfigファイルを作成したら、PowerShell(あるいはWindowsターミナルで)次のコマンドを入力し、いったんWSL2を停止させます。

wsl --shutdown

そしてWSL2を再度開始します。

WSL2が起動したらLinux Kernelの詳細情報を表示させてみましょう。

$ uname -a
Linux baron 5.10.102.1-microsoft-standard-WSL2+ #1 SMP Sat Apr 23 20:43:18 JST 2022 x86_64 x86_64 x86_64 GNU/Linux

このように表示される日時がビルドした日時になっていれば、自分でビルドしたLinux kernelで起動しています。

またV4L2とUVCが有効になっていることも確認しておきましょう。

$ zgrep V4L2 /proc/config.gz
CONFIG_VIDEO_V4L2=y
CONFIG_VIDEO_V4L2_I2C=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_VIDEOBUF2_V4L2=y
$ zgrep USB_VIDEO /proc/config.gz
CONFIG_USB_VIDEO_CLASS=y
CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y

USBカメラの利用

V4L2とUVCに対応したLinux KernelでWSL2が動いていることを確認したら、USBカメラを試してみましょう。

今回は下記のUSBカメラを利用しています。

USBカメラの接続

まず前回紹介した手順でUSBカメラをアタッチします。

WSL2でUSBカメラを使う - 前編
今回はWSL2のUbuntuでUSBデバイスを認識できるようにしてみます。WSL2は仮想マシンのようなものなので物理的なUSBポートは有りませんが、USBIPD-WINというツールを使うことでWindowsに接続されたUSBデバイスを認識することができます。ただWSL2のLinux kernelにはUSBカメラのドライバが含まれていないため、USBカメラを使うにはもう一工夫必要です。

Windows側でUSBカメラをアタッチすると、WSL2からはUSBカメラが接続された様に見えます。

そこでWSL2側でdmesgを実行してみます。次のように「uvcvideo」で始まる行があればUVCのカメラとして認識されています。

UVCを認識

パーミッションの修正

USBカメラが無事に認識されると/dev以下にvideoで始めるファイル(デバイスノード)が作成されます。

$ ls -l /dev/video*
crw------- 1 root root 81, 0  4月 23 23:06 /dev/video0
crw------- 1 root root 81, 1  4月 23 23:06 /dev/video1

このパーミッションではルート権限を持つユーザしかUSBカメラを利用できません。

これでは不便なのでグループをvideoに変更し、グループでも読み書き可能なようにしておきます。

$ sudo chgrp video /dev/video*
$ sudo chmod g+rw /dev/video*
$ ls -l /dev/video*
crw-rw---- 1 root video 81, 0  4月 23 23:06 /dev/video0
crw-rw---- 1 root video 81, 1  4月 23 23:06 /dev/video1

このパーミッションの修正は毎回行う必要があります。

これでは不便なのでなんとかしたいのですが、今回は先送りにしておきます。

v4l-ctlでの確認

次にV4L2で今回接続したカメラが認識できるか確認してみます。この確認にはv4l2-ctlというツールを使いますのでv4l-utilsパッケージをインストールします。

$ sudo apt-get install v4l-utils

そしてv4l2-ctlでデバイスの情報を表示させてみます。

$ v4l2-ctl --all
Driver Info:
        Driver name      : uvcvideo
        Card type        : Microsoft® LifeCam HD-3000: Mi
        Bus info         : usb-vhci_hcd.0-1
        Driver version   : 5.10.102
        Capabilities     : 0x84a00001
                Video Capture
                Metadata Capture
                Streaming
                Extended Pix Format
                Device Capabilities
        Device Caps      : 0x04200001
                Video Capture
                Streaming
                Extended Pix Format
Priority: 2
Video input : 0 (Camera 1: ok)
Format Video Capture:
        Width/Height      : 640/480
        Pixel Format      : 'YUYV' (YUYV 4:2:2)
        Field             : None
        Bytes per Line    : 1280
        Size Image        : 614400
        Colorspace        : sRGB
        Transfer Function : Rec. 709
        YCbCr/HSV Encoding: ITU-R 601
        Quantization      : Default (maps to Limited Range)
        Flags             :
Crop Capability Video Capture:
        Bounds      : Left 0, Top 0, Width 640, Height 480
        Default     : Left 0, Top 0, Width 640, Height 480
        Pixel Aspect: 1/1
Selection Video Capture: crop_default, Left 0, Top 0, Width 640, Height 480, Flags:
Selection Video Capture: crop_bounds, Left 0, Top 0, Width 640, Height 480, Flags:
Streaming Parameters Video Capture:
        Capabilities     : timeperframe
        Frames per second: 30.000 (30/1)
        Read buffers     : 0
                     brightness 0x00980900 (int)    : min=30 max=255 step=1 default=133 value=133
                       contrast 0x00980901 (int)    : min=0 max=10 step=1 default=5 value=5
                     saturation 0x00980902 (int)    : min=0 max=200 step=1 default=83 value=83
 white_balance_temperature_auto 0x0098090c (bool)   : default=1 value=1
           power_line_frequency 0x00980918 (menu)   : min=0 max=2 default=2 value=2
                                0: Disabled
                                1: 50 Hz
                                2: 60 Hz
      white_balance_temperature 0x0098091a (int)    : min=2800 max=10000 step=1 default=4500 value=4500 flags=inactive
                      sharpness 0x0098091b (int)    : min=0 max=50 step=1 default=25 value=25
         backlight_compensation 0x0098091c (int)    : min=0 max=10 step=1 default=0 value=0
                  exposure_auto 0x009a0901 (menu)   : min=0 max=3 default=1 value=3
                                1: Manual Mode
                                3: Aperture Priority Mode
              exposure_absolute 0x009a0902 (int)    : min=5 max=20000 step=1 default=156 value=156 flags=inactive
                   pan_absolute 0x009a0908 (int)    : min=-201600 max=201600 step=3600 default=0 value=0
                  tilt_absolute 0x009a0909 (int)    : min=-201600 max=201600 step=3600 default=0 value=0
                  zoom_absolute 0x009a090d (int)    : min=0 max=10 step=1 default=0 value=0

V4L2も問題なく動作しているようです。

USBカメラの映像の表示

ここまできたらUSBカメラの映像を表示してみましょう。

今回はUVCに対応したツールである「guvcview」を使って見ます。インストールは下記のコマンドです。

$ apt-get install guvcview

これでguvcviewというコマンドがつかるようになるので実行してみましょう。

$ guvcview

WSLgが使える環境であればこれで「Guvcview」と制御するウィンドウとカメラの映像を表示するウィンドウの2つのウィンドウが表示されます。

しかし、私の場合はカメラ映像を表示するウィンドウは真っ暗で何も表示されません。

カメラの映像が表示されない

guvcviewを起動したターミナルを確認すると

V4L2_CORE: Could not grab image (select timeout): リソースが一時的に利用できません

というメッセージが繰り返して表示されています。

このような場合はguvcviewの制御ウィンドウで解像度を下げてみましょう。

guvcviewの設定画面 - 解像度を320x240にする

私の環境では解像度を320×240まで下げると、カメラ映像が表示されるようになりました。

表示されたカメラの映像

WSL2でUSBデバイスを使う際に、USBをネットワーク(IP)に変換する処理が入っており、高い解像度ではデータ転送が間に合わないようです。

なお、フレームレートを下げると、VGA(640×480)ぐらいならなんとか表示させることができました。

guvcviewの設定画面 - 解像度をVGAにする

ただ、映像にノイズが入ってしまっており、今子設定での実用性には少々難があると感じます。

VGAでのカメラ画像

この辺は現状の仕組みの限界なのかもしれません。

解像度の変更などをいろいろ試していると、guvcviewがエラーで落ちてしまうことがたびたびありました。

このような場合では、USBIPD-WINのアタッチが無効になっている(勝手にデタッチされてしまう)ことが多かったです。

まとめ

今回はWSL2でUSBカメラを使えるようにしてみました。

WSL2のLinux KernelはV4L2やUVCが有効になっていないため、USBカメラを利用するにはLinux Kernelを自分でコンパイルして差し替える必要があります。

Linux Kernelを変更すればUSBIPD-WINと組み合わせることによってWSL2でUSBカメラを利用することができます。ただ転送速度に難があるようなのが残念です。

次回はroot権限がなくてもUSBカメラを使えるようにしてみたいと思います。

コメント

タイトルとURLをコピーしました