10 Common Video codecs and How to use them in FFmpeg

By | June 19, 2023

FFmpeg can work with a lot of different codecs for both encoding and decoding video files. It is used as a backend by video editors like Shotcut and media processing library frameworks like MLT Multimedia Framework.

In this post we shall take a look at some of the most commonly used video codecs, their features and how they can be used inside ffmpeg for encoding and decoding videos.

We shall be covering codecs like ut video, mjpeg, prores, dnxhd/hr, h264 (av1), h265 (hevc) etc.

Check Video Details

The ffprobe command can be used to examine the video file details like the current codec, bitrate, resolution etc. The usage is quite simple

ffprobe input_file

So here we have a video file downloaded from youtube. We can check the details using the ffprobe command.

PS C:\videotestsk> ffprobe .\nature_film_4k.webm -hide_banner
Input #0, matroska,webm, from '.\nature_film_4k.webm':
  Metadata:
    ENCODER         : Lavf59.27.100
  Duration: 01:00:25.40, start: -0.007000, bitrate: 16990 kb/s
  Stream #0:0(eng): Video: vp9 (Profile 0), yuv420p(tv, bt709), 3840x2160, SAR 1:1 DAR 16:9, 30 fps, 30 tbr, 1k tbn (default)
    Metadata:
      DURATION        : 01:00:25.367000000
  Stream #0:1(eng): Audio: opus, 48000 Hz, stereo, fltp (default)
    Metadata:
      DURATION        : 01:00:25.401000000
>

Look at the lines titled "Duration" and "Stream". The first stream is usually the video for a video file, while the next stream is the audio. The details for this file can be summarized as follows:

Container: WebM
Codec: VP9
Resolution: 3840x2160
FPS: 30
Bitrate: 16840 kb/s
Duration: 01:00:25
Size: 7.17 GB
Colorspace (Pixel Format): yuv420p(tv, bt709)

The colorspace might be a confusing concept for some of the readers. Check out this detailed guide on ffmpeg on colorspaces.

HDR Video

VLC Player can also show the codec and metadata information of a video file. Simply open the video in vlc player and pause the video. Then click Tools > Codec Information. Or use the keyboard shortcut Ctrl+J.

VLC Player Codec Details - Costa Rica HDR Video

VLC Player Codec Details - Costa Rica HDR Video

The ffprobe output for an hdr video file would look like this:

ffprobe .\costa_rica_4k_60fps_hdr_uhd.webm -hide_banner
Input #0, matroska,webm, from '.\costa_rica_4k_60fps_hdr_uhd.webm':
  Metadata:
    ENCODER         : Lavf59.27.100
  Duration: 00:05:13.80, start: -0.007000, bitrate: 28952 kb/s
  Stream #0:0(eng): Video: vp9 (Profile 2), yuv420p10le(tv, bt2020nc/bt2020/smpte2084), 3840x2160, SAR 1:1 DAR 16:9, 59.94 fps, 59.94 tbr, 1k tbn (default)
    Metadata:
      DURATION        : 00:05:13.780000000
    Side data:
      Content Light Level Metadata, MaxCLL=1100, MaxFALL=180
      Mastering Display Metadata, has_primaries:1 has_luminance:1 r(0.6780,0.3220) g(0.2450,0.7030) b(0.1380 0.0520) wp(0.3127, 0.3290) min_luminance=0.000000, max_luminance=1000.000000
  Stream #0:1(eng): Audio: opus, 48000 Hz, stereo, fltp (default)
    Metadata:
      DURATION        : 00:05:13.801000000
>

The line that indicates hdr is:
yuv420p10le(tv, bt2020nc/bt2020/smpte2084)

Now we shall try to transcode this particular video file using different codecs. We shall convert only a short part (the first 10 seconds: using the ss and t options) to keep the experiments short and simple. If you want to convert a whole video you can remove the -ss and -t options

Using Codecs with FFmpeg

FFmpeg supports a huge number of codecs, however in this post we shall limit ourselves only to some of the popular ones and learn to use them in ffmpeg. If you want to check whether a particular encoder is supported by ffmpeg, use the following command:

> ffmpeg -encoders -hide_banner | findstr /c:"mpeg"
 V.S... ffv1                 FFmpeg video codec #1
 VF.... ffvhuff              Huffyuv FFmpeg variant
 V.S... mpeg1video           MPEG-1 video
 V.S... mpeg2video           MPEG-2 video
 V..... mpeg2_qsv            MPEG-2 video (Intel Quick Sync Video acceleration) (codec mpeg2video)
 V.S... mpeg4                MPEG-4 part 2
 V..... libxvid              libxvidcore MPEG-4 part 2 (codec mpeg4)
 V..... msmpeg4v2            MPEG-4 part 2 Microsoft variant version 2
 V..... msmpeg4              MPEG-4 part 2 Microsoft variant version 3 (codec msmpeg4v3)
>

On linux use the grep command to filter the ffmpeg output.

The codecs we shall be covering in this article include:

  • MPEG-4 (Part 2) / Xvid - Most popular before H.264
  • UT Video - Lossless format. Suitable for video editing
  • MJPEG - Motion JPEG. Intra-frame coding/compression.
  • Apple Prores - Successor of "Apple Intermediate Codec". Suitable profiles for video editing/post production
  • Avid DNxHD / DNxHR - Suitable profiles for editing/post production
  • H.264 - Most widely used standard, supports gpu encoding. Suitable for delivery/distribution
  • H.265 / HEVC - Successor of H.264
  • VP9 - Used by youtube for 4K/8K and HDR videos
  • AV1 - AOMedia Video 1. Successor of VP9. Used by youtube for 4K/8K and HDR videos

