2025/03/14更新
2022年5月に作成した記事を、Windows 11 + Ubuntu 24.04 LTSの環境を念頭に更新しました。
前回はWSL2上のOpenCVでUSBカメラを利用する方法を紹介しました。この記事ではWSL2でUSBカメラを使うためにUSBIPD-WINというツールを使いましたが、いろいろ課題がありました。
そこで今回はこの課題の解消を試みたいと思います。
USBIPD-WIN利用時の課題
WSL2は仮想環境のようなものでUSBデバイスを直接利用することができません。
そこでUSBIPD-WINというツールを使って、USBデータをIPに変換したうえでWSL2に転送し、WSL2側でIPからUSBデータを復元することでUSBデバイスを利用できるようになります。


これでWSL2でUSBカメラを利用できるようになるのですが、試したところ次のような課題があると感じました。
- 環境構築が面倒
USBIPD-WINの導入と、Linux Kernelのコンパイルが必要 - 事前設定が面倒
Windowsの管理者権限でUSBカメラを共有する必要がある - USBのスループットが低い
解像度やフレームレートを下げないとUSBカメラの映像をWSL2で取得できない
全部を改善するのは無理かもしれませんが、なんとか改善する方法を考えたいと思います。
ストリーミングの利用
そこで試してみたのはUSBカメラの映像をWindowsからWSL2へストリーミングする方法です。
参考にしたのはこちらのサイトです。

