Linux中國

如何在 Linux 中使用舊相機作為網路攝像頭

我用 gphoto2 給我的舊單反相機帶來了新的生命,把它變成了 Linux 電腦的網路攝像頭

今年,在我基本上放棄了 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 和類似的 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

自動啟動你的網路攝像頭

每次想使用網路攝像頭時都需要執行一次命令有點麻煩。幸運的是,你可以在啟動時自動運行此命令。我將其實現為一個 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" &apos;&apos;
  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&apos;&apos;

接下來,實際定義 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 = &apos;&apos;
  ACTION=="add",  
  SUBSYSTEM=="usb", 
  ATTR{idVendor}=="04a9", 
  ATTR{idProduct}=="317b",  
  RUN+="${startWebcam}/bin/start-webcam"&apos;&apos;;[...]

最後,在你的 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中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國