NetBSD上のpkgsrc/www/firefoxでwebcamを使えない問題を解析した

この記事は、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 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。

USBシリアルアダプターをUEFIブートの場合にconsoleとして使う機能を試してみる

この記事は、 NetBSD Advent Calendar 2025 の7日目の記事です。 はじめに 2025年10月9日のmanu@のコミット と関連するコミットで、UEFIブートの際にuftdi(4)として認識されるUSBシリアルコンバーターをconsol...