この記事は、NetBSD Advent Calendar 2025の5日目の記事です。
はじめに
いまいちどの時点からか分からなくなってしまったのですが、pkgsrc/www/firefoxでは、私の今利用しているHP Envy 14 fa0000にインストールしたNetBSD/amd64-currentではwebcamを利用できなくなってしまっていました。 もしかしたら、PCを変えたタイミングだったかもしれませんが、全く分かりません。
いずれにしても、WebRTCでwebcamの映像を使えないのは残念です。 しばらく放置してしまっていましたが、直すことにしました。
認識されないのを確認できるウェブサイトを特定する
HP Envy 14にインストールされたNetBSD/amd64-currentでは、以下のようにvideo0からvideo3の4つのデバイスが認識されます。
uvideo0 at uhub3 port 1 configuration 1 interface 0: SunplusIT Inc (0x04f2) HP 5MP Camera (0xb7fe), rev 2.01/0.06, addr 1 video0 at uvideo0: SunplusIT Inc (0x04f2) HP 5MP Camera (0xb7fe), rev 2.01/0.06, addr 1 video1 at uvideo0: SunplusIT Inc (0x04f2) HP 5MP Camera (0xb7fe), rev 2.01/0.06, addr 1 uvideo1 at uhub3 port 1 configuration 1 interface 2: SunplusIT Inc (0x04f2) HP 5MP Camera (0xb7fe), rev 2.01/0.06, addr 1 video2 at uvideo1: SunplusIT Inc (0x04f2) HP 5MP Camera (0xb7fe), rev 2.01/0.06, addr 1 video3 at uvideo1: SunplusIT Inc (0x04f2) HP 5MP Camera (0xb7fe), rev 2.01/0.06, addr 1
ただし、pkgsrc/multimedia/mplayerで確認してみると、video1とvideo3だけが使えます。 ちなみに、確認した方法は以下のようです。
$ mplayer tv:// -tv device=/dev/video1 $ mplayer tv:// -tv device=/dev/video3
mplayerでのvideo(4)デバイスの動作確認の方法は、別に書いていた方が良いかもしれません。
これまでは、getUserMedia / getDisplayMedia Test Pageを使って来たのですが、 これはそもそも複数のwebcamを選択することはできないので、適切ではありません。 そこで、WebRTC samplesSelect sources & outputsを利用することにします。 ここでは、webcamを選択することができます。 ちなみに、現時点ではwebcamを選択するまでもなくエラーになってしまいます。
エラーにつながる箇所を特定する
広大なFirefoxのソースコードベースの中で、getUserMediaでそもそもエラーになってしまう箇所の当たりを付けるのは大変なはずですが、 third_party/libwebrtc以下にしかwebcamを認識するロジックはないはずなのと、 おそらくVideo4Linix2のioctlでエラーになっていて、それによりwebcamを選択するまでもなくエラーになっているはずということは当たりがついています。 なので、third_party/libwebrtc以下にあるmoz.buildを読んで、NetBSDである場合にbuildされるsource codeのうち、ioctlでVIDIOC_*を第2引数に与えている箇所を探せば良さそうと思いました。
と言うことは、grep -r "ioctl.*VIDIOC_" ${WRKSRC}/third_party/libwebrtcを実行した上で、moz.buildと照合すれば良さそうです。
$ ugrep -r "ioctl.*VIDIOC_" third_party/libwebrtc third_party/libwebrtc/modules/video_capture/linux/device_info_v4l2.cc: (snip) (snip) third_party/libwebrtc/modules/video_capture/linux/video_capture_v4l2.cc: (snip) (snip)
moz.buildを見るまでもなく、NtBSDでも使っているファイルです。 と言うことで、各ioctlの結果が分かるようにprintfを入れてbuildしてみました。
解析の結果と修正案
結果として、以下の188行目のioctlが返すfmtに返って来ている内容が想定外であり、そのために全てのwebcamが認識されなっくなっていました。
$ cat -n third_party/libwebrtc/modules/video_capture/linux/video_capture_v4l2.cc
(snip)
181 // Enumerate image formats.
182 struct v4l2_fmtdesc fmt;
183 int fmtsIdx = nFormats;
184 memset(&fmt, 0, sizeof(fmt));
185 fmt.index = 0;
186 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
187 RTC_LOG(LS_INFO) << "Video Capture enumerats supported image formats:";
188 while (ioctl(_deviceFd, VIDIOC_ENUM_FMT, &fmt) == 0) {
189 RTC_LOG(LS_INFO) << " { pixelformat = " << GetFourccName(fmt.pixelformat)
190 << ", description = '" << fmt.description << "' }";
191 // Match the preferred order.
192 for (int i = 0; i < nFormats; i++) {
193 if (fmt.pixelformat == fmts[i] && i < fmtsIdx)
194 fmtsIdx = i;
195 }
196 // Keep enumerating.
197 fmt.index++;
198 }
(snip)
更に良く見ていくと、以下のように最初はioctl(fd, VIDIOC_QUERYCAP, &cap)でのみwebcamが利用可能か認識して使えるとなっているのに、この箇所でエラーになってしまうという流れになっており、これが想定外なようです。
$ cat -n third_party/libwebrtc/modules/video_capture/linux/video_capture_v4l2.cc
86 /* detect /dev/video [0-63] entries */
87 int n;
88 for (n = 0; n < 64; n++) {
89 snprintf(device, sizeof(device), "/dev/video%d", n);
90 if ((fd = open(device, O_RDONLY)) != -1) {
91 // query device capabilities
92 struct v4l2_capability cap;
93 if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) {
94 if (cap.bus_info[0] != 0) {
95 if (strncmp((const char*)cap.bus_info,
96 (const char*)deviceUniqueIdUTF8,
97 strlen((const char*)deviceUniqueIdUTF8)) ==
98 0) { // match with device id
99 close(fd);
100 found = true;
101 break; // fd matches with device unique id supplied
102 }
103 }
104 }
105 close(fd); // close since this is not the matching device
106 }
107 }
108 if (!found) {
(snip)
と言うことで、最初からioctl(_deviceFd, VIDIOC_ENUM_FMT, &fmt)もチェックしておけば良さそうです。
--- third_party/libwebrtc/modules/video_capture/linux/video_capture_v4l2.cc.orig 2025-12-05 17:43:20.000000000 +0000
+++ third_party/libwebrtc/modules/video_capture/linux/video_capture_v4l2.cc
@@ -90,18 +90,28 @@ int32_t VideoCaptureModuleV4L2::Init(con
if ((fd = open(device, O_RDONLY)) != -1) {
// query device capabilities
struct v4l2_capability cap;
+#if defined(VIDIOC_QUERYCAP)
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) {
if (cap.bus_info[0] != 0) {
if (strncmp((const char*)cap.bus_info,
(const char*)deviceUniqueIdUTF8,
strlen((const char*)deviceUniqueIdUTF8)) ==
0) { // match with device id
- close(fd);
- found = true;
- break; // fd matches with device unique id supplied
+ struct v4l2_fmtdesc fmt;
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.index = 0;
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == 0) {
+ if (fmt.pixelformat != 0) {
+ close(fd);
+ found = true;
+ break; // fd matches with device unique id supplied
+ }
+ }
}
}
}
+#endif
close(fd); // close since this is not the matching device
}
}
とりあえず、pkgsrc/www/firefoxを146.0にアップデートする際には含めておきたいと思います。 ですが、そもそもこのwebcamのvideo0とvideo2をサポートした方が良いかもしれません。
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。