Table of Contents

ffmpeg - Encoding - GPU Encoding

Convert videos to H.265 / HEVC using ffmpeg and GPU hardware encoding

ffmpeg -i "input.mkv" -vaapi_device /dev/dri/renderD128 -vf 'format=nv12,hwupload,scale_vaapi=w=1920:h=1080' -map 0:v -metadata:s:v:0 language=eng -map 0:a -metadata:s:a:0 language=eng -map 0:s? -metadata:s:s:0 language=eng -profile:v main -c:v hevc_vaapi -c:a copy -c:s copy -rc_mode CQP -global_quality 25 -v verbose "output.mkv"
 
ffmpeg -i "input.mkv" -vaapi_device /dev/dri/renderD128 -vf 'format=nv12,hwupload,scale_vaapi=w=1920:h=1080' -map 0:v -metadata:s:v:0 language=eng -map 0:a:m:language:eng? -metadata:s:a:0 language=eng -map 0:s? -metadata:s:s:0 language=eng -profile:v main -c:v hevc_vaapi -c:a copy -c:s copy -rc_mode CQP -global_quality 25 -v verbose "output.mkv"

Explanation

ffmpeg
  -i "input.mkv" \
  -vaapi_device /dev/dri/renderD128 \
  -vf 'format=nv12,hwupload,scale_vaapi=w=1920:h=1080' \
  -map 0:v -metadata:s:v:0 language=eng \
  -map 0:a -metadata:s:a:0 language=eng \
  -map 0:s? -metadata:s:s:0 language=eng \
  -c:v hevc_vaapi \
  -c:a copy \
  -c:s copy \
  -rc_mode CQP \
  -global_quality 25 \
  -profile:v main \
  -v verbose \
  "output.mkv"

