我用 gphoto2 给我的旧单反相机带来了新的生命,把它变成了 Linux 电脑的网络摄像头。
今年,在我基本上放弃了 MacBook,转而使用 NixOS 机器之后,我开始在与人进行视频通话时被要求“打开摄像头”。这是一个问题,因为我没有网络摄像头。我考虑购买一个,但后来我意识到我有一台完好无损的 2008 年产的佳能 EOS Rebel XS 数码单反相机放在书架上。这台相机有一个 mini-USB 接口,所以我自然而然地思考:一台数码单反相机、一个 mini-USB 接口和一台台式电脑,是否意味着我能拥有一个网络摄像头?
只有一个问题。我的佳能 EOS Rebel XS 不能录制视频。它可以拍摄一些漂亮的照片,仅此而已。所以这结束了?
还是有别的办法?
恰好有一个叫做 gphoto2 的神奇的开源软件。一旦安装,它允许你从计算机控制各种支持的相机,并拍摄照片和视频。
支持的相机 首先,了解你的设备是否得到支持:
拍摄图像 你可以用它拍照:
快门触发,图像会保存到你当前的工作目录中。
录制视频 我意识到了这里的潜力,所以尽管我的相机没有视频功能,我还是决定尝试 gphoto2 --capture-movie
命令。不知怎么,尽管我的相机不支持视频功能,gphoto2
仍然能够生成一个 MJPEG 文件!
在我的相机上,我需要将其置于“实时预览”模式下,然后 gphoto2
才能录制视频。这包括将相机设置为纵向模式,然后按下 “ 设置 Set ” 按钮,使取景器关闭,相机屏幕显示图像。不幸的是,这还不足以将其用作网络摄像头。它仍然需要分配一个视频设备,例如 /dev/video0
。
安装 ffmpeg 和 v4l2loopback 毫不奇怪,有一个开源的解决方案来解决这个问题。首先,使用你的包管理器安装 gphoto2
、ffmpeg
和 mpv
。例如,在 Fedora 、CentOS 、Mageia 和类似的 Linux 发行版上:
1 2 $ sudo dnf install gphoto2 ffmpeg mpv
在 Debian、Linux Mint 及其类似发行版:
1 2 $ sudo apt install gphoto2 ffmpeg mpv
我使用的是 NixOS,这是我的配置文件:
1 2 3 4 5 6 7 8 # configuration.nix... environment.systemPackages = with pkgs; [ ffmpeg gphoto2 mpv... ]
创建虚拟视频设备需要使用 v4l2loopback
Linux 内核模块。在撰写本文时,该功能未包含在主线内核中,因此你需要自己下载和编译它:
1 2 3 4 5 6 $ git clone https://github.com/umlaeute/v4l2loopback $ cd v4l2loopback$ make $ sudo make install$ sudo depmod -a
如果你像我一样使用 NixOS ,你可以在 configuration.nix
中添加额外的模块包:
1 2 3 4 5 6 7 8 9 10 11 [...] 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
设备:
1 2 3 $ gphoto2 --stdout --capture-movie | ffmpeg -i - -vcodec rawvideo -pix_fmt yuv420 p -f v4 l2 /dev/video0
你得到的输出是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 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 @ 0 x1dd0380] 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), 768 x512 ...Stream mapping: Stream #0 :0 -> #0 :0 (mjpeg (native) -> rawvideo (native))[swscaler @ 0 x1e27340] deprecated pixel format used, make sure you did set range correctlyOutput #0 , video4linux2,v4l2, to '/dev/video0': Metadata : encoder : Lavf58.76 .100 Stream #0 :0 : Video: rawvideo (I420 / 0 x30323449) ... 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 .907 x
要查看来自网络摄像头的视频,请使用 mpv
命令:
1 2 $ mpv av://v4l2 :/dev/video0 --profile=low-latency --untimed
自动启动你的网络摄像头 每次想使用网络摄像头时都需要执行一次命令有点麻烦。幸运的是,你可以在启动时自动运行此命令。我将其实现为一个 systemd
服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 ... 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 服务:
1 2 3 4 5 6 7 8 # start-webcam.nixwith 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
安装它:
1 2 $ nix-shell -p usbutils
无论你的计算机上已经安装了它,还是刚刚安装,请运行 lsusb
:
1 2 3 $ lsusbBus 002 Device 008 : ID 04 a9:317 b Canon, Inc. Canon Digital Camera[...]
在此输出中,厂商 ID 为 04a9
,设备 ID 为 317b
。这已足以创建 udev 规则:
1 2 3 4 5 ACTION=="add" , SUBSYSTEM=="usb" ,ATTR {idVendor}=="04a9" ,ATTR {idProduct}=="317b" ,RUN +="/usr/local/bin/start-webcam.sh"
或者,如果你使用的是 NixOS:
1 2 3 4 5 6 7 8 9 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 选题:lkxed 译者:Pabloxllwe 校对:wxy
本文由 LCTT 原创编译,Linux中国 荣誉推出