====== 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 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 ====
^Format^Chroma sampling^Packed or planar^Bits per channel^
|NV12|4:2:0|Planar|8|
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 ====
^Format^Chroma sampling^Packed or planar^Bits per channel^
|P010|4:2:0|Planar|10|
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 ====
^Format^Chroma sampling^Packed or planar^Bits per channel^
|P010|4:2:0|Planar|16|
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