Table of Contents

Final Rendering with libx264 and ffmpeg

Whether you are working with Ffmepg, Avidemux or Olive Video Editor, you should be wondering what parameters to use to final render a video montage. Here are my choices for some specific purpose.

Encoding for High Definition Video

There is no standardized meaning for high-definition, generally the minimum standard is 720p, a progressive HD signal where each frame is sized 1280×720 pixels. Many mid-sized TV sets produced in the early 2000s, known as HD Ready, were capable of 1280×720, 1360×768 or 1366×768. The next evolution step, called Full HD or 1080p, have a frame size of 1920×1080 is common in interlaced or progressive mode.

At first we aimed to produce videos for the entry level High Definition Video, so we choosed a target resolution of 1366×768 pixel. After all, we have a 32-inch television capable only of 1366×768 pixels.

Our main source of videos is the Xiaomi Yi action camera, which records full HD videos 1920×1080 pixels at a variable bitrate of 12.0 Mb/s. So we re-encode the final montage with the following settings:

Video codec MPEG-4 AVC (x264)
Video filter swresize, 1366×768, Bilinear
Basic x264 Preset: slow (or less), Tuning: film, Profile: High, IDC Level: Auto
Video encoding Average Bitrate (Two Pass), Average Bitrate 4096 kb/s (about 1.8 Gb per hour)
Pixel format Our source videos use yuvj420p pixel format, so we use the same for the final rendering (see the considerations below).
Bits per sample Our source videos use 8 bits per raw sample, so we stay on this.
Color range We use the full range of colors. The j letter in the yuvj420p pixel format means that YUV values are stored as full 0-255 range (8 bits), as in JPEG. This is better than the so called studio swing, with Y in the 16-235 range and UV in the 16-240 range.
Audio codec Lame MP3 Vorbis
Audio bitrate CBR 192 (or higher)

We can use Avidemux to make the final rendering (re-encoding). For a command line only solution you can consider ffmpeg to perfomr the re-encoding and to make the merge (mux) all into a Matroska container.

#!/bin/sh
TITLE="Balcani, maggio 2022"
ffmpeg \
    -i "video-high-quality.mkv" \
    -i 'audio-music.ogg' -i 'audio-live.ogg' \
    -map '0:v:0' -map '1:a:0' -map '2:a:0' \
    -metadata title="$TITLE" -metadata:s:v:0 title="$TITLE" \
    -metadata:s:a:0 title="Accompagnamento musicale" \
    -metadata:s:a:1 title="Audio in presa diretta" \
    -filter:v "scale=1366x768" -aspect "16:9" \
    -vcodec 'libx264' -pix_fmt 'yuvj420p' -preset 'veryslow' -tune 'film' -profile:v 'high' -level:v 5 \
    -b:v 4M -maxrate:v 6M -bufsize:v 6M \
    -acodec copy \
    "2022-05_balcani.mkv"

Notice that we selected a target bitrate of 4 Mbps and a maximum bitrate of 6 Mbps. Sepcifying both the bitrate and the max bitrate tolerance requires also to specify a buffer size; ffmpeg will re-adjust the bitrate on each buffer size, so if the buffer size is equal to the max rate, ffmpeg will re-calculate the bitrate at least every second.

A warning about the H.264 profile level

It turned out that Kodi 19.4 (running on a Raspberry Pi 4 with Raspbian GNU/Linux 11 Bullseye o.s.) has some problems playing H.264 video files depending on the video format profile used for the encoding. The video actually starts to play, but nothing is seen on the screen; sometimes the screen goes totally green. Similarly a Google TV with Kodi 21.0 has problems with the same files, showing stuttering and video artifacts.

Here it is a table of playing capabilities based on experimental testing:

Format profile Resolution Mbps Can play on Kodi
High@L5 1366×768 4 yes
High@L4 1920×1080 6 Yes
High@L4.1 1920×1080 6 Yes
High@5 1920×1080 4 No
High@5 1920×1080 6 No

Two pass encoding

Here it is a recipe of two-pass encoding from an high quality master produced with Olive Video Editor. The target video will be a 6 Mbit stream, 1920×1080@30. The profile level selected is High@L4.1, so that the video will play nicely with Kodi 19.4 on the Raspberry Pi 4:

TITLE='Marocco - Maggio 2024'
ffmpeg \
    -i full32bit-veryslow-crf18-fullcolor.mkv \
    -metadata title="$TITLE" -metadata:s:v:0 title="$TITLE" \
    -vcodec 'libx264' -pix_fmt 'yuvj420p' -preset 'veryslow' -tune 'film' \
    -profile:v 'high' -level:v 4.1 \
    -b:v 6M -maxrate:v 9M -bufsize:v 18M \
    -x264-params 'keyint=64' \
    -an \
    -pass 1 \
    -f matroska -y /dev/null
# First pass produces two files: ffmpeg2pass-0.log and ffmpeg2pass-0.log.mbtree.
ffmpeg \
    -i full32bit-veryslow-crf18-fullcolor.mkv \
    -metadata title="$TITLE" -metadata:s:v:0 title="$TITLE" \
    -vcodec 'libx264' -pix_fmt 'yuvj420p' -preset 'veryslow' -tune 'film' \
    -profile:v 'high' -level:v 4.1 \
    -b:v 6M -maxrate:v 9M -bufsize:v 18M \
    -x264-params 'keyint=64' \
    -an \
    -pass 2 \
    -f matroska marocco-twopass-6max9-level41.mkv

The transcoding works on the video only, suppressing any audio stream (-an option). Using the keyint=64 option will produce a keyframe every 64 frames (about two seconds), this make seeking back and forward in the video more smooth.

Pixel format considerations

We used the yuvj420p pixel format. What does it means?

First of all consider the 420 code; this means tat for each matrix of 4×2 pixels the stream encode all the values for the luminance, only 2 values for the chrominance on the X axis and zero values for the chrominance on the Y axis. This figure explains clearly the 4:4:4, 4:2:2 and 4:2:0 subsampling methods:

Chroma Subsampling

Is file size is not a concern, we might ask ourselves whether a pixel format with less loss of chroma information would be preferable. Obviously is useless to add more chroma information if the final rendering has the same resolution of the original video, but if we are scaling down the video resolution we may retain chroma information using a different pixel format.

The fact is that in movies 4:2:0 is almost lossless visually, which is why it can be found used in Blu-ray discs and a lot of modern video cameras. There is virtually no advantage to using 4:4:4 for consuming video content.

Furthermore, it may happen that some players (software or hardware) are not compatible with pixel formats other than 4:2:0.

How to probe a video

How to get the piexel format:

ffprobe -loglevel error \
    -show_entries stream=pix_fmt \
    -select_streams v YDXJ4050.mp4

How to get the bits per raw sample:

ffprobe -loglevel panic \
    -show_entries stream=bits_per_raw_sample \
    -select_streams v YDXJ4050.mp4 

Web Resources