3

I am trying to use ffmpeg to encode VP9 video with vp9_qsv (Intel Quick Sync Video hardware support) on windows 10. I have previously successfully encoded VP9 video with libvpx-vp9, but that uses the CPU and is rather slow. Now that I am trying to switch to vp9_sqv I get some error messages that are not so helpful and the documentation is rather lacking as well.

ffmpeg.exe -i input.mp4 -c:v vp9_qsv -c:a copy output.webm

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.20.100
  Duration: 00:00:46.74, start: 0.040000, bitrate: 15752 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080, 15561 kb/s, 25.02 fps, 25 tbr, 12800 tbn, 50 tbc (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 193 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> vp9 (vp9_qsv))
  Stream #0:1 -> #0:1 (copy)
Press [q] to stop, [?] for help
[vp9_qsv @ 000001b156147b40] Selected ratecontrol mode is unsupported
[vp9_qsv @ 000001b156147b40] Low power mode is unsupported
[vp9_qsv @ 000001b156147b40] Current frame rate is unsupported
[vp9_qsv @ 000001b156147b40] Current picture structure is unsupported
[vp9_qsv @ 000001b156147b40] Current resolution is unsupported
[vp9_qsv @ 000001b156147b40] Current pixel format is unsupported
[vp9_qsv @ 000001b156147b40] some encoding parameters are not supported by the QSV runtime. Please double check the input parameters.
Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as bit_rate, rate, width or height
Conversion failed!

I tried specifying some of the things it is asking for, but this produces exactly the same errors.

ffmpeg.exe -i input.mp4 -c:v vp9_qsv -preset veryslow -low_power 0 -b:v 800K -c:a copy output.webm

EDIT: Based on Mokubai's suggestion I now get this: ffmpeg.exe -init_hw_device qsv=hw -filter_hw_device hw -f rawvideo -pix_fmt yuv420p -s:v 1920x1080 -i input.mp4 -vf hwupload=extra_hw_frames=64,format=qsv -c:v vp9_qsv -c:a copy output.webm

[AVHWDeviceContext @ 000001d30eccb640] Error setting child device handle: -6
Bazzz
  • 167
  • 2
  • 10
  • 1
    The QSV examples section at https://trac.ffmpeg.org/wiki/Hardware/QuickSync seems to suggest that you might need to add `-init_hw_device qsv=hw -filter_hw_device hw -f rawvideo -pix_fmt yuv420p -s:v 1920x1080` before your `-i input.mp4` and then `-vf hwupload=extra_hw_frames=64,format=qsv` before your `-c:v` to properly specify the format the encoder wants... not 100% sure hence only a comment. It looks a lot like handholding the encoder to tell it exactly what you are giving it. – Mokubai Dec 09 '20 at 11:21
  • @Mokubai Excellent comment and it surely helped a lot, but now I get another super helpful error message. ☺ – Bazzz Dec 09 '20 at 11:34
  • Do you have a display connected to the output? The only things I can find seem to suggest a problem with headless systems... Got rid of all the format errors from the encoder though... – Mokubai Dec 09 '20 at 11:37
  • @Mokubai no display is attached to the intel iGPU, but to my dGPU, so it may consider itself headless in fact. Worth a try! – Bazzz Dec 09 '20 at 11:39
  • It does seem a very obscure error, and there is a [bug that has a common thread](https://trac.ffmpeg.org/ticket/6996) in that they have a dGPU and are trying to use the iGPU encoder with nothing connected. It is also possible that the VP9 encoder simply isn't there: https://en.wikipedia.org/wiki/VP9#Hardware_implementations seems to suggest that under Linux it is available on the 7th generation (Kaby Lake) and above and only available on Windows under Ice Lake processors. – Mokubai Dec 09 '20 at 11:51
  • I switched the monitor to the iGPU and now *with* your suggestions I get the exact same ~6 errors as I got at my first attempt. Which does not make any sense to me. The finding about it not being available in Windows makes me doubt as well, I have a 7th generation CPU (Kaby Lake), so thought that the hardware support should be there. hmmmm.... – Bazzz Dec 09 '20 at 12:14
  • I'd suspect that the hardware is there, but that the Windows drivers either actively disable it or just don't enable it at all. Sorry I couldn't be more help. – Mokubai Dec 09 '20 at 12:22
  • @Mokubai No problem, you have certainly enriched my knowledge on the subject, so for that I thank you. If only the error message from ffmpeg would say "Hey you are on windows, and your cpu is 7th gen, so vp9_qsv is not going to work. bye!", it would have saved us quite some time. – Bazzz Dec 09 '20 at 12:31
  • @Mokubai if you summarise your information together into an answer, I will accept that. Even though my issue is not resolved, your info is the best there is for any other person who searches for the same thing. – Bazzz Dec 10 '20 at 20:25
  • Will do, give me a short while to piece it together into something sensible. – Mokubai Dec 10 '20 at 20:30

2 Answers2

3

Firstly it may be worth bearing in mind that Intel have not officially enabled VP9 support in their Quicksync Encoder before Tiger Lake CPUs. There is some hints that it might be able to be made to work in Linux on Kaby Lake (7th Generation) processorsand above with some mangling, but one user with contributions to the Intel media driver states

sorry for late response, we will not enable VP9 encode on Gen9 platforms , if someone still want it, he could try PR #717 , it add VP9 encode support. but Gen9 VME design is not optimized for VP9. so we have concerns on it.

Gen9 being a large number of platforms pre-Tiger Lake which itself uses Gen 11 graphics.

That said the QSV examples section at the FFMPEG wiki: Hardware / QuickSync seems to suggest that you can add -init_hw_device qsv=hw -filter_hw_device hw -f rawvideo -pix_fmt yuv420p -s:v 1920x1080 before your -i input.mp4 to initialise the hardware (assuming a YUV420 source).

Then use -vf hwupload=extra_hw_frames=64,format=qsv before your -c:v to specify the format the encoder wants, though I do not have functional hardware with which to test.

At the very least the FFMPEG wiki does hold some promise but even on a Tiger Lake CPU I cannot get it to transcode any video. No matter what I try I get the following lines

[swscaler @ 000001c902edec40] deprecated pixel format used, make sure you did set range correctly
[vp9_qsv @ 000001c97dc7ef40] Selected ratecontrol mode is unsupported
[vp9_qsv @ 000001c97dc7ef40] some encoding parameters are not supported by the QSV runtime. Please double check the input parameters.
Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as bit_rate, rate, width or height
Conversion failed!

I can use the h264_qvc encoder happily, but switching to vp9_qvc throws the error and I cannot find any hints on how to specify the necessary ratecontrol.

My example command line that works

.\ffmpeg.exe -init_hw_device qsv=hw -i 'MVI_7664.mov' -vf hwupload=extra_hw_frames=64,format=qsv -c:v h264_qsv -strict experimental -preset veryslow -c:a copy output.mkv -y

but it is using h264 not VP9. Perhaps I need a newer FFMPEG.

Mokubai
  • 89,133
  • 25
  • 207
  • 233
3

Using Intel's QuickSync (on supported platforms):

This answer extends the answer above, with a few changes:

  1. For vp9_qsv encoder wrapper, note that low power mode is mandatory (for now). Failure to set this (via the private codec option -low_power 1) will result in failure, whereupon the MFX runtime will print out a log similar to:
[vp9_qsv @ 000001b156147b40] Selected ratecontrol mode is unsupported
[vp9_qsv @ 000001b156147b40] Low power mode is unsupported
[vp9_qsv @ 000001b156147b40] Current frame rate is unsupported
[vp9_qsv @ 000001b156147b40] Current picture structure is unsupported
[vp9_qsv @ 000001b156147b40] Current resolution is unsupported
[vp9_qsv @ 000001b156147b40] Current pixel format is unsupported
[vp9_qsv @ 000001b156147b40] some encoding parameters are not supported by the QSV runtime. Please double check the input parameters.
Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as bit_rate, rate, width or height
Conversion failed!

This is because the QSV MFX runtime must negotiate all requirements with the device driver (iHD, on Linux) before an MFX session can register successfully. To my knowledge, this wrapper will only work on Linux at the moment. This may change in the near future.

  1. All examples below show a case of 1:N transcoding (ie one input used to provide multiple outputs). A complex filter chain is also in use, as well as the tee muxer slaves calling up the underlying segment muxers.

On Intel Icelake and above, you can use the vp9_qsv encoder wrapper with the following known limitations (for now), as tested on Linux:

(a). You must enable low_power mode because only the VDENC decode path is exposed by the iHD driver for now.

(b). Coding option1 and extra_data are not supported by MSDK.

(c). The IVF header will be inserted in MSDK by default, but it is not needed for FFmpeg, and remains disabled by default.

See the examples below, taking a single input and producing multiple outputs via the tee muxer slaves calling up segment muxers:

  1. If you need to deinterlace, call up the vpp_qsv filter as shown:
    ffmpeg -nostdin -y -fflags +genpts \
    -init_hw_device vaapi=va:/dev/dri/renderD128,driver=iHD \
    -filter_hw_device va -hwaccel vaapi -hwaccel_output_format vaapi \
    -threads 4 -vsync 1 -async 1 \
    -i 'http://server:port' \
    -filter_complex "[0:v]hwmap=derive_device=qsv,format=qsv,vpp_qsv=deinterlace=2:async_depth=4,split[n0][n1][n2]; \
    [n0]vpp_qsv=w=1152:h=648:async_depth=4[v0]; \
    [n1]vpp_qsv=w=848:h=480:async_depth=4[v1];
    [n2]vpp_qsv=w=640:h=360:async_depth=4[v2]" \
    -b:v:0 2250k -maxrate:v:0 2250k -bufsize:v:0 360k -c:v:0 vp9_qsv -g:v:0 50 -r:v:0 25 -low_power:v:0 2 \
    -b:v:1 1750k -maxrate:v:1 1750k -bufsize:v:1 280k -c:v:1 vp9_qsv -g:v:1 50 -r:v:1 25 -low_power:v:1 2 \
    -b:v:2 1000k -maxrate:v:2 1000k -bufsize:v:2 160k -c:v:2 vp9_qsv -g:v:2 50 -r:v:2 25 -low_power:v:2 2 \
    -c:a aac -b:a 128k -ar 48000 -ac 2 \
    -flags -global_header -f tee -use_fifo 1 \
    -map "[v0]" -map "[v1]" -map "[v2]" -map 0:a \
    "[select=\'v:0,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path0/output%03d.mp4| \
     [select=\'v:1,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path1/output%03d.mp4| \
     [select=\'v:2,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path2/output%03d.mp4"
  1. Without deinterlacing:
    ffmpeg -nostdin -y -fflags +genpts \
    -init_hw_device vaapi=va:/dev/dri/renderD128,driver=iHD \
    -filter_hw_device va -hwaccel vaapi -hwaccel_output_format vaapi \
    -threads 4 -vsync 1 -async 1 \
    -i 'http://server:port' \
    -filter_complex "[0:v]hwmap=derive_device=qsv,format=qsv,split=3[n0][n1][n2]; \
    [n0]vpp_qsv=w=1152:h=648:async_depth=4[v0]; \
    [n1]vpp_qsv=w=848:h=480:async_depth=4[v1];
    [n2]vpp_qsv=w=640:h=360:async_depth=4[v2]" \
    -b:v:0 2250k -maxrate:v:0 2250k -bufsize:v:0 2250k -c:v:0 vp9_qsv -g:v:0 50 -r:v:0 25 -low_power:v:0 2  \
    -b:v:1 1750k -maxrate:v:1 1750k -bufsize:v:1 1750k -c:v:1 vp9_qsv -g:v:1 50 -r:v:1 25 -low_power:v:1 2  \
    -b:v:2 1000k -maxrate:v:2 1000k -bufsize:v:2 1000k -c:v:2 vp9_qsv -g:v:2 50 -r:v:2 25 -low_power:v:2 2  \
    -c:a aac -b:a 128k -ar 48000 -ac 2 \
    -flags -global_header -f tee -use_fifo 1 \
    -map "[v0]" -map "[v1]" -map "[v2]" -map 0:a \
    "[select=\'v:0,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path0/output%03d.mp4| \
     [select=\'v:1,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path1/output%03d.mp4| \
     [select=\'v:2,a\':f=segment:segment_time=5:segment_format_options=movflags=+faststart]$output_path2/output%03d.mp4"

Note that we use the vpp_qsv filter with the async_depth option set to 4. This massively improves transcode performance over using scale_qsv and deinterlace_qsv. See this commit on FFmpeg's git.

Notes:

This will only work on Linux, running the current media-driver package for VAAPI H/W acceleration, which ffmpeg picks via -init_hw_device vaapi=va:/dev/dri/renderD128,driver=iHD -filter_hw_device va -hwaccel vaapi -hwaccel_output_format vaapi bound to a DRI node /dev/dri/rendereD128. This is the default on single-GPU systems. However, this will change if more than one GPU is present. We use VAAPI for H/W acceleration as its' more resilient for decode acceleration. QuickSync decode is surprisingly fragile and will result in MFX errors on multiple input files.

We also derive a QSV context via the hwmap filter, called up via hwmap=derive_device=qsv,format=qsv which is then chained immediately to the format=qsv filter, specifying that we want QSV H/W frames to be fed to the adjacent filter vpp_qsv in the complex filter chain.

Warnings:

  1. With QuickSync, regardless of input formats and the QSV encoder wrapper in use, expect a slightly higher CPU overhead especially on smaller processors such as the Intel Atom® x7-E3950 Processor. The same overhead is greatly mitigated against on more capable desktop-grade processors and the Iris Pro capable CPUs.
  2. For VP9-based H/W based encoding, I'd still strongly recommend using the vp9_vaapi encoder wrapper instead, and with caveats (related to the use of B-frames and rate control modes). VAAPI tends to be more stable overall than QSV.

References:

  1. See the encoder options, including rate control methods supported:
ffmpeg -h encoder=vp9_qsv
  1. On the vpp_qsv filter usage, see:
ffmpeg -h filter=vpp_qsv

Warning:

Note that the SDK requires at least 2 threads to prevent deadlock, see this code block.

Dennis Mungai
  • 3,074
  • 1
  • 22
  • 33