1. MPEG-4 (MPEG-4 Part 2)

MPEG-4 (technically MPEG-4 Part 2) was the most widely used video compression format before it was superseded by Mpeg-4 Part 10 (H.264) standard. It was an improvement over the previous standard MPEG-2.

To encode a video using this codec use the following command:

ffmpeg -hide_banner -y -i .\peru-4k-sdr.libx264.mp4 -c:v mpeg4 -ss 0 -t 10  peru-10s.mpeg4.mp4

The MPEG-4 standard defines many different "profiles" like SP (Simple Profile), ASP (Advanced Simple Profile), SSTP (Simple Studio Profile). MPEG-4 supports only 8-bit colors. FFmpeg has a page here explaining quality control parameters for this codec.

Xvid

Xvid is another free and open source video encoding/decoding library that implements the MPEG-4 Part 2 ASP and supported in ffmpeg.

ffmpeg -hide_banner -y -i .\peru-4k-sdr.libx264.mp4 -c:v libxvid -q:v 10 -ss 0 -t 10  peru-10s.libxvid.mp4

I noticed that the nvidia hardware decoder (NVDEC) can decode MPEG-1 and MPEG-2 videos but not MPEG-4 videos. The same can be verified from nvidia's video support matrix data on this page.

2. UT Video

The UT Video codec is an old one and uses minimal compression resulting in large file sizes. It is ideal as a editing format for tools like Shotcut. The container used is avi. We can also use the mkv container with utvideo codec.

ffmpeg -hide_banner -i .\nature_film_4k.webm -c:v utvideo -ss 0 -t 10 .\nature_film_4k.utvideo.avi
ffmpeg -hide_banner -i .\nature_film_4k.webm -c:v utvideo -ss 0 -t 10 .\nature_film_4k.utvideo.avi
Input #0, matroska,webm, from '.\nature_film_4k.webm':
  Metadata:
    ENCODER         : Lavf59.27.100
  Duration: 01:00:25.40, start: -0.007000, bitrate: 16990 kb/s
  Stream #0:0(eng): Video: vp9 (Profile 0), yuv420p(tv, bt709), 3840x2160, SAR 1:1 DAR 16:9, 30 fps, 30 tbr, 1k tbn (default)
    Metadata:
      DURATION        : 01:00:25.367000000
  Stream #0:1(eng): Audio: opus, 48000 Hz, stereo, fltp (default)
    Metadata:
      DURATION        : 01:00:25.401000000
Stream mapping:
  Stream #0:0 -> #0:0 (vp9 (native) -> utvideo (native))
  Stream #0:1 -> #0:1 (opus (native) -> mp3 (libmp3lame))
Press [q] to stop, [?] for help
Output #0, avi, to '.\nature_film_4k.utvideo.avi':
  Metadata:
    ISFT            : Lavf59.27.100
  Stream #0:0(eng): Video: utvideo (ULH0 / 0x30484C55), yuv420p(tv, bt709, progressive), 3840x2160 [SAR 1:1 DAR 16:9], q=2-31, 200 kb/s, 30 fps, 30 tbn (default)
    Metadata:
      DURATION        : 01:00:25.367000000
      encoder         : Lavc59.37.100 utvideo
  Stream #0:1(eng): Audio: mp3 (U[0][0][0] / 0x0055), 48000 Hz, stereo, fltp (default)
    Metadata:
      DURATION        : 01:00:25.401000000
      encoder         : Lavc59.37.100 libmp3lame
frame=  300 fps= 84 q=-0.0 Lsize= 1160072kB time=00:00:10.00 bitrate=949571.4kbits/s speed=2.82x
video:1159884kB audio:157kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.002708%
PS C:\videotestsk>

Duration: 10 seconds.
Size: 1.10 GB.

Pro Tip: If you want to just run a dry test of encoding the video, without actually writing a file, then output the whole thing to null stream and monitor the system resource load. Here is an example:

ffmpeg -hide_banner -i .\nature_film_4k.webm -c:v utvideo -ss 0 -t 10 -f null -

3. MJPEG (Motion JPEG)

In the mjpeg format each frame is compressed a separate jpg frame without any dependency on the previous or next frames (like in IPB compression used in h.264). Its more like an All-I format h.264 file. Consequently the video files are much larger in size, typically 3-5 times larger than an h264 file. Mjpeg is now an old (obsolete ?) codec, with better alternatives available.

Because it uses intra-frame compression and compress lossless-ly, it can be used for video editing purposes. It needs much less cpu processing when decoding.

Containers: Supported containers that can be used with this compression format are avi, mkv and mov. I noticed that if mp4 container is used with this codec, then the videos do not play properly and only the audio plays.

Note: If you want to open mjpeg video files in Davinci, then you must wrap them in mov container.

To use mjpeg codec with ffmpeg use the following command:

ffmpeg -hide_banner -y -i .\nature_film_4k.webm -vcodec mjpeg -ss 0 -t 10 output.mjpeg.avi

Quality Control: The quality can be controlled using the "-q:v" option with values from 1-31. Lower value means higher quality with 1 being the best quality and 31 being the worst.

