如何在 Linux 中使用旧相机作为网络摄像头
我用 gphoto2 给我的旧单反相机带来了新的生命，把它变成了 Linux 电脑的网络摄像头。
相机 摄像头
我用 gphoto2 给我的旧单反相机带来了新的生命，把它变成了 Linux 电脑的网络摄像头。
![](/data/attachment/album/202303/21/233633z1qxdoq1shrx1xmc.jpg)



> 
> 我用 gphoto2 给我的旧单反相机带来了新的生命，把它变成了 Linux 电脑的网络摄像头。
> 
> 
> 


今年，在我基本上放弃了 MacBook，转而使用 NixOS 机器之后，我开始在与人进行视频通话时被要求“打开摄像头”。这是一个问题，因为我没有网络摄像头。我考虑购买一个，但后来我意识到我有一台完好无损的 2008 年产的佳能 EOS Rebel XS 数码单反相机放在书架上。这台相机有一个 mini-USB 接口，所以我自然而然地思考：一台数码单反相机、一个 mini-USB 接口和一台台式电脑，是否意味着我能拥有一个网络摄像头？


只有一个问题。我的佳能 EOS Rebel XS 不能录制视频。它可以拍摄一些漂亮的照片，仅此而已。所以这结束了？


还是有别的办法？


恰好有一个叫做 [gphoto2](http://gphoto.org/) 的神奇的开源软件。一旦安装，它允许你从计算机控制各种支持的相机，并拍摄照片和视频。


### 支持的相机


首先，了解你的设备是否得到支持：



```
$ gphoto2 --list-cameras

```

### 拍摄图像


你可以用它拍照：



```
$ gphoto2 --capture-image-and-download

```

快门触发，图像会保存到你当前的工作目录中。


### 录制视频


我意识到了这里的潜力，所以尽管我的相机没有视频功能，我还是决定尝试 `gphoto2 --capture-movie` 命令。不知怎么，尽管我的相机不支持视频功能，`gphoto2` 仍然能够生成一个 MJPEG 文件！


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


### 安装 ffmpeg 和 v4l2loopback


毫不奇怪，有一个开源的解决方案来解决这个问题。首先，使用你的包管理器安装 `gphoto2`、`ffmpeg` 和 `mpv`。例如，在 Fedora 、CentOS 、Mageia 和类似的 Linux 发行版上：



```
$ 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 rawvideoframe=  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](/data/attachment/album/202303/21/233414pjm6que6y6zj6mlu.jpg)


### 自动启动你的网络摄像头


每次想使用网络摄像头时都需要执行一次命令有点麻烦。幸运的是，你可以在启动时自动运行此命令。我将其实现为一个 `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` 命令。它会告诉你服务最后一次运行的时间，并提供其以前输出的日志。这对于调试非常有用。


### 迭代以使其变得更好


止步于此也许很诱人。但是，考虑到当前的全球危机，我们可能需要思考是否有必要一直开着网络摄像头。这让我感到不太理想，原因如下：


* 这浪费电。
* 这类事情涉及隐私问题。


我的摄像头有一个镜头盖，所以说实话，第二个原因并不真的让我感到困扰。当我不使用网络摄像头时，我总是可以把镜头盖上。然而，让一个耗电量大的单反相机整天开着（更不用说需要解码视频所需的 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 可以为技术注入活力，无论是你的电脑还是数码相机或其他外围设备等简单的东西。




---


via: <https://opensource.com/article/22/12/old-camera-webcam-linux>


作者：[Tom Oliver](https://opensource.com/users/tomoliver) 选题：[lkxed](https://github.com/lkxed) 译者：[Pabloxllwe](https://github.com/Pabloxllwe) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出

