WSLでUSBデバイスを使う(その3)

WSLでUSBデバイスを使う(その3:USBカメラ編)

概要

WSLのカーネルをビルドするで WSLカーネル v6.6.36.3 をビルドしたのでもうv5.15.153は使わなくて良くなったのですが、 やっぱりカーネル入れ替えずにUSBカメラ使いたい衝動にかられ、手順をまとめてみました。
(その2でUSBストレージ編を書こうと思っていたので、その2は欠番、その3になりました)

参考:
WSLでUSBデバイスを使う(その1)
WSLのカーネルをビルドする

開発環境の準備

開発環境の準備については、 WSLのカーネルをビルドする の「Linuxカーネルのビルド環境の構築」を参照してください。

カーネルモジュールのビルド

作業用ディレクトリの作成

たとえば、以下。 どこでも良いけど、以下の手順はこのディレクトリで行います。

mkdir /proj/wsl_kernel && cd /proj/wsl_kernel

カーネルソースの取得

作業ディレクトリ(/proj/wsl_kernel)にカーネルソースをダウンロードします。
gitリポジトリをcloneするか、リリースソースをダウンロードして展開します。

gitでcloneする場合

git clone https://github.com/microsoft/WSL2-Linux-Kernel.git

# 目的のタグをチェックアウト
git -C WSL2-Linux-Kernel checkout -b WSL-5.15.153.1 refs/tags/linux-msft-wsl-5.15.153.1

# linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成
ln -s WSL2-Linux-Kernel linux

[!NOTE] clone済みなら念のためgit pullして最新状態にしておく

[!NOTE] ブランチ作る必要ないけど、念のため。

リリースソース(zip)をダウンロードする場合

wget https://github.com/microsoft/WSL2-Linux-Kernel/archive/refs/tags/linux-msft-wsl-5.15.153.1.zip
unzip linux-msft-wsl-5.15.153.1.zip
# linuxディレクトリとしてアクセスしたいのでシンボリックリンク作成
ln -s linux-msft-wsl-5.15.153.1 linux

[!NOTE] unzipはデフォルトではインストールされていないのでインストール必要。

スクリプト&Dockerfileの入手

[!NOTE] Gistに必要なスクリプト&Dockerfileを置いておいたので以下のページのDownloadZIPボタンからダウンロードして 作業ディレクトリ(/proj/wsl_kernel)に展開してください。
Gist:WSLカーネルビルド環境

または以下のコマンドで取得できます。

wget https://gist.github.com/ippei8jp/03c9a19e7c83281f43224786a9cc2021/archive/main.zip
unzip -j main.zip

Dockerイメージを作成~起動確認

Dockerイメージを作成~起動確認は WSLのカーネルをビルドする のDockerイメージを作成~起動確認 を参照してください。
作成済みならスキップしてください。

カーネルモジュールのビルド

カーネルソースの取得、Dockeイメージのビルドが終わったら、以下のコマンドを実行します。

bash build_wsl_multimedia.sh

実行には数十分~1時間程度かかります(PCのスペックによる)。

実行完了後、outディレクトリにlinux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.debができます。
これを使用するディストリビューションから見えるフォルダ(ディストリビューション内でなくWindowsのディレクトリでも可)にコピーします。

カーネルビルド用スクリプト

用意したスクリプトの概要は以下の通りです。

build_functions.sh

build_functions.shはビルドに関わる処理を関数化したものをまとめたファイルです。
以下のスクリプトからインクルードして使用します。

Dockerコンテナを使用するので、あらかじめDockerイメージを作成しておく必要があります。

build_wsl_multimedia.sh

build_wsl_multimedia.shはマルチメディア関連のカーネルモジュールのビルドを行います。
build_wsl_usb-storage.shADD_CONFIG変数の設定値を変更しただけです。

その他はWSLのカーネルをビルドするを参照してください。

実行環境の準備

実行環境の準備は WSLでUSBデバイスを使う(その1) と同じです。
使用するUSBデバイスがUSBカメラに変わるだけです。

実行ディストリビューションの準備

デフォルト状態ではカーネルモジュールのインストール先(/usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/)が書き込みできないので、 overlayfsで書き込みできるファイルシステムをマウントします。

まず、マウントする(実際に書き込むための)ディレクトリを用意します。
upperとworkの2つが必要です。workにはなにも書き込まないでください。

sudo mkdir -p /modules_overlay/upper/$(uname -r)
sudo mkdir -p /modules_overlay/work/$(uname -r)

次にお試しマウントしてみます。

sudo mount -t overlay overlay -o \
    lowerdir=/usr/lib/modules/$(uname -r),\
    upperdir=/modules_overlay/upper/$(uname -r),\
    workdir=/modules_overlay/work/$(uname -r) \
    /usr/lib/modules/$(uname -r)

マウントできたか確認するため、ファイルを作成してみます。

echo hogehoge | sudo tee /usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txt

/usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txtが出来ていること(内容が正しいこと)と、 /modules_overlay/upper/5.15.153.1-microsoft-standard-WSL2/test.txtに同じファイルがあることを確認します。

終わったら削除しておきましょう。

sudo rm /usr/lib/modules/5.15.153.1-microsoft-standard-WSL2/test.txt

再起動したときに自動的にマウントされるように、/etc/wsl.confに先ほどのマウントコマンドを command=に指定します。
以下は書き込んだ後の/etc/wsl.confの例。

[boot]
systemd=true
command=mount -t overlay overlay -o \
    lowerdir=/usr/lib/modules/$(uname -r),\
    upperdir=/modules_overlay/upper/$(uname -r),\
    workdir=/modules_overlay/work/$(uname -r) \
    /usr/lib/modules/$(uname -r)

/etc/wsl.confが正常に変更できたか確認するにはWSLの再起動が必要です(ウィンドウ閉じただけではダメ)。

カーネルモジュールのインストール

先ほど作成したlinux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.debを使用して 以下のように実行します。

sudo dpkg -i linux-module-multimedia-5.15.153.1-microsoft-standard-wsl2_5.15.153.1-3_amd64.deb

USBカメラを繋いでみる

実行手順は 実行環境の準備は WSLでUSBデバイスを使う(その1) の「USB-Serialデバイスを接続」を参照してください。

USBカメラのを接続したときのログはこんな感じ

[22183.171276] vhci_hcd vhci_hcd.0: pdev(0) rhport(0) sockfd(3)
[22183.171281] vhci_hcd vhci_hcd.0: devid(196610) speed(3) speed_str(high-speed)
[22183.171334] vhci_hcd vhci_hcd.0: Device attached
[22183.550422] usb 1-1: new high-speed USB device number 3 using vhci_hcd
[22183.700457] usb 1-1: SetAddress Request (3) to port 0
[22183.786408] usb 1-1: New USB device found, idVendor=056e, idProduct=700a, bcdDevice= 1.00
[22183.786412] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[22183.786414] usb 1-1: Product: Venus USB2.0 Camera
[22183.786416] usb 1-1: Manufacturer: Vimicro Corp.
[22183.799190] usb 1-1: Found UVC 1.00 device Venus USB2.0 Camera (056e:700a)
[22183.844401] input: Venus USB2.0 Camera: Venus USB2 as /devices/platform/vhci_hcd.0/usb1/1-1/1-1:1.0/input/input1

画出し確認

pythonのopwnCVでもguvcviewでもお好きな方でどうぞ。

データ転送帯域が足りなくて画像が表示できない場合は、解像度を落としたり、 フォーマットをYUYV等からMKPEGに変更したりしてデータ量を少なくして試してみてください。