2024-08-06, 09:25 PM
(This post was last modified: 2024-11-12, 09:18 PM by TheDreadPirate. Edited 12 times in total.)
****This guide has been updated****
Jellyfin-ffmpeg 7.0.2-4 added a feature to remove Dolby Vision directly. The process of removing Dolby Vision can now be accomplished with a single ffmpeg command, greatly simplifying the process. I am leaving the original walkthrough for those on non-Jellyfin builds of ffmpeg or jellyfin-ffmpeg6.
And that is it. Still no re-encoding required.
A bonus feature: If you do re-encode, to AV1 specifically, you can skip using the bitstream filter entirely. Re-encoding to AV1 will automatically strip the Dolby Vision EL and RPU while maintaining the BT2020 HDR10 color space.
=========================================================================
****Original Walkthrough****
If you've watched HDR content on Jellyfin you've likely struggled with the mish-mash of client/server compatibility that comes with HDR content. Especially with Dolby Vision.
In my quest to encode my entire library with AV1, that required I tackle the issue of Dolby Vision. Both because HDR10 is vastly more compatible (yay open standards) and because AV1 does not officially support these Dolby Vision profiles anyway (AV1 Dolby Vision via Profile 10). To be clear, you can still use HEVC if you haven't gotten on the AV1 bandwagon yet. We're going to focus on simply removing Dolby Vision, which does not require any re-encoding.
For this guide we are focusing on the two more common Dolby Vision profiles: 7.6 and 8.1. Profile 7.6 is used exclusively by 4K HDR Blurays and can only be decoded by Bluray players. To my knowledge, there are no mobile phones or streaming devices that support profile 7.6. Then there's the related profile 8.1.
Both Dolby Vision profiles use HDR10 as their base and add dynamic metadata, a.k.a. enhancement layers, on top of it. A single layer, called the RPU (Reference Picture Unit), for profile 8.1. And two enhancement layers for profile 7.6, RPU and MEL/FEL (minimum or full enhancement layer). Converting Dolby Vision 7.6 and 8.1 to HDR10 simply requires discarding these extra layers.
FFMPEG cannot, by itself, discard Dolby Vision metadata. We will need the aid of an open source app called dovi_tool. I've tested this process in Linux, but both dovi_tool and jellyfin-ffmpeg6 are available on Windows and Mac. You may need to make minor syntax adjustments for Windows and Mac. Vanilla FFMPEG should also work fine.
First we need extract the video and run it through dovi_tool to remove the Dolby Vision layers.
Now we have a naked HDR10 HEVC file with no structure. I tried directly remuxing the video back into the source MKV file, but muxing it into a MP4 container first seemed to work better.
NOW we can remux the new HDR10 video with the original audio and subtitles.
Now we've muxed the HDR10 video with the original audio, subtitles, and chapter markers. Zero re-encoding required.
Jellyfin-ffmpeg 7.0.2-4 added a feature to remove Dolby Vision directly. The process of removing Dolby Vision can now be accomplished with a single ffmpeg command, greatly simplifying the process. I am leaving the original walkthrough for those on non-Jellyfin builds of ffmpeg or jellyfin-ffmpeg6.
Code:
/usr/lib/jellyfin-ffmpeg/ffmpeg -y -hide_banner -stats -fflags +genpts+igndts -loglevel error -i "/path/to/dv_video.mkv" -map 0 -bsf:v hevc_metadata=remove_dovi=1 -codec copy -max_muxing_queue_size 2048 -max_interleave_delta 0 -avoid_negative_ts disabled hdr10_video.mkv
And that is it. Still no re-encoding required.
A bonus feature: If you do re-encode, to AV1 specifically, you can skip using the bitstream filter entirely. Re-encoding to AV1 will automatically strip the Dolby Vision EL and RPU while maintaining the BT2020 HDR10 color space.
=========================================================================
****Original Walkthrough****
If you've watched HDR content on Jellyfin you've likely struggled with the mish-mash of client/server compatibility that comes with HDR content. Especially with Dolby Vision.
In my quest to encode my entire library with AV1, that required I tackle the issue of Dolby Vision. Both because HDR10 is vastly more compatible (yay open standards) and because AV1 does not officially support these Dolby Vision profiles anyway (AV1 Dolby Vision via Profile 10). To be clear, you can still use HEVC if you haven't gotten on the AV1 bandwagon yet. We're going to focus on simply removing Dolby Vision, which does not require any re-encoding.
For this guide we are focusing on the two more common Dolby Vision profiles: 7.6 and 8.1. Profile 7.6 is used exclusively by 4K HDR Blurays and can only be decoded by Bluray players. To my knowledge, there are no mobile phones or streaming devices that support profile 7.6. Then there's the related profile 8.1.
Both Dolby Vision profiles use HDR10 as their base and add dynamic metadata, a.k.a. enhancement layers, on top of it. A single layer, called the RPU (Reference Picture Unit), for profile 8.1. And two enhancement layers for profile 7.6, RPU and MEL/FEL (minimum or full enhancement layer). Converting Dolby Vision 7.6 and 8.1 to HDR10 simply requires discarding these extra layers.
FFMPEG cannot, by itself, discard Dolby Vision metadata. We will need the aid of an open source app called dovi_tool. I've tested this process in Linux, but both dovi_tool and jellyfin-ffmpeg6 are available on Windows and Mac. You may need to make minor syntax adjustments for Windows and Mac. Vanilla FFMPEG should also work fine.
First we need extract the video and run it through dovi_tool to remove the Dolby Vision layers.
Code:
/usr/lib/jellyfin-ffmpeg/ffmpeg -y -hide_banner -loglevel error -stats -i "/path/to/your/DV_video.mkv" -dn -c:v copy -bsf:v hevc_mp4toannexb -f hevc - | dovi_tool remove - -o "hdr10_video.hevc"
Now we have a naked HDR10 HEVC file with no structure. I tried directly remuxing the video back into the source MKV file, but muxing it into a MP4 container first seemed to work better.
Code:
/usr/lib/jellyfin-ffmpeg/ffmpeg -hide_banner -loglevel error -stats -y -fflags +genpts -i "hdr10_video.hevc" -c:v copy "hdr10_video.mp4"
NOW we can remux the new HDR10 video with the original audio and subtitles.
Code:
/usr/lib/jellyfin-ffmpeg/ffmpeg -hide_banner -loglevel error -stats -y -fflags +genpts+igndts -i "hdr10_video.mp4" -i "/path/to/your/DV_video.mkv" -map_chapters 1 -map 0:v -map 1:a -map 1:s -c:v copy -c:a copy -c:s copy -max_muxing_queue_size 2048 -avoid_negative_ts disabled -max_interleave_delta 0 "new_hdr10_video.mkv"
Now we've muxed the HDR10 video with the original audio, subtitles, and chapter markers. Zero re-encoding required.