この元ネタのサイトを参考にしつつ、次のようなシステムを構築してみます。
USBカメラはWindows PCに接続する
Windows PCからWSL2のLinuxへUSBカメラの映像をストリーミングする
WSL2のLinuxで動作するOpenCVではストリーミングされた映像を受信する
つまり、USBカメラから映像をキャプチャするのはWindows側で、そのキャプチャした映像をWSL2側にストリーミングすることで、WSL2のOpenCVでUSBカメラの映像(正確にはストリーミングされたUSBカメラの映像)を取得することを目指します。
Windows側の準備
Windowsにはストリーミングを行うソフトウェアとしてFFMPEGをインストールします。
FFMEPGは下記のサイトからダウンロードできます。
「Get packages & executable files」でWindowsロゴを選び、表示された「Windows EXE Files」のリストからダウンロード先を選びます。
ダウンロード先は2つありますが、私が見た感じ「Windows builds by BtbN」の方がわかりやすい気がしました。
「Windows builds by BtbN」には多数のファイルがあります。
今回はWindowsで利用するので「win64」のものをダウンロードします。
バージョンは「master(最新のソースコード)」「n6.1」「n7.1」がありますが、最新のリリース版である「n7.1」にしてみました。
さらにライセンスとして「gpl」「lgpl」、リンク形式として「shared」「非shared(static)」が有ります。今回はライセンスはGPLで問題ないので「gpl」の「非shared」をダウンロードします。
ダウンロードしたzipファイルは展開して、「ffmpeg」というフォルダーに変えてCドライブ直下に移動しておきます。
さらに、Windowsの環境変数Pathにffmpegフォルダー内のbinフォルダーを追加します。
これでFFMPEGのインストールは完了です。PowerShell (Windows Terminal)を起動して「ffmpeg –version」で情報が表示されればOKです。
> ffmpeg -version
ffmpeg version n7.1-214-g71889a8437-20250228 Copyright (c) 2000-2024 the FFmpeg developers
built with gcc 14.2.0 (crosstool-NG 1.26.0.120_4d36f27)
configuration: --prefix=/ffbuild/prefix --pkg-config-flags=--static --pkg-config=pkg-config --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 --enable-gpl --enable-version3 --disable-debug --disable-w32threads --enable-pthreads --enable-iconv --enable-zlib --enable-libfreetype --enable-libfribidi --enable-gmp --enable-libxml2 --enable-lzma --enable-fontconfig --enable-libharfbuzz --enable-libvorbis --enable-opencl --disable-libpulse --enable-libvmaf --disable-libxcb --disable-xlib --enable-amf --enable-libaom --enable-libaribb24 --enable-avisynth --enable-chromaprint --enable-libdav1d --enable-libdavs2 --enable-libdvdread --enable-libdvdnav --disable-libfdk-aac --enable-ffnvcodec --enable-cuda-llvm --enable-frei0r --enable-libgme --enable-libkvazaar --enable-libaribcaption --enable-libass --enable-libbluray --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librist --enable-libssh --enable-libtheora --enable-libvpx --enable-libwebp --enable-libzmq --enable-lv2 --enable-libvpl --enable-openal --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopenmpt --enable-librav1e --enable-librubberband --enable-schannel --enable-sdl2 --enable-libsnappy --enable-libsoxr --enable-libsrt --enable-libsvtav1 --enable-libtwolame --enable-libuavs3d --disable-libdrm --enable-vaapi --enable-libvidstab --enable-vulkan --enable-libshaderc --enable-libplacebo --disable-libvvenc --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libzimg --enable-libzvbi --extra-cflags=-DLIBTWOLAME_STATIC --extra-cxxflags= --extra-libs=-lgomp --extra-ldflags=-pthread --extra-ldexeflags= --cc=x86_64-w64-mingw32-gcc --cxx=x86_64-w64-mingw32-g++ --ar=x86_64-w64-mingw32-gcc-ar --ranlib=x86_64-w64-mingw32-gcc-ranlib --nm=x86_64-w64-mingw32-gcc-nm --extra-version=20250228
libavutil 59. 39.100 / 59. 39.100
libavcodec 61. 19.101 / 61. 19.101
libavformat 61. 7.100 / 61. 7.100
libavdevice 61. 3.100 / 61. 3.100
libavfilter 10. 4.100 / 10. 4.100
libswscale 8. 3.100 / 8. 3.100
libswresample 5. 3.100 / 5. 3.100
libpostproc 58. 3.100 / 58. 3.100
WSL2側の準備
WSL2のLinuxで導入する必要があるのはOpenCVとFFMPEGです。FFMPEGは事前の動作確認時に利用します。
OpenCVについては次のコマンドで導入できます。
sudo apt-get install libopencv-dev
FFMPEGのインストールは次のコマンドです。
sudo apt-get install ffmpeg
またストリーミングに必要な情報としてWSL2側のIPアドレスが必要です。WSL2のIPアドレスは次のコマンドで表示されます。
$ hostname -I
172.21.92.66
つまりWSL2側のIPアドレスは「172.21.92.66」となります。このIPアドレスはのちのち使うのでメモしておきます。
FFMPEGによるUSBカメラのストリーミング
それではWindowsにインストールしたFFMPEGを使ってUSBカメラの映像をストリーミングしてみましょう。
操作はWindowsのコマンドライン(PowerShell・Windows Terminal・コマンドプロンプト)で行います。
USBカメラ名の確認
まずUSBカメラの名前を次のコマンドで確認しましょう。
cmd /c "chcp 65001 & ffmpeg -sources dshow"
本来はffmpeg -sources dshow
でよいのですが、USBカメラの名称が日本語の場合に文字化けしてしまいます。
文字化けを回避するために、cmd.exeを介してffmpegを実行しています。
私の場合は次のような結果となりました。
> cmd /c "chcp 65001 & ffmpeg -sources dshow"
Active code page: 65001
ffmpeg version n7.1-214-g71889a8437-20250228 Copyright (c) 2000-2024 the FFmpeg developers
built with gcc 14.2.0 (crosstool-NG 1.26.0.120_4d36f27)
configuration: --prefix=/ffbuild/prefix --pkg-config-flags=--static --pkg-config=pkg-config --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 --enable-gpl --enable-version3 --disable-debug --disable-w32threads --enable-pthreads --enable-iconv --enable-zlib --enable-libfreetype --enable-libfribidi --enable-gmp --enable-libxml2 --enable-lzma --enable-fontconfig --enable-libharfbuzz --enable-libvorbis --enable-opencl --disable-libpulse --enable-libvmaf --disable-libxcb --disable-xlib --enable-amf --enable-libaom --enable-libaribb24 --enable-avisynth --enable-chromaprint --enable-libdav1d --enable-libdavs2 --enable-libdvdread --enable-libdvdnav --disable-libfdk-aac --enable-ffnvcodec --enable-cuda-llvm --enable-frei0r --enable-libgme --enable-libkvazaar --enable-libaribcaption --enable-libass --enable-libbluray --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librist --enable-libssh --enable-libtheora --enable-libvpx --enable-libwebp --enable-libzmq --enable-lv2 --enable-libvpl --enable-openal --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopenmpt --enable-librav1e --enable-librubberband --enable-schannel --enable-sdl2 --enable-libsnappy --enable-libsoxr --enable-libsrt --enable-libsvtav1 --enable-libtwolame --enable-libuavs3d --disable-libdrm --enable-vaapi --enable-libvidstab --enable-vulkan --enable-libshaderc --enable-libplacebo --disable-libvvenc --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libzimg --enable-libzvbi --extra-cflags=-DLIBTWOLAME_STATIC --extra-cxxflags= --extra-libs=-lgomp --extra-ldflags=-pthread --extra-ldexeflags= --cc=x86_64-w64-mingw32-gcc --cxx=x86_64-w64-mingw32-g++ --ar=x86_64-w64-mingw32-gcc-ar --ranlib=x86_64-w64-mingw32-gcc-ranlib --nm=x86_64-w64-mingw32-gcc-nm --extra-version=20250228
libavutil 59. 39.100 / 59. 39.100
libavcodec 61. 19.101 / 61. 19.101
libavformat 61. 7.100 / 61. 7.100
libavdevice 61. 3.100 / 61. 3.100
libavfilter 10. 4.100 / 10. 4.100
libswscale 8. 3.100 / 8. 3.100
libswresample 5. 3.100 / 5. 3.100
libpostproc 58. 3.100 / 58. 3.100
Auto-detected sources for dshow:
@device_pnp_\\?\usb#vid_045e&pid_0779&mi_00#7&12243f&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global [Microsoft® LifeCam HD-3000] (video)
@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{BD418239-DA33-4ECF-BFF6-7D18DBE1C438} [デスクトップ マイク (2- Microsoft® LifeCam HD-3000)] (audio)
@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{7C7417DC-DB94-446F-ACFD-5FEBB13F7D62} [ヘッドセット (2- OpenRun Pro by Shokz)] (audio)
重要なのは「Auto-detected sources for dshow」以降に表示されるUSBカメラの名前です。私の場合は「Microsoft® LifeCam HD-3000」です。
ストリーミングの開始
名前がわかったらFFMPEGによるUSBカメラのストリーミングを開始します。
FFMPEGによるストリーミングは次のコマンドで行います。
ffmpeg -f dshow -i video="Microsoft® LifeCam HD-3000" -vcodec mjpeg -r 15 -s 640x480 -b:v 10M -f mjpeg udp://172.21.92.66:1234
ここではストリーミングのフォーマットしてMotionJPEGを利用しています。そのため
以前は次のようにコーデックをH.264にして、MPEG-TSでストリーミングしていたのですが、OpenCVでのキャプチャに失敗することが多いようです。
ffmpeg -f dshow -i video="Microsoft® LifeCam HD-3000" -preset ultrafast -tune zerolatency -vcodec libx264 -r 15 -s 640x480 -b:v 10M -f mpegts -flush_packets 0 udp://172.21.92.66:1234
そのため安定して動作するMotionJPEGを利用するようにしました。
「video」で指定するカメラの名前は先ほど調べたものを利用します。
また「udp://172.21.92.66」の部分には、事前に調査したWSL2側のIPアドレスを指定します。
このコマンドでは、videoで指定したUSBカメラの映像を解像度640×480、フレームレート15fpsでストリーミングしています。フォーマットはMotionJPEG、そしてストリーミングはUDPを利用しています。
ビットレートは10Mbpsを指定していますが、この解像度とフレームレートなら実際にはもっと低くなるようです。
ビットレートを指定しないと、かなり画質が悪くなるので、ビットレートを指定するのがオススメです。
また、私のPCではフレームレートをこれ以上高くすると、遅延が大きくなってしまうようでした。
このコマンドを実行すると、FFMPEGは指定されたIPアドレスとポートに対して、UDPでストリーミングデータを送信を開始します。
ストリーミングの確認
FFMPEGによるストリーミングを開始したら、このストリーミングデータがWSL2側に届いているかどうかを確認してみましょう。
この確認はFFMPEGに付属する「ffplay」というコマンドを利用します。WSL2側のターミナルで
ffplay udp://@:1234
を実行してみましょう。
数秒待つとウィンドウが表示され、USBカメラの映像(=WindowsのFFMPEGでストリーミングされている映像)が表示されるはずです。
これでFFMPEGでストリーミングができることが確認できました。
WSL2のターミナルでffplayコマンドを実行する際には、WSL2でGUIが利用できる状態であることを確認してください。

