===== What's here? =====
My attempts to grab HDMI with [[|an addon board for the Raspi]] worked, but did not give me audio. For this, I ordered this device here, usb id 534d:2109. Works nicely on Linux for up to 720p@60Hz 1080p@30Hz. Latency induced by the grabber is ~130ms, also audio is grabbed. Stereo sound initially required a patch, it's now in the upstream Linux kernel. Michael Lynch has built a [[https://mtlynch.io/tinypilot/|tinypilot, a KVM solution]] from this usb-device and a Raspi.
**A summary of the HDMI grabbers I looked at is [[https://blog.fluxcoil.net/posts/2020/11/linux-hdmi-grabber-1/|here]].**
{{ https://fluxcoil.net/files/tmp/raspi-grabber/20201107_043709411_usb_grabberb.jpg?300x|usb-grabber}}
* USB2/1080p@30Hz CamLink, the device I used in this article
* Buying: [[https://www.amazon.co.jp/dp/B088T5M7GX/|@amazon for 700円]]
* Potential alternatives:
* USB2/1080p@30Hz Wiistar USB Video Capture, [[https://de.aliexpress.com/item/4000315619046.html|@aliexpress]]
* USB2/1080p@30Hz CHD201, [[https://www.soundhouse.co.jp/products/detail/item/280483/|@soundhouse jp]]
* USB3/1080p@60Hz Kebidumei, was available on aliexpress, driver was merged into the Linux 5.8 tree
* USB3/1080p@60Hz: Marcan42 had written about this on X/Twitter, [[https://www.aliexpress.com/item/4001044872081.html|@aliexpress]], fake 60Hz?
* 1080p@60Hz ezcap311
* 1080p@60Hz CamLink, [[https://www.amazon.co.jp/dp/B08DTY1VG8/|@amazon]]
* For pure encoding, raspi alternative: the NVidia Jetson Nano 2GB ($60) has some impressive specs, encoding 4kp@30 live, [[https://gigazine.net/news/20201006-nvidia-jetson-nano-2gb/|details]]
* [[hardwarerelated/raspberry_pi_4_tc358743|H2C-RPI-B01]] addon board for Raspi/Nvidia Jetson Nano
===== Configuration =====
These are the steps to find out which video device is used, and to verify some basic settings.
dnf -y install v4l-utils ffmpeg
# video0 is my thinkpad internal camera
[chris@電脳 ~]$ v4l2-ctl --list-devices
UVC Camera (534d:2109): USB Vid (usb-0000:00:14.0-2): <-- the usb grabber
/dev/video2
/dev/video3
Integrated Camera: Integrated C (usb-0000:00:14.0-7): <-- internal Thinkpad cam
/dev/video0
/dev/video1
# The hdmi grabber provides video2:
[chris@電脳 ~]$ lsusb
[..]
Bus 001 Device 007: ID 534d:2109 MACROSILICON
[..]
[chris@電脳 ~]$ v4l2-ctl --all -d /dev/video2
Driver Info:
Driver name : uvcvideo
Card type : UVC Camera (534d:2109): USB Vid
Bus info : usb-0000:00:14.0-2
Driver version : 5.6.19
Capabilities : 0x84a00001
Video Capture
Metadata Capture
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x04200001
Video Capture
Streaming
Extended Pix Format
Priority: 2
Video input : 0 (Camera 1: ok)
Format Video Capture:
Width/Height : 1280/720
Pixel Format : 'YUYV' (YUYV 4:2:2)
Field : None
Bytes per Line : 2560
Size Image : 1843200
Colorspace : sRGB
Transfer Function : Default (maps to sRGB)
YCbCr/HSV Encoding: Default (maps to ITU-R 601)
Quantization : Default (maps to Limited Range)
Flags :
[..]
# Let's list the supported resolutions:
[chris@電脳 ~]$ ffmpeg -f v4l2 -list_formats all -i /dev/video2
ffmpeg version 4.2.3 Copyright (c) 2000-2020 the FFmpeg developers
[..]
[video4linux2,v4l2 @ 0x558496514600] Compressed: mjpeg : Motion-JPEG : 1920x1080 1600x1200 1360x768 1280x1024 1280x960 1280x720 1024x768 800x600 720x576 720x480 640x480
[video4linux2,v4l2 @ 0x558496514600] Raw : yuyv422 : YUYV 4:2:2 : 1920x1080 1600x1200 1360x768 1280x1024 1280x960 1280x720 1024x768 800x600 720x576 720x480 640x480
/dev/video2: Immediate exit requested
[chris@電脳 ~]$
===== Simple network streaming, no audio =====
# Server: the process to be started on the Raspi
# exchange the ip with your clients IP, who should receive the stream
ffmpeg -f v4l2 -input_format yuyv422 -s 1280x720 -r 60 -i /dev/video2 \
-tune zerolatency -vcodec mpeg2video -f mpegts udp://192.168.0.2:4242
# Note: also do not forget to deal with the firewall on your client,
# it needs to allow incoming packets!
# Client process, exchange with the IP of the system sending the stream:
ffplay -an -sn -i -fflags nobuffer udp://192.168.0.3:4242?listen
===== Audio test =====
* https://wiki.archlinux.org/index.php/Advanced_Linux_Sound_Architecture
* https://sysplay.in/blog/linux/2019/06/playing-with-alsa-loopback-devices/
[chris@電脳 ~]$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: PCH [HDA Intel PCH], device 0: ALC257 Analog [ALC257 Analog]
Subdevices: 0/1
Subdevice #0: subdevice #0
card 1: U0x534d0x2109 [USB Device 0x534d:0x2109], device 0: USB Audio [USB Audio]
Subdevices: 0/1
Subdevice #0: subdevice #0
[chris@電脳 ~]$
==> The second device is from our HDMI grabber, good!
[chris@電脳 ~]$ arecord -d 25 -f cd test1.wav
==> This is recording audio from HDMI!
### Setup pure audio streaming for a start, no video.
# server:
[chris@電脳 ~]$ ffmpeg -f alsa -ar 44100 \
-i hw:1 -acodec mp3 -f mpegts udp://192.168.0.2:4242
# client:
[chris@電脳 ~]$ ffplay -acodec mp3 -i -fflags nobuffer udp://192.168.0.2:4242?listen
==> This grabs audio from the HDMI stream, makes it audible.
I had to add my user chris to group "audio", to access
/dev/snd/* devices
===== Best low latency local streaming, including audio =====
This streams not over the network, just displays on the system where the usb adapter is plugged in. Optimized for low latency.
### Where is our HDMI grabber soundcard? Here card 1, device 0:
$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: PCH [HDA Intel PCH], device 0: ALC257 Analog [ALC257 Analog]
Subdevices: 0/1
Subdevice #0: subdevice #0
card 1: U0x534d0x2109 [USB Device 0x534d:0x2109], device 0: USB Audio [USB Audio]
Subdevices: 0/1
Subdevice #0: subdevice #0
# Quickest local streaming is for me with mplayer:
# - here reading from /dev/video2, 720p
# - alsa audio card 1, device 0
$ mplayer tv:// -vo gl_nosw -tv \
driver=v4l2:device=/dev/video2:width=1280:height=720:fps=60:outfmt=mjpeg:\
alsa:adevice=hw.1,0:forceaudio:immediatemode=0:audiorate=44100
===== Latency testing, local =====
### following gives me 220ms-350ms
### Sends data uncompressed, 15MB/sec on usb
$ ffplay /dev/video2
### following gives me 100-120ms
### Sends data mjpeg compressed, 4MB/sec go over usb
$ xawtv /dev/video2
### following gives me 124ms latency in average (95ms-164ms)
### Sends data mjpeg compressed, 4MB/sec go over usb
$ mplayer tv:// -vo gl_nosw -tv \
driver=v4l2:device=/dev/video2:width=1280:height=720:fps=60:outfmt=mjpeg
### following gives me 400ms latency in average (321ms-474ms)
### Sends data uncompressed, 18.4MB/sec on usb -> maxed out
$ mplayer tv:// -vo gl_nosw -tv \
driver=v4l2:device=/dev/video2:width=1280:height=720:fps=60:outfmt=yuy2
===== Streaming via internet =====
This uses [[https://github.com/owncast/owncast|owncast]]. Following components:
* a system on the internet, where we will run Owncast. Should not be behind a NAT, so incoming packets make it to the system. Only requirement: ffmpeg 4.1.5 or later. I use a KVM system running Debian 10, which comes with ffmpeg 4.1.6.
* a system where the usb-grabber is connected to, Fedora 33 for me. ffmpeg needs to be installed.
* the HDMI source
### on our server system
# https://owncast.online/docs/quickstart/
mkdir /opt/soft/owncast-0.0.2-linux-64bit
cd /opt/soft/owncast-0.0.2-linux-64bit
wget https://github.com/owncast/owncast/releases/download/v0.0.2/owncast-0.0.2-linux-64bit.zip
unzip owncast-0.0.2-linux-64bit.zip
vi config.yaml
# customize at least the streamingKey
./owncast
### on the system where the usb-grabber is connected to
# this assumes /dev/video2 as video device, and that
# hw:1,0 is the alsa device from the grabber
ffmpeg -f alsa -ac 2 -i hw:1,0 -thread_queue_size 64 \
-f v4l2 -framerate 60 -video_size 1280x720 -input_format yuyv422 -i /dev/video2 \
-c:v libx264 -preset veryfast -b:v 1984k -maxrate 1984k -bufsize 3968k \
-vf "format=yuv420p" -g 60 -c:a aac -b:a 128k -ar 44100 \
-f flv rtmp:///live/
### on clients
On clients start a browser, and access :8080 .
===== Latency testing, network =====
Latency testing with this setup: USB-HDMI-grabber -> Raspi4 -> Gbit -> Fedora desktop. For testing, I send my desktop via HDMI, capture this with the USB-HDMI-grabber, display it eventually on the desktop and measure latency.
^ latency [1] ^ command on server ^ command on client ^ HDMI latency [2] ^
| 0.1ms (GBit) | ssh -X / mplayer / xforwarding [3] | - | ~400ms |
| 0.1ms (GBit) | ffmpeg [4] | ffplay [5] | ~700ms |
| 0.1ms (GBit) | VLC: cvlc [6] | ffplay [7] | ~330ms |
| 0.1ms (GBit) | ustreamer [8] | firefox [9] | ~120ms |
[1] round trip time over network, between server with usb-grabber connected,
and the client
[2] Timespan between drawing something in HDMI input, vs. it shown on client
[3] mplayer tv:// -tv driver=v4l2:device=/dev/video1:width=1280:height=720:fps=30:outfmt=yuy2
[4] ffmpeg -f v4l2 -input_format yuyv422 -s 1280x720 -r 60 -i /dev/video2 \
-tune zerolatency -vcodec mpeg2video -f mpegts udp://192.168.0.2:4242
[5] ffplay -an -sn -i -fflags nobuffer udp://192.168.0.3:4242?listen
[6] cvlc -vvv v4l2:// :v4l2-dev=/dev/video1 :v4l2-width=1280 \
:v4l2-height=720 :v4l2-fps 25 --sout '#standard{access=http,mux=raw,dst=:8081}'
[7] ffplay -f rawvideo -pixel_format yuyv422 -video_size 1280x720 \
-framerate 25 http://192.168.0.3:8081
[8] ustreamer --device=/dev/video2 -r 1280x720 --format=jpeg \
--workers=4 --persistent --drop-same-frames=30 --host=0.0.0.0 --port=8080
[9] firefox http://:8080/stream
===== Hints =====
== Building ustreamer ==
# on Fedora/x86_64
sudo dnf -y install libevent-devel libbsd-devel \
libjpeg-turbo-devel
git clone --depth=1 https://github.com/pikvm/ustreamer
cd ustreamer/
make