TranslateProject/sources/tech/20221219.1 ⭐️⭐️ How I use my old camera as a webcam with Linux.md

261 lines
10 KiB
Markdown
Raw Normal View History

[#]: subject: "How I use my old camera as a webcam with Linux"
[#]: via: "https://opensource.com/article/22/12/old-camera-webcam-linux"
[#]: author: "Tom Oliver https://opensource.com/users/tomoliver"
[#]: collector: "lkxed"
[#]: translator: "Pabloxllwe"
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
How I use my old camera as a webcam with Linux
======
This year after largely abandoning my MacBook in favor of a NixOS machine, I started getting requests to "turn my camera on" when video calling people. This was a problem because I didn't have a webcam. I thought about buying one, but then I realized I had a perfectly good Canon EOS Rebel XS DSLR from 2008 lying around on my shelf. This camera has a mini-USB port, so naturally, I pondered: Did a DSLR, mini-USB port, and a desktop PC mean I could have a webcam?
There's just one problem. My Canon EOS Rebel XS isn't capable of recording video. It can take some nice pictures, but that's about it. So that's the end of that.
Or is it?
There happens to be some amazing open source software called [gphoto2][1]. Once installed, it allows you to control various supported cameras from your computer and it takes photos and videos.
### Supported cameras
First, find out whether yours is supported:
```
$ gphoto2 --list-cameras
```
### Capture an image
You can take a picture with it:
```
$ gphoto2 --capture-image-and-download
```
The shutter activates, and the image is saved to your current working directory.
### Capture video
I sensed the potential here, so despite the aforementioned lack of video functionality on my camera, I decided to try `gphoto2 --capture-movie`. Somehow, although my camera does not support video natively, gphoto2 still manages to spit out an MJPEG file!
On my camera, I need to put it in "live-view" mode before gphoto2 records video. This consists of setting the camera to portrait mode and then pressing the **Set** button so that the viewfinder is off and the camera screen displays an image. Unfortunately, though, this isn't enough to be able to use it as a webcam. It still needs to get assigned a video device, such as `/dev/video0`.
### Install ffmpeg and v4l2loopback
Not surprisingly, there's an open source solution to this problem. First, use your package manager to install `gphoto2`, `ffmpeg`, and `mpv`. For example, on Fedora, CentOS, Mageia, and similar:
```
$ sudo dnf install gphoto2 ffmpeg mpv
```
On Debian, Linux Mint, and similar:
```
$ sudo apt install gphoto2 ffmpeg mpv
```
I use NixOS, so here's my configuration:
```
# configuration.nix
...
environment.systemPackages = with pkgs; [
  ffmpeg
  gphoto2
  mpv
...
```
Creating a virtual video device requires the `v4l2loopback` Linux kernel module. At the time of this writing, that capability is not included in the mainline kernel, so you must download and compile it yourself:
```
$ git clone https://github.com/umlaeute/v4l2loopback
$ cd v4l2loopback
$ make
$ sudo make install
$ sudo depmod -a
```
If you're using NixOS like me, you can just add the extra module package in `configuration.nix`:
```
[...]
boot.extraModulePackages = with config.boot.kernelPackages;
[ v4l2loopback.out ];
boot.kernelModules = [
  "v4l2loopback"
];
boot.extraModprobeConfig = ''
  options v4l2loopback exclusive_caps=1 card_label="Virtual Camera"
'';
[...]
```
On NixOS, run `sudo nixos-rebuild switch` and then reboot.
### Create a video device
Assuming your computer currently has no `/dev/video` device, you can create one on demand thanks to the `v4l2loopback`.
Run this command to send data from `gphoto2` to `ffmpeg`, using a device such as `/dev/video0` device:
```
$ gphoto2 --stdout --capture-movie |
 ffmpeg -i - -vcodec rawvideo -pix_fmt yuv420p -f v4l2 /dev/video0
```
You get output like this:
```
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
```
To see the video feed from your webcam, use `mpv`:
```
$ mpv av://v4l2:/dev/video0 --profile=low-latency --untimed
```
![Streaming a live feed from the webcam][2]
### Start your webcam automatically
It's a bit annoying to execute a command every time you want to use your webcam. Luckily, you can run this command automatically at startup. I implement it as a `systemd` service:
```
# 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" ];
  };
...
```
On NixOS, run `sudo nixos-rebuild switch` and then reboot your computer. Your webcam is on and active.
To check for any problems, you can use `systemctl status webcam`. This tells you the last time the service was run and provides a log of its previous output. It's useful for debugging.
### Iterating to make it better
It's tempting to stop here. However, considering the current global crises, it may be pertinent to wonder whether it's necessary to have a webcam on all the time. It strikes me as sub-optimal for two reasons:
- It's a waste of electricity.
- There are privacy concerns associated with this kind of thing.
My camera has a lens cap, so to be honest, the second point doesn't really bother me. I can always put the lens cap on when I'm not using the webcam. However, leaving a big power-hungry DSLR camera on all day (not to mention the CPU overhead required for decoding the video) isn't doing anything for my electricity bill.
The ideal scenario:
- I leave my camera plugged in to my computer all the time but switched off.
- When I want to use the webcam, I switch on the camera with its power button.
- My computer detects the camera and starts the systemd service.
- After finishing with the webcam, I switch it off again.
To achieve this, you need to use a custom [udev rule][3].
A udev rule tells your computer to perform a certain task when it discovers that a device has become available. This could be an external hard drive or even a non-USB device. In this case, you need it to [recognize the camera through its USB connection][4].
First, specify what command to run when the udev rule is triggered. You can do that as a shell script (`systemctl restart webcam` should work). I run NixOS, so I just create a derivation (a Nix package) that restarts the systemd service:
```
# 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''
```
Next, actually define the udev rule. Find the device and vendor ID of the camera. Do this by using the `lsusb` command. That command is likely already installed on your distribution, but I don't use it often, so I just install it as needed using `nix-shell`:
```
$ nix-shell -p usbutils
```
Whether you already have it on your computer or you've just installed it, run `lsusb`:
```
$ lsusb
Bus 002 Device 008: ID 04a9:317b Canon, Inc. Canon Digital Camera[...]
```
In this output, the vendor ID is 04a9 and the device ID is 317b. That's enough to create the udev rule:
```
ACTION=="add", SUBSYSTEM=="usb",
ATTR{idVendor}=="04a9",
ATTR{idProduct}=="317b",
RUN+="/usr/local/bin/start-webcam.sh"
```
Alternatively, if you're using 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"'';[...]
```
Finally, remove the **wantedBy = ["multi-user.target"];** line in your `start-webcam` systemd service. (If you leave it, then the service starts automatically when you next reboot, whether the camera is switched on or not.)
### Reuse old technology
I hope this article has made you think twice before chucking some of your old tech. Linux can breathe life back into technology, whether it's your [computer][5] or something simple like a digital camera or some other peripheral.
--------------------------------------------------------------------------------
via: https://opensource.com/article/22/12/old-camera-webcam-linux
作者:[Tom Oliver][a]
选题:[lkxed][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/tomoliver
[b]: https://github.com/lkxed
[1]: https://opensource.com/article/20/7/gphoto2-linux
[2]: https://opensource.com/sites/default/files/2022-12/streaming-webcam.png
[3]: https://opensource.com/article/18/11/udev
[4]: https://opensource.com/article/22/1/cameras-usb-ports-obs
[5]: https://opensource.com/article/22/4/how-linux-saves-earth