ffmpeg -hide_banner -y -i .\peru-4k-sdr.libx264.mp4 -c:v mjpeg -q:v 5 .\peru-4k-sdr.mjpeg.qv5.mp4

List of supported options can be viewed with this command:

ffmpeg -h encoder=mjpeg -hide_banner

JPEG2000 - Motion JPEG 2000

This particular codec uses a similar approach to MJPEG. It compresses each frame in a video separately with JPG2000 compression algorithm which is better than MJPEG. It offers better compression with higher quality.

I noticed that it takes a lot more time compared to MJPEG to encode videos.

4. Apple Prores

Its the successor of Apple Intermediate codec and used for post-production editing and used in apps like Final Cut Pro. It has different profiles like ProRes 422 Proxy, ProRes 422 LT, ProRes 422 , ProRes 422 HQ, ProRes 4444. Each profile has different set of features in terms of compression level, alpha channel support, maximum supported resolution etc.

  • ProRes 422 Proxy
  • ProRes 422 LT
  • ProRes 422
  • ProRes 422 HQ
  • ProRes 4444

To learn more about the profiles, check this support page on apple.com

Inside of ffmpeg, there are actually 3 different encoders for prores, namely prores, prores_aw and prores_ks. The prores_ks has most features and we can check the supported options like this:

ffmpeg -h encoder=prores_ks -hide_banner
Encoder prores_ks [Apple ProRes (iCodec Pro)]:
    General capabilities: threads
    Threading capabilities: frame and slice
    Supported pixel formats: yuv422p10le yuv444p10le yuva444p10le
ProRes encoder AVOptions:
  -mbs_per_slice     <int>        E..V....... macroblocks per slice (from 1 to 8) (default 8)
  -profile           <int>        E..V....... (from -1 to 5) (default auto)
     auto            -1           E..V.......
     proxy           0            E..V.......
     lt              1            E..V.......
     standard        2            E..V.......
     hq              3            E..V.......
     4444            4            E..V.......
     4444xq          5            E..V.......
  -vendor            <string>     E..V....... vendor ID (default "Lavc")
  -bits_per_mb       <int>        E..V....... desired bits per macroblock (from 0 to 8192) (default 0)
  -quant_mat         <int>        E..V....... quantiser matrix (from -1 to 6) (default auto)
     auto            -1           E..V.......
     proxy           0            E..V.......
     lt              2            E..V.......
     standard        3            E..V.......
     hq              4            E..V.......
     default         6            E..V.......
  -alpha_bits        <int>        E..V....... bits for alpha plane (from 0 to 16) (default 16)

\...>

Note that 4:2:0 color spaces are not supported by prores. So if you have a video that is already using yuv420p or yuv420p10le, then do not try to convert it to prores as it would lead to deterioration. Use an alternative codec like ut video, mjpeg

Note the list of profile and corresponding numeric id.

To convert a video to prores format we can use a command like this:

ffmpeg -hide_banner -y -i .\nature_film_4k.webm -c:v prores_ks -profile:v hq -ss 20 -t 10 output.prores.mov

Note: that some media players like VLC 3.0.18 cannot play prores video with alpha channel. You can verify that the video is playing fine using ffplay command.

ffplay output.prores.mov -vf "scale=1920:1080"

5. Avid DNxHD / DNxHR

DNxHD falls in the category known as Intermediate (Mezzanine) codecs similar to Prores. It uses less compression making it ideal for editing and color grading in post production. As a rule of thumb, any codec that uses light compression (or can be decompressed quickly without loading the cpu too much) is ideal for editing.

If you work with a dnxhr video in davinci for example, you would notice that you can scrub on the timeline a lot more smoothly in realtime, compared to h264/hevc. This is because for any moment of time, the cpu has to do much less processing to generated the desired frame.

The profiles supported by dnxhd can be listed like this:

PS C:\videotestsk> ffmpeg -h encoder=dnxhd -hide_banner
Encoder dnxhd [VC3/DNxHD]:
    General capabilities: dr1 threads
    Threading capabilities: frame and slice
    Supported pixel formats: yuv422p yuv422p10le yuv444p10le gbrp10le
dnxhd AVOptions:
  -nitris_compat     <boolean>    E..V....... encode with Avid Nitris compatibility (default false)
  -ibias             <int>        E..V....... intra quant bias (from INT_MIN to INT_MAX) (default 0)
  -profile           <int>        E..V....... (from 0 to 5) (default dnxhd)
     dnxhd           0            E..V.......
     dnxhr_444       5            E..V.......
     dnxhr_hqx       4            E..V.......
     dnxhr_hq        3            E..V.......
     dnxhr_sq        2            E..V.......
     dnxhr_lb        1            E..V.......

PS C:\videotestsk>

The profiles are:

Profile Color sampling Description Usage Prores Equivalent
dnxhd For resolution upto 1440x1080
dnxhr_444 4:4:4 Finishing quality 4:4:4 / Cinema Quality Delivery Finishing ProRes 444
dnxhr_hqx 4:2:2 High Quality Extended 10-bit / 4K-UHD broadcast Finishing ProRes 422HQ
dnxhr_hq 4:2:2 High Quality / roughly Mezzanine ProRes 422
dnxhr_sq 4:2:2 Standard Quality / Suitable Delivery/roughly Editing ProRes LT
dnxhr_lb 4:2:2 Low bitrate / Offline quality / roughly Editing ProRes Proxy

