如何将我的旧相机用作 Linux 系统的网络摄像头

我通过将我的旧数码单反相机变成 Linux 电脑的网络摄像头,用 gphoto2 赋予了它新的生命。
5 位读者喜欢这篇文章。
Old camera yellow

互联网档案馆图书图片。由 Opensource.com 修改。CC BY-SA 4.0

今年,在我很大程度上放弃了 MacBook 转而使用 NixOS 机器后,我开始收到人们在视频通话时要求我“打开摄像头”的请求。这是一个问题,因为我没有网络摄像头。我考虑过买一个,但后来我意识到我有一个 2008 年的佳能 EOS Rebel XS 数码单反相机闲置在架子上。这款相机有一个 mini-USB 端口,所以我自然而然地思考:数码单反相机、mini-USB 端口和台式电脑是否意味着我可以拥有一个网络摄像头?

但这里有一个问题。我的佳能 EOS Rebel XS 不具备录制视频的功能。它可以拍一些不错的照片,但仅此而已。所以这事就到此为止了。

真的是这样吗?

恰好有一些很棒的开源软件叫做 gphoto2。安装后,它允许您从电脑控制各种受支持的相机,并拍摄照片和视频。

受支持的相机

首先, выясните 是否您的相机受支持

$ gphoto2 --list-cameras

拍摄图像

您可以用它拍照

$ gphoto2 --capture-image-and-download

快门激活,图像保存到您当前的工作目录。

拍摄视频

我在这里感受到了潜力,所以尽管我的相机如前所述缺乏视频功能,我还是决定尝试 gphoto2 --capture-movie。不知何故,尽管我的相机本身不支持视频,但 gphoto2 仍然设法吐出一个 MJPEG 文件!

在我的相机上,我需要将其置于“实时取景”模式,然后 gphoto2 才能录制视频。这包括将相机设置为人像模式,然后按下 Set 按钮,使取景器关闭,相机屏幕显示图像。然而,不幸的是,这还不足以将其用作网络摄像头。它仍然需要被分配一个视频设备,例如 /dev/video0

安装 ffmpeg 和 v4l2loopback

毫不奇怪,这个问题有一个开源解决方案。首先,使用您的软件包管理器安装 gphoto2ffmpegmpv。例如,在 Fedora、CentOS、Mageia 和类似的系统上

$ sudo dnf install gphoto2 ffmpeg mpv

在 Debian、Linux Mint 和类似的系统上

$ sudo apt install gphoto2 ffmpeg mpv

我使用 NixOS,所以这是我的配置