NOTE:

  • -i “input.mkv” is the source file.
  • -vaapi_device /dev/dri/renderD128 is a shortcut to -init_hw_device vaapi=vaapi0:/dev/dri/renderD128 -filter_hw_device vaapi0, and initializes a new hardware device of type vaapi.
  • -vf 'format=nv12,hwupload,scale_vaapi=w=1920:h=1080' creates the filtergraph and uses it to filter the stream.
    • The encoders only accept input as VAAPI surfaces. If the input is in normal memory, it will need to be uploaded before giving the frames to the encoder - in the ffmpeg utility, the hwupload filter can be used for this.
    • It will upload to a surface with the same layout as the software frame, so it may be necessary to add a format filter immediately before to get the input into the right format (hardware generally wants the nv12 layout).
    • The hwupload filter also requires a device to upload to, which needs to be defined before the filter graph is created which is done with -vaapi_device.
    • The scale_vaapi=w=1920:h=1080 scales the video to 1080p.
    • Use -vf 'format=nv12,hwupload' to not do any scaling, and to use NV12 (8-bit encoding).
    • Use -vf 'format=p010,hwupload' for 10-bit encoding; and also change the profile to Main10.
      • See further below for other pixel formats..
  • -map 0:v selects the Video streams from the inputs which will go into the output.
  • -metadata:s:v:0 language=eng has the output Video stream to show English as the language.
  • -map 0:a selects the Audio streams from the inputs which will go into the output.
  • -map 0:s? selects the Sub-Title streams from the inputs which will go into the output.
    • The “?” is to have this optional, i.e. only write Sub-Titles if they exist in the source.
  • -c:v hevc_vaapi converts the input file to H.265 in the destination file.
    • hevc_vaapi means H.265 / MPEG-H part 2 (HEVC).
    • Instead of using the H.265 codec, optionally select any other code that the GPU supports.

      To figure out for which codecs the GPU supports, run the following command:

      vainfo

      This returns something like this:

            VAProfileH264ConstrainedBaseline:	VAEntrypointVLD
            VAProfileH264ConstrainedBaseline:	VAEntrypointEncSlice
            VAProfileH264Main               :	VAEntrypointVLD
            VAProfileH264Main               :	VAEntrypointEncSlice
            VAProfileH264High               :	VAEntrypointVLD
            VAProfileH264High               :	VAEntrypointEncSlice
            VAProfileHEVCMain               :	VAEntrypointVLD
            VAProfileHEVCMain               :	VAEntrypointEncSlice
            VAProfileHEVCMain10             :	VAEntrypointVLD
            VAProfileHEVCMain10             :	VAEntrypointEncSlice
            VAProfileJPEGBaseline           :	VAEntrypointVLD
            VAProfileVP9Profile0            :	VAEntrypointVLD
            VAProfileVP9Profile2            :	VAEntrypointVLD
            VAProfileAV1Profile0            :	VAEntrypointVLD
            VAProfileAV1Profile0            :	VAEntrypointEncSlice
            VAProfileNone                   :	VAEntrypointVideoProc

      For all entries with a value of VAEntrypointEncSlice hardware encoding is supported and can be used.

  • -c:a copy copies the Audio streams without modification to the output.
  • -c:s copy copies the Subtitle streams without modification to the output.
  • -rc_mode CQP sets the rate control mode to CQP.
    • CQP works well.
    • Run the following to see all possible modes:

      ffmpeg -h encoder=hevc_vaapi

      This returns all H.265 VAAPI options. These are the available rate control modes:

      ...
        -rc_mode           <int>        E..V....... Set rate control mode (from 0 to 6) (default auto)
           auto            0            E..V....... Choose mode automatically based on other parameters
           CQP             1            E..V....... Constant-quality
           CBR             2            E..V....... Constant-bitrate
           VBR             3            E..V....... Variable-bitrate
           ICQ             4            E..V....... Intelligent constant-quality
           QVBR            5            E..V....... Quality-defined variable-bitrate
           AVBR            6            E..V....... Average variable-bitrate
      ...
  • -global_quality 25 selects the video quality.
    • The default value is 25 which returns decent enough output.
    • The lower the value, the better is the video quality, but the output file gets larger.
  • -profile:v main selects the x265 profile, main, which should work with every output device.
    • For h.265, main is the default profile. All decoders, which can decode h.265, will support it.
    • But there are other profiles that can be used, for supporting additional decoder capabilities like higher colour depth (10, 12 or 16 bit), less subsampling (4:2:2 or 4:4:4) or intra-constrained (mainly for editing, as it's not efficient). Plus more specialized things.
    • Main 10 is fine to use for 8 or 10 bit color depths and its inclusion in version 1 of the standard means it will enjoy a high level of support as long as the decoder supports 10 bit.
  • -v verbose
  • output.mkv is the output file.

Using other pixel formats

Check which pixel formats are supported:

ffmpeg -pix_fmts

returns

Pixel formats:
I.... = Supported Input  format for conversion
.O... = Supported Output format for conversion
..H.. = Hardware accelerated format
...P. = Paletted format
....B = Bitstream format
FLAGS NAME            NB_COMPONENTS BITS_PER_PIXEL BIT_DEPTHS
-----
IO... yuv420p                3             12      8-8-8
IO... yuyv422                3             16      8-8-8
...
...
IO... nv12                   3             12      8-8-8
IO... p010le                 3             15      10-10-10

NOTE: When using a different pixel format, usually the following options will need to be set:

  • -vf 'format=nv12' and -profile:v main
  • -vf 'format=p010' and -profile:v main10
  • -vf 'format=p016' and -profile:v rext

Encode with 8-bit

FormatChroma samplingPacked or planarBits per channel
NV124:2:0Planar8
ffmpeg -i "input.mkv" -vaapi_device /dev/dri/renderD128 -vf 'format=nv12,hwupload,scale_vaapi=w=1920:h=1080' -map 0:v -metadata:s:v:0 language=eng -map 0:a -metadata:s:a:0 language=eng -map 0:s? -metadata:s:s:0 language=eng -profile:v main -c:v hevc_vaapi -c:a copy -c:s copy -rc_mode CQP -global_quality 25 -v verbose "output.mkv"
 
ffmpeg -i "input.mkv" -vaapi_device /dev/dri/renderD128 -vf 'format=nv12,hwupload,scale_vaapi=w=1920:h=1080' -map 0:v -metadata:s:v:0 language=eng -map 0:a:m:language:eng? -metadata:s:a:0 language=eng -map 0:s? -metadata:s:s:0 language=eng -profile:v main -c:v hevc_vaapi -c:a copy -c:s copy -rc_mode CQP -global_quality 25 -v verbose "output.mkv"

Encode with 10-bit

FormatChroma samplingPacked or planarBits per channel
P0104:2:0Planar10
ffmpeg -i "input.mkv" -vaapi_device /dev/dri/renderD128 -vf 'format=p010,hwupload,scale_vaapi=w=1920:h=1080' -map 0:v -metadata:s:v:0 language=eng -map 0:a -metadata:s:a:0 language=eng -map 0:s? -metadata:s:s:0 language=eng -profile:v main10 -c:v hevc_vaapi -c:a copy -c:s copy -rc_mode CQP -global_quality 25 -v verbose "output.mkv"
 
ffmpeg -i "input.mkv" -vaapi_device /dev/dri/renderD128 -vf 'format=p010,hwupload,scale_vaapi=w=1920:h=1080' -map 0:v -metadata:s:v:0 language=eng -map 0:a:m:language:eng? -metadata:s:a:0 language=eng -map 0:s? -metadata:s:s:0 language=eng -profile:v main10 -c:v hevc_vaapi -c:a copy -c:s copy -rc_mode CQP -global_quality 25 -v verbose "output.mkv"

Encode with 16-bit

FormatChroma samplingPacked or planarBits per channel
P0104:2:0Planar16
ffmpeg -i "input.mkv" -vaapi_device /dev/dri/renderD128 -vf 'format=p016,hwupload,scale_vaapi=w=1920:h=1080' -map 0:v -metadata:s:v:0 language=eng -map 0:a -metadata:s:a:0 language=eng -map 0:s? -metadata:s:s:0 language=eng -profile:v rext -c:v hevc_vaapi -c:a copy -c:s copy -rc_mode CQP -global_quality 25 -v verbose "output.mkv"
 
ffmpeg -i "input.mkv" -vaapi_device /dev/dri/renderD128 -vf 'format=p016,hwupload,scale_vaapi=w=1920:h=1080' -map 0:v -metadata:s:v:0 language=eng -map 0:a:m:language:eng? -metadata:s:a:0 language=eng -map 0:s? -metadata:s:s:0 language=eng -profile:v rext -c:v hevc_vaapi -c:a copy -c:s copy -rc_mode CQP -global_quality 25 -v verbose "output.mkv"

References

https://trac.ffmpeg.org/wiki/Hardware/VAAPI

https://trac.ffmpeg.org/wiki/Encode/H.265

https://ffmpeg.org/ffmpeg-filters.html