Note that dnxhd/hr does not support 4:2:0 color space. So if you have a video that is using pixel format "yuv420p10le" for example, do not try to convert it to dnxhr_* formats since it would try to convert it to 4:2:2 which would result in degradation of the colors

ffprobe .\costa_rica_4k_60fps_hdr_uhd.webm -hide_banner
Input #0, matroska,webm, from '.\costa_rica_4k_60fps_hdr_uhd.webm':
  Metadata:
    ENCODER         : Lavf59.27.100
  Duration: 00:05:13.80, start: -0.007000, bitrate: 28952 kb/s
  Stream #0:0(eng): Video: vp9 (Profile 2), yuv420p10le(tv, bt2020nc/bt2020/smpte2084), 3840x2160, SAR 1:1 DAR 16:9, 59.94 fps, 59.94 tbr, 1k tbn (default)
    Metadata:
      DURATION        : 00:05:13.780000000
    Side data:
      Content Light Level Metadata, MaxCLL=1100, MaxFALL=180
      Mastering Display Metadata, has_primaries:1 has_luminance:1 r(0.6780,0.3220) g(0.2450,0.7030) b(0.1380 0.0520) wp(0.3127, 0.3290) min_luminance=0.000000, max_luminance=1000.000000
  Stream #0:1(eng): Audio: opus, 48000 Hz, stereo, fltp (default)
    Metadata:
      DURATION        : 00:05:13.801000000
PS C:\videotestsk>

Containers: Containers supported MOV or MXF

There is this pdf from avid which explains the codec features in great details. Check page 111. Another resource is here for codec bandwidth details.

With the DNxHD/HR codecs its very important to specify the correct parameters like resolution, frame rate, pixel format and bitrate. Otherwise the encoding would fail to proceed.

For dnxhd the valid bitrate and pixel format information can be retrieved with this dummy command:

ffmpeg -loglevel error -f lavfi -i testsrc2 -c:v dnxhd -f null -
Frame size: 1920x1080p; bitrate: 175Mbps; pixel format: yuv422p10
Frame size: 1920x1080p; bitrate: 185Mbps; pixel format: yuv422p10
Frame size: 1920x1080p; bitrate: 365Mbps; pixel format: yuv422p10
Frame size: 1920x1080p; bitrate: 440Mbps; pixel format: yuv422p10
...

Output a 10 seconds clip of the source video to DNxHR_HQ format.

ffmpeg -hide_banner -y -i .\nature_film_4k.webm -c:v dnxhd -vf "scale=3840:2160,fps=30,format=yuv422p" -profile:v dnxhr_hq -b:v 874M -ss 0 -t 10  output-10s.dnxhr_hq.mov

File Size: 1.01 GB
The file size is going to be big since dnxhr is designed to be an intermediate codec suitable for editing.

Benchmark Runtime: To benchmark the system performance can use the "-benchmark" option and check the runtime.

ffmpeg -hide_banner -y -i .\nature_film_4k.webm -c:v dnxhd -vf "scale=3840:2160,fps=30,format=yuv422p" -profile:v dnxhr_hq -b:v 874M -ss 0 -t 10  output-10s.dnxhr_hq.mov -benchmark

In the output check the rtime field value which indicates the total running time for the transcoding process.

Fun Fact:

The ram consumption during transcoding will depend on the number of available cpu cores. If you have fewer cores, but high ram, then the ram utilization will stay low, since the program cannot spawn multiple threads beyond a certain point.

6. H.264

This is the most popular codec in use today. Technically its known as MPEG-4 Part 10 (AVC). Most video editor applications can export to h.264 and some use this as the default codec for exporting. This codec is primarily designed for high level of compression and distribution. Overall the size of files created with this codec are much smaller compared to other formats discussed above.

Most gpus (infact all modern ones) from nvidia, amd and intel have hardware encoders and decoders for this particular format.

  • Nvidia NVENC/NVDEC
  • AMD AMF
  • Intel Quick Sync

If you have a supporting gpu on your system ffmpeg can use hardware acceleration for both encoding and decoding. Else you can use cpu based encoder/decoder.

On my system i see the support for h264_amf, h264_nvenc encoders as shown below. This means that i can use hardware acceleration for encoding h264 videos.

ffmpeg -codecs -hide_banner | findstr /c:"h264"
 DEV.LS h264                 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (decoders: h264 h264_qsv h264_cuvid ) (encoders: libx264 libx264rgb h264_amf h264_mf h264_nvenc h264_qsv )
...>

Note that libx264 is the cpu based encoder. The following command will encode the video to h264 using cpu based encoder copying the audio codec as it is.

ffmpeg -hide_banner -y -i .\nature_film_4k.webm -c:v libx264 -ss 20 -t 10 output.libx264.mp4

The -profile:v option can be used to specify the profile which can be one of the following:

  • baseline
  • main
  • high

Using the high profile.

ffmpeg -i input.mp4 -c:v libx264 -profile:v high output.mp4

Converting HDR videos: The libx264 cpu based encoder works well with hdr videos as well. HDR videos use a different colorspace and transfer characteristics. Here is a quick example of an hdr video.

