How to change mjpeg to yuyv422 from a webcam to a v4l2loopback?
Asked Answered
P

1

9

Backstory: One livestreaming site I use isn't smart enough to detect the capabilities of my webcam (Logitech Brio, 4k), and instead just uses the default frames per second settings, which is 5fps.

(full solution walk-through in the answer)

The best solution I could think of (besides changing livestream providers) was to create a loopback virtual webcam using v4l2loopback that I could force to have the exact settings I wanted to use on that livestream site.

For the brio, the higher frame rates come with mjpeg, not the default yuyv.

Problem 1:

I could easily read mjpeg, but unfortunately kept banging my head against the wall because v4l2loopback evidently only wanted yuyv.

I tried things like:

ffmpeg -f v4l2              \
       -input_format mjpeg  \
       -framerate 30        \
       -video_size 1280x720 \
       -i /dev/video0       \
       -vcodec copy         \
       -f v4l2 /dev/video6

and

ffmpeg -f v4l2              \
       -input_format mjpeg  \
       -framerate 30        \
       -video_size 1280x720 \
       -i /dev/video0       \
       -vcodec yuyv422      \ # this line changed (even tried "copy")
       -f v4l2 /dev/video6

But they wouldn't work. I got errors like:

Unknown V4L2 pixel format equivalent for yuvj422p

and

...deprecated pixel format used, make sure you did set range correctly...

...V4L2 output device supports only a single raw video stream...

Eventually I got this to work:

ffmpeg -f v4l2              \
       -input_format mjpeg  \
       -framerate 30        \
       -video_size 1280x720 \
       -i /dev/video0       \
       -pix_fmt yuyv422     \ # The winning entry
       -f v4l2 /dev/video6

Problem 2

The next problem was getting chrome to see the virtual webcam. It worked correctly with guvcview, and on firefox I could use webcam testing sites and it would pick the virtual camera up without a problem.

Turns out google, in it's overly-protective nature (while it's siphoning off all our data, btw), doesn't want to use webcams that can be read and written to.

So when starting v4l2loopback you have to tell it to announce that it's "read only" to consumers like chrome.

Here's the exact modprobe I use that works:

sudo modprobe v4l2loopback devices=1 exclusive_caps=1
Pyrography answered 3/1, 2020 at 7:53 Comment(0)
P
15

Exact solution.

1. Figure out which webcam is the correct input webcam

Use v4l2-ctl to list all the webcams:

v4l2-ctl --list-devices

My output is this (yours will vary, I'll use mine as an example as I go):

Logitech BRIO (usb-0000:00:14.0-5.2):
    /dev/video0
    /dev/video1

HP HD Camera: HP HD Camera (usb-0000:00:14.0-9):
    /dev/video2
    /dev/video3
    /dev/video4
    /dev/video5

In this case my brio is video0.

2. Start v4l2loopback:

sudo modprobe v4l2loopback devices=1 exclusive_caps=1

3. Confirm your loopback device:

v4l2-ctl --list-devices

Mine now shows this, indicating video6 is the loopback:

Dummy video device (0x0000) (platform:v4l2loopback-000):
    /dev/video6

Logitech BRIO (usb-0000:00:14.0-5.2):
    /dev/video0
    /dev/video1

HP HD Camera: HP HD Camera (usb-0000:00:14.0-9):
    /dev/video2
    /dev/video3
    /dev/video4
    /dev/video5

4. Determine your optimal input settings

Use guvcview to figure out which codec gives you the resolution and framerate you're looking for (you may have to use the menu -> Video -> Video Codec -> Raw camera input).

I got 60fps using mjpeg, I only needed 30. The default yuyv gave a miserable 5fps.

Now use ffmpeg to list the capabilities of the camera and get the matching codec:

ffmpeg -f v4l2 -list_formats all -i /dev/video0  #use your camera here from step 2

In the output you'll see something like this:

[video4linux2,v4l2 @ 0x55f1a4e989c0] Raw       :     yuyv422 :           YUYV 4:2:2 : 640x480 160x120 176x144 320x180 320x240 352x288 340x340 424x240 440x440 480x270 640x360 800x448 800x600 848x480 960x540 1024x576 1280x720 1600x896 1920x1080
[video4linux2,v4l2 @ 0x55f1a4e989c0] Compressed:       mjpeg :          Motion-JPEG : 640x480 160x120 176x144 320x180 320x240 352x288 424x240 480x270 640x360 800x448 800x600 848x480 960x540 1024x576 1280x720 1600x896 1920x1080

In my case it was the mjpeg that gave the best output in guvcview, and that was the exact name of the codec (as indicated above).

5. Start ffmpeg using that input codec and changing the pixel format to yuyv:

ffmpeg -f v4l2              \
       -input_format mjpeg  \
       -framerate 30        \
       -video_size 1280x720 \
       -i /dev/video0       \
       -pix_fmt yuyv422     \
       -f v4l2 /dev/video6  

Update the video size to the highest size your livestream/video record will support, as long as your camera also supports it.

Now when you want to livestream, just use the camera labeled "Dummy"

Pyrography answered 3/1, 2020 at 7:53 Comment(3)
If you are using GStreamer, you can get the device's capabilities by running gst-device-monitor-1.0Converse
For me the -input_format mjpeg was enough, no need for a loopback of any kind. But by default it would select the rawvideo which was really slow.Nanna
Hello.. I am using your solution for a similar application but I am getting low frame rates. This is the only post on the internet (haha) regarding this problem. My output stream from ffmpeg has a frame rate of 1 FPS only! How can I troubleshoot this?Sealskin

© 2022 - 2024 — McMap. All rights reserved.