tl;dr: If you don’t want to do the work by hand on the command line, use FastFlix. If you have any issues, reach out on discord or open a github issue.
I talked about this before with my encoding setting for handbrake post, but there is was a fundamental flaw using Handbrake for HDR 10-bit video….it only has had a 8-bit internal pipeline! It and most other GUIs don’t yet support dynamic metadata, such as HDR10+ or Dolby Vision though.
2021-02 Update: Handbrake’s latest code has HDR10 static metadata support.
Thankfully, you can avoid some hassle and save HDR10 or HDR10+ by using FastFlix instead, or directly use FFmpeg. (To learn about extracting and converting with HDR10+ or saving Dolby Vision by remuxing, skip ahead.) If you want to do the work yourself, here are the two most basic commands you need to save your juicy HDR10 data. This will use the Dolby Vision (profile 8.1) Glass Blowing demo.
Extract the Mastering Display metadata
First, we need to use FFprobe to extract the Mastering Display and Content Light Level metadata. We are going to tell it to only read the first frame’s metadata -read_intervals "%+#1"
for the file GlassBlowingUHD.mp4
If you don’t see metadata in the output, you may need to select a specific stream.
ffprobe -hide_banner -loglevel warning -select_streams v -print_format json -show_frames -read_intervals "%+#1" -show_entries "frame=color_space,color_primaries,color_transfer,side_data_list,pix_fmt" -i GlassBlowingUHD.mp4
A quick breakdown of what we are sending ffprobe
:
-hide_banner -loglevel warning
Don’t display what we don’t need-select_streams v
We only want the details for the video (v
) stream (or use a specific stream)-print_format json
Make it easier to parse-read_intervals "%+#1"
Only grab data from the first frame-show_entries ...
Pick only the relevant data we want-i GlassBlowingUHD.mp4
input (-i
) is our Dobly Vision demo file
That will output something like this:
{ "frames": [ { "pix_fmt": "yuv420p10le", "color_space": "bt2020nc", "color_primaries": "bt2020", "color_transfer": "smpte2084", "side_data_list": [ { "side_data_type": "Mastering display metadata", "red_x": "35400/50000", "red_y": "14600/50000", "green_x": "8500/50000", "green_y": "39850/50000", "blue_x": "6550/50000", "blue_y": "2300/50000", "white_point_x": "15635/50000", "white_point_y": "16450/50000", "min_luminance": "50/10000", "max_luminance": "40000000/10000" }, { "side_data_type": "Content light level metadata", "max_content": 0, "max_average": 0 } ] } ] }
I chose to output it with json
via the -print_format json
option to make it more machine parsible, but you can omit that if you just want the text.
We are now going to take all that data, and break it down into groups of <color abbreviation>(<x>, <y>)
while leaving off the right side of the in most cases*, so for example we combine
red_x
"35400/50000"
and red_y
"14600/50000"
into R(35400,14600)
.
G(8500,39850)B(6550,2300)R(35400,14600)WP(15635,16450)L(40000000, 50)
*If your data for colors is not divided by /50000
or luminescence not divided by 10000
and have been simplified, you will have to expand it back out to the full ratio. For example if yours lists 'red_x': '17/25', 'red_y': '8/25'
you will have to divide 50000
by the current denominator (25
) to get the ratio (2000
) and multiply that by the numerator (17
and 8
) to get the proper R(34000,16000)
.
This data, as well as the Content light level <max_content>,<max_average>
of 0,0
will be fed into the encoder command options.
Convert the video
This command converts only the video, keeping the HDR10 intact. We will have to pass these arguments not to ffmpeg, but to the x265 encoder directly via the -x265-params
option. (If you’re not familiar with FFmpeg, don’t fret. FastFlix, which I talk about later, will do the work for you!)
ffmpeg -i GlassBlowingUHD.mp4 -map 0 -c:v libx265 -x265-params hdr-opt=1:repeat-headers=1:colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc:master-display=G(8500,39850)B(6550,2300)R(35400,14600)WP(15635,16450)L(40000000,50):max-cll=0,0 -crf 20 -preset veryfast -pix_fmt yuv420p10le GlassBlowingConverted.mkv
Let’s break down what we are throwing into the x265-params
:
hdr-opt=1
we are telling it yes, we will be using HDRrepeat-headers=1
we want these headers on every frame as requiredcolorprim
,transfer
andcolormatrix
the same as ffprobe listedmaster-display
this is where we add our color string from abovemax-cll
Content light level data, in our case0,0
During a conversion like this, when a Dolby Vision layer exists, you will see a lot of messages like [hevc @ 000001f93ece2e00] Skipping NAL unit 62
because there is an entire layer that ffmpeg does not yet know how to decode.
For the quality of the conversion, I was setting it to -crf 20
with a -preset veryfast
to convert it quickly without a lot of quality loss. I dig deeper into how FFmpeg handles crf
vs preset
with regards to quality below.
All sound and data and everything will be copied over thanks to the -map 0
option, that is a blanket statement of “copy everything from the first (0 start index) input stream”.
That is really all you need to know for the basics of how to encode your video and save the HDR10 data!
FFmpeg conversion settings
I covered this a bit before in the other post, but I wanted to go through the full gauntlet of preset
s and crf
s one might feel inclined to use. I compared each encoding with the original using VMAF and SSIM calculations over a 11 second clip. Then, I created over a 100 conversions for this single chart, so it is a little cramped:
First takeaways are that there is no real difference between veryslow
and slower
, nor between veryfast
and faster
, as their lines are drawn on top of each other. The same is true for both VMAF
and SSIM
scores.
Second, no one in their right mind would ever keep a recording stored by using ultrafast
. That is purely for real time streaming use.
Now for VMAF scores, 5~6 points away from source is visually distinguishable when watching. In other words it will have very noticeable artifacts. Personally I can tell on my screen with just a single digit difference, and some people are even more sensitive, so this is by no means an exact tell all. At minimum, lets zoom in a bit and get rid of anything that will produce video with very noticeable artifacts.
From these chart, it seems clear that there is obviously no reason whatsoever to ever use anything other than slow
. Which I personally do for anything I am encoding. However, slow
lives up to its namesake.
Encoding Speed and Bitrate
I had to trim off veryslow
and slower
from the main chart to be able to even see the rest, and slow
is still almost three times slower than medium
. All the charts contain the same data, just with some of the longer running presets removed from each to better see details of the faster presets.
Please note, the first three crf
datapoints are little dirty, as the system was in use for the first three tests. However, there is enough clean data to see how that compares down the line.
To see a clearer picture of how long it takes for each of the presets, I will exclude those first three times, and average the remaining data. The data is then compared against the medium
(default) present and the original clip length of eleven seconds.
Preset | Time | vs “medium” | vs clip length (11s) |
ultrafast | 11.204 | 3.370x | 0.982x |
superfast | 12.175 | 3.101x | 0.903x |
veryfast | 19.139 | 1.973x | 0.575x |
faster | 19.169 | 1.970x | 0.574x |
fast | 22.792 | 1.657x | 0.482x |
medium | 37.764 | 1.000x | 0.291x |
slow | 97.755 | 0.386x | 0.112x |
slower | 315.900 | 0.120x | 0.035x |
veryslow | 574.580 | 0.066x | 0.019x |
What is a little scary here is that even with “ultrafast” preset we are not able to get realtime conversion, and these tests were run on a fairly high powered system wielding an i9-9900k! While it might be clear from the crf
graph that slow
is the clear winner, unless you have a beefy computer, it may be a non-option.
Use the slowest preset that you have patience for
FFmpeg encoding guide
Also unlike VBR
encoding, the average bitrate and filesize using crf
will wildly differ based upon different source material. This next chart is just showing off the basic curve effect you will see, however it cannot be compared to what you may expect to see with your file.
The two big jumps are between slow and medium as well as veryfast and superfast. That is interesting because while slow and medium are quite far apart on the VMAF comparison, veryfast
and superfast
are not. I expected a much larger dip from superfast
to ultrafast
but was wrong.
FastFlix, doing the heavy lifting for you!
I have written a GUI program, FastFlix, around FFmpeg and other tools to convert videos easily to HEVC, AV1 and other formats. While I won’t promise it will provide everything you are looking for, it will do the work for you of extracting the HDR10 details of a video and passing them into a FFmpeg command. FastFlix can even handle HDR10+ metadata! It also has a panel that shows you exactly the command(s) it is about to run, so you could copy it and modify it to your hearts content!
If you have any problems with it please help by raising an issue!
Extracting and encoding with HDR10+ metadata
First off, this is not for the faint of heart. Thankfully the newest FFmpeg builds for Windows now support HDR10+ metadata files by default, so this process has become a lot easier. Here is a quick overview how to do it, also a huge shutout to “Frank” in the comments below for this tool out to me!
You will have to download a copy of hdr10plus_tool
from quietviod’s repo.
Check to make sure your video has HDR10+ information it can read.
ffmpeg -loglevel panic -i input.mkv -c:v copy -vbsf hevc_mp4toannexb -f hevc - | hdr10plus_tool --verify -
It should produce a nice message stating there is HDR10+ metadata.
Parsing HEVC file for dynamic metadata… Dynamic HDR10+ metadata detected.
Once you confirmed it exists, extract it to a json file
ffmpeg -i input.mkv -c:v copy -vbsf hevc_mp4toannexb -f hevc - | hdr10plus_tool -o metadata.json -
Option 1: Using the newest FFmpeg
You just need to pass the metadata file via the dhdr10-info
option in the x265-params
. And don’t forget to add your audio and subtitle settings!
ffmpeg.exe -i input.mkv -c:v libx265 -pix_fmt yuv420p10le -x265-params "colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc:master-display=G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1):max-cll=1016,115:hdr10=1:dhdr10-info=metadata.json" -crf 20 -preset medium "output.mkv"
Option 2: (original article) Using custom compiled x265
Now the painful part you’ll have to work on a bit yourself. To use the metadata file, you will need to custom compiled x265 with the cmake option “HDR10_PLUS” . Otherwise when you try to convert with it, you’ll see a message like “x265 [warning]: –dhdr10-info disabled. Enable HDR10_PLUS in cmake.” in the the output, but it will still encode, just without HDR10+ support.
Once that is compiled, you will have to use x265 as part of your conversion pipeline. Use x265 to convert your video with the HDR10+ metadata and other details you discovered earlier.
ffmpeg -loglevel panic -y -i input.mkv -to 30.0 -f yuv4mpegpipe -strict -1 - | x265 - --y4m --crf=20 --repeat-headers --hdr10 --colorprim=bt2020 --transfer=smpte2084 --colormatrix=bt2020nc --master-display="G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1)" --max-cll="1016,115" -D 10 --dhdr10-info=metadata.json output.hevc
Then you will have to use that output.hevc file with ffmpeg to combine it with your audio conversions and subtitles and so on to repackage it.
Saving Dolby Vision
Thanks to Jesse Robinson in the comments, it seems it now may be possible to extract and convert a video with Dolby Vision without the original RPU file. Like the original HDR10+ section, you will need the x265 executable directly, as it does not support that option through FFmpeg
at all. Note I say “saving” and not “converting”, because unless you have the original RPU file for the DV to pass to x265, you’re out of luck as of now and cannot convert the video. The x265 encoder is able to take a RPU file and create a Dolby Vision ready movie. This does require you to have the RPU file for the video.
2022 Update: NVEncC also takes RPU files, and is easier to work with if you have a Nvidia graphics card.
There are a few extra caveats when converting a Dolby Vision file with x265. First you need to use the appropriate 10 or 12 bit version. Second, change pix_fmt
, input-depth
and output-depth
as required. Finally you MUST provide a dobly-vision-profile
level for it to read the RPU as well as enable VBV by providing vbv-bufsize
and vbv-maxrate
(read the x265 command line options to see what settings are best for you.)
ffmpeg -i GlassBlowing.mp4 -f yuv4mpegpipe -strict -1 -pix_fmt yuv420p10le - | x265-10b - --input-depth 10 --output-depth 10 --y4m --preset veryfast --crf 22 --master-display "G(8500,39850)B(6550,2300)R(35400,14600)WP(15635,16450)L(40000000,50)" --max-cll "0,0" --colormatrix bt2020nc --colorprim bt2020 --transfer smpte2084 --dolby-vision-rpu glass.rpu --dolby-vision-profile 8.1 --vbv-bufsize 20000 --vbv-maxrate 20000 glass_dv.hevc
Once the glass_dv.hevc
file is created, you will need to use tsMuxerR
( this version is recommended by some, and the newest nightly is linked below) to put it back into a container as well as add the audio back.
Currently trying to add the FFmpeg 5.0+ supports remuxing with Dolby Vision. You can do with with the “Copy” function in FastFlix or by hand with ffmpeg on command line and glass_dv.hevc
back into a container with FFmpeg or MP4Box will break the Dolby Vision. Hence the need for the special Muxer.-c:v copy
for the video track. Make sure you’re using at minimum 5.0 or it won’t work! This will result in video that has BL+RPU Dolby Vision.
It is possible to also only convert the audio and change around the streams with remuxers. For example tsMuxeR (nightly build, not default download) is popular to be able to take mkv
files that most TVs won’t recognize HDR in, and remux them into into ts
files so they do. If you also have TrueHD
sound tracks, you may need to use eac3to first to break it into the TrueHD
and AC3 Core
tracks before muxing.
Easily Viewing HDR / Video information
Another helpful program to quickly view what type of HDR a video has is MediaInfo. For example here is the original Dolby Vision Glass Blowing video info (some trimmed):
Video ID : 1 Format : HEVC Format/Info : High Efficiency Video Coding Format profile : Main 10@L5.1@Main HDR format : Dolby Vision, Version 1.0, dvhe.08.09, BL+RPU, HDR10 compatible / SMPTE ST 2086, HDR10 compatible Codec ID : hev1 Color space : YUV Chroma subsampling : 4:2:0 (Type 2) Bit depth : 10 bits Color range : Limited Color primaries : BT.2020 Transfer characteristics : PQ Matrix coefficients : BT.2020 non-constant Mastering display color primaries : BT.2020 Mastering display luminance : min: 0.0050 cd/m2, max: 4000 cd/m2 Codec configuration box : hvcC+dvvC
And here it is after conversion:
Video ID : 1 Format : HEVC Format/Info : High Efficiency Video Coding Format profile : Main 10@L5.1@Main HDR format : SMPTE ST 2086, HDR10 compatible Codec ID : V_MPEGH/ISO/HEVC Color space : YUV Chroma subsampling : 4:2:0 Bit depth : 10 bits Color range : Limited Color primaries : BT.2020 Transfer characteristics : PQ Matrix coefficients : BT.2020 non-constant Mastering display color primaries : BT.2020 Mastering display luminance : min: 0.0050 cd/m2, max: 4000 cd/m2
Notice we have lost the Dolby Vision, BL+RPU
information but at least we retained the HDR10 data, which Handbrake can’t do!
That’s a wrap!
Hope you found this information useful, and please feel free to leave a comment for feedback, suggestions or questions!
Until next time, stay safe and love each other!
Appendix: Using a specific stream in the FFprobe command (Not seeing HDR data)
You may have a video with covers or even a second video track, and that could be causing the missing info. First run:
ffmpeg -i <video_name>
It will return a list of streams, for example this one has 4 streams, two of which are considered “video” streams even though the second is an image.
Stream #0:0(eng): Video: hevc (Main 10), yuv420p10le(tv, bt2020nc/bt2020/smpte2084), 3840x2160 [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn Metadata: BPS-eng : 77574554 DURATION-eng : 01:58:18.257833333 NUMBER_OF_FRAMES-eng: 170188 NUMBER_OF_BYTES-eng: 68830515604 SOURCE_ID-eng : 001011 Side data: DOVI configuration record: version: 1.0, profile: 7, level: 6, rpu flag: 1, el flag: 1, bl flag: 1, compatibility id: 6 Stream #0:1(eng): Audio: truehd (Dolby TrueHD + Dolby Atmos), 48000 Hz, 7.1, s32 (24 bit) (default) Metadata: title : Surround 7.1 BPS-eng : 4609091 DURATION-eng : 01:58:18.258333333 NUMBER_OF_FRAMES-eng: 8517910 NUMBER_OF_BYTES-eng: 4089565476 SOURCE_ID-eng : 001100 Stream #0:2(eng): Audio: ac3, 48000 Hz, 5.1(side), fltp, 448 kb/s Metadata: title : Surround 5.1 BPS-eng : 448000 DURATION-eng : 01:58:18.272000000 NUMBER_OF_FRAMES-eng: 221821 NUMBER_OF_BYTES-eng: 397503232 SOURCE_ID-eng : 001100 Stream #0:3(eng): Subtitle: hdmv_pgs_subtitle Metadata: BPS-eng : 44628 DURATION-eng : 01:50:33.939812500 NUMBER_OF_FRAMES-eng: 3576 NUMBER_OF_BYTES-eng: 37007803 SOURCE_ID-eng : 0012A0 Stream #0:4: Video: mjpeg (Baseline), yuvj420p(pc, bt470bg/unknown/unknown), 640x360 [SAR 96:96 DAR 16:9], 90k tbr, 90k tbn (attached pic) Metadata: filename : cover.jpg mimetype : image/jpeg
If I ran the same command as above with -select_streams v
it would return
"frames": [ { "pix_fmt": "yuvj420p", "color_space": "bt470bg" } ] }
So instead, find the number of the track you want to use from the output and change it in the command like call. When the output shows Stream #0:2
for example, that means the first input specified on the command line, as you can open multiple files at once with FFprobe, and the 3rd stream (because it starts at 0). In my case, I want to specify 0
as that is the main video track Stream #0:0(eng): Video: hevc
.
ffprobe -hide_banner -loglevel warning -select_streams 0 -print_format json -show_frames -read_intervals "%+#1" -show_entries "frame=color_space,color_primaries,color_transfer,side_data_list,pix_fmt" -i <video_name>
Your guide is excellent. I felt like I was never explained about the filesize difference between slow and fast, so I didn’t understand the quality compensation. Ever since I’ve been doing Slow at RF20-23 for archival purposes and mobile rips with little compromise. I’m doing a project where I’m trying to batch upload some mobile rips so I’m finding that sweetspot. I find that some frames look a bit poor on dark and specially lit scenes, especially on 720p, with RF23 Slow. I was using RF19 Fast before, though in general, and slow is giving me a great quality output for the filesize. . In general the guide is very useful for anything 1080p+. Slow RF20 is a bit too big for a mobile encode but great for archiving anime, as for well lit scenes I can’t tell the difference with an A/B test even on RF23 in most 1080p scenes, 18 inches from my 22″ monitor. Anime is a bit trickier too and usually needs a lower RF, so it’s very promising overall.
Thanks for the feedback and more info!
I’m honestly surprised at the bad details at RF23 slow with lower resolution, thanks for that heads up. Maybe someday I’ll get around to doing a test like this across more resolutions, though I might recommenced using x264 for anything non HDR as the time to encode isn’t really worth it IMO.
You’re also right that a sample size of a single source isn’t super telling for stuff like anime vs action vs documentary. I find myself using a range of around 16~22CRF depending on source. 16~18 for anime, 20 for most things, then 22 for old / film gray heavy movies (looking at you Ron Howard).
Curious to hear your thoughts on staxrip or any other gui based program besides handbrake. For some of us the cli commands involved here are a bit much to tackle. Have you compared staxrip or tried it for 10bit encoding. I think it has a 10bit pipeline and provides a gui to make things a little easier for those of us that just can’t get used to CLI based tools. Thanks for the guide either way.
I haven’t used staxrip so I can’t verify, but it looks to be a wrapper around FFmpeg (and other tools) like FastFlix does, so if they internally copy the HDR details they may be doing the same thing.
There is a way to extract hdr10+ metadata with hdr10plus_parser.exe by quietvoid from Github.
Then use ffmpeg to extract:
ffmpeg64.exe -i “input.mkv” -c:v copy -vbsf hevc_mp4toannexb -f hevc – | hdr10plus_parser.exe -o metadata.json –
You can reencode with x265 or with special compiled ffmpeg (HDR10_PLUS enabled in cmake)
That could be a game changer, I will have to try that out and update the article, thank you so much!
I used the ffmpeg.exe from StaxRip.
You can find it (and me) on doom9.
Greetz from Germany.
Thanks for the great guide. I’ve been playing with ffmpeg CLI, StaxRip, and FastFlix and am thankful for the simple GUI offerings. I’ve started to test (but am struggling) with VMAF, but still need to work out some of the kinks in compiling windows.
I’ve been encoding my UHD movie library to x265 on an i7-10700 w 64gb of ram, testing RF18 and RF20, fast, medium, and slow presets. To be honest, I don’t see very much difference between them, even on a 110″ screen. The difference in filesize between them is insignificant relative to the total amount of storage needed for 200 UHD movies.
Some of the medium and slow encodes take between 18 and 30 hours. My most recent test, a UHD video, took 5 hours at RF18 Fast (9.8 GB), 5 hours with RF20 Fast (8.3 GB), and 16.5 hours at RF20 Slow preset (9.3 GB). I tested another UHD at RF18 Medium, and it took 10.5 hours, RF18 Fast took 7 hours. RF 18 Slow gave me an ETA of 36 hours, so I aborted that one.
I’m basically stuck in deciding which is the best way to go. RF18 Slow seems to be a bit unreasonable for my purposes. Is there much of a real-world difference between RF18 Fast and RF20 Slow? They seem to give me pretty similar file sizes. Is Medium a happy medium or more of a compromise to both?
Glad to be of any help! Despite the name “Fast” still produces high quality encodings overall. I would always avoid “ultrafast” and “superfast” as they are meant for real-time operations, but anything above that is fair game for storage. Especially when talking about RF20 or above, most videos (*in my own experience) would be hard pressed to see most visual differences. There might be some high motion scenes or particularly in animated videos have a little “blur” effect, but not to the extent you could tell without zooming in.
“Medium” I have found to be a pretty even split between “Fast” and “Slow” in both time and VMAF scores (for a single test video). However, it all comes down to what looks good to you. I doubt most people, including myself, could tell a difference from the couch between RF 18 SLOW and RF 20 FAST. I simply do mine slower for peace of mind more than anything else.
For building FFmpeg for Windows, I personally have done it via a Linux system (not WSL as that has issues), i.e. a virtual machine using https://github.com/rdp/ffmpeg-windows-build-helpers
Good luck with your endeavors, and thanks for commenting!
I have compiled ffmpeg 64 bit with media-autobuild_suite (Win 10) from Github – Zeranoe compatible – and it works now perfectly. HDR10+ and VMAF are enabled.
So you can then convert with the integrated x265 module.
So, interesting result with one movie. I tested with RF20 Fast, RF18 Fast, and RF 18 Medium. The original 4k UHD movie is 75GB.
RF 18 Medium: 27 hours, 95 GB output
RF 18 Fast: 12 hours, 87 GB output
RF 20 Fast: 11.5 hours, 63 GB output.
Other than the RF and preset, all parameters were the same.
“C:\StaxRip\Apps\Encoders\x265\x265.exe –crf 18 –output-depth 10 –master-display “G(13250,34500)B(7500,3000)R(34000,16000) WP(15635,16450)L(10000000,50)” –hdr10 –colorprim bt2020 –colormatrix bt2020nc –transfer smpte2084 –range limited –max-cll “1179,501” –repeat-headers –hrd –aud –frames 252890 –y4m –output “K:\4k UHD\movie.mkv”
This is the only movie, out of about a dozen I’ve tested, where the output was larger than the input. What happened?
The really terse answer is that it has to do with how the QP is calculated based on the CRF may be too high for that particular case. Keep in mind for x265 the CRFs can actually be a lot lower than x264 for same quality. From FFmpeg guide “The default is 28, and it should visually correspond to libx264 video at CRF 23, but result in about half the file size. CRF works just like in x264, so choose the highest value that provides an acceptable quality.”
So it sounds like for that video you will have to drop down to 22 or 24. Can always calculate VMAF to tell a benchmarked difference, but in the end it’s all up to your eyes.
Just I’d let you know that I used FastFlix to generate the command, but updated it to use the NVidia gpu in my system. It reduced the 56GB video down to 6GB, but the artifacts were horrible. I’m running a few more tests to see if there is some way to improve the output from the GPU or if I really do need to stick with CPU only.
On 1080 material, the output from the GPU has been quite good. This is my first time trying 4K material with it.
The options for the nvidia encoder are different than x265, so will take quite a bit of changes. It also does not support HDR10 metadata from what I understand.
View the options with: “ffmpeg -h encoder=hevc_nvenc”
I have done some light playing with it with settings like “-qp 20 -preset slow -tune hq -profile main10” though it may be better to do “-rc vbr_hq” and specify a bitrate instead. I personally would rather encoder at a faster preset with x265 (anything above “superfast”) than hardware accelerated encoding for storage of videos.
After a bit of experimenting with 1080 encoding, I settled on Nvidia crf 18 slow. I sampled 10 movies, CPU vs. GPU crf 18 preset slow. Playing the samples back on a 4k display, I can’t tell enough of a difference to identify which is which.
4K material looked awful looked awful using the same settings (CRF 18, preset slow and add profile main10) on GPU. 4K material looked pretty good with those settings on CPU. Using the settings produced by FastFlix, the 4K sources looked virtually identical to the original.
Thanks to your research, I now have personal “presets” that work for 1080 and 4K/10Bit/HDR material.
Just did my first successful HDR 10+ conversion, but when I did the first one it only had 8bit depth. I had to use “-D10” to get 10 bit.
Was that with
x265
directly I assume? Was the source 8-bit? For ffmpeg, to convert to a different pixel format, specifically 10-bit can use-pix_fmt yuv420p10le
Is there a progress bar or anything I can see that’ll show how long the encode will take?
For FastFlix I have in the backlog to add a ETA timer. For ffmpeg itself, it displays a line like “frame= 275 fps= 61 q=38.1 Lsize= 374kB time=00:00:04.69 bitrate= 653.7kbits/s speed=0.309x” while encoding. You can use the “speed” and divide it by the duration of the entire video. For example if you have a one hour video (60 minutes) and the speed is 0.309 it would equal 60 / 0.309 == 194 minutes for the encoding.
Hi Chris, so do I understand you right, that for x265 setting the quality to 20 (2160p) isn’t necessary for 4k quality and that it can be set lower? I have recently seen an increase in file size of ~100% since going from v2 to v3 of Fastflix but havent had chance to check if this just coincidence and its actually the film in question.
It is totally fine to adjust it as needed, yes, those are just rough guide lines. It really is source and preset dependent. I usually encode stuff with “medium” present anymore as I don’t have time for “slow”. Then with older films that contain a lot of film grain I will usually set it down to 22 before even trying the encode. Sometimes down to 24 for extreme cases.
CRF is just a programmatic guess at quality. So if the film has a lot of tiny changes always happening (i.e. film grain or constant action flix) the encoder will think it’s failing at keeping quality and keep pumping more and more bitrate needlessly at it. Whereas for stuff like animation that doesn’t change large portions of the screen, it’s going “I got this!” and may not put enough work into making sure the few lines that move are crisp.
Hello, thank you for all this explanations. The enconding in x265 is new for me and HDR, so I still don’t exactly understand what is the problem. If I have a video 4k UHD HDR, why can’t I simply rencode with something like that:
ffmpeg -i my_file.mkv -map 0 -c copy -c:v libx265 -preset slow -crf 18 output.mkv
If I understand right, the HDR information are lost. At the moment, I don’t have a device with HDR support, so I can’t check if the HDR is still present in the video after reencoding. So I won’t simply lose some metadata, I will also lose some quality in the video. Right ?
My second question: if I have Dolby Vision in the video or HDR10+, It’s better to avoid a reencoding. Otherwise, those information will be lost. In the future it will be possible but for now it’s better to keep the video unchanged.
Thank you for your help!
You can use a tool like mediainfo to check HDR details. But you are correct, without manually passing those details along, FFmpeg does not currently copy them when re-encoding, check out FastFlix as it will copy those details for you. You are also correct that anytime you re-encode something you lose quality. The only reasons to re-encode videos is either to save on storage space or to support a specific device’s format limitations.
Right now HDR10+ is actually possible to save! For Dolby Vision there is little chance of it ever being able to be-rencoded unless you are the original creator of the video with the RPU file. (Due to how it’s royalty based, that is not likely to change.)
Thank you
what is the problem?
Error while filtering: Cannot allocate memory
Failed to inject frame into filter network: Cannot allocate memory
Error while processing the decoded data for stream #0:0
x265 [info]: frame I: 1, Avg QP:18.39 kb/s: 94.75
x265 [info]: frame P: 2, Avg QP:19.50 kb/s: 18.32
x265 [info]: frame B: 4, Avg QP:22.31 kb/s: 16.35
x265 [info]: Weighted P-Frames: Y:0.0% UV:0.0%
x265 [info]: consecutive B-frames: 25.0% 0.0% 0.0% 0.0% 75.0%
encoded 7 frames in 23.06s (0.30 fps), 28.11 kb/s, Avg QP:20.95
Conversion failed!
Ran out of memory. I am guessing you have some filters applied? I see that most often with the
overlay
filter. What is the full command you are running (can remove file names)?Thanks so much for the info. I have been having washed out colors in all my videos that I encoded with FFMPEG. So I was forced to use Handbrake for everything. By copying the color group data into the encode string, like you showed above, I can finally get the correct color. My only problem now is that I would like to use the hevc_nvenc encoder, but it is not accepting the X265-params color data. Is there another way to pass the correct color data to the NVenc encoder?
The only way I have heard of how to do it is with another tool that adds the HDR10 data back after the video encoding. So would be a three step process of 1. Convert just video to .h265 / .hevc file. 2 Use NV HDR Patcher to add the master-display / CLL data back in. 3. Combine that file with the audio / subtitles you want to transfer or convert from the original source.
I should add that in most cases it’s just better to do libx265 at faster preset than hardware encoding if you’re storing the video, as HW Acceleration is lower quality / higher bitrate primarily meant for streaming.
Thanks, I think I will. I am ripping my movie collection and storing them on a media server. For a 4K UHD movie encoded at 9MB/s, at slow, libx265 only takes about 3 hrs, compared to Handbrake, which was taking a little over 2 days. But hevc_nvenc was taking about an hour, albeit with washed out colors. I can live with 3 hrs if I am getting better quality for my movie library, especially after watching Handbrake take multiple days for 4K and about 24 hrs for a 7MB/s 1080p.
Actually I was wrong about the encode time with libx265. I though that the counter in the DOS box was the elapsed time. It is actually the elapsed time of the movie that has been encoded. If it continues at this pace, it should take around 12 hours to finish the encode.
I was super shocked at the large time difference, so that sounds much better! From some quick googling it looks like NVENC slow is about the same as x265 faster https://www.reddit.com/r/Twitch/comments/c8ec2h/guide_x264_encoding_is_still_the_best_slow_isnt/ So even taking it down to x265 medium should be about 3x faster than slow, and still produce higher quality / lower file size than hardware.
it is difficult to find information about the picture quality of the newer nVidia GFX with Turin encoder and HEVC, especoially NVENC vs. x265. The few I found suggest that it may be not only (much!) faster but even delivers better quality! I am not talking about the older pascal or maxwell encoders. Did you do your tests with a newer card? It would be great to have support for this! the new iiPhones can shoot 4K HDR…
I know that Turing is a lot better, and possibly even on par with x265 slow in bitrate mode. However the two biggest problems I have are that it lacks a CRF mode and doesn’t currently support HDR10 through FFmpeg. For any near real-time time I would suggest hardware encoder, for storage I will stick with software encoders myself.
I do not have that new of a card to test with personally. If anyone feels like providing me hardware I would love to do some analysis between the various H.265 software and hardware options, but I doubt that will ever happen. This site and my projects cost me money to maintain, as I don’t want to profitize them, so I can only really test the software side of things.
thank you for your prompt, kind and detailed reply! Also for your work and superb unique transcoder tool. Yes, all three restrictions seem to be a game-killer for HDR turing hw-transcoding 😦 The best I can offer is to make some test runs with my turing gfx if it helped you and you were interested. Best regards.
I just got my gtx 1650 super and did a test run on the video “crowd run”. maybe interested.
x265 CRF 22 gives VMAF score 98,6 @22,3 MB size
nvenc HW-2pass at 0,15 bits/pixel gives VMAF score 96,1 @20,1 MB size
Great article, thank you! I didn’t suspect that the whole HDR encoding problem is so complex before I tried to reencode HDR10+ movie with SVT-HEVC in ffmpeg (manual patching required). Do you know if it’s technically possible to mux HDR metadata with encoded video stream? I couldn’t find any tools for this task, but if it’s possible in theory then creating such a tool would open a possibility to use any encoder with HDR material.
I do know of https://github.com/SK-Hardwired/nv_hevc_hdr_patcher which should be able to do that to a raw stream. I have not gotten around to testing it myself, so let me know if it works!
Does have the warning: “NOTE: This may not work well with HEVC streams made by x265 (x265 lib) with REPEATING NAL and SEI units! Output stream most probably could be corrupted!”
Have you encountered any issues with 10-bit files and FFProbe not showing the side_data_list information? For 10-bit files (including the linked glass blowing files) its not displaying for me. I tried a few FFProbe builds without success. Works fine for 8-bit videos though.
I have not come across that issue myself, extra worrying that it isn’t a specific ffprobe version. Are you sure you tried the right demo file (from the middle row, profile 8.1), the two top ones for iOS will not list that info.
Hm you are correct I had the wrong video and the 8.1 video does include the metadata. Is there a reason that the other videos don’t report that information? Are they simply missing that metadata and therefore FFProbe can’t report it?
I’m attempting to look into this issue presented here for a script I develop where someone thought it was a 10 bit issue but this sample file seems to prove otherwise
https://github.com/mdhiggins/sickbeard_mp4_automator/issues/1377
Your article here was incredibly helpful for pulling this data and just wanted to say thank you for putting it together
Glad it has helped!
Dolby Vision profile levels are confusing as they come with different information. Profile 5 only comes with Dolby Vision, whereas 8.1 comes with DV + HDR10 information. There is also 8.2 and 8.4 that do not, https://dolby.force.com/professionalsupport/s/article/What-is-Dolby-Vision-Profile?language=en_US.
The file in that issue is reporting it is a “bt.470bg” color space in uncompressed 4:4:4 chroma (yuvj444p), so it does not have HDR10 information (which is for bt.2020 + yuv420p10le). 4:4:4 chroma is usually reserved for content developers, so odd to see it outside that realm, and I do not personally have experience converting that to it’s HDR10 equivalent.
4:4:4 is also what graphics cards / PCs output for monitors. So my guess is someone was doing a raw copy from that, thinking they were getting 4K HDR without really understanding video encoding.
Appreciate you taking a look, that’s a very helpful clarification
Also I noticed a small error in the article where you have the initial parameters listed in the “Extract the Mastering Display metadata” section as
G(8500,39850)B(6550,2300)R(35400,14600)WP(15635,16450)L(50,40000000)
Looks like you switched the min/max luminance here but have it in the correct order later in the article
Great catch, thank you! Updated
Same error on this other article
https://codecalamity.com/hdr-hdr10-hdr10-hlg-and-dolby-vision/
Great read btw
Good eyes! BTW, thought of a quick test to tell if a video is in bt.2020 color space. FFmpeg and VLC do not automatically downmap colors from 10 -> 8 bit when capturing pictures. So take a screenshot with VLC or FFmpeg (
ffmpeg -ss 60 -i GlassBlowing.mp4 -map 0:v -vframes 1 out.jpg
) and if it looks washed out, that means it’s using the expected bt.2020 color space. That trick does not tell you if it has HDR10 info, but it’s a quick litmus test to avoid the issues like you just had. You’re also correct MediaInfo is a great tool that will tell you specifics in a really nice format, love that thing.I know that this is a freetime project of yours but still I have a feature request without any expectations 😉 NVENC h265 10 bit HDR support… Hybrid generates this line in this setup (using Rigayas NnvEncC) if you would come to the idea to implement it…
NVEnc –y4m -i – –fps 23.976 –codec h265 –profile main10 –level auto –tier high –sar 1:1 –lookahead 16 –output-depth 10 –vbrhq 10000 –max-bitrate 240000 –gop-len 0 –ref 3 –bframes 5 –bref-mode middle –mv-precision Q-pel –preset quality –fullrange –colorprim bt2020 –transfer smpte2084 –colormatrix bt2020nc –max-cll 1838,277 –master-display G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(40000000,50) –cuda-schedule sync –output “C:\xxxxx”
That’s good to know NVEnc itself supports HDR10 static metadata. I am trying to stick to what’s available through ffmpeg at the moment (I have tested and at least the 10-bit color space trasnfer works) and have not seen a way to pass master display / cll content through. The tracking issue for adding the nvenc_hevc encoder is here https://github.com/cdgriffith/FastFlix/issues/109
Great guide. Thanks so much. Only problem that I have is that ffprobe gives me an error on -read_intervals “%+#1”
(Win10 DOS bat). Coudnt not find out why.
Try retyping out the ” quotes, it may be copying them as fancy unicode realm quotes instead of standard ascii ones
No. Thats not it. I get
Invalid interval start specification ‘#’
Error parsing read interval #0 ‘+#’
Failed to set value ‘+#’ for option ‘read_intervals’: Invalid argument
Hrmm, only thing I can think of is possible the ffprobe version is out of date? Can grab the latest from https://github.com/BtbN/FFmpeg-Builds/releases (ffmpeg-N-*-win64-gpl.zip is a safe bet)
I’ve been using the tool below to create RPUs
[removed]
The StaxRip encoded file then needs to be run thru MakeMKV to restore/fix DV info.
Thanks for sharing, I will have to try that out and update the article!
Great article, saves me a lot of time researching optimal settings. My free antivirus software ‘Avira’ has a problem with a (probably) false positive (heuristic) with Fastflix. Uploaded it to virustotal to check with all AV solutions and 3 came back: https://www.virustotal.com/gui/file/b800297aa2fe161971c7f6d91f1564658ddf1179af0a61e7f82be2ad593a8bef/detection
Thanks for the heads up, I will have to submit my files to them to get them cleared up probably. I imagine it’s because I use PyInstaller to make them into exeutables, and because there are some bad actors that use it to create malicious stuff it’s tripping on how it bundles it up into an exe.
I don’t write any malicious code, and you can always run it directly from source if you want to stay safe in case of a DNS attack against github itself, but I currently don’t have Hashes nor GPG key setup to “prove” a certain download was built cleanly via the CI/CD because of the enormous hassle.
Avast and F-secure false positives have both gotten fixed as of 4.0.4 https://www.virustotal.com/gui/file/b439003974c1acec63a1faf68ed1702d7a87ec340234cd7b4af6569b4699c61a/detection
Hi Chris,
you did a very good job here! Thanks. And the info about Handbrake´s 8-bit pipeline was helpful too.
I made some tests with HDR10 and HDR10+ material and it seems to work. Why not implement the metadata extraction for HDR10+ in the Fastflix-GUI? That would make things a lot easier.
With DolbyVision I´m making tests right now. BTW: what is meant by FEL, MEL and RPU and what do do with it after extraction?
Had to look up the MEL vs FEL myself from https://avdisco.com/t/demystifying-dolby-vision-profile-levels-dolby-vision-levels-mel-fel/95 “An enhancement layer that carries a residual signal is = 0 (zero), that is, the decoder does not need to process the residual signal, is called minimum enhancement layer (MEL). If the residual signal is > 0, it is called full enhancement layer (FEL).”
RPU is the file generated by the extraction and is like the HDR10+ metadata.json file, you use that to re-encode with.
I also totally agree a long term goal of FastFlix is to integrate that tool into the UI as well. Right now it technically only supports FFmpeg / FFprobe fully so adding other tools is a decent bit of work, but not impossible. It is nicely MIT licenesed and already built for windows, mac and linux, so might just bundle it in when it comes time.
Every time, i try to import a plain HEVC-File (base layer with HDR10 in this case) and no container with video and audio, Fastflix crashes…
Hi Jan, thanks for the report! Funny enough I had a similar issue when stress testing it with just an Image file. Fix is currently in
advanced-panel
branch and will be in 4.1.0 release.So I experimented a little bit with the HLG samples that are out there. Some say “HLG” as the transfer method. I know how to set this (arib-std-b67). But there are also videos where Mediainfo says there are two: “HLG / BT.2020 (10-bit)” I dont know what that means (some kind of fallback where both are included?) and how to the settings for x265 would be for these. Any Ideas?
I honestly only came across the first from the samples from https://4kmedia.org/tag/hlg/. If you have a link to where I could find the second, please send it to me at chris@cdgriffith.com and I will take a closer look at it.
I thinks its from here : https://4kmedia.org/lg-cymatic-jazz-hdr-hlg-uhd-4k-demo/ but when I downloaded it it was .ts not .mp4 like displayed on that page.
I think its the file mentioned here: https://github.com/cdgriffith/FastFlix/issues/135
So maybe Mediainfo detects it wrong?
What’s interesting with that video is that the regular color transfer shows as
arib-std-b67
but if you look at an individual frame it lists"color_transfer": "bt2020-10"
. Then after a conversion MediaInfo will instead sayTransfer characteristics: BT.2020 (10-bit) transfer_characteristics_Original: HLG
so it may be losing some of it’s true HLGness. (Honestly that video does not play for me properly before encoding, but does after so I am not sure what’s going on with it.)I normally use Kodi for playback of my movies and would like to know how to go forward (step by step) for creating working transcoded DV-MKVs. [removed] I’m unable to create transcoded videos with DV.
Demuxing und remuxing of BL, EL+RPU works practically but never on transcoded Streams!
The MKVs [sources] do contain only one single stream with BL+EL+RPU and profile 7.06. Tests with mp4muxer always create containers with two streams – despite of the used muxing profile! That looks like the structure of the .m2ts containers on the disc.
The other thing this is that right now, I do only have a projector without HDR capabilities so I can’t test the result! Tests will be done with Kodi 19 (beta) because of the included HDR capability.
I’m open to your thoughts!
[Edited by Moderator]
By the way, it is no longer true, that HandBrake has a 8-bit pipeline. The newest snapshot build has a 10-bit pipeline now. Will be released with HandBrake 1.4.0 in the future. But you need to disable all filters that are limited to 8-bit (I just disabled all filters).
Could you provide source for that please? Last I saw was https://github.com/HandBrake/HandBrake/issues/1307 which didn’t give dates, just a rando guess of “Definitely not before 2021, surely not before 2022”.
I just tried their latest release from yesterday, https://github.com/HandBrake/HandBrake/actions/runs/478528491 and even if it does have 10-bit pipeline it does not save HDR10 data yet.
Is there any way to analyse if a video actually uses the 10bit colors or if it uses only 8bit of it. (In other words if the source was 8 bit).
Love your guide, got me started with preserving HDR10+, now working on preserving DoVi 8,1. I see you recently expanded your guide around that.
Can I ask what the HDR format header in Mediainfo looks like on the .hevc file once you have created it? My tests so far have not shown anything except HDR10 in the resulting hevc file according to mediainfo, even though x265 sure looks like it did what it was supposed to, and lsof confirmed it was reading from the file. I don’t know how to confirm that the DoVi data is really there.
I also haven’t found a way to detect it in a HEVC file itself. However, if you use tsMuxeR to wrap that HEVC file into a
.ts
file, it should then show up properly in the HDR section of MediaInfo.The muxed MKV file containing the DV 8.1 .hevc file needs to then be opened inside MakeMKV to restore/fix the DV info.
That works, even though I did the muxing in mkvtoolnix.
One more question, when pulling the RPU from the original MKV created from the disc with MakeMKV, should I be using the -m 2 option in dovi_tool since I will be running x265 with –dolby-vision-profile 8.1? I get very different file sizes for the RPU file I create depending on whether I use that option, so I know there is a difference….
Thanks!
According to the “Readme” [removed] -m 2 is what you need for an 8.1 RPU.bin.
I’ve tried your FastFlix and have a problem. Having tried to re-encode a 34GB movie using your default UHD preset (slow, crf 18) on a Threadripper 3970x it took more than 8hrs and the file was bigger than the original. Also I tried fast crf 24, which took 2hrs 8mins file size 16.4GB but on a i9-9980HK it took 7hrs 30mins but file size was 11.35GB. Such a massive difference in size even when using the same settings. Is this normal or expected?
For reference tried different settings also for timing and size comparison on the 3970x.
Fast crf 20 2hrs 13mins Size 28.5GB
Medium crf 22 3hrs 10mins Size 23.4GB
I’m not re-encoding the audio it’s being passed through.
I’m after a decent file reduction but not lossing too much quality but also not taking forever to encode.
I have yet to analyse the results as I find having to watch them all the way through to find any imperfections.
Same settings should produce the same file size, as long as using the same encoder version (x265 did some preset updates between two of the latest versions IIRC). If you look at the resulting files with MediaInfo or other tool that shows metadata, look for the
Writing library
field for the video, will start with something like “x265 3.4+2-73ca1d7be377”. Can also do a compare of the “Encoding settings” line to see if anything was set differently for some reason.I agree CRF is tricky to nail down, it is super variant of type of video (film grain really messes with it, and need a lot higher CRF for less bitrate / filesize). My range is generally 24~16 (24 for lots of film grain, 16 for smooth 2D animation).
I checked the “Encoding settings” and they are identical, however I should have mentioned that the i9 results are from the Mac version and 3970x are from the Linux (Ubuntu) version.
Encoders are slightly different but not too much. Mac Lavf58.65.101, Linux Lavf57.107.100.
I might re-run see if it’s a one off or repeatable.
OK to my surprise exactly the same results even the times. So I will update ffmpeg on linux to the same release and try again.
Thank you for this fantastic article. I loved how you explained every detail of the CLI commands, making it seem much less “magical”.
I did encounter one problem running the ffmpeg command on Linux Mint: I got a “syntax error near unexpected token `(‘”. In case anyone else encounters this, adding a backslash to the command to escape the parentheses (e.g. master-display=G(13250,34500) etc) fixed it.
Well after looking at what showed up on this page, it seems the backslashes from my comment were stripped out (probably some kind of data sanitization). In the example I gave before, just imagine there are backslashes before the ( and ), e.g. “master-display=Gbackslash(13250,34500backslash)”
Great tutorial but I don’t understand how to extract HDR data with ffprobe… I was thinking that FastFlix could extract and copy the hdr in the new video but no trace of HDR data (I see only 10bits – bt2020)… I try with a lot of options but same result…. Am I stupid ? Can You help me ?? ^^”’ Thanks
Hey sorry for late reply, yes, so first lets verify the HDR10 data is there. What is the output of the command “ffprobe -select_streams v -show_frames -read_intervals “%+#1″ -i <Your video’s name>”?
Don’t worry I found the solution ^^
The video to encode has HDR datas (mediainfo confirm)
I understand that I need to use “%windir%\system32\cmd.exe” to launch FFprobe with the video to encode with “ffprobe -hide_banner -loglevel warning -select_streams v -print_format json -show_frames -read_intervals “%+#1” -show_entries “frame=color_space,color_primaries,color_transfer,side_data_list,pix_fmt” -i d:\video.mkv”
I have got the same result that you explain up there . (The same values : G(8500,39850)B(6550,2300)R(35400,14600)WP(15635,16450)L(40000000,50) I don’t know if it’s normal)
I have copied and pasted all in Fastflix and launched my encode with my settings.
I have got the HDR datas in the new video 🙂 (always with Mediainfo)
So :
– We need to always use FFprobe with cmd.exe to have the HDR datas ?
– Fastflix can’t extract this datas itself ?
in any case thanks again 🙂
Recently encountered an error with FastFlix that if the video track is not the first track, it can sometimes miss that information. So if the video in that case is not stream 0 that may be the problem. That should be fixed in next release (two weeks or so probably.)
Ok I understand.
Sorry but I need help… again ^^”
Is it normal to have all the “Encoding settings” written in mediainfo ?
Finally I’m not sure that yhe HDR datas are corrctly paste ine the new file …
(not he same data for Mastering display luminance /
Maximum Content Light Level / Maximum Frame-Average Light Level )
old video have :
Mastering display luminance : min: 0.0050 cd/m2, max: 1000 cd/m2
Maximum Content Light Level : 2059 cd/m2
Maximum Frame-Average Light Level : 486 cd/m2
new video is :
Video
ID : 1
Format : HEVC
Format/Info : High Efficiency Video Coding
Format profile : Main 10@L5@Main
HDR format : SMPTE ST 2086, HDR10 compatible
Codec ID : V_MPEGH/ISO/HEVC
Duration : 1 h 17 min
Bit rate : 7 815 kb/s
Width : 3 840 pixels
Height : 2 076 pixels
Display aspect ratio : 1.85:1
Frame rate mode : Constant
Frame rate : 23.976 (24000/1001) FPS
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 10 bits
Bits/(Pixel*Frame) : 0.041
Stream size : 4.23 GiB (82%)
Writing library : x265 3.4+28-419182243:[Windows][GCC 9.3.0][64 bit] 10bit
Encoding settings : cpuid=1111039 / frame-threads=4 / numa-pools=16 / wpp / no-pmode / no-pme / no-psnr / no-ssim / log-level=2 / input-csp=1 / input-res=3840×2076 / interlace=0 / total-frames=0 / level-idc=0 / high-tier=1 / uhd-bd=0 / ref=5 / no-allow-non-conformance / repeat-headers / annexb / no-aud / no-hrd / info / hash=0 / no-temporal-layers / open-gop / min-keyint=23 / keyint=250 / gop-lookahead=0 / bframes=4 / b-adapt=2 / b-pyramid / bframe-bias=0 / rc-lookahead=40 / lookahead-slices=0 / scenecut=40 / hist-scenecut=0 / radl=0 / no-splice / no-intra-refresh / ctu=64 / min-cu-size=8 / rect / amp / max-tu-size=32 / tu-inter-depth=3 / tu-intra-depth=3 / limit-tu=4 / rdoq-level=2 / dynamic-rd=0.00 / no-ssim-rd / signhide / no-tskip / nr-intra=0 / nr-inter=0 / no-constrained-intra / strong-intra-smoothing / max-merge=4 / limit-refs=1 / limit-modes / me=3 / subme=4 / merange=57 / temporal-mvp / no-frame-dup / no-hme / weightp / weightb / no-analyze-src-pics / deblock=1:1 / sao / no-sao-non-deblock / rd=6 / selective-sao=4 / no-early-skip / rskip / no-fast-intra / no-tskip-fast / no-cu-lossless / b-intra / no-splitrd-skip / rdpenalty=0 / psy-rd=0.40 / psy-rdoq=1.00 / no-rd-refine / no-lossless / cbqpoffs=0 / crqpoffs=0 / rc=abr / bitrate=8000 / qcomp=0.60 / qpstep=4 / stats-write=0 / stats-read=2 / cplxblur=20.0 / qblur=0.5 / ipratio=1.40 / pbratio=1.30 / aq-mode=2 / aq-strength=0.40 / cutree / zone-count=0 / no-strict-cbr / qg-size=32 / no-rc-grain / qpmax=69 / qpmin=0 / no-const-vbv / sar=1 / overscan=0 / videoformat=5 / range=0 / colorprim=9 / transfer=16 / colormatrix=9 / chromaloc=0 / display-window=0 / master-display=G(8500,39850)B(6550,2300)R(35400,14600)WP(15635,16450)L(40000000,50) / cll=0,0 / min-luma=0 / max-luma=1023 / log2-max-poc-lsb=8 / vui-timing-info / vui-hrd-info / slices=1 / no-opt-qp-pps / no-opt-ref-list-length-pps / no-multi-pass-opt-rps / scenecut-bias=0.05 / hist-threshold=0.03 / no-opt-cu-delta-qp / no-aq-motion / hdr10 / hdr10-opt / no-dhdr10-opt / no-idr-recovery-sei / analysis-reuse-level=0 / analysis-save-reuse-level=0 / analysis-load-reuse-level=0 / scale-factor=0 / refine-intra=0 / refine-inter=0 / refine-mv=1 / refine-ctu-distortion=0 / no-limit-sao / ctu-info=0 / no-lowpass-dct / refine-analysis-type=0 / copy-pic=1 / max-ausize-factor=1.0 / no-dynamic-refine / no-single-sei / no-hevc-aq / no-svt / no-field / qp-adaptation-range=1.00 / no-scenecut-aware-qpconformance-window-offsets / right=0 / bottom=0 / decoder-max-rate=0 / no-vbv-live-multi-pass
Default : Yes
Forced : No
Color range : Limited
Color primaries : BT.2020
Transfer characteristics : PQ
Matrix coefficients : BT.2020 non-constant
Mastering display color primaries : BT.2020
Mastering display luminance : min: 0.0050 cd/m2, max: 4000 cd/m2
thanks for your help !! 🙂
Again me…. I found that I can correct the order of tracks with mkvtoolnix. And now Fastflix extract correctly the HDR datas !! 🙂
Ok I’m back having updated ffmpeg on Linux to the latest release, the file size for fast crf24 was now the same for both Mac and Linux. That was promising, however I reran the uhd default preset again. But again the file size was equal if not slightly bigger than the original. Where’s my compression?
I have chosen and two pass average bit rate approach. Its a compromise. I believe you can mitigate crf bit rate with the “minrate”, “-maxrate” & “-bufsize” flags.
This is an extremely helpful post, thank you so much. What is the current status of converting a Dolbyvision file to HDR10+? Samsung are still steadfastly refusing to support DV so it would be great to be able to convert to a format that will work with my TV.
I haven’t seen any progress on DV to HDR10+, only DV to HDR10. It seems keeping HDR10+ from a film mastered with it is the only way to get HDR10+. Samsung should support HDR10. Is that what you’re asking?
Handbrake/master now keeps HDR10 metadata. No signs of HDR10+ support yet.
Firstly, thanks for a great tool in FastFlix. I compiled ffmpeg and libx265 today to enable hdr10+ metadata then tested out hdr10plus_parser. All worked fine. I then tried my ffmpeg on macos for giggles fully expecting this to fail but it seems that the latest Homebrew ffmpeg tap (https://github.com/homebrew-ffmpeg/homebrew-ffmpeg) is compiled with HDR10+ metadata suuport enabled. The mac hdr10plus_parser binary successfully verified a sample file and extracted the metadata to json. Thought this might help mac users not wanting the headache of compiling.
How would you have handbrake include the HDR meta data now? Is it possible to do that now?
Looks like it is merged to master in Feb, but they haven’t had a release since Jun 2020. https://github.com/HandBrake/HandBrake/pull/3376
So would need to build from source, and looks like their automated builds for windows are not currently working :-/ but they do have pre-release for MacOSX in their Releases.
Handbrake have snapshot builds for macos/win on their site. These are based on git master and have HDR support. Usual disclaimers apply about using dev software but I use the macos releases and have had no issues. Note: the app updater is disabledsto you need to manually update snapshots if required. When 1.4 is released (with HDR support) , you can go back to supported releases. HTH.
https://handbrake.fr/nightly.php
Not sure it’s appropriate here, but the article is brilliant so thought I’d try. I have followed your guide and created HEVC HDR 4k content that includes Master Display Metadata like below:
“side_data_list”: [
{
“side_data_type”: “Mastering display metadata”,
“red_x”: “34000/50000”,
“red_y”: “16000/50000”,
“green_x”: “13250/50000”,
“green_y”: “34500/50000”,
“blue_x”: “7500/50000”,
“blue_y”: “3000/50000”,
“white_point_x”: “15635/50000”,
“white_point_y”: “16450/50000”,
“min_luminance”: “50/10000”,
“max_luminance”: “40000000/10000”
},
{
“side_data_type”: “Content light level metadata”,
“max_content”: 349,
“max_average”: 86
}
]
However when I try to do this, and here’s the deviation from the article, in Premiere Pro or Davinci Resolve Studio, I do not get the Matering Display metadata. In Premiere the mediainfo doesn’t even include HDR info. I’ve followed every guide I can find but none of them return this detail and none of them seem to have a way to define things like red/gree/blue values and luminance values. Any thoughts?
I am pretty sure Premiere doesn’t support HDR10, they only got basic HDR support not long ago https://larryjordan.com/articles/new-hdr-workflow-in-adobe-premiere-pro/
I have not used Resolve myself, but a quick search doesn’t shed much light on the subject. Best Guide I have seen so far is this one https://daejeonchronicles.com/2021/03/06/comprehensive-workflow-sony-a7s-iii-s-log3-hdr-10-in-davinci-resolve-studio-17-part-iii/ that goes over the color correction some. I am not sure if that information is saved in the Prores 4444 codec as I have not worked with that myself. I will have to give it a try!
Thanks Chris. It’s my understanding that HDR10 is static metadata? So guess any info it ocntains wouldn’t vary per frame? Seems odd but OK. That said, is there a way that you know of to inject it into a video based on the data from the source, after the fact without encoding again?
Hello, and thank you for the FastFlix. Been trying to run it against few UHD HDR10 videos, and getting the same error every time. Would you suggest how to get around it?
ffmpeg version N-94652-g808a6717e0 Copyright (c) 2000-2019 the FFmpeg developers
built with gcc 9.1.1 (GCC) 20190807
configuration: –enable-gpl –enable-version3 –enable-sdl2 –enable-fontconfig –enable-gnutls –enable-iconv –enable-libass –enable-libdav1d –enable-libbluray –enable-libfreetype –enable-libmp3lame –enable-libopencore-amrnb –enable-libopencore-amrwb –enable-libopenjpeg –enable-libopus –enable-libshine –enable-libsnappy –enable-libsoxr –enable-libtheora –enable-libtwolame –enable-libvpx –enable-libwavpack –enable-libwebp –enable-libx264 –enable-libx265 –enable-libxml2 –enable-libzimg –enable-lzma –enable-zlib –enable-gmp –enable-libvidstab –enable-libvorbis –enable-libvo-amrwbenc –enable-libmysofa –enable-libspeex –enable-libxvid –enable-libaom –enable-libmfx –enable-amf –enable-ffnvcodec –enable-cuvid –enable-d3d11va –enable-nvenc –enable-nvdec –enable-dxva2 –enable-avisynth –enable-libopenmpt
libavutil 56. 33.100 / 56. 33.100
libavcodec 58. 55.101 / 58. 55.101
libavformat 58. 31.104 / 58. 31.104
libavdevice 58. 9.100 / 58. 9.100
libavfilter 7. 58.101 / 7. 58.101
libswscale 5. 6.100 / 5. 6.100
libswresample 3. 6.100 / 3. 6.100
libpostproc 55. 6.100 / 55. 6.100
Unrecognized option ‘default_mode’.
Error splitting the argument list: Option not found
Always check for the FFmpeg minimum version requirement on the README, it is currently FFmpeg 4.3 (released in 2020, so the copyright is the giveaway that version is too old.)
Thanks Chris, that worked.
One more question please. In your guide you gave an example of ffmpeg command to convert a video stream “ffmpeg -i g:\my-video.mp4 -map 0 -c:v libx265 -x265-params hdr-opt=1…” but that doesn’t seem to do cropping. Where can I get cropping info of a particular video file and what params to use in ffmpeg to remove black bars?. Thanks.
Cropping is a pain the rear with FFmpeg. You can use cropdetect to try to figure it out for you (https://github.com/cdgriffith/FastFlix/issues/81), it’s added in FastFlix if you hit the “Auto” button in the crop area (looks at multiple points).
When it’s added into the command line it’s an additional filter. For example taking 120px off top and bottom of a 1920p video would look like:
-filter_complex "[0:0]crop=1920:840:0:120[v]" -map "[v]"
If you want to have Main 10@L5.1@High instead of main like: Main 10@L5.1@Main where the @ at the end is High vs Main, how would you do that? Tried setting a tier to high but maybe doing it wrong. My call right now is:
ffmpeg.exe -i prores422.mov -c:v libx265 -x265-params level=5.1:hdr-opt=1:repeat-headers=1:colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc:master-display=G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(40000000,50):max-cll=349,86:vbv-bufsize=15000:vbv-maxrate=15000:bitrate=15000 -preset slow -pix_fmt yuv420p10le -sn -an hevc.mkv
Not something I have looked at before, but according to https://x265.readthedocs.io/en/master/cli.html#cmdoption-high-tier you would have to add it as part of the x265 params
Edit: I read that wrong, you probably want to set it explicitly to high tier
high-tier=1
Chris, would you please elaborate a bit on CRF options in FastFlix? Is 20(2160p) the highest quality that can be applied to UHD HDR video encode or is it 14 (higher quality)?
You can set CRF to whatever you want, it’s all about quality vs size of the file. https://codecalamity.com/encoding-uhd-4k-hdr10-videos-with-ffmpeg/#ffmpeg-conversion-settings 20 is what I just set as a generally safe average, however some sources would be silly to make it “lower” (aka higher quality) than 22, while others might need to be taken the whole way to 16 to not have artifacts. It’s really source dependent.
I find CRF recommendations in FastFlix somewhat misleading. From my experience the lower source resolution is the lower CRF you need to keep desired amount of details. Speaking of the best CRF value, personally I don’t see any real difference between CRF 24 and say 20 in sharp 4k sources when watching them on TV. Noisy sources take lower CRF to keep the noise, but it doesn’t contain any useful information anyway.
Article is very informative. Is it possible for you to update article with information regarding rigaya nvenc.
I saw for this codec that there is multipass option available.
Is it make a different with piture quality?
final question: which video codec is better x265 or nvenc?
hi,
great article.
is it possible for you to update this article regarding codec NVEnc?
Hi Luke, sadly I don’t have the hardware to do a fair comparison of the current state of NVENC vs x265 or even QuickSync or AMD VCE. The latest 2xxx\3xxx series from Nvidia added B-frame support and apparently are near on par with software encoders currently. However, I do not have the hardware to test that out. If anyone sends a 2xxx\3xxx card my way I’d be happy to help out!
Regarding QuickSync or NVENC: don´t they do only eight bits? I never read anything about that they were capable of ten or more bits.
NVENC since Pascal has been able to do 10-bit https://docs.nvidia.com/video-technologies/video-codec-sdk/nvenc-application-note/ and QuickSync looks to have supported it since the 6th version of it (around Kaby Lake time) https://en.wikipedia.org/wiki/Intel_Quick_Sync_Video#Development
Hey there, I have a dynamic metadata file (hdr10+, json) and I want to add it to a video file but without rencoding it (just copying),since I dont want to cause quality loss and I dont have the proper hardware for that. Is that possible? if so what tool does that?
is there any way to translate this:
cpuid=1111039 / frame-threads=4 / numa-pools=16 / wpp / no-pmode / no-pme / no-psnr / ssim / log-level=2 / input-csp=1 / input-res=3840×1608 / interlace=0 / total-frames=76615 / level-idc=0 / high-tier=1 / uhd-bd=0 / ref=3 / no-allow-non-conformance / no-repeat-headers / annexb / no-aud / no-eob / no-eos / no-hrd / info / hash=0 / no-temporal-layers / open-gop / min-keyint=24 / keyint=250 / gop-lookahead=0 / bframes=8 / b-adapt=2 / b-pyramid / bframe-bias=0 / rc-lookahead=80 / lookahead-slices=8 / scenecut=40 / hist-scenecut=0 / radl=0 / no-splice / no-intra-refresh / ctu=64 / min-cu-size=8 / no-rect / no-amp / max-tu-size=32 / tu-inter-depth=1 / tu-intra-depth=1 / limit-tu=0 / rdoq-level=0 / dynamic-rd=0.00 / no-ssim-rd / signhide / no-tskip / nr-intra=0 / nr-inter=0 / no-constrained-intra / no-strong-intra-smoothing / max-merge=5 / limit-refs=3 / no-limit-modes / me=3 / subme=5 / merange=57 / temporal-mvp / no-frame-dup / no-hme / weightp / no-weightb / no-analyze-src-pics / deblock=0:0 / sao / no-sao-non-deblock / rd=3 / selective-sao=4 / early-skip / no-rskip / no-fast-intra / no-tskip-fast / no-cu-lossless / b-intra / no-splitrd-skip / rdpenalty=0 / psy-rd=2.00 / psy-rdoq=0.00 / no-rd-refine / no-lossless / cbqpoffs=0 / crqpoffs=0 / rc=crf / crf=20.0 / qcomp=0.60 / qpstep=4 / stats-write=0 / stats-read=0 / ipratio=1.40 / pbratio=1.30 / aq-mode=3 / aq-strength=1.00 / cutree / zone-count=0 / no-strict-cbr / qg-size=32 / no-rc-grain / qpmax=69 / qpmin=0 / no-const-vbv / sar=0 / overscan=0 / videoformat=5 / range=0 / colorprim=1 / transfer=1 / colormatrix=1 / chromaloc=0 / display-window=0 / cll=0,0 / min-luma=0 / max-luma=1023 / log2-max-poc-lsb=8 / vui-timing-info / vui-hrd-info / slices=1 / no-opt-qp-pps / no-opt-ref-list-length-pps / no-multi-pass-opt-rps / scenecut-bias=0.05 / hist-threshold=0.03 / no-opt-cu-delta-qp / no-aq-motion / no-hdr10 / no-hdr10-opt / no-dhdr10-opt / no-idr-recovery-sei / analysis-reuse-level=0 / analysis-save-reuse-level=0 / analysis-load-reuse-level=0 / scale-factor=0 / refine-intra=0 / refine-inter=0 / refine-mv=1 / refine-ctu-distortion=0 / no-limit-sao / ctu-info=0 / no-lowpass-dct / refine-analysis-type=0 / copy-pic=1 / max-ausize-factor=1.0 / no-dynamic-refine / no-single-sei / no-hevc-aq / no-svt / no-field / qp-adaptation-range=1.00 / scenecut-aware-qp=0 / conformance-window-right-offset=0 / conformance-window-bottom-offset=0 / decoder-max-rate=0 / no-vbv-live-multi-pass
to options available of x265 or NVENC codec itself to be able to use them.
Hi,
Thanks for the page, it sent me in the right direction to get DolbyVision [removed] playing “natively” on my LG TV; [removed] I immediately found out that HDR was a raging pain when reencoding and my TV can’t maintain a high enough speed stream for most high bitrate streams.
I’d originally planned on using Adobe Premiere which I have a subscription for, but it has far too many constraints on both inputs (Adobe dropped their Dolby license so no writing of ac3 or reading of TrueHD is possible without additional plugins, none of their tools seem to support multiple audio streams per container, subs dropped, etc) and outputs to produce anything useable, and my AMD Vega GPU supposedly supports 10 bit transcode but in reality no software picks up on that anymore (last year’s betas of Media Encoder could do it and now neither beta nor stable can), etc, etc. It also only supports basic HDR10 AFAICT.
Searching the web naturally found a bunch of 8 year old reddit posts saying it was impossible at first, because google is now the official search engine of long-outdated reddit posts. I got to your blog via some odd search terms.
Anywho, here are some comments, and I’m still working out which HDR types want which options and what may or may not be ignored:
1) The mess of colormatrix settings that seems to be common to most videos can be specified as a one-off in x265 options… x265 -help lists them but the most common one seems to be –colorprim bt2020 –transfer smpte2084 –colormatrix bt2020nc –range limited. This can be specified instead as “–video-signal-type-preset BT2020_RGB”.
2) Likewise anything using PQ BT2100 (which is mostly the same as above except for input signal) can have the display color volume specified in that same command, which fills in one of the 3 standard mastering display color sets. I’m not sure that BT2100 shows up anywhere in the mediainfo but with “BT2100_PQ_YCC: –colorprim bt2020 –transfer smpte2084 –colormatrix bt2020nc –range limited –chromaloc 2” seems to be the closest to most videos, since chromaloc specifies chroma location in 4:2:0 input and the chroma from ffmpeg can probably be coaxed into the correct position with some option or another when piping (and I don’t believe affects the output). This may or may not be default anyway and the option is just to force compliance, I’m not sure. Anyway, this allows specifying one of 3 variants of the mastering display info like so:
–video-signal-type-preset BT2100_PQ-YCC:P3D65x1000n0005 (or P3D65x4000n005 or BT2100x108n0005)
The first of these expands to –master-display G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,5).
So far all of the BD-XLs I’ve looked at used that string but with a min luminance of 0.0001 instead of 0.0005. Given the scale of the luma there I’m lazy enough that I’d accept BSing that the mastering display had 4/10000 higher level for black out of 1000 just to avoid error prone typing of color primaries that matter more, but that’s just me 😉
The chromaloc thing needs to be tested but it’s worth looking into just to shorten these godawfully long command lines. Maybe the x265 people could be convinced (or a fork could be made) to enable using the few common mastering display values with any of the video signal type presets and we can ditch the whole mess of trying to properly parse them out of ffprobe dumps. If nothing else the mastering display type and luma levels are enough to generate the string. The luma levels are the only real variance I’ve seen. All other values are just BT.2020 or DCI-P3 depending on the video and can be boilerplate from that. A simple option to specify (–master-display-colorspace ?) would make it so much more usable.
3) Some forms of DV apparently require the ICTCP or HLG options; I believe L8.2 may be one of the HLG compatible with RPU profiles that could be used on the rare 8 bit + DV source video, but I don’t think there are many of these floating around. dovi_tool can re-inject all of the RPU versions that x265 doesn’t support by not specifying a conversion option so once
Onto the non-theoretical:
1) Since DolbyVision is backwards compatible with HDR10, I’d suggest turning on –hdr10-opt for it. Whatever it’s doing it seems to improve file size and quality without any real performance hit.
2) dovi_tool has been updated since your article and can demux to a BL.hevc + EL_RPU.hevc which could be useful for reencoding both a BL and FEL stream and muxing them back together into a single track dual layer before putting them in a container, although I’m not sure what will do this properly. A dual track dual layer can apparently be done with Dolby’s open source mp4muxer but I haven’t attempted it as I don’t have any FEL sources as of yet.
3) dovi_tool can also do RPU injection into an hevc stream, which means non-software encoders without support can be used. For BL+MEL+RPU files there’s really no point in keeping the MEL layer (just change the RPU to 8.1) so
dovi_tool -m 2 extract-rpu –input in.hevc –rpu-out out.rpu
will produce an 8.1 compatible RPU file. It can also convert FEL files to MEL or RPU, although I can’t imagine that this isn’t lossy.
Anyway after you have the 8.1 RPU the EL can be discarded with dovi_tool -m 2 convert –discard –input in.hevc –output out.hevc. For MEL files this generally shaves off about 1/10th the file size.
3.5) A nice trick to make sure everything is working is that dovi_tool and x265 will both still write out a file if only a few minutes of video exists to inject the RPU into even if it is much longer, and the resulting file should trigger dolbyvision mode on compatible devices. It’ll spit out a big red error message, but it still works when muxed into an appropriate container.
4) LG TVs are… weird in their file handling. They can’t play DolbyVision 7.1 in an mkv container apparently. The .mkv still triggers HDR10 so it may just not be able to read the MEL stream out of that container. I tried .ts DV8.1 files next but for whatever reason the TV could only play a given file once; after pausing or backing out of the file, the TV would error out the next time you attempt to play it. I suspect it’s related to the auto-resume feature but .m2ts works (with loss of seek functionality, probably because I failed to encode keyframes or something equally silly). Pause still works but you have to make sure you’re going to watch the entire movie. This isn’t great but seems easily fixable.
It plays almost everything I throw at it, but having for example an .aac audio track 100ms longer than the video track will cause the video to not even show up in the network browser until the lengths are made equal. That’s about as picky as I’ve seen out of it.
.m2ts isn’t optimal anyway as it doesn’t support TrueHD, but .mp4 apparently does (and anecdotal evidence online suggests they support most levels of DolbyVision via direct stream including the 7.1 used on bluray), so it looks like that’s the way to go for them assuming I can find something that won’t stupidly throw out data it doesn’t understand when muxing like ffmpeg does. Dolby’s muxer has limitations and might require downconverting to 5.x profiles which might(?) be deprecated. The manuals for my TV (a nano85) claim that it only supports 50Mb/s streams for the video portion of DolbyVision files. Over the network I got some buffering every ~20s trying to play a 75Mb/s video stream but I suspect that’s the silly 100Mb/s ethernet they built in (overall file bitrate would have been at least saturating the connection) and not a decoding hardware limitation.
5) It might be worth looking into why exactly ffmpeg can output the hevc stream with all DV info intact using the flags on this page but can’t mux that back into a container with anything. Would similar flags help?
On a side note I find the whole situation kinda silly from a color nerd perspective. I have attached to my computer an aging dell monitor that supported xvYCC over HDMI and ~99.8% of the AdobeRGB colorspace. When I originally read about this feature I was strongly hoping that HDR would be implemented as a colorspace improvement that would continue upwards using something more like log-gamma… so we got BT.2020 and that seemed awesome; pumping 12 or 14 bit color into the TV would be plenty to have HDR both in brightness and color range, but they just ignored the brightness part and came up with all these bizarre competing metadata formats for reasons unknown to me. Meanwhile I’ll just keep on waiting for a 100% ProPhotoRGB display (imaginary colors included 😉 ) for the lulz.
I’ve since done some tests on FEL files. Dolby has updated their mp4muxer to either refuse to merge streams with incompatible settings for the level selected or possibly not mux video streams internal to an mp4 anymore. In any case, any profile 7 source requires –chromaloc 2 as an x265 parameter to produce profile 7 compatible output. Lacking that flag, muxing the video with tsmuxer followed by [another program] to get a single layer / dual stream or whatever their bizarre terminology is will produce a profile 4 file which isn’t compatible with anything.
It’s possible that my model of TV is lacking the secondary decoder required for profile 7 to begin with and I’m just on a futile quest here but I’m going to try setting chromaloc properly and had a couple more ideas that involve using the FEL to transform the file into a main12. I can take a guess at what layer settings would handle it just from looking at the FEL in a video player, but it may not turn out to be worth it to lose the RPU data until dolby comes out with a profile that supports main12 hevc.
Looking into it more, when max_cll and max_fall are set to zero in the file header shown by ffmpeg and the stream also contains a dolby vision RPU (as in your first example), and conversion is being done to plain HDR10 or a DV format which requires HDR10 fallback (versions with FEL support only seem to support proper fallback to MEL) I think these values are meant to be pulled from the RPU data. I’m also seeing weird non-standard mastering display values in some file headers that are set to more normal ones in RPU.
Running dovi_tool info -f 0 -i file.rpu will show real max_cll and max_fall values in the Level6 block… for example one of my source files with 0,0 for cll values in the header shows 4856,1305. Presumably this would need to be scaled into the 10 bit range to be usable in the header; right shifting them by 3 does it but probably isn’t correct since that doesn’t correspond to any of the intermediate bit depths in ETSI GS CCM 001 V1.1.1. Mastering display luma is the odd 10000000, 1 in the header which doesn’t really correspond to any of the standard displays, but a more normal 40000000,5 (equiv) in the RPU.
Even more weirdly, another file with the same profile has the cll / fall values set in the header but zero’d in the RPU data. The mastering display luma range has the same set of two different values.
ETSI GS CCM 001 V1.1.1 describes how to, using the standard data (headers / vdr) in an RPU, map a dolby BL into HDR space, apply the EL to it, and map it back into display space. It’s an open broadcast standard available at https://www.etsi.org/deliver/etsi_gs/CCM/001_099/001/01.01.01_60/gs_CCM001v010101p.pdf for anyone interested. It doesn’t describe how to apply the Dolby-Specific extended data that constitutes “Dolby Vision” afaict, but there’s generally not much of that in a file compared to the dynamic tonemapping data. Applying this standard should allow producing 12bpc HEVC files as HDR but they’d need at least generic HDR10+ data to work; I can’t find anything about whether regular HDR10 header settings will be applied if a 12bpc file is played. The FEL is only 1080p so the 12 bit portion of the chroma is (effectively) even further downsampled from the 4:2:0 4k BL and it won’t be the same as true 12bpc 4:2:0. It probably introduces subtle blocking artifacts in the luma channel as well but they won’t likely be very visible at normal viewing distance.
The max_cll / fall would need to be recalculated but the color coordinates and luma wouldn’t. Colorspace conversion from BT.2020 wrapped DCI-P3 to plain BT.2020 should probably be performed if that’s the origin space, and the signal needs to change to full range. Other than that it’s fairly straightforward if not a bit sparse on details. Any variable they define in the standard is available in the dolby metadata, so you just need to read that, decode the BL, decode and upscale the FEL, then follow their simple recipe. The pivots and mmr / polynomial counts / coefficients change wildly throughout videos so they need to be applied frame-by frame. Maybe not that useful for current TVs and such but it’s a far better backup format than 10bpc that future decoders and current GPU decoders will likely have less trouble with than DV BL + FEL.
AFAICT from reading that standard, 12bpc output is sort of arbitrary and based on current commercial decoders; the intermediate mapping produced from the BL + FEL is at least 16bpc, so it could be encoded as such (though likely not as HEVC). Some of the transfer info would need to be scaled but there is more than 2 bits of additional info in the FEL.
I did try the –master-display setting with BT2100 on a file but it immediately error’d out on some aspect of the input (chromaloc I think), and I wasn’t too motivated to look into it further.
Hopefully my ramblings have helped somebody, if I ever produce a working project out of this I’ll come back and post a link to a repo.
This is a good guide, but it’s much easier to use a GUI tool like Shutter Encoder. H.265, 10bit, and HDR are all supported. Converts from one format to another and plays nice with VLC and Premiere, even with HDR.
He’s actually written a very nice GUI (which he linked above but since you apparently missed it https://github.com/cdgriffith/FastFlix/) which handles everything but DolbyVision for you, the command lines are there so you know what’s being done behind the scenes and masochists like me can do things like re-encode the first file I’ve seen with both HDR10+ and DolbyVision + MEL in the same stream to a smaller size while keeping all of the fancy dynamic HDR data around.
Out of curiosity, what do you mean by “plays nicely with premiere”? The latest CC beta I tried is still broken for basic HDR metadata (it requires hand-entry of MaxCLL / MaxFALL rather than providing a way to calculate them from video as they’re supposed to be), and couldn’t set the mastering display values within the full allowed range for BT.2100. Of course HEVC encode is broken entirely because of its weird method of downloading a .dll into a Public/Documents subdirectory instead of including it and Windows isn’t having that (I don’t blame it, that’s unsafe as all hell as far as security goes).
If you mean Premiere will open the files and detect their color space, I wouldn’t be too shocked if it can do that much.
The MaxCLL / MaxFALL thing can be solved with x265 via a 2-pass encode or something that can manipulate those values without encoding after a 1-pass with analysis dump turned on.
Last I tried media encoder wasn’t automatically reading any of the mastering luminance values or MaxCLL / MaxFALL from source files so couldn’t pass that through correctly on a straight transcode, which means you’d still need to resort to a command line utility to grab those values.
That’s just HDR, it doesn’t handle HDR10+ or DolbyVision at all which makes it kind of irrelevant to a lot of this guide.
Any tip on how to keep the HDR10+ metadata in its correct place while trimming the beginning of a video? I’ve tried a couple things but no luck, so I’d need to recalculate the whole metadata set. Some other way?
I undrstand that for HDR10+ processing, even through the FastFlix, I still need to extract HDR10+ metadata using hdr10plus_tool. After downloading the hdr10plus_tool.exe, where do I put it? The executable comes inside of “dist” folder, and I tried placing it to the root of C: as well as in the ffmpeg folder, but when I try running this:
ffmpeg -i “d:\input.mkv” -map 0:v:0 -c copy -vbsf hevc_mp4toannexb -f hevc – | hdr10plus_tool extract -o metadata.json –
I’m getting:
‘hdr10plus_tool’ is not recognized as an internal or external command,
operable program or batch file.
What am I missing here?
The tool needs to either be linked up in File > Settings (can select where it is on the system), or can add the folder it is in to the system PATH.
Hope that helps!
Also, if you’re running from command line, the tool needs to be on the system PATH or in the same directory you are in.
I need some help whit saving Dolby vision. I don’t know how to get the x265 10b encoder from https://www.x265.org/v3-5-is-out-now/ site I download the newest version and all thing to need and add to the path. And I have trouble with visual studio (I install the “Desktop Development whit C++” ).
Handbrake 1.4 says “Further refining the HandBrake engine to support native 10 and 12-bit encodes, including HDR10 metadata passthru”. Has anyone checked its capabilities yet?
In the new update for hdr10plus tool there is an option to inject the JSON to the hevc stream, Does that mean I can just inject it and put it back to the container without encoding?
You would have to ask the creator, this is first I am hearing of that feature! Not sure the use case there, except maybe encode a video with a tool that doesn’t support HDR10+ and then add it back afterwards?
Well, I tried it and the tv does detect the 10+ signal. I created multiple samples (the original bluray, original web-dl with 10+, a hybrid of bluray and 10+) and I am not really sure it works as intened there was a slight difference of colors between the hdr10 and hdr10+, but here is the punch line I also created a sample with a random json I got the same result. I would expect the image to be incorrect right? How can I confirm it works as it should?
I just tried it with a different movie(Jolt) and theres a difference, but its off by somting like a second how can get in sync? is there a tool to edit the metadata on a frame level?
I know it’s not your (Chris) expertise and I should maybe find help elsewhere, but I have great difficulty extracting the HDR10+ metadata with the provided command.
I use Windows and ** ffmpeg -loglevel panic -i movie.mkv -c:v copy -vbsf hevc_mp4toannexb -f hevc – | hdr10plus.exe –verify – ** doesn’t work as it gives an error due to that last dash -> “error: Found argument ‘-‘ which wasn’t expected, or isn’t valid in this context”. That’s easily fixed by deleting it, but still begs the question why is it in there then? Who does it work for like this? Maybe Linux users?
Deleting it however gets me one step further but also doesn’t fix it. Then I get “ffmpeg -loglevel panic -i movie.mkv -c:v copy -vbsf hevc_mp4toannexb -f hevc – | hdr10plus.exe –verify
hdr10plus_tool 1.2.2
quietvoid
Parses HDR10+ dynamic metadata in HEVC video files
USAGE:
hdr10plus.exe [OPTIONS]
OPTIONS:
-h, –help Print help information
–skip-validation Skip profile conformity validation
-V, –version Print version information
–verify Checks if input file contains dynamic metadata
SUBCOMMANDS:
extract
help Print this message or the help of the given subcommand(s)
inject”
So it ignores the ffmpeg command in front of it and does not see it as an input.
Now, I am thinking perhaps this is a Windows vs Linux thing as I had to use ** hdr10plus.exe –input movie.hevc –output data.json ** to get it working, though I had to extract the hevc file first and even had to come up with that command myself as the parser gave no help whatsoever regarding input and output syntaxes.
I’d still love the proper commands for detecting the metadata and extracting it without having to convert it first to a pure hevc stream. Can you assist?
I think with
hdr10plus
you also need a-
at the end of the command to specify that it is expecting input piped to it instead of asking for an input file.Their example is
ffmpeg -i "input.mkv" -map 0:v:0 -c copy -vbsf hevc_mp4toannexb -f hevc - | hdr10plus_tool extract -o metadata.json -
I wanted to find why this command failed for me (I have a clue), but since FastFlix already does it for me I’m kinda reluctant to invest more time into it.
If I absolutely need to do it by hand I might look at it again or just use hdr10plus by itself and extract the hevc stream by hand first.
Is there a way to force profile level 5.1? I got an output of level 5 after an encode but I wanted to have it 5.1 like the original.
When I extracted the HDR10+ metadata by hand (before I learned that FastFlix can automate it) I got a 170MB file. When I injected that into the hevc stream the stream only got around 15MB bigger, not 170MB.
I think this might be because the new metadata is mainly using the space that was already occupied by less relevant metadata and any excess is just added on.
Is this correct? Or should the new metadata cause the stream to be bigger by approximately the same amount as the separate metadata file?
The stream is binary while hdr10+ metadata file is JSON. The comparison is not exactly correct, but try to zip this JSON file and see the size difference.
Oh my, it zips down to about 10%… so that matches perfectly. Got it. Slowly wrapping my head around it all!
Nope, I lied.. zips down to 1%.. not 10%
Update – dovi_tool has had some neat updates. One can now generate Dolby Vision data from any file with HDR10 metadata. [removed]
One can also generate Dolby Vision metadata from an HDR10+ json file.
Hello,
1st of all thank you for amazing job you’ve done with this study. It helps me a lot when I’ve was choosing a proper way to manage my personal movie library. 2nd thing is that Fastflix is great and very user friendly tool – thank you as well for making it!
Hello 🙂
I have a few HDR Dolby Vision videos that are cropped, 1920×800, meaning black bars on top and bottom removed.
I would like to add them back and keeping Dolby Visison intact.
I have this ffmpeg .bat script for adding black bars and it works perfectly, but…
The Dolby Vision isn’t kept intact.
Is it possible to add some parameters in the script, or maybe FastFlix can do this?
Any ideas are most welcome and much appreciated.
Best regards
Miracles
@echo off
set SOURCEPATH=X:\SOURCEPATH
set TARGETPATH=Y:\TARGETPATH
if not exist “%SOURCEPATH%” goto ErrorSource
if not exist “%TARGETPATH%” goto ErrorTarget
for %%i in (“%SOURCEPATH%*.mkv”) do (
start/b/wait/low ffmpeg -i “%%i” -vf “pad=1920:1080:(ow-iw)/2:(oh-ih)/2” -c:v libx264 -preset slow -crf 18 -c:a copy “%TARGETPATH%\%%~ni.mkv”
echo.
)
goto Exit
:ErrorSource
echo Source path “%SOURCEPATH%” does not exist.
goto :eof
:ErrorTarget
echo Target path “%TARGETPATH%” does not exist.
goto :eof
:Exit
echo Done.
echo.
So first to lay out the problem space some: You will need two different types of tools, one that can do the filters for the black bars, and one to encode the new video. FFmpeg nicely wraps those together, like with your script you’re calling some built in filters and then the
x264
encoder to “make” to movie.The only two encoders I know that currently supports Dolby Vision are
x265
which only support it through their own encoder, not ffmpeg so wouldn’t be able to add those bars. Then an Nvidia Hardware Encoder program (only works if you have newer Nvidia graphics card). It does have some filtering abilities, but not sure if it can do that. Would also have have the RPU file on hand first, and then as their docs say remux it afterwards.Overall it is not simple, and maybe not possible with current free tools.
You would need to use dovi_tool to extract the RPU from you DV video. Then, after padding the video, inject the RPU with the correct L5 metadata (adjusting for the black bars). If x265 supports padding you could simply encode and apply the RPU metadata at the same time. I see that the links a posted earlier have been removed, but you should be able to find the information you need easily.
Hello!
Been trying to post a question but it doesn’t show, when trying again I get the answer:
“Duplicate comment detected; it looks as though you’ve already said that!”
Anyone have ideas about this?
Best regards,
Kim
Hi Kim, sorry for the issues. All comments have to be approved, and those were posted while we were asleep. So there may be delay between posting and seeing a comment appear!
Hello!
Good morning! 😀
Thank you for your kind and knowledgeable answer, much appreciated! I really like FastFlix which has a beautiful interface, thank you very much for that! You can not have enough tools in the toolbox! 😀 Will use FastFlix in the future and evaluate if it is something for me.
Best regards, Kim
When running commands to extract the HDR10+ data I get:
error: unrecognized subcommand ‘-‘
Usage: hdr10plus_tool [OPTIONS]
For more information, try ‘–help’.
What am I missing? Windows 11 command prompt
Thanks for the guide, very helpful. I could extract HDR10+ metadata using hdr10plus_tool. However, when trying to reencode with the metadata.json file, the output file does not contain the metadata. I checked using ffprobe by extracting a frame as below:
{
“frames”: [
{
“pix_fmt”: “yuv420p10le”,
“color_space”: “bt2020nc”,
“color_primaries”: “bt2020”,
“color_transfer”: “smpte2084”,
“side_data_list”: [
{
“side_data_type”: “Mastering display metadata”,
“red_x”: “34000/50000”,
“red_y”: “16000/50000”,
“green_x”: “13250/50000”,
“green_y”: “34500/50000”,
“blue_x”: “7500/50000”,
“blue_y”: “3000/50000”,
“white_point_x”: “15635/50000”,
“white_point_y”: “16450/50000”,
“min_luminance”: “1/10000”,
“max_luminance”: “10000000/10000”
},
{
“side_data_type”: “Content light level metadata”,
“max_content”: 598,
“max_average”: 273
},
{
“side_data_type”: “H.26[45] User Data Unregistered SEI message”
},
{
“side_data_type”: “H.26[45] User Data Unregistered SEI message”
}
]
}
]
}
It seems that the metadata format that x265 expects (https://bitbucket.org/multicoreware/x265_git/downloads/DCIP3_4K_to_400_dynamic.json) is different from the format that the hdr10plus_tool generates.
Am I missing something here?