Как я использую свою старую камеру в качестве веб-камеры с Linux
Я дал новую жизнь своей старой зеркальной камере с помощью gphoto2, превратив ее в веб-камеру для своего компьютера с Linux.
В этом году, после того как я практически отказался от своего MacBook в пользу машины с NixOS, я начал получать просьбы «включить камеру» при видеозвонках людям. Это была проблема, потому что у меня не было веб-камеры. Я подумывал о покупке такой, но потом понял, что у меня на полке лежит отличная зеркальная камера Canon EOS Rebel XS 2008 года выпуска. У этой камеры есть порт мини-USB, поэтому, естественно, я задумался: означает ли наличие зеркальной фотокамеры, порта мини-USB и настольного ПК, что у меня может быть веб-камера?
Есть только одна проблема. Мой Canon EOS Rebel XS не поддерживает запись видео. Он может сделать несколько хороших фотографий, но это все. Так что это конец.
Или это?
Есть удивительное программное обеспечение с открытым исходным кодом под названием gphoto2. После установки он позволяет вам управлять различными поддерживаемыми камерами с вашего компьютера, а также снимать фотографии и видео.
Поддерживаемые камеры
Сначала узнайте, поддерживается ли ваш:
$ gphoto2 --list-cameras
Захват изображения
С ним можно сфотографироваться:
$ gphoto2 --capture-image-and-download
Затвор активируется, и изображение сохраняется в вашем текущем рабочем каталоге.
Захват видео
Я почувствовал здесь потенциал, поэтому, несмотря на вышеупомянутое отсутствие функций видео на моей камере, я решил попробовать gphoto2 --capture-movie
. Каким-то образом, хотя моя камера изначально не поддерживает видео, gphoto2 все же умудряется выдавать файл MJPEG!
На моей камере мне нужно перевести ее в режим «живого просмотра», прежде чем gphoto2 запишет видео. Для этого необходимо перевести камеру в портретный режим и затем нажать кнопку Установить, чтобы видоискатель выключился и на экране камеры появилось изображение. К сожалению, этого недостаточно, чтобы использовать его в качестве веб-камеры. Ему по-прежнему необходимо назначить видеоустройство, например /dev/video0
.
Установите ffmpeg и v4l2loopback.
Неудивительно, что существует решение этой проблемы с открытым исходным кодом. Сначала используйте менеджер пакетов для установки gphoto2
, ffmpeg
и mpv
. Например, в 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
...
Для создания виртуального видеоустройства требуется модуль ядра Linux v4l2loopback
. На момент написания этой статьи эта возможность не включена в основное ядро, поэтому вам придется загрузить и скомпилировать ее самостоятельно:
$ 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
(Том Оливер, 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
. Это сообщает вам, когда служба запускалась в последний раз, и предоставляет журнал ее предыдущих результатов. Это полезно для отладки.
Итерация, чтобы сделать это лучше
Соблазнительно остановиться здесь. Однако, учитывая нынешний глобальный кризис, возможно, уместно задаться вопросом, необходимо ли постоянно иметь веб-камеру включенной. Мне это кажется неоптимальным по двум причинам:
- Это пустая трата электроэнергии.
- С подобными вещами связаны проблемы конфиденциальности.
У моей камеры есть крышка объектива, так что, если честно, второй пункт меня не особо смущает. Я всегда могу надеть крышку объектива, когда не использую веб-камеру. Однако оставление большой энергоемкой зеркальной камеры включенной на целый день (не говоря уже о нагрузке на процессор, необходимой для декодирования видео), никак не повлияет на мой счет за электроэнергию.
Идеальный сценарий:
- Я все время оставляю камеру подключенной к компьютеру, но выключенной.
- Когда я хочу использовать веб-камеру, я включаю камеру с помощью кнопки питания.
- Мой компьютер обнаруживает камеру и запускает службу systemd.
- Закончив работу с веб-камерой, я снова ее выключаю.
Для этого вам нужно использовать собственное правило udev.
Правило udev предписывает вашему компьютеру выполнить определенную задачу, когда он обнаружит, что устройство стало доступным. Это может быть внешний жесткий диск или даже устройство, не поддерживающее USB. В этом случае вам необходимо, чтобы камера распознавалась через USB-соединение.
Сначала укажите, какую команду следует запускать при срабатывании правила udev. Вы можете сделать это с помощью сценария оболочки (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. Найдите устройство и идентификатор поставщика камеры. Сделайте это с помощью команды lsusb
. Эта команда, скорее всего, уже установлена в вашем дистрибутиве, но я использую ее нечасто, поэтому просто устанавливаю ее по мере необходимости с помощью nix-shell
:
$ nix-shell -p usbutils
Независимо от того, есть ли он у вас на компьютере или вы только что его установили, запустите lsusb
:
$ lsusb
Bus 002 Device 008: ID 04a9:317b Canon, Inc. Canon Digital Camera
[...]
В этом выводе идентификатор поставщика — 04a9, а идентификатор устройства — 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"
'';
[...]
Наконец, удалите строку wantedBy=["multi-user.target"]; в вашей службе start-webcam
systemd. (Если оставить, то служба запустится автоматически при следующей перезагрузке, независимо от того, включена камера или нет.)
Повторное использование старых технологий
Надеюсь, эта статья заставила вас дважды подумать, прежде чем выбрасывать старые технологии. Linux может вдохнуть жизнь в технологии, будь то ваш компьютер или что-то простое, например, цифровая камера или другое периферийное устройство.