ffprobe -hide_banner costa_rica_4k_60fps_hdr_uhd.webm
Input #0, matroska,webm, from 'costa_rica_4k_60fps_hdr_uhd.webm':
  Metadata:
    ENCODER         : Lavf59.27.100
  Duration: 00:05:13.80, start: -0.007000, bitrate: 28952 kb/s
  Stream #0:0(eng): Video: vp9 (Profile 2), yuv420p10le(tv, bt2020nc/bt2020/smpte2084), 3840x2160, SAR 1:1 DAR 16:9, 59.94 fps, 59.94 tbr, 1k tbn (default)
...

Now lets convert it to h264 using the libx264 codec.

ffmpeg -hide_banner -y -i .\costa_rica_4k_60fps_hdr_uhd.webm -c:v libx264 -ss 5 -t 15  costa-10s.libx264.mp4

The output video is compact in size with decent quality and plays fine in vlc player.

Now check the details of the output video costa-10s.libx264.mp4 with ffprobe:

ffprobe -hide_banner  costa-10s.libx264.mp4
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'costa-10s.libx264.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf59.27.100
  Duration: 00:00:15.02, start: 0.000000, bitrate: 10717 kb/s
  Stream #0:0[0x1](eng): Video: h264 (High 10) (avc1 / 0x31637661), yuv420p10le(tv, bt2020nc/bt2020/smpte2084, progressive), 3840x2160 [SAR 1:1 DAR 16:9], 10576 kb/s, 59.94 fps, 59.94 tbr, 19001 tbn (default)
...

As we can see that the colorspace is totally preserved and is the same as the source file: yuv420p10le(tv, bt2020nc/bt2020/smpte2084, progressive)

Encoding with Nvidia NVENC:

Encoding with Nvidia hardware encoder will be significantly faster than the cpu based encoder. Here is a quick example

ffmpeg -hide_banner -y -i .\nature_film_4k.webm -c:v h264_nvenc -ss 0 -t 10 output.h264_nvenc.mp4

File Size: 89MB. Size is very small due to heavy compression (low quality)

The h264_nvenc encoder has the following profiles that control quality and size parameters.

...
  -profile           <int>        E..V....... Set the encoding profile (from 0 to 3) (default main)
     baseline        0            E..V.......
     main            1            E..V.......
     high            2            E..V.......
     high444p        3            E..V.......
...

Lets try a better quality.

ffmpeg -hide_banner -y -i .\nature_film_4k.webm -c:v h264_nvenc -ss 0 -t 10 output.h264_nvenc.mp4

10-bit encoding not supported: There are quite a few drawbacks to the nvidia nvenc hardware encoder. Firstly it does not support 10-bit color spaces like yuv420p10le.

ffmpeg -h encoder=h264_nvenc -hide_banner
Encoder h264_nvenc [NVIDIA NVENC H.264 encoder]:
    General capabilities: dr1 delay hardware
    Threading capabilities: none
    Supported hardware devices: cuda cuda d3d11va d3d11va
    Supported pixel formats: yuv420p nv12 p010le yuv444p p016le yuv444p16le bgr0 bgra rgb0 rgba x2rgb10le x2bgr10le gbrp gbrp16le cuda d3d11
h264_nvenc AVOptions:
  -preset            <int>        E..V....... Set the encoding preset (from 0 to 18) (default p4)
     default         0            E..V.......
     slow            1            E..V....... hq 2 passes
     medium          2            E..V....... hq 1 pass
     fast            3            E..V....... hp 1 pass
     hp              4            E..V.......
...

If you try to convert a video which is encoded with yuv420p10le using this encoder, it will fail with an error message.

> ffmpeg -hide_banner -y -i .\costa_rica_4k_60fps_hdr_uhd.webm -c:v h264_nvenc -b:v 0 -ss 5 -t 15  costa-10s.h264_nvenc.mp4
Input #0, matroska,webm, from '.\costa_rica_4k_60fps_hdr_uhd.webm':
...
  Stream #0:0(eng): Video: vp9 (Profile 2), yuv420p10le(tv, bt2020nc/bt2020/smpte2084), 3840x2160, SAR 1:1 DAR 16:9, 59.94 fps, 59.94 tbr, 1k tbn (default)
...
[h264_nvenc @ 000001263212f080] 10 bit encode not supported
[h264_nvenc @ 000001263212f080] No capable devices found
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
[aac @ 0000012632131580] Qavg: 164.678
[aac @ 0000012632131580] 2 frames left in the queue on closing
Conversion failed!
>

One way to work around this is to specify a pixel format like this:

ffmpeg -hide_banner -y -i .\costa_rica_4k_60fps_hdr_uhd.webm -c:v h264_nvenc -b:v 0 -pix_fmt yuv420p -ss 5 -t 15  costa-10s.h264_nvenc.mp4

H.264 HDR decoding not supported: NVDEC cannot decode hdr videos encoded with h264. So cpu processing will be used to play h264 hdr videos.

Intel Quick Sync:

Intel gpus have the intel quick sync technology that supports encoding and decoding h264 and hevc formats and are usable from within ffmpeg. In a previous article we talked about using intel quick sync with ffmpeg on ubuntu

AMD AMF

AMD cpus on laptops like the 5800H have integrated gpus with encoder modules that can be used to encode to h264. I use them to encode my fortnite gameplay via obs studio which supports using AMD H.264 for hardware accelerated screen capture.

The codec for encoding to h264 with amd hardware acceleration is h264_amf and here is how you would use it

ffmpeg -hide_banner -y -i .\costa_rica_4k_60fps_hdr_uhd.webm -c:v h264_amf -b:v 0 -ss 5 -t 15  costa-10s.h264_amf.mp4