# configuration.nix
...
environment.systemPackages = with pkgs; [
  ffmpeg
  gphoto2
  mpv
...

创建虚拟视频设备需要 v4l2loopback Linux 内核模块。在撰写本文时,该功能未包含在主线内核中,因此您必须自行下载并编译它

$ git clone https://github.com/umlaeute/v4l2loopback

$ cd v4l2loopback

$ make

$ sudo make install

$ sudo depmod -a

如果您像我一样使用 NixOS,您可以直接在 configuration.nix 中添加额外的模块包

[...]
boot.extraModulePackages = with config.boot.kernelPackages;
[ v4l2loopback.out ];
boot.kernelModules = [
  "v4l2loopback"
];
boot.extraModprobeConfig = ''
  options v4l2loopback exclusive_caps=1 card_label="Virtual Camera"
'';
[...]

在 NixOS 上,运行 sudo nixos-rebuild switch 然后重启。

创建视频设备

假设您的计算机当前没有 /dev/video 设备,您可以借助 v4l2loopback 按需创建一个。

运行此命令将数据从 gphoto2 发送到 ffmpeg,使用诸如 /dev/video0 设备

$ gphoto2 --stdout --capture-movie |
 ffmpeg -i - -vcodec rawvideo -pix_fmt yuv420p -f v4l2 /dev/video0

您会得到这样的输出

ffmpeg version 4.4.1 Copyright (c) 2000-2021 the FFmpeg developers
  built with gcc 11.3.0 (GCC)
  configuration: --disable-static ...
  libavutil      56. 70.100 / 56. 70.100
  libavcodec     58.134.100 / 58.134.100
  libavformat    58. 76.100 / 58. 76.100
  libavdevice    58. 13.100 / 58. 13.100
  libavfilter     7.110.100 /  7.110.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  9.100 /  5.  9.100
  libswresample   3.  9.100 /  3.  9.100
  libpostproc    55.  9.100 / 55.  9.100
Capturing preview frames as movie to 'stdout'. Press Ctrl-C to abort.
[mjpeg @ 0x1dd0380] Format mjpeg detected only with low score of 25, misdetection possible!
Input #0, mjpeg, from 'pipe:':
  Duration: N/A, bitrate: N/A
  Stream #0:0: Video: mjpeg (Baseline), yuvj422p(pc, bt470bg/unknown/unknown), 768x512 ...
Stream mapping:
  Stream #0:0 -> #0:0 (mjpeg (native) -> rawvideo (native))
[swscaler @ 0x1e27340] deprecated pixel format used, make sure you did set range correctly
Output #0, video4linux2,v4l2, to '/dev/video0':
  Metadata:
    encoder         : Lavf58.76.100
  Stream #0:0: Video: rawvideo (I420 / 0x30323449) ...
    Metadata:
      encoder         : Lavc58.134.100 rawvideo
frame=  289 fps= 23 q=-0.0 size=N/A time=00:00:11.56 bitrate=N/A speed=0.907x

要查看来自网络摄像头的视频源,请使用 mpv

$ mpv av://v4l2:/dev/video0 --profile=low-latency --untimed
Streaming a live feed from the webcam

(Tom Oliver, CC BY-SA 4.0)

自动启动您的网络摄像头

每次您想使用网络摄像头时都执行命令有点烦人。幸运的是,您可以让此命令在启动时自动运行。我将其实现为一个 systemd 服务

# configuration.nix
...
  systemd.services.webcam = {
    enable = true;
    script = ''
      ${pkgs.gphoto2}/bin/gphoto2 --stdout --capture-movie |
        ${pkgs.ffmpeg}/bin/ffmpeg -i - \
            -vcodec rawvideo -pix_fmt yuv420p -f v4l2  /dev/video0
    '';
wantedBy = [ "multi-user.target" ];
  };

...

在 NixOS 上,运行 sudo nixos-rebuild switch 然后重启您的计算机。您的网络摄像头已开启并激活。

要检查是否有任何问题,您可以使用 systemctl status webcam。这会告诉您服务上次运行的时间,并提供其先前输出的日志。它对于调试很有用。

迭代以使其更好

在这里停下来是很诱人的。然而,考虑到当前的全球危机,可能需要思考是否有必要一直打开网络摄像头。在我看来,这在两个方面都不是最佳的

  1. 这是一种电力浪费。
  2. 与这类事情相关的隐私问题。

我的相机有一个镜头盖,所以老实说,第二点并没有真正困扰我。当我不用网络摄像头时,我总是可以盖上镜头盖。然而,让一个耗电量大的数码单反相机整天开着(更不用说解码视频所需的 CPU 开销)对我的电费没有任何好处。

理想的情况

  • 我一直将相机插在电脑上,但处于关闭状态。
  • 当我想使用网络摄像头时,我用它的电源按钮打开相机。
  • 我的电脑检测到相机并启动 systemd 服务。
  • 使用完网络摄像头后,我再次将其关闭。

要实现这一点,您需要使用自定义的 udev 规则

udev 规则告诉您的电脑,当它发现某个设备可用时执行特定任务。这可以是外部硬盘驱动器,甚至是非 USB 设备。在这种情况下,您需要它通过其 USB 连接识别相机

首先,指定在触发 udev 规则时要运行的命令。您可以将其作为 shell 脚本(systemctl restart webcam 应该可以工作)。我运行 NixOS,所以我只是创建一个派生(一个 Nix 包)来重启 systemd 服务

# start-webcam.nix
with import <nixpkgs> { };

writeShellScriptBin "start-webcam" ''
  systemctl restart webcam
  # debugging example
  # echo "hello" &> /home/tom/myfile.txt
  # If myfile.txt gets created then we know the udev rule has triggered properly
''

接下来,实际定义 udev 规则。找到相机的设备和供应商 ID。使用 lsusb 命令执行此操作。该命令可能已安装在您的发行版上,但我不经常使用它,所以我只是根据需要使用 nix-shell 安装它

$ nix-shell -p usbutils

无论您是否已经安装在电脑上,或者您刚刚安装了它,运行 lsusb

$ lsusb
Bus 002 Device 008: ID 04a9:317b Canon, Inc. Canon Digital Camera
[...]

在此输出中,供应商 ID 是 04a9,设备 ID 是 317b。这足以创建 udev 规则

ACTION=="add", SUBSYSTEM=="usb",
ATTR{idVendor}=="04a9",
ATTR{idProduct}=="317b",
RUN+="/usr/local/bin/start-webcam.sh"

或者,如果您使用 NixOS

# configuration.nix
[...]
let
  startWebcam = import ./start-webcam.nix;
[...]
services.udev.extraRules = ''
  ACTION=="add",  \
  SUBSYSTEM=="usb", \
  ATTR{idVendor}=="04a9", \
  ATTR{idProduct}=="317b",  \
  RUN+="${startWebcam}/bin/start-webcam"
'';
[...]

最后,删除您的 start-webcam systemd 服务中的 wantedBy = ["multi-user.target"]; 行。(如果您保留它,那么服务会在您下次重启时自动启动,无论相机是否已开启。)

重用旧技术

我希望本文能让您在扔掉一些旧技术之前三思而后行。Linux 可以让技术重获新生,无论是您的 电脑 还是像数码相机或其他外围设备这样简单的东西。

标签
Tom Oliver's profile picture
您好!我热衷于 Web 开发、函数式编程和玩转 Linux。我的软件工程职业生涯始于日本(这样我就可以在没有字幕的情况下观看动漫),但现在在全球拥有客户。您可以在这里找到我的个人网站:https://www.tomoliver.net

1 条评论

我已经有一个网络摄像头了,但我非常喜欢这篇文章,以至于我想我也会尝试将我的旧数码相机设置为网络摄像头,只是为了这样做。感谢这篇精彩的文章!

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 许可。
© . All rights reserved.