Search code examples
ffmpeg

Working with raw output from ffmpeg 'gdigrab' on Windows


I'm trying to capture high quality screen recording with the minimum CPU load (what we're recording is already CPU intensive and suffers slowdown if encoding is being done at the same time as screen recording).

I'm using this command:

ffmpeg -f gdigrab -t 00:00:05 -i desktop -pix_fmt yuv420p -vcodec copy -y testing.avi

When I open this in Windows Media Player or VLC it sort of works. It's the right size and duration, but the pixels are messed up, as shown below.

output in media player

Ultimately I'd like to be able to re-encode this to something smaller, again using ffmpeg, but I can't find the right ffmpeg incantation/options for this given the raw input file generated by the first command.


Solution

  • The output codec of gdigrab is BMP.
    For grabbing with -codec copy we have to store each frame in separate BMP image file.

    Example:
    ffmpeg -r 30 -f gdigrab -t 00:00:05 -i desktop -vcodec copy %08d.bmp

    Later we can encode the images offline:
    ffmpeg -r 30 -i %8d.bmp -vcodec libx264 -pix_fmt yuv420p -y testing.mp4


    Using gdigrab and BMP images is probably not the most efficient solution.
    Modern CPUs that has an internal GPU support iGPU accelerated encoding.

    Example for using Intel Quick Sync encoder:
    ffmpeg -init_hw_device qsv=hw,child_device_type=dxva2 -filter_hw_device hw -f dshow -i video="screen-capture-recorder" -t 00:00:05 -vf "hwupload=extra_hw_frames=64,format=qsv" -c:v h264_qsv -b:v 5M -pix_fmt nv12 -y testing.mp4

    It may not work if your system doesn't support Intel Quick Sync.
    Note: I am getting an error message: "Impossible to convert between the formats supported by the filter" (I think it's an issue with my system configuration because QSV encoding is not working in general).

    The following command is working in my machine (but 20% CPU utilized by FFmpeg):
    ffmpeg -init_hw_device qsv=hw,child_device_type=dxva2 -filter_hw_device hw -f dshow -i video="screen-capture-recorder" -t 00:00:05 -c:v h264_qsv -b:v 5M -y testing.mp4


    In case your system has discrete GPU, it may be possible to use the discrete GPU for encoding the video.

    Intel and AMD names are QSV and AMF.


    When GPU encoding is used, gdigrab may not be the most efficient solution.
    FFmpeg version 6 (not yet stable release) supports ddagrab for capturing the Windows Desktop.
    The main advantage of ddagrab over gdigrab is that ddagrab doesn't transfer the video frame from the GPU to the CPU (and also saves the pixel format conversions).

    • Example for using ddagrab with NVIDIA GPU:
      ffmpeg -f lavfi -i ddagrab -t 00:00:05 -c:v h264_nvenc -cq 18 -y output.mp4

    • Example for using ddagrab with Intel Quick Sync:
      ffmpeg -init_hw_device qsv=hw,child_device_type=dxva2 -filter_hw_device hw -f lavfi -i ddagrab -t 00:00:05 -c:v h264_qsv -b:v 5M -y testing.mp4
      Note: I couldn't test the QSV solution yet.


    When I use ffmpeg -f lavfi -i ddagrab -c:v h264_nvenc -cq 18 -y testing.mp4, FFmpeg CPU utilization is around 0%:

    enter image description here
    Note: The above command is working in my system because it has a discrete NVIDIA GPU.