WSL2上のOpenCVによるキャプチャ
ようやく本題です。
WSL上のOpenCVで上記のFFMPEGによるストリーミングをキャプチャするために、次のようなソースコードを作成します。
#include <string>
#include <iostream>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
int main(int argc, char* argv[]) {
const std::string window_name("OpenCV Sample");
cv::VideoCapture cap("udp://@:1234", cv::CAP_FFMPEG);
if ( !cap.isOpened() ) {
std::cerr << "Can't open capture device" << std::endl;
return -1;
}
cv::namedWindow(window_name, cv::WINDOW_GUI_NORMAL | cv::WINDOW_AUTOSIZE);
cv::Mat frame;
while (1) {
cap >> frame;
if ( frame.empty() ) {
std::cerr << "Fail to capture video" << std::endl;
break;
}
cv::imshow(window_name, frame);
if ( cv::waitKey(1) >= 0 ) {
break;
}
}
return 0;
}
このファイルをcapture-streaming.cppとして保存して、次のようにコンパイルします。
/usr/bin/g++ -I/usr/include/opencv4 -fdiagnostics-color=always capture-streaming.cpp -o capture-streaming -lopencv_core -lopencv_imgcodecs -lopencv_highgui -lopencv_videoio
ビルドに成功すると「capture-streaming」というファイル名の実行ファイルが生成されます。
そしてその実行ファイルを実行してみます。
./capture-streaming
2,3秒ほどすると「OpenCV Sample」というタイトルのウィンドウが表示され、そのウィンドウでUSBカメラの映像(=Windows上のFFMPEGがストリーミングしている映像)が表示されます。
もし「Can’t open capture device」というエラーになってしまう場合は
- Windows上のFFMPEGでストリーミングを開始しているか?
- WSL2上でストリーミングを受信しているプログラムはないか?(たとえば、テストに利用したffplay)
を確認してみてください。
まとめ
今回はWSL2上のOpenCVでUSBカメラの映像を取得するために、Windows上のFFMPEGを使ってストリーミングしてみました。
事前にストリーミングを開始する手間が必要ですが、USBIPD-WINを使ってWSL2にUSBデバイスを見せるよりも、高解像度の映像を取得できるのがメリットです。
ただし、映像の遅延はストリーミングの方が大きくなるので、使い分けると良さそうです。
次回はストリーミングにFFMPEGではなくVLC media playerを使ってみます。
コメント