Skip to content

Instantly share code, notes, and snippets.

@turbo
Last active January 18, 2023 16:24
Show Gist options
  • Save turbo/2b02d7ddb74422303496c57e3aa5fdae to your computer and use it in GitHub Desktop.
Save turbo/2b02d7ddb74422303496c57e3aa5fdae to your computer and use it in GitHub Desktop.
Recording 4k 4:2:2 from Brio 4k In Linux using FFMpeg

Turn auto-exposure off, set absolute exposure to a low level and use gain to compensate for low light if needed. E.g.:

v4l2-ctl -d /dev/video2 -c exposure_absolute=400
v4l2-ctl -d /dev/video2 -c gain=110

# check with
v4l2-ctl -d /dev/video2 -L

Sample:

                     brightness 0x00980900 (int)    : min=0 max=255 step=1 default=128 value=128
                       contrast 0x00980901 (int)    : min=0 max=255 step=1 default=128 value=128
                     saturation 0x00980902 (int)    : min=0 max=255 step=1 default=128 value=128
 white_balance_temperature_auto 0x0098090c (bool)   : default=1 value=1
                           gain 0x00980913 (int)    : min=0 max=255 step=1 default=0 value=255
           power_line_frequency 0x00980918 (menu)   : min=0 max=2 default=2 value=1
                                0: Disabled
                                1: 50 Hz
                                2: 60 Hz
      white_balance_temperature 0x0098091a (int)    : min=2000 max=7500 step=10 default=4000 value=3200 flags=inactive
                      sharpness 0x0098091b (int)    : min=0 max=255 step=1 default=128 value=128
         backlight_compensation 0x0098091c (int)    : min=0 max=1 step=1 default=1 value=0
                  exposure_auto 0x009a0901 (menu)   : min=0 max=3 default=3 value=1
                                1: Manual Mode
                                3: Aperture Priority Mode
              exposure_absolute 0x009a0902 (int)    : min=3 max=2047 step=1 default=250 value=180
         exposure_auto_priority 0x009a0903 (bool)   : default=0 value=0
                   pan_absolute 0x009a0908 (int)    : min=-36000 max=36000 step=3600 default=0 value=0
                  tilt_absolute 0x009a0909 (int)    : min=-36000 max=36000 step=3600 default=0 value=0
                 focus_absolute 0x009a090a (int)    : min=0 max=255 step=5 default=0 value=10 flags=inactive
                     focus_auto 0x009a090c (bool)   : default=1 value=1
                  zoom_absolute 0x009a090d (int)    : min=100 max=500 step=1 default=100 value=100

Since shutter speeds can't be changed (because we're receiving an image stream), the maximum exposure you should use is the one where your target framerate is stable. The ffmpeg stats will show the current FPS, which must be exactly at your target. If it's below, decrease exposure. Gain doesn't have any effect on the frame rate. So lock in your exposure, then add as much physical light as possible, then add gain if it's still too dark - in that order.

Live preview the feed at 1:1 resolution (you can use v4l2-ctl while this is running to dial in image settings):

ffmpeg -f v4l2 -input_format mjpeg -video_size 3280x2160 -r 24 -i /dev/video2 -c:v copy -f avi - | mpv - >/dev/null 2>&1

(press q to quit)

If you change settings during the live view which affect frame rate / shutter speed, you must restart because ffmpeg's FPS measurement averages over the entire time it's been running.

Keep in mind that higher framerates have lower frametimes and require more light. I.e. to go from 30 to 60 fps, halve the exposure setting and add more light.

The MJPEG stream is capable of high framerate capture, but exposure must be lowered even further. Most interesting are 1280x720 at 90 FPS and 640x480 at 120 (haven't gotten this one to work yet).

Record 90 FPS HF and convert to 30 FPS slow-mo (last line shows off encoding):

# 90 fps HF recording
ffmpeg -f v4l2 -input_format mjpeg -video_size 1280x720 -r 90 -i /dev/video2 -c:v copy -f avi -q 0 -a
n fast.avi

# same quality, just slower
ffmpeg -i fast.avi -filter:v "setpts=3.0*PTS" -r 30 -qscale 0  slow.avi

# medium quality, encoded to 264
ffmpeg -i fast.avi -filter:v "setpts=3.0*PTS" -r 30 -vcodec libx264 -crf 27 -preset fast -an slow.mp4

Recording to a file works the same for non-HF. The recording step above doesn't do any encoding, which produces huge AVI files, but consumes basically no CPU resources. You can easily record many 4k streams at the same time.

If you do encoding at the same time, you'll need a lot of CPU power, or a GPU that can be used for encoding (NVENC for example) and a build of ffmpeg that support that.

@nmschulte
Copy link

I've found that my FPS beings to degrade when exposure_absolute is >= ~400. When testing, if increasing the value by 1, the FPS begins to fall (from the max of ~28.986) when issuing exposure_absolute=410. However, the FPS does not again increase until issuing exposure_absolute=407, when reversing the test direction.

@Swivelgames
Copy link

It's pretty unfortunate, but I have had quite a hard time getting my BRIO to record 4K or HF.

Unfortunately, I consistently get in issue where V4L2 decreases the stream from 3280x2160 to 1920x1080. Here's what it looks like:

[video4linux2,v4l2 @ 0x56102c651740] The V4L2 driver changed the video from 3280x2160 to 1920x1080

For High Frame Rate, I get the following:

[video4linux2,v4l2 @ 0x55713a041740] The driver changed the time per frame from 1/90 to 1/60
Input #0, video4linux2,v4l2, from '/dev/video0':
  Duration: N/A, start: 802428.147589, bitrate: N/A
  Stream #0:0: Video: mjpeg (Baseline), yuvj422p(pc, bt470bg/unknown/unknown), 1280x720, 60 fps, 60 tbr, 1000k tbn
Output #0, avi, to 'fast.avi':
  Metadata:
    ISFT            : Lavf59.16.100
  Stream #0:0: Video: mjpeg (Baseline) (MJPG / 0x47504A4D), yuvj422p(pc, bt470bg/unknown/unknown), 1280x720, q=2-31, 60 fps, 60 tbr, 90 tbn

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment