I thought that it would be nice to share this not only because it would save others a lot of time figuring out this mess. So if you find something that could be improved or is just wrong, I will happily update this post.
- Introduction
- Step One: MakeMKV
- Step Two: Subtitles and Container Optimisation
- Step Three: Encoding
- Step Four: Library Organisation
- Step Five: Configure Jellyfin 'The Right Way'
- Final Step: Enjoy Your Media
- Code Appendix (Presets)
I spent a lot of time reading all sorts of different blogs, reddit posts, guides etc. and came up with this Media Workflow that I will use from now on to rip and encode my media for use with the wonderfull Jellyfin Media Server. I had three main criteria when doing my research:
- Since I don't have infinite space on my server the file size has to be reasonable.
- I want to keep as much quality and detail as possible while not breaking criteria number one.
- The media has to be compatible for direct play with the most, if possible all devices through one or more clients.
A note on Dolby Atmos and Dolby Vision. While it is technically possible to put those into a
.mp4
container, I was not able to get it to work. Also, Dolby Atmos is often uncompressed and I could not find a way to compress it whithout losing the Dolby Atmos black magic. Today, this is not a concern for me but I would like to make my media future proof so that when the day comes, I have media that supports dynamic HDR metadata and object based audio.
Before we start: I recommend you use Windows for this as it probably is the easier to install and use the software on we are going to use. Not hating Linux here, I'm into it myself.
Step One: MakeMKV
Not much to say here other than please, buy a key! Once you have the software installed, insert a disc and select the files you want to rip. When selecting audio tracks look for terms like True-HD
or DTS
as this will give you the best possible audio most of the time (reddit post). Use the default profile and rip to a .mkv
conainer.
If you have trouble opening an UHD Blu-ray with MakeMKV you might want to look at this forum post and find someone who would sell you a so called UHD Friendly Drive on eBay. Alternatively, if you find your drives model number on the Ultimate UHD Drives Flashing Guide and you feel lucky, you can flash it with a custom firmware that would enable MakeMKV to read any disc. I have had success in flashing an LG-BU40N drive inside a TechPulse120 disc enclosure.
kakarroto007 on reddit suggested I include MKVToolNix in this. It essentially gives you the opportunity to edit what's the default audio or subtitle track plus some other nice features to make your media behave exactly like you would expect it to when you press play. Definitely do this before step three as this software doesn't support mp4
containers.
Skip this part if you don't care about subtitles or you use Open Subtitles.
Use Subtitle Edit to extract Subtitles from your .mkv
file and save it as MEDIAFILENAME.LANGUAGECODE.srt
. Make sure that you select Tesseract
as OCR method
and download the nessesary libraries. You might want it to promt you for words it doesn't know for the first files. I found it really reliable but it sometimes needs help when processing italic text.
You will have to install Handbrake, FastFlix and hdr10plus_tool in order to follow. ffmpeg comes installed with FastFlix I believe.
I use 10-bit encoding on everything. Chris Griffith explains this very well in one of his articles (link to his source). While it doesn't save time, it does save disk space. I don't use hardware encoders for the same reason (for one exception). Downside is, software encoding is very slow. We can save a bit of time by avoiding x265 if possible: DVDs and Blu-rays are AVC (H.264) video, so there is no real benefit from using the x265 encoder. UHD Blu-ray and therefore HDR media uses HEVC (H.265), so defenetly use the x265 encoder here. I prefer crf
over constant bitrate, since the bitrate needed to keep the quality on a constant level varies a lot. I chose a crf
setting of 22
with the slow
preset for all encodings. You might want to choose a lower setting like 20
or 18
if you see a difference.
I also compress audio to aac
to save on disk space. It's not like I can hear the difference between lossless and a 512 bit/s stream. Sure I lose Dolby Atmos or DTS:X but 7.1 is still pretty good.
I did a few testruns with short cuts from MakeMKV rips and was able to shrink the filesize down to about 20 %.
If you have a DVD or Blu-ray source, jump to the Handbrake profile. If not, read further.
The next step depends on the source. We need to know two things: 1. What resolution was the source mastered at? 2. Does it contain HDR10+ or Dolby Vision metadata?
find out what resolution your media was mastered at. Look at the Technical Specifications section on the corresponding IMDb page. At Cinematographic Process you will find a note that says 2k or 4k master format.
While an UHD Blu-ray with a 2k master is only upscaled to 4k, it still is of better quality than the standard Blu-ray. Even after reencoding in 2k resolution. The UHD Blu-ray specifikation requires:
- at least HDR10, most newer movies have HDR10+ and Dolby Vision metatdata included
- 10-bit color space means about 30 % bigger color gamut
- support for 60 frames per second
Personally, I find it easier to do this through WSL. If you are already used to it, I assume you know how to install packages manually and add them to the
PATH
variable.
To find out if your media has HDR10+ metadata, you need to install hdr10plus_tool. Make sure that you add it to the PATH
variable (how to do I do this?). If you already installed FastFlix, it should also have installed ffmpeg for you. If not, install manually and also don't forget to add it to the PATH
variable (guide).
From now on, this section follows this guide by Chris Griffith.
Now that you have everything you need to find out if your media has HDR10+ metadata, open a Command Promt Window (I like to use Windows Terminal) and run this command:
ffmpeg -loglevel panic -i FILENAMEHERE.mkv -c:v copy -vbsf hevc_mp4toannexb -f hevc - | hdr10plus_tool --verify extract -
Another way to find out if your media has HDR10+ metadata is to search it on blu-ray.com. Although you can't know for sure unless you ask the command line. Now choose your preset unless you are interested in Dolby Vision.
I know, ffmpeg 5.0+ can do Dolby Vision but only through the -v:c copy
option which will leave the video stream as is and does not copy the enhancement layer (which is the whole point since it alone contains all the dynamic metadata. Read the Dolby Vision Specifications). After all, I am going through all this effort, because I want to reduce filesize. But there is another way. First, find out if your media contains Dolby Vision layers. Mediainfo is a great tool for that.
mediainfo FILENAMEHERE.mkv
This will produce something like this (I have shortened it to the relevant information):
General
Unique ID : 235157854891415310469122651174257647686 (0xB0E9C16478B8E96A4E98F0CC0FDD6046)
Complete name : Dune_t00.mkv
Format : Matroska
Format version : Version 2
File size : 73.5 GiB
Duration : 2 h 35 min
Overall bit rate mode : Variable
Overall bit rate : 67.7 Mb/s
Movie name : Dune
Encoded date : UTC 2022-02-03 12:54:58
Writing application : MakeMKV v1.16.5 win(x64-release)
Writing library : libmakemkv v1.16.5 (1.3.10/1.5.2) win(x64-release)
Video
ID : 1
ID in the original source medium : 4113 (0x1011)
Format : HEVC
Format/Info : High Efficiency Video Coding
Format profile : Main 10@L5.1@High
HDR format : Dolby Vision, Version 1.0, dvhe.07.06, BL+EL+RPU, Blu-ray compatible / SMPTE ST 2086, HDR10 compatible
Codec ID : V_MPEGH/ISO/HEVC
Duration : 2 h 35 min
Bit rate : 59.8 Mb/s
Width : 3 840 pixels
Height : 2 160 pixels
Display aspect ratio : 16:9
Frame rate mode : Constant
Frame rate : 23.976 (24000/1001) FPS
Color space : YUV
Chroma subsampling : 4:2:0 (Type 2)
Bit depth : 10 bits
Bits/(Pixel*Frame) : 0.300
Stream size : 64.9 GiB (88%)
Language : English
Default : No
Forced : No
Color range : Limited
Color primaries : BT.2020
Transfer characteristics : PQ
Matrix coefficients : BT.2020 non-constant
Mastering display color primaries : Display P3
Mastering display luminance : min: 0.0050 cd/m2, max: 4000 cd/m2
Maximum Content Light Level : 787 cd/m2
Maximum Frame-Average Light Level : 239 cd/m2
Original source medium : Blu-ray
Notice the line HDR format
. This tells us that this container has indeed Dolby Vision with a base layer (BC), enhancement layer (EL) and RPU. And also that it is Profile 7. I found this article pretty helpful. You can always refer to the Dolby Vision Specifications. About dvhe.07.06
it says: This string represents a dual-layer Blu-ray HDR10 compatible Dolby Vision stream encoded as 10-bit HEVC video with a pixel rate that does not exceed 299,065,600 pixels/sec (for example, 3840 × 2160 at 24 fps).
- UHD Blu-ray, 2k Master, HDR10
- UHD Blu-ray, 4k Master, HDR10
- UHD Blu-ray, any Master, HDR10+
- UHD Blu-ray, any Master, Dolby Vision
Organise your media according to the Jellyfin Documentation and don't forget to include your subtitle files.
- to reduce server load: configure Hardware Acceleration
- use the right clients: use clients that are compatible with your media so that your server doesn't have to transcode in the first place
- disallow transcoding for certain users. Find this setting in
Administration -> Users -> USERNAME -> Media Playback
. I don't know how that plays out for tone mapping...
A video stream can only be either SDR or HDR. If it's HDR, it's HDR10. HDR10+ video is simply HDR10 video with HDR10+ metadata. So no difference in the video itself. This means that if the client cannot display HDR10, it won't most certainly do nothing with any HDR related metadata. So, as long as either Jellyfin or your client takes care of tone mapping, it will be fine.
A note on tone mapping: I have tried different ways to do this with MPV (Jellyfin Media Player is essentially the same thing whith the web client strapped to it) but they all look like poop. Pink spots everywhere. So now I keep one SDR and one HDR version of a movie (UHD Blu-rays often include a regular Blu-ray).Thanks to TheLegendaryCat on Reddit for giving me a headsup on this. I compared a few encodes with the sourcemkv
container and found that the Interlace recognition or Deinterlace in Handbrake must have caused this. These filters are set by default and I saw no reason to disable them. Well, now I know better. Now, without any tweaking, tone mapping looks good!
I was very specific about the word 'devices'. For example: I have a Samsung Tablet and the Android client is not compatible with HEVC media. I was able to solve this by changing a setting in the client settings. Whenever I play media through Jellyfin on my tablet now, it uses the tablet's media player, not the media player inside the Jellyfin Android client.
Cheers!
{
"PresetList": [
{
"AlignAVStart": true,
"AudioCopyMask": [],
"AudioEncoderFallback": "av_aac",
"AudioLanguageList": [
"eng",
"deu"
],
"AudioList": [
{
"AudioBitrate": 0,
"AudioCompressionLevel": 0,
"AudioEncoder": "copy",
"AudioMixdown": "none",
"AudioNormalizeMixLevel": false,
"AudioSamplerate": "auto",
"AudioTrackQualityEnable": false,
"AudioTrackQuality": 5,
"AudioTrackGainSlider": 0,
"AudioTrackDRCSlider": 0
}
],
"AudioSecondaryEncoderMode": true,
"AudioTrackSelectionBehavior": "all",
"ChapterMarkers": true,
"ChildrenArray": [],
"Default": true,
"FileFormat": "av_mp4",
"Folder": false,
"FolderOpen": false,
"Mp4HttpOptimize": true,
"Mp4iPodCompatible": false,
"PictureAutoCrop": true,
"PictureBottomCrop": 42,
"PictureLeftCrop": 0,
"PictureRightCrop": 0,
"PictureTopCrop": 42,
"PictureDARWidth": 1998,
"PictureDeblockPreset": "off",
"PictureDeblockTune": "medium",
"PictureDeblockCustom": "strength=strong:thresh=20:blocksize=8",
"PictureDeinterlaceFilter": "off",
"PictureCombDetectPreset": "off",
"PictureCombDetectCustom": "",
"PictureDeinterlaceCustom": "",
"PictureDenoiseCustom": "",
"PictureDenoiseFilter": "off",
"PictureDenoisePreset": "light",
"PictureDenoiseTune": "none",
"PictureSharpenCustom": "",
"PictureSharpenFilter": "off",
"PictureSharpenPreset": "medium",
"PictureSharpenTune": "none",
"PictureDetelecine": "off",
"PictureDetelecineCustom": "",
"PictureColorspacePreset": "off",
"PictureColorspaceCustom": "",
"PictureChromaSmoothPreset": "off",
"PictureChromaSmoothTune": "none",
"PictureChromaSmoothCustom": "",
"PictureItuPAR": false,
"PictureKeepRatio": true,
"PictureLooseCrop": false,
"PicturePAR": "auto",
"PicturePARWidth": 180,
"PicturePARHeight": 173,
"PictureWidth": 1920,
"PictureHeight": 1080,
"PictureUseMaximumSize": true,
"PictureAllowUpscaling": false,
"PictureForceHeight": 0,
"PictureForceWidth": 0,
"PicturePadMode": "none",
"PicturePadTop": 0,
"PicturePadBottom": 0,
"PicturePadLeft": 0,
"PicturePadRight": 0,
"PresetName": "DVD/Blu-ray",
"Type": 1,
"SubtitleAddCC": false,
"SubtitleAddForeignAudioSearch": false,
"SubtitleAddForeignAudioSubtitle": false,
"SubtitleBurnBehavior": "none",
"SubtitleBurnBDSub": false,
"SubtitleBurnDVDSub": false,
"SubtitleLanguageList": [],
"SubtitleTrackSelectionBehavior": "none",
"VideoAvgBitrate": 0,
"VideoColorMatrixCode": 0,
"VideoEncoder": "x264_10bit",
"VideoFramerateMode": "vfr",
"VideoGrayScale": false,
"VideoScaler": "swscale",
"VideoPreset": "slow",
"VideoTune": "",
"VideoProfile": "auto",
"VideoLevel": "auto",
"VideoOptionExtra": "",
"VideoQualityType": 2,
"VideoQualitySlider": 22,
"VideoQSVDecode": true,
"VideoQSVAsyncDepth": 0,
"VideoTwoPass": true,
"VideoTurboTwoPass": false,
"x264UseAdvancedOptions": false,
"PresetDisabled": false,
"MetadataPassthrough": true
}
],
"VersionMajor": 47,
"VersionMicro": 0,
"VersionMinor": 0
}
Once you're done encoding, go to Step Four.
{
"PresetList": [
{
"AlignAVStart": true,
"AudioCopyMask": [],
"AudioEncoderFallback": "av_aac",
"AudioLanguageList": [
"eng",
"deu"
],
"AudioList": [
{
"AudioBitrate": 0,
"AudioCompressionLevel": 0,
"AudioEncoder": "copy",
"AudioMixdown": "none",
"AudioNormalizeMixLevel": false,
"AudioSamplerate": "auto",
"AudioTrackQualityEnable": false,
"AudioTrackQuality": 5,
"AudioTrackGainSlider": 0,
"AudioTrackDRCSlider": 0
}
],
"AudioSecondaryEncoderMode": true,
"AudioTrackSelectionBehavior": "all",
"ChapterMarkers": true,
"ChildrenArray": [],
"Default": false,
"FileFormat": "av_mp4",
"Folder": false,
"FolderOpen": false,
"Mp4HttpOptimize": true,
"Mp4iPodCompatible": false,
"PictureAutoCrop": true,
"PictureBottomCrop": 42,
"PictureLeftCrop": 0,
"PictureRightCrop": 0,
"PictureTopCrop": 42,
"PictureDARWidth": 1998,
"PictureDeblockPreset": "off",
"PictureDeblockTune": "medium",
"PictureDeblockCustom": "strength=strong:thresh=20:blocksize=8",
"PictureDeinterlaceFilter": "off",
"PictureCombDetectPreset": "off",
"PictureCombDetectCustom": "",
"PictureDeinterlaceCustom": "",
"PictureDenoiseCustom": "",
"PictureDenoiseFilter": "off",
"PictureDenoisePreset": "light",
"PictureDenoiseTune": "none",
"PictureSharpenCustom": "",
"PictureSharpenFilter": "off",
"PictureSharpenPreset": "medium",
"PictureSharpenTune": "none",
"PictureDetelecine": "off",
"PictureDetelecineCustom": "",
"PictureColorspacePreset": "off",
"PictureColorspaceCustom": "",
"PictureChromaSmoothPreset": "off",
"PictureChromaSmoothTune": "none",
"PictureChromaSmoothCustom": "",
"PictureItuPAR": false,
"PictureKeepRatio": true,
"PictureLooseCrop": false,
"PicturePAR": "auto",
"PicturePARWidth": 180,
"PicturePARHeight": 173,
"PictureWidth": 1920,
"PictureHeight": 1080,
"PictureUseMaximumSize": true,
"PictureAllowUpscaling": false,
"PictureForceHeight": 0,
"PictureForceWidth": 0,
"PicturePadMode": "none",
"PicturePadTop": 0,
"PicturePadBottom": 0,
"PicturePadLeft": 0,
"PicturePadRight": 0,
"PresetName": "UHD Blu-ray 2k Master HDR10",
"Type": 1,
"SubtitleAddCC": false,
"SubtitleAddForeignAudioSearch": false,
"SubtitleAddForeignAudioSubtitle": false,
"SubtitleBurnBehavior": "none",
"SubtitleBurnBDSub": false,
"SubtitleBurnDVDSub": false,
"SubtitleLanguageList": [],
"SubtitleTrackSelectionBehavior": "none",
"VideoAvgBitrate": 0,
"VideoColorMatrixCode": 0,
"VideoEncoder": "x265_10bit",
"VideoFramerateMode": "vfr",
"VideoGrayScale": false,
"VideoScaler": "swscale",
"VideoPreset": "slow",
"VideoTune": "",
"VideoProfile": "auto",
"VideoLevel": "auto",
"VideoOptionExtra": "",
"VideoQualityType": 2,
"VideoQualitySlider": 22,
"VideoQSVDecode": true,
"VideoQSVAsyncDepth": 0,
"VideoTwoPass": false,
"VideoTurboTwoPass": false,
"x264UseAdvancedOptions": false,
"PresetDisabled": false,
"MetadataPassthrough": true
}
],
"VersionMajor": 47,
"VersionMicro": 0,
"VersionMinor": 0
}
Once you're done encoding, go to Step Four.
A note on this one: I tend to use hardware encoding with 4k media despite the larger filesize. It just takes too long with software encoding on my hardware.
{
"PresetList": [
{
"AlignAVStart": true,
"AudioCopyMask": [],
"AudioEncoderFallback": "av_aac",
"AudioLanguageList": [
"eng",
"deu"
],
"AudioList": [
{
"AudioBitrate": 0,
"AudioCompressionLevel": 0,
"AudioEncoder": "copy",
"AudioMixdown": "none",
"AudioNormalizeMixLevel": false,
"AudioSamplerate": "auto",
"AudioTrackQualityEnable": false,
"AudioTrackQuality": 5,
"AudioTrackGainSlider": 0,
"AudioTrackDRCSlider": 0
}
],
"AudioSecondaryEncoderMode": true,
"AudioTrackSelectionBehavior": "all",
"ChapterMarkers": true,
"ChildrenArray": [],
"Default": false,
"FileFormat": "av_mp4",
"Folder": false,
"FolderOpen": false,
"Mp4HttpOptimize": true,
"Mp4iPodCompatible": false,
"PictureAutoCrop": true,
"PictureBottomCrop": 42,
"PictureLeftCrop": 0,
"PictureRightCrop": 0,
"PictureTopCrop": 42,
"PictureDARWidth": 3840,
"PictureDeblockPreset": "off",
"PictureDeblockTune": "medium",
"PictureDeblockCustom": "strength=strong:thresh=20:blocksize=8",
"PictureDeinterlaceFilter": "off",
"PictureCombDetectPreset": "off",
"PictureCombDetectCustom": "",
"PictureDeinterlaceCustom": "",
"PictureDenoiseCustom": "",
"PictureDenoiseFilter": "off",
"PictureDenoisePreset": "light",
"PictureDenoiseTune": "none",
"PictureSharpenCustom": "",
"PictureSharpenFilter": "off",
"PictureSharpenPreset": "medium",
"PictureSharpenTune": "none",
"PictureDetelecine": "off",
"PictureDetelecineCustom": "",
"PictureColorspacePreset": "off",
"PictureColorspaceCustom": "",
"PictureChromaSmoothPreset": "off",
"PictureChromaSmoothTune": "none",
"PictureChromaSmoothCustom": "",
"PictureItuPAR": false,
"PictureKeepRatio": true,
"PictureLooseCrop": false,
"PicturePAR": "auto",
"PicturePARWidth": 1,
"PicturePARHeight": 1,
"PictureWidth": 3840,
"PictureHeight": 2160,
"PictureUseMaximumSize": true,
"PictureAllowUpscaling": false,
"PictureForceHeight": 0,
"PictureForceWidth": 0,
"PicturePadMode": "none",
"PicturePadTop": 0,
"PicturePadBottom": 0,
"PicturePadLeft": 0,
"PicturePadRight": 0,
"PresetName": "UHD Blu-ray 4k Master HDR10",
"Type": 1,
"SubtitleAddCC": false,
"SubtitleAddForeignAudioSearch": false,
"SubtitleAddForeignAudioSubtitle": false,
"SubtitleBurnBehavior": "none",
"SubtitleBurnBDSub": false,
"SubtitleBurnDVDSub": false,
"SubtitleLanguageList": [],
"SubtitleTrackSelectionBehavior": "none",
"VideoAvgBitrate": 0,
"VideoColorMatrixCode": 0,
"VideoEncoder": "qsv_h265_10bit",
"VideoFramerateMode": "vfr",
"VideoGrayScale": false,
"VideoScaler": "swscale",
"VideoPreset": "quality",
"VideoTune": "",
"VideoProfile": "auto",
"VideoLevel": "auto",
"VideoOptionExtra": "",
"VideoQualityType": 2,
"VideoQualitySlider": 22,
"VideoQSVDecode": true,
"VideoQSVAsyncDepth": 0,
"VideoTwoPass": false,
"VideoTurboTwoPass": false,
"x264UseAdvancedOptions": false,
"PresetDisabled": false,
"MetadataPassthrough": true
}
],
"VersionMajor": 47,
"VersionMicro": 0,
"VersionMinor": 0
}
Once you're done encoding, go to Step Four.
Unfortunately, I have found no 'nice' way (%APPDATA%\FastFlix\fastflix.yaml
) of exporting and importing presets in FastFlix, so you will have to make and save your own preset.
- Set the encoder to
x265
. - Dependent on the master format, set the resolution width to
1920
or3840
but keep the aspect ratio. - In the Quality tab
slow
preset10-bit
bit depth- CRF
22
- check
HDR10+ Optimizations
- browse your
metadata.json
file
- In the Advanced tab: set HDR -> SDR Tone Map to
none
- Select audio tracks and disable subtitles.
Once you're done encoding, go to Step Four.
Please refer to Chris Griffith's Guide on how to do this. I have chosen not to do this and spend my time on something else.
Once you're done encoding, go to Step Four.