Preserve Quality: Note that setting the bitrate to 0, will preserve the original quality without having to specify any other parameters. This is the same trick that works for nvidia hardware encoder h264_nvenc as well.

Washed out color: In the above example we are converting an hdr video to h264 using the amf hardware encoder. The resulting video will likely have faded/washed out colors. This is because amd gpu encoder does not support the color spaces required for hdr, and will convert to something much poor in visual quality.

Possible Error: In this particular conversion when i verified the generated video file i noticed something unusual. When checking with ffprobe this showed up

> ffprobe  costa-10s.h264_amf.mp4 -hide_banner
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'costa-10s.h264_amf.mp4':
...
  Duration: 00:00:15.02, start: 0.000000, bitrate: 20144 kb/s
  Stream #0:0[0x1](eng): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709/reserved/reserved, progressive), 3840x2160 [SAR 1:1 DAR 16:9], 20006 kb/s, 59.94 fps, 59.94 tbr, 19001 tbn (default)
...

If you note the video stream information we can see that the colorspace has changed quite a bit: yuv420p(tv, bt709/reserved/reserved, progressive)

-pix_fmt = yuv420p
-color_range = tv
-colorspace = bt709
-color_primaries = reserved
-color_trc = reserved

Note that the color_primaries and color_trc is showing reserved. Reserved indicates unsupported or invalid values. In the current context it simply means that the encoder does not support HDR so it will fallback to sdr colorspaces or simply refuse to encode with a "Conversion failed!" message like below.

ffmpeg -hide_banner -y -i .\costa_rica_4k_60fps_hdr_uhd.webm -c:v h264_amf -b:v 0 -vf "colorspace=space=bt709:trc=bt709:primaries=bt709" -pix_fmt yuv420p -ss 5 -t 2  costa-2s.h264_amf.mp4

Output:

> ffmpeg -hide_banner -y -i .\costa_rica_4k_60fps_hdr_uhd.webm -c:v h264_amf -b:v 0 -vf "colorspace=space=bt709:trc=bt709:primaries=bt709" -pix_fmt yuv420p -ss 5 -t 2  costa-2s.h264_amf.mp4
Input #0, matroska,webm, from '.\costa_rica_4k_60fps_hdr_uhd.webm':
  Metadata:
    ENCODER         : Lavf59.27.100
  Duration: 00:05:13.80, start: -0.007000, bitrate: 28952 kb/s
  Stream #0:0(eng): Video: vp9 (Profile 2), yuv420p10le(tv, bt2020nc/bt2020/smpte2084), 3840x2160, SAR 1:1 DAR 16:9, 59.94 fps, 59.94 tbr, 1k tbn (default)
    Metadata:
      DURATION        : 00:05:13.780000000
    Side data:
      Content Light Level Metadata, MaxCLL=1100, MaxFALL=180
      Mastering Display Metadata, has_primaries:1 has_luminance:1 r(0.6780,0.3220) g(0.2450,0.7030) b(0.1380 0.0520) wp(0.3127, 0.3290) min_luminance=0.000000, max_luminance=1000.000000
  Stream #0:1(eng): Audio: opus, 48000 Hz, stereo, fltp (default)
    Metadata:
      DURATION        : 00:05:13.801000000
Stream mapping:
  Stream #0:0 -> #0:0 (vp9 (native) -> h264 (h264_amf))
  Stream #0:1 -> #0:1 (opus (native) -> aac (native))
Press [q] to stop, [?] for help
[Parsed_colorspace_0 @ 0000023088f72280] Unsupported input transfer characteristics 16 (smpte2084)
Error while filtering: Invalid argument
Failed to inject frame into filter network: Invalid argument
Error while processing the decoded data for stream #0:0
[aac @ 0000023088eccb00] Qavg: nan
Conversion failed!
>

The original source file structure was like this:

-pix_fmt = yuv420p10le
-color_range = tv
-colorspace = bt2020nc
-color_primaries = bt2020
-color_trc (color transfer characteristics) = smpte2084

This implies that the amd h264 encoder does not support the color_primary bt2020 (needed for uhd) and color_trc=smpte2084 (perceptual quantizer transfer function needed for HDR)

The resulting video had pale or washed out colors as a result

A possible work around this is to apply filters on the video to convert it from hdr to sdr in order to preserve the colors as close to the original ones as possible.

Here is a possible command:

> ffmpeg -hide_banner -y -i .\costa_rica_4k_60fps_hdr_uhd.webm -vf "zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p" -c:v h264_amf -b:v 0 -ss 5 -t 10 .\costa-10s-sdr.h264_amf.mp4

In the above command the video is passed through a series of filters in chain, that work to convert it from hdr to sdr, and then in the final step it is encoded with h264_amf encoder which produces the final video. With this technique the colors are preserved very well.

Supported Options

Now lets take a quick look at the options supported by h264_amf. Note that it has limited color space support. yuv420p is supported but there is no support for yuv420p10le. This implies that if you try to encode a source video which is in yuv420p10le or any other higher quality pixel format, there will be inevitable loss of color information and quality.

This is one drawback of the amd hardware encoder, that limits its application.

ffmpeg -h encoder=h264_amf -hide_banner
Encoder h264_amf [AMD AMF H.264 Encoder]:
    General capabilities: dr1 delay hardware
    Threading capabilities: none
    Supported hardware devices: d3d11va d3d11va dxva2 dxva2
    Supported pixel formats: nv12 yuv420p d3d11 dxva2_vld
h264_amf AVOptions:
  -usage             <int>        E..V....... Encoder Usage (from 0 to 3) (default transcoding)
     transcoding     0            E..V....... Generic Transcoding
     ultralowlatency 1            E..V.......
     lowlatency      2            E..V.......
     webcam          3            E..V....... Webcam
  -profile           <int>        E..V....... Profile (from 66 to 257) (default main)
     main            77           E..V.......
     high            100          E..V.......
     constrained_baseline 256          E..V.......
     constrained_high 257          E..V.......
  -level             <int>        E..V....... Profile Level (from 0 to 62) (default auto)
     auto            0            E..V.......
     1.0             10           E..V.......
     1.1             11           E..V.......

...

7. HEVC/H.265

This is supposed to be the successor of h264. Supported encoders and decoders in ffmpeg can be checked with the following command.

ffmpeg -encoders -hide_banner | findstr /c:"hevc"
 V....D libx265              libx265 H.265 / HEVC (codec hevc)
 V....D hevc_amf             AMD AMF HEVC encoder (codec hevc)
 V....D hevc_mf              HEVC via MediaFoundation (codec hevc)
 V....D hevc_nvenc           NVIDIA NVENC hevc encoder (codec hevc)
 V..... hevc_qsv             HEVC (Intel Quick Sync Video acceleration) (codec hevc)
>
ffmpeg -encoders -hide_banner | findstr /c:"265"
 V....D libx265              libx265 H.265 / HEVC (codec hevc)
>

The libx265 is the cpu based h.265 encoder. Supported features can be retrieved like this

ffmpeg -h encoder=libx265 -hide_banner
Encoder libx265 [libx265 H.265 / HEVC]:
    General capabilities: dr1 delay threads
    Threading capabilities: other
    Supported pixel formats: yuv420p yuvj420p yuv422p yuvj422p yuv444p yuvj444p gbrp yuv420p10le yuv422p10le yuv444p10le gbrp10le yuv420p12le yuv422p12le yuv444p12le gbrp12le gray gray10le gray12le
libx265 AVOptions:
  -crf               <float>      E..V....... set the x265 crf (from -1 to FLT_MAX) (default -1)
  -qp                <int>        E..V....... set the x265 qp (from -1 to INT_MAX) (default -1)
  -forced-idr        <boolean>    E..V....... if forcing keyframes, force them as IDR frames (default false)
  -preset            <string>     E..V....... set the x265 preset
  -tune              <string>     E..V....... set the x265 tune parameter
  -profile           <string>     E..V....... set the x265 profile
  -udu_sei           <boolean>    E..V....... Use user data unregistered SEI if available (default false)
  -x265-params       <dictionary> E..V....... set the x265 configuration using a :-separated list of key=value parameters

>

Supported chroma color spaces includes 4:2:0, 4:2:2 and 4:4:4 with color depth 8, 10 and 12. This codec has nearly all the features for good compression and delivery read format.

For cpu based encoding VP9 is implemented via the libvpx-vp9 codec in ffmpeg. For gpu based encoding we have hevc_amf (amd), hevc_nvenc(nvidia), hevc_qsv (intel). Encoding in the h265 codec will be slow (when using cpu) since it applies high quality compression.

ffmpeg -hide_banner -y -i .\costa_rica_4k_60fps_hdr_uhd.webm -c:v libx265 -ss 5 -t 15  costa-10s.lib265.mp4

On my system, VLC player could use nvidia rtx3060 laptop for hardware accelerated decoding of h265 video.

Nvidia NVENC: To encode with nvidia nvenc use the following command:

ffmpeg -hide_banner -y -i .\costa_rica_4k_60fps_hdr_uhd.webm -c:v hevc_nvenc -ss 5 -t 15  costa-10s.hevc_nvenc.mp4

To preserve the source quality as close as possible, here is a neat trick that works with hevc_nvenc encoder. Setting the bitrate to 0 makes the encoder automatically follow the source video bitrate as closely as possible, keeping the quality nearly the same as in the source video

ffmpeg -hide_banner -y -i .\costa_rica_4k_60fps_hdr_uhd.webm -c:v hevc_nvenc -b:v 0 -ss 5 -t 15  costa-10s.hevc_nvenc.mp4

8. VP9

This codec was developed by google to compete with the HEVC / H.265 codec and is used to serve HDR and 4k/8k videos on youtube. VP9 is the successor of vp8. To check supported vp9 encoders in ffmpeg, run the following command:

> ffmpeg -encoders -hide_banner | findstr /c:"vp9"
 V....D libvpx-vp9           libvpx VP9 (codec vp9)
 V..... vp9_qsv              VP9 video (Intel Quick Sync Video acceleration) (codec vp9)
>

The first codec, libvpx-vp9 is the cpu based encoder, whereas vp9_qsv is the intel gpu based encoder. On this particular machine I have nvidia rtx 3060 Laptop gpu which supports vp9 decoding only but not encoding. According to the gpu matrix the 4000 series of nvidia gpus have support for av1 encoding which is the successor of vp9.

9. AV1 - AOMedia Video 1

The av1 video codec is a the successor of vp9 and uses containers webm or mkv. Its supports both lossy and lossless encoding modes. Its used by youtube to serve 4k/8k hdr videos.

