Thursday, January 07, 2021

HDMI capture using Raspberry Pi 4

My Sony TV only has two HDMI inputs, but I want to connect my Raspberry Pi 4, Amazon Fire TV Stick, and Blu-ray player to it. So what can I do?

After some thought... I rarely use my Blu-ray player, so the two inputs should be used for the Raspberry Pi 4 and the Fire TV Stick. But I still want to use my Blu-ray player once in a while, which means I have to find some solution. It was around this time that I came upon a YouTube video about cheap HDMI capture devices. So I thought, why not give it a try?

The concept is to connect the HDMI output of the Blu-ray player to a cheap HDMI capture device, plug that capture device into the Raspberry Pi 4 (which is connected to the TV via HDMI), and use VLC to play the input from the Blu-ray player (captured via the capture device).

Basically:
1. Raspberry Pi 4's video output is connected to the TV via HDMI.
2. Blu-ray's player video output is connected to capture device via HDMI.
3. Capture device is plugged into Raspberry Pi 4 via USB.
4. VLC is used to show the input captured by the capture device.

I got this USB HDMI capture device on Amazon Japan which was having a New Year sale. In addition to the sale's discounted price, there was a further 20% discount coupon, which made it even cheaper (around 1,500 yen after all discounts). Besides the discount, the other reason for choosing this model is because it has the USB connector on a cable, which means I don't have to find a separate USB extension cable since I don't want to have a device sticking out from the Raspberry Pi 4.
 

dmesg gives the following:
usb 1-1.2: new high-speed USB device number 5 using xhci_hcd
usb 1-1.2: New USB device found, idVendor=534d, idProduct=2109, bcdDevice=21.00
usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 1-1.2: Product: USB3. 0 capture
usb 1-1.2: Manufacturer: MACROSILICON
hid-generic 0003:534D:2109.0005: hiddev97,hidraw4: USB HID v1.10 Device [MACROSILICON USB3. 0 capture] on usb-0000:01:00.0-1.2/input4
uvcvideo: Found UVC 1.00 device USB3. 0 capture (534d:2109)
usbcore: registered new interface driver uvcvideo
USB Video Class driver (1.1.1)
usbcore: registered new interface driver snd-usb-audio

v4l2-ctl -d /dev/video0 --list-formats-ext
gives a list of video formats supported. The chip being used should be a MacroSilicon MS2109.

ioctl: VIDIOC_ENUM_FMT
    Type: Video Capture

    [0]: 'MJPG' (Motion-JPEG, compressed)
        Size: Discrete 1920x1080
            Interval: Discrete 0.017s (60.000 fps)
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
        Size: Discrete 1600x1200
            Interval: Discrete 0.017s (60.000 fps)
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
        Size: Discrete 1360x768
            Interval: Discrete 0.017s (60.000 fps)
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
        Size: Discrete 1280x1024
            Interval: Discrete 0.017s (60.000 fps)
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
        Size: Discrete 1280x960
            Interval: Discrete 0.017s (60.000 fps)
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
        Size: Discrete 1280x720
            Interval: Discrete 0.017s (60.000 fps)
            Interval: Discrete 0.020s (50.000 fps)
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
        Size: Discrete 1024x768
            Interval: Discrete 0.017s (60.000 fps)
            Interval: Discrete 0.020s (50.000 fps)
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
        Size: Discrete 800x600
            Interval: Discrete 0.017s (60.000 fps)
            Interval: Discrete 0.020s (50.000 fps)
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
        Size: Discrete 720x576
            Interval: Discrete 0.017s (60.000 fps)
            Interval: Discrete 0.020s (50.000 fps)
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
        Size: Discrete 720x480
            Interval: Discrete 0.017s (60.000 fps)
            Interval: Discrete 0.020s (50.000 fps)
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
        Size: Discrete 640x480
            Interval: Discrete 0.017s (60.000 fps)
            Interval: Discrete 0.020s (50.000 fps)
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
    [1]: 'YUYV' (YUYV 4:2:2)
        Size: Discrete 1920x1080
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 1600x1200
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 1360x768
            Interval: Discrete 0.125s (8.000 fps)
        Size: Discrete 1280x1024
            Interval: Discrete 0.125s (8.000 fps)
        Size: Discrete 1280x960
            Interval: Discrete 0.125s (8.000 fps)
        Size: Discrete 1280x720
            Interval: Discrete 0.100s (10.000 fps)
        Size: Discrete 1024x768
            Interval: Discrete 0.100s (10.000 fps)
        Size: Discrete 800x600
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 720x576
            Interval: Discrete 0.040s (25.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 720x480
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 640x480
            Interval: Discrete 0.033s (30.000 fps)
            Interval: Discrete 0.050s (20.000 fps)
            Interval: Discrete 0.100s (10.000 fps)
            Interval: Discrete 0.200s (5.000 fps)


Based on the output above, it is supposed to be USB 3.0, and capable of 1080p capture at 60 fps. Supposedly. But when I tried 60 fps, it did not work. Even 1080p at 30 fps was giving me problems.I experienced stutter during playback with buffering issues. I suspect it is because the capture device is not able to stream out the data fast enough for VLC to display at 30 fps. Anyway, I settled with 1080p at 25 fps, which seems to allow stable playback without stutter.

Anyway, in the end, I used the following command to display the captured input using VLC.
cvlc v4l2:///dev/video0 :v4l2-standard= :input-slave=alsa://hw:2,0 :v4l2-chroma=MJPG :v4l2-width=1920 :v4l2-height=1080 :v4l2-aspect-ratio=16\:9 :v4l2-fps=25 :live-caching=300

What it does is:
- Use /dev/video0 which is the identifier for this capture device. Depending on what else is connected, it can be some other number, like video1, video2, etc. 
- Audio device is hw:2,0 but again, this may be different. I got this from running VLC and selecting "Open capture device..."
- Chroma is MJPG; otherwise, it defaults to YUYV which is uncompressed and can only give 5 fps at 1080p.
- Video resolution is 1920 by 1080 (aka 1080p) with aspect ratio of 16:9.
- FPS set at 25 fps
- Live caching is set at 300ms which seems to provide enough of a buffer for smooth playback.

In TwisterOS, I created an app launcher that runs this command, so next time, all I have to do is click on the app launcher icon to call up VLC with these settings.

Based on an article that I read (see this and this), it seems the color may be a bit off, but can be adjusted. The following are settings which I want to try but have not done so.
v4l2-ctl -d /dev/video0 --set-ctrl=brightness=-9
v4l2-ctl -d /dev/video0 --set-ctrl=contrast=148
v4l2-ctl -d /dev/video0 --set-ctrl=saturation=127
 
So now, I am able to watch Blu-ray/DVDs again! 😄

Update January 9, 2021: If anyone is having trouble with video playback on Raspberry Pi OS, such as the screen hanging, do a sudo apt update and sudo apt full-upgrade to fix it. A recent update had a bug, but it will quickly fixed once the issue was raised on the forums.

No comments: