Search code examples
ffmpegvideo-capture

ffmpeg records 5 frames per second on a device that cheese records at 20 fps


Running the following ffmpeg capture on my built in webcam:

ffmpeg -f v4l2 -framerate 30 -video_size 1920x1080 -i /dev/video0 output.mkv

I get only 5 fps and see this message:

The driver changed the time per frame from 1/30 to 1/5

When I record using cheese I get what looks like 20 fps on that device. And v4l2 seems to claim it can do 30 fps.

v4l2-ctl --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
    Index       : 0
    Type        : Video Capture
    Pixel Format: 'MJPG' (compressed)
    Name        : Motion-JPEG
        Size: Discrete 1920x1080
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 1280x720
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 800x600
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 640x480
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 640x360
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 640x480
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 160x120
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 320x240
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 640x480
            Interval: Discrete 0.033s (30.000 fps)

    Index       : 1
    Type        : Video Capture
    Pixel Format: 'YUYV'
    Name        : YUYV 4:2:2
        Size: Discrete 1920x1080
            Interval: Discrete 0.200s (5.000 fps)
        Size: Discrete 1280x720
            Interval: Discrete 0.100s (10.000 fps)
        Size: Discrete 800x600
            Interval: Discrete 0.050s (20.000 fps)
        Size: Discrete 640x480
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 640x360
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 640x480
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 160x120
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 320x240
            Interval: Discrete 0.033s (30.000 fps)
        Size: Discrete 640x480
            Interval: Discrete 0.033s (30.000 fps)

When I run ffmpeg:

Output #0, mjpeg, to 'output.mjpg':
  Metadata:
    encoder         : Lavf56.40.101
    Stream #0:0: Video: mjpeg, yuvj422p(pc), 1920x1080, q=2-31, 200 kb/s, 5 fps, 5 tbn, 5 tbc
    Metadata:
      encoder         : Lavc56.60.100 mjpeg

My guess is that it's recording in raw form from the device and doing the encoding in ffmpeg. If this is correct, how would I get ffmpeg to use the mjpeg native format?


Solution

  • I needed to record in the native compressed motion jpeg format supported by my webcam. Once I got that configured (see below) it records at 30 fps at full resolution.

    ffmpeg -f v4l2 -framerate 30 -video_size 1920x1080 -c:v mjpeg -i /dev/video0 -c:v copy output.mov
    

    Note the -c:v (video codec) before the -i (input) indicates what recording codec the device should be using (mjpeg is supported natively on my webcam), and the -c:v (video codec) after the -i (input) indicates what recording codec ffmpeg should convert to. copy does not change the codec, it simply copies the bytes that were provided by the device.