FFmpeg supports encoding with this codec.

> ffmpeg -encoders -hide_banner | findstr /c:"av1"
 V....D libaom-av1           libaom AV1 (codec av1)
 V....D librav1e             librav1e AV1 (codec av1)
 V..... libsvtav1            SVT-AV1(Scalable Video Technology for AV1) encoder (codec av1)
 A..... wmav1                Windows Media Audio 1
>

As we can see above, there are actually 3 different encoders for this codec namely, aom-av1, rave1e and svtav1. Hardware accelerated av1 encoding is supported only by 4000 series nvidia gpus.

aom-av1

To encode into AV1 format with aom-av1 use the following command:

ffmpeg -hide_banner -y -i .\peru-4k-sdr.libx264.mp4 -c:v libaom-av1 -aom-params lossless=1 "peru-4k-sdr.av1.mp4"

Very Slow Encoding: By default the encoding process with libaom-av1 (cpu based) will be very very slow, and consume a lot of cpu processing power (25-50% on 5800H). To speed up the process set the option "cpu-used" to 8.

ffmpeg -hide_banner -y -i .\peru-4k-sdr.libx264.mp4 -c:v libaom-av1 -cpu-used 8 -ss 0 -t 10 "peru-4k-sdr.av1.webm"

This will speed up and bring down the encoding time to acceptable levels, though it would still be far slower compared to h264. The cpu utilization was low at around 50% when compressing with libaom-av1. Higher utilization might have delivered faster encoding. The algorithm does not seem to be efficient.

rav1e

This librav1e encoder is another alternative, but is slow just like libaom-av1.

ffmpeg -hide_banner -y -i .\peru-4k-sdr.libx264.mp4 -c:v librav1e -ss 0 -t 10 "peru-4k-sdr.librav1e.mp4"

It uses around 10% of the cpu (5800H) by default. Had to use other options to speed the encoding process.

svtav1

The libsvtav1 encoder yielded much better performance and results. The encoding process was fast, like h.264 and cpu usage was high.

ffmpeg -hide_banner -y -i .\peru-4k-sdr.libx264.mp4 -c:v libsvtav1 -speed 10 -ss 0 -t 10 "peru-4k-sdr.libsvtav1.mp4"

Out of the 3, svtav1 seems to be the most practically usable. Handbrake video transcoder also uses svt for av1 encoding.

10. Gopro Cineform

Cineform is another intermediate codec that is designed for video editing, specially high resolution videos. It produces really large size files and use containers like avi and mov.

To convert a video to GoPro CineForm format with ffmpeg use the cfhd codec.

ffmpeg -hide_banner -y -i .\peru-4k-sdr.libx264.mp4 -c:v cfhd -ss 0 -t 10 peru.cform.mov

Hardware Acceleration with Encoders

The following command shows the supported hardware acceleration options available.

> ffmpeg -hwaccels -hide_banner
Hardware acceleration methods:
cuda
dxva2
qsv
d3d11va
opencl
vulkan
>

More details available at this page on ffmpeg.

Note about HDR

If your source video is using HDR, then you will likely run into problems with some codecs that do not support HDR. HDR uses 10-bit colors, bt2020 colorspace and smpte2084 color transfer function, which not all codecs will support. For example h264_amf (amd hardware based encoder does not support it).

CPU based encoders like libx264 or libx265 work best with hdr. So with hdr your codec options are limited.

Any codec or encoder not capable of using hdr file as input, or outputting hdr will either fail to encode or result in an output file with washed out (pale/faded) colors that would look very different from the original source video.

Many more codecs

Here is a bigger list of codecs, many of which we have covered above. Most of these codecs are supported by FFmpeg and other transcoding applications like Handbrake and Shutter Encoder.

Editing Codecs:

DNXHD
DNxHR
Apple Prores
Apple QuickTime Animation
GoPro CineForm
HuffYUV
MJPEG
UT Video

Distribution/Delivery Codecs:

H.264
H.265
VP8
VP9
AV1
OGV
MPEG-4
MPEG-2

Codecs for Storage/Archiving:

FFV1
UT Video

Some Old Codecs:

MPJEG
Xvid
WMV
MPEG-1
DV PAL

Conclusion

Each codec has its own advantages and disadvantages. For example H.264, H.265 provide higher compressions without compromising quality, but consequently need more complex and intensive processing for decoding the video for playback.

On the other side codecs like UT Video, MJPEG generate large sized video files, but require much less cpu power to decode the video. These codecs are ideal for video editing as they load quickly in video editing applications and can handle operations like timeline preview and scrubbing without any lags. These codecs often times use only "intra-frame coding" (each frame is compressed without any dependency on adjacent frames) and are also known as intermediate (Mezzanine) codecs.

Some codecs are more suitable for hdr support and 10/12 bit colors whereas some codecs do not support these features. Some codecs like FFV1 are suitable for video storage at original quality, whereas some are suitable for delivery/distribution and/or live streaming.

Links and Resources

Data on Nvidia NVENC/NVDEC support in various gpus:
https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new

FFmpeg documentation of all codecs:
https://ffmpeg.org/ffmpeg-codecs.html

About Silver Moon

A Tech Enthusiast, Blogger, Linux Fan and a Software Developer. Writes about Computer hardware, Linux and Open Source software and coding in Python, Php and Javascript. He can be reached at [email protected].

Leave a Reply

Your email address will not be published. Required fields are marked *