meta

These are some notes gathered on my exploration of transcoding videos for more reliable playback. This doesn’t cover the downloading of the video files; just post-processing them into different formats for playback, primarily on an Apple TV 4k (2019).

Hardware used:

  • AMD Ryzen 7 3800X 8-Core Processor + NVIDIA GeForce RTX 2060 SUPER
  • 11th Gen Intel(R) Core(TM) i5-11400 @ 2.60GHz + (iGPU)

overview

Most titles downloaded from the internet are h264 encoded, mkv container files. Audio codecs vary and subtitles are complete anarchy.

AppleTV (my primary playback client) can play the h264 encoded stream generally without issue. The remux from MKV to MP4 and audio transcoding generally uses very little cpu on the plex server.

HEVC / h265 can be more space efficient for the same quality, so converting the library to it is worthwhile. However, there are observable limits to how much space can be saved for a given quality level. The main heuristic is thus: if the source file is a high-bitrate, h264 or original iso, then convert to HEVC at about 10mbps (for 1080p).In general, the quality trade off (as well as the energy required to process the transcode) just doesn’t make sense if the file is already below an avg bitrate of 15 mbps. Also, a “how much do i like this movie” factor should be considered for if and how much quality loss is acceptable.

Prefer libx265 (cpu / software) based transcodes to GPU-assisted transcodes. GPU is ideal for real-time transcoding. Although it will take much longer, x265 will yield higher quality at smaller space. Consider GPU transcodes for “less important” titles; i.e., movies and series that don’t need “archival quality”.

Subtitles are … annoying if converting from mkv to mp4. The “other transcoding” script seems to handle this, but because mp4 lacks support for lots of subtitle formats, there are still limitations.

video_transcode tool

This is basically an easier-to-understand wrapper for ffmpeg. Install ruby, then install this with ruby gems. You can just read the script to get a better understanding of all the options and how they map to ffmpeg params.

https://github.com/donmelton/other_video_transcoding

use this script to generate an ffmpeg command that can be executed on another system, if needed.

requires [ffmpeg] , and mkvtoolnix-cli packages

Example with libx265 (software/CPU transcode):

other-transcode \
  --target 12000 \  # there are defaults for each resolution, but imo they're too low
  --x265 \  # change this to VAAPI for gpu hw transcode
  --hevc \  # no point in not doing HEVC 
  --mp4 \   # imo it's widely enough compatible. great for appleTV
  --add-audio all \  # without this, the default will strip out all the extraneous audio
  --add-subtitle eng \
  </path/to/file.mkv> \
  -n # "dry run" (just prints the ffmpeg commmand)mi

Example with iGPU (hardware accelerated transcode):

other-transcode \
  --vaapi \  # this is a reliable api for linux + intel w/ iGPU (QuickSync)
  --target 12000 \  # VAAPI doesn't have an easy equivalent of CRF ; this should be tweaked per title
  --hevc \
  --add-audio all \
  --add-subtitle eng \
  </path/to/file.mkv>  # note: omitted --mp4 here because of subtitle incompatability

[Feb 19, 2022] - there is currently a bug in intel-media-driver that results in corrputed video output when using VAAPI (intel iGPU hw accelerated transcode).

[Feb 20, 2022] - went down the rabbit hole of manually building libva, intel-media-driver (and all intermediate dependencies, yikes!) and ffmpeg with this patch.

example ffmpeg command that is generated:

ffmpeg -loglevel error -stats -vaapi_device /dev/dri/renderD128 \
-i /media/movies/Honeyland\ \(2019\)/Honeyland\ \(2019\)\ Remux-1080p.mkv \
-map 0:0 -filter:v yadif,format\=nv12,hwupload -c:v hevc_vaapi -b:v 9000k \
-color_primaries:v bt709 -color_trc:v bt709 -colorspace:v bt709 \
-metadata:s:v title\= -disposition:v default -map 0:1 -c:a:0 ac3 \
-metadata:s:a:0 title\= -disposition:a:0 default -map 0:2 -c:a:1 aac \
-metadata:s:a:1 title\= -disposition:a:1 0 -sn \
-metadata:g title\= -default_mode passthrough \
Honeyland\ \(2019\)\ Remux-1080p.mkv

general ffmpeg param structure:

ffmpeg -i <input file> \
		-stats \
		-<extra params> \
		<output_file_name>

(likely rare), but remux + transcode BR disk .iso rip:

https://unixsheikh.com/tutorials/remuxing-iso-dvd-or-bluray-using-cat-and-ffmpeg-on-linux.html

essentially, the process is 1) mount the iso, find the correct m2ts file, combine them if necessary, then ffmpeg to package it up into .mkv and transcode if desired. Here’s an example of processing Apollo 11:

ffmpeg -i br/BDMV/STREAM/00006.m2ts -stats -map 0:0 -pix_fmt yuv420p10le -c:v libx265 -x265-params profile=main10:crf=20 -tag:v hvc1 -map 0:a 'Apollo 11 (2019) Remux-2160p.mp4’

using CRF for 4k main10:

nohup ffmpeg -loglevel error -stats -i ../Jojo\ Rabbit\ \(2019\)\ Remux-2160p.mkv \
  -map 0:0 \
  -c:v libx265 -pix_fmt:v yuv420p10le -crf 17 -preset slower \
  -color_primaries:v bt2020 -color_trc:v smpte2084 -colorspace:v bt2020nc \
  -metadata:s:v title\= -disposition:v default \
  -map 0:1 -c:a:0 ac3 -metadata:s:a:0 title\= -disposition:a:0 default \
  -sn -metadata:g title\= -default_mode passthrough \
  Jojo\ Rabbit\ \(2019\)\ Remux-2160p.mkv &

Quality checking the transcoded output is essential.

further reading

https://codecalamity.com/encoding-settings-for-hdr-4k-videos-using-10-bit-x265/ - tl;dr CRF 20 preset slow

Apple TV 4k hevc - Use the -tag:v hvc1 parameter in your FFmpeg command make your HEVC file work on Apple devices.

https://codecalamity.com/stop-re-encoding-videos/

https://slhck.info/video/2017/02/24/crf-guide.html

https://netflixtechblog.com/per-title-encode-optimization-7e99442b62a2 - very interesting. Big takeaways are:

  1. every netflix title is considered to have its own optimal bitrate + quality level for each resolution
  2. Lower resolution + higher precision can result in greater quality than higher res + lower precision, but mostly at the low side of the quality curve.
  3. netflix stores multiple encodes per resolution, per title. Storage tradeoff gives bandwidth + user experience wins

https://gist.github.com/Brainiarc7/95c9338a737aa36d9bb2931bed379219

still TODO / open questions

  • test performance / effect of performing conversion over NFS
    • for the ryzen + Nvidia system, the source file is first copied to the local machine
    • when a 3rd system is used for transcode directly via NFS, CPU on the NFS server rises to about 25% usage!
  • audio codecs
    • probably can find a good preset for “basic 5.1”