View Full Version : Plugin HDRTools for Avisynth
Alexkral
20th November 2022, 16:45
May I ask why the default pct_hdr_skin for PQMode in ConvertXYZ_BT2446_C_HDRtoSDR is set to 0.44? I haven't seen anything in ITU-R BT.2408 regarding this, only about HLG.
jpsdr
20th November 2022, 19:03
I don't remember exactly... But if indeed there is nothing in BT.2408, i probably "estimate" it using informations from several BT, and i probably choose this value because "it seems not too bad".
There is probably some curve or anything which lead me to this choice.
Alexkral
20th November 2022, 20:45
Ah ok, I think I know why you did it. 44% PQ equals 50 nits, same as 50% HLG. It doesn't seem too bad indeed.
Alexkral
20th November 2022, 22:49
I found something funny looking at your code, not that it's in the least important, but I think I should let you know. You use 2.404 as the power in the BT.1886 EOTF, but the last 4 is actually a footnote :D. It's not that it's important as I say, but when I found the reason it made me laugh.
Also, I'm not too sure that the inverse OETF should be used, ITU repeats all over the place something that seems to imply this opinion, but I can understand why you do it.
jpsdr
21st November 2022, 01:43
Thanks for the 2.404, i'll change this later. My guess is that at the time i read it, i didn't see the footnotes and thought it was misprint... :D
jpsdr
21st November 2022, 19:30
New version, see first post.
jpsdr
26th February 2023, 12:36
New version, see first post.
LouieChuckyMerry
4th June 2023, 21:15
First, many thanks jpsdr for all your effort :) .
I was gifted a UHD Blu-ray but don't have a 4K TV, so I figured I'd shrivel it to 1080p using AviSynth after color converting and resizing losslessly with VirtualDub2. Unfortunately, after hours of effort, I can't figure out how to tonemap BT.2020 to BT.709. I'm here because it seems to me that that's what your HDRTools plugin is for but using
ConvertYUVToXYZ(Color=1)
ConvertXYZToYUV(pColor=1)
as in your example runs fine but appears to do nothing. Please, what am I missing?
Ahhh, a video sample (https://www.mediafire.com/file/tjhzaxbdhkfaw7g/TestClip2%255B2160p%255D.7z/file).
FranceBB
5th June 2023, 12:03
Unfortunately, after hours of effort, I can't figure out how to tonemap BT.2020 to BT.709.
Try this to go from BT2020 HDR PQ to BT709 with HDRTools:
ConvertBits(16)
ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=2.5, contrast_X=0.9)
ConvertXYZtoYUV(pColor=0)
Converttoyuv420()
If the conversion is fine but looks a bit off, change Reinhard's parameters accordingly 'till you're ok with the end result.
LouieChuckyMerry
6th June 2023, 00:48
Thanks for your reply, FranceBB. Your suggested script runs fine but doesn't appear to change the video in any way; i.e., the output looks the same as the input, dull and muted (the same-looking result as the script I posted above).
Boulder
6th June 2023, 07:05
If you have an nVidia GPU available, you can use DGHDRtoSDR to do the grading in one simple step. DGIndexNV can be used to tune the parameters per source.
FranceBB
6th June 2023, 11:58
Thanks for your reply, FranceBB. [...] the output looks dull and muted
Well, I wouldn't call it "Dull and Muted", but ok xD
Anyway, here's a comparison:
https://i.imgur.com/oCUGCkD.png
This is done with the following script:
FFVideoSource("D:\TestClip2[2160p].mkv")
SinPowerResize(848, 480)
original=last.Text("BT2020 HDR PQ 1043 nits - Original")
ConvertBits(16)
hbd=last
ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=2.5, contrast_X=0.9)
ConvertXYZtoYUV(pColor=0)
Converttoyuv420()
ConvertBits(bits=10, dither=1)
Text("BT709 SDR 100 nits - Reinhard tonemapping")
tonemapped=last
ConvertToPlanarRGB(hbd, matrix="Rec2020", interlaced=false)
Cube("C:\Programmi\AviSynth+\LUTs\PQ_to_BT709_v2.cube", fullrange=true)
Converttoyuv420()
ConvertBits(bits=10, dither=1)
Text("BT709 SDR 100 nits - FranceBB LUT")
lutted=last
StackVertical(original, tonemapped, lutted)
If you like the last one, then I strongly suggest you to check this out: https://forum.doom9.org/showthread.php?t=176091
LouieChuckyMerry
7th June 2023, 01:58
Boulder: Thanks for your reply. I do have an nVidia GPU and a license for DGIndexNV, so I'll attack your suggestion ASAP.
_____________
FranceBB: Thanks again for your help. Your latest suggestion looks good but I'll need a goodly stretch of free time to wrap my head around it.
_____________
I should have time this weekend to work on the above, possibly (but doubtfully) earlier. I really appreciate the help :) .
_____________
Edit: FranceBB: I took a quick look at your last link and, wow, that's really cool! Of course, I understand it intellectually but not really any of the details :o .
jpsdr
20th November 2023, 21:52
New version, see first post, but nothing big...
rgr
18th March 2024, 09:35
ConvertToPlanarRGB(hbd, matrix="Rec2020", interlaced=false)
Cube("C:\Programmi\AviSynth+\LUTs\PQ_to_BT709_v2.cube", fullrange=true)
Converttoyuv420()
ConvertBits(bits=10, dither=1)
Text("BT709 SDR 100 nits - FranceBB LUT")
lutted=last
StackVertical(original, tonemapped, lutted)
[/CODE]
If you like the last one, then I strongly suggest you to check this out: https://forum.doom9.org/showthread.php?t=176091
The latter worked great when playing the script through MPC-HC, but after conversion through ffmpeg it's still HDR -- there must be something missing in the script somewhere.
Video
ID : 1
Format : AVC
Format/Info : Advanced Video Codec
Format profile : High@L4
Format settings : CABAC / 4 Ref Frames
Format settings, CABAC : Yes
Format settings, Reference fra : 4 frames
Codec ID : V_MPEG4/ISO/AVC
Duration : 3 h 0 min
Width : 1 920 pixels
Height : 1 080 pixels
Display aspect ratio : 16:9
Frame rate mode : Constant
Frame rate : 23.976 (24000/1001) FPS
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Writing library : x264 core 164 r3179 12426f5
Default : No
Forced : No
Color range : Limited
Color primaries : BT.2020
Transfer characteristics : PQ
Matrix coefficients : BT.601
ffmpeg sets such data in the output:
Stream #0:0: Video: h264 (H264 / 0x34363248), yuv420p(tv, smpte170m/bt2020/smpte2084, progressive), 1920x1080, q=2-31, 23.98 fps, 1k tbn
FranceBB
18th March 2024, 10:35
Welcome to the world of frame properties, rgr!
No, jokes aside, it's not actually HDR but the reason why ffmpeg is reading it as HDR is that the frame properties are not updated.
When I wrote the script initially, we were in simpler times, when Avisynth only had the good old clip properties.
Anyway, to signal the right properties to ffmpeg you need to set them manually, so your script would become:
- For HDR Tools
#Indexing PQ source
video=LWLibavVideoSource("D:\TestClip.mxf")
audio=LWLibavVideoSource("D:\TestClip.mxf")
AudioDub(video, audio)
#Screw frame properties
propclearall()
#Bring everything to 16bit planar
ConvertBits(16)
#From YUV to XYZ with 16bit precision
ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)
#BT2020 PQ to BT709 SDR tonemapping in XYZ with 16bit precision
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=2.5, contrast_X=0.9)
#From XYZ to YUV with 16bit precision
ConvertXYZtoYUV(pColor=0)
#Conversion to YUV 4:2:0 with 16bit precision
ConverttoYUV420(matrix="Rec709", interlaced=false)
#Dithering down to 8bit with the Floyd Steinberg Error Diffusion
ConvertBits(bits=8, dither=1)
#Limiter TV Range 0.0 - 0.7V
Limiter(min_luma=16, max_luma=235, min_chroma=16, max_chroma=240)
#Setting frame properties to make FFMpeg happy
propSet("_FieldBased", 0) #progressive
propSet("_ColorRange", 1) #Limited TV Range
propSet("_Matrix", 1) #BT709
propSet("_Transfer", 1) #BT709
propSet("_Primaries", 1) #BT709
- For LUTs
#Indexing PQ source
video=LWLibavVideoSource("D:\TestClip.mxf")
audio=LWLibavVideoSource("D:\TestClip.mxf")
AudioDub(video, audio)
#Screw frame properties
propclearall()
#Bring everything to 16bit planar
ConvertBits(16)
#From YUV to RGB with 16bit precision
ConvertToPlanarRGB(matrix="Rec2020", interlaced=false)
#From BT2020 PQ to BT709 SDR with 16bit precision and tetrahedral interpolation
Cube("C:\Program Files (x86)\AviSynth+\LUTs\PQ_to_BT709_v2.cube", fullrange=1, interp=1)
#Conversion to YUV 4:2:0 with 16bit precision
ConverttoYUV420(matrix="Rec709", interlaced=false)
#Dithering down to 8bit with the Floyd Steinberg Error Diffusion
ConvertBits(bits=8, dither=1)
#Limiter TV Range 0.0 - 0.7V
Limiter(min_luma=16, max_luma=235, min_chroma=16, max_chroma=240)
#Setting frame properties to make FFMpeg happy
propSet("_FieldBased", 0) #progressive
propSet("_ColorRange", 1) #Limited TV Range
propSet("_Matrix", 1) #BT709
propSet("_Transfer", 1) #BT709
propSet("_Primaries", 1) #BT709
Needless to say, I hate frame properties.
Frame properties have their own utility in the sense that we can now tell other things outside of Avisynth (like the filter_builder in FFAStrans, FFMpeg, MPV etc) what we're outputting from Avisynth, but the problem is that not every function sets them correctly, so you almost always end up with the wrong ones. An easy workaround is to get rid of them all, always, at the very beginning, right after indexing, write the script as you're used to back when Avisynth didn't have them, then populate the right ones manually at the very end.
This is how I've done it for all the supply chains at work anyway, while for my personal stuff at home I use x264/x265 directly which don't really give a crap about frame properties so I'm safe from this.
rgr
18th March 2024, 15:26
Yes, I just found out.
If it already exists, it's a pity it doesn't have a pixel aspect ratio.
I also found in my notes:
"Color primaries" had an effect only on Quick Time...
"Transfer characteristics" did not have an effect on any player.
"Matrix coefficients" was the one that mattered in proper BT.601/BT.709 reproduction...
:)
Atlantis
28th April 2024, 08:52
I'm using staxrip to do HDR to SDR, it gives these default values.
ConvertYUVtoXYZ(Color=0, HDRMode=0, OOTF=false, OutputMode=2)
ConverXYZ_BT2446_C_HDRtoSDR(PQMode=true, Lhdr=10000, Lsdr=100.0, pColor=0)
ConvertXYZtoYUV(Color=2, pColor=0, OOTF=false, OutputMode=2)
ConvertBits(8)
Things look good except the whites are crushed and too much contrast. I played with Lhdr and increasing it gives better results.
I go to the point Lhdr=17000 which is kind of the sweet spot. Now I'm 90% happy with the image.
There are still some scenes where the contrast could be lower for the highlights. I can't go up or down anymore with Lhdr.
What are some other things, values I can tweak to get a better result? I don't want complicated scripts, just a simple thing.
Atak_Snajpera
28th April 2024, 14:24
Try this
ConvertYUVtoXYZ(Color=0,HDRMode=0,OOTF=false,OutputMode=2)
ConverXYZ_BT2446_C_HDRtoSDR(PQMode=true,Lhdr=50000.0,Lsdr=100.0,pColor=0,pct_ref=0.6,pct_ip=0.6,pct_wp=1.0,pct_sdr_skin=1.0,pct_hdr_skin=0.44)
ConvertXYZtoYUV(Color=2,pColor=0,OOTF=false)
ConvertBits(8)
These values emulate tonemapping in MadVR
https://forum.doom9.org/showthread.php?p=1893684#post1893684
Atlantis
28th April 2024, 16:09
Thank you, I will check to see. Any value that I changed in ConverXYZ_BT2446_C_HDRtoSDR had no effect at all except Lhdr!
tormento
17th October 2024, 15:50
Is there any way to have gamma-aware internal resizing?
I read this (https://forum.doom9.org/showthread.php?p=1722300) thread and it's a bit confusing to me.
Is
ConvertYUVtoLinearRGB()
Do_resample()
ConvertLinearRGBtoYUV()
enough?
DTL
20th October 2024, 23:00
In the modern complex world it is no more simple gamma transform but much more complex. So it may be better to write about resizing in linear domain. You may or may not get benefit with resizing in linear because there is no common standards about preparation of digital data for resize in linear or (system) transform domain. Also any conversion to and from subsampled chroma will damage your perfectly mastered digital data too.
You may get some benefit if you prepare your content in linear domain and also your display resize in linear domain. But if you prepare digital data for unknown users with unknown display resizers - it may not work as expected. So it is better to test best resize domain with your own displays if you prepare content for yourself. If you prepare for unknown users - may be better to resize in transform domain (because I think many displays are not doing resize in linear domain).
Your downsize operation is compression and displaying upsize is decompression operations and they must match to get perfect results (same as you compress/downsize with SinPow/UserDefined2 resize and master monitor with SincResize or SincLin2Resize). You can simulate with AVS scripting how much will be distortions if resize/codec domains are not match. But do not go to ugly subsampled chroma in between - it will damage irreversibly.
Also with HDR transform domains remember to re-transform to scene linear light to get correct linear data. Also see thread about usage of HDRtools in attempt to resize in linear domain - https://forum.doom9.org/showthread.php?t=183224 .
tormento
21st October 2024, 11:03
In the modern complex world it is no more simple gamma transform but much more complex.
Thanks for your kind and well argued answer.
My doubts arose both for gamma content but above all for HLG one, where the domain is "squished" in different ways on different parts. What could happen if we apply noise reduction that is not aware that the light part and the dark ones are not linearly represented? I tend to leave the PQ to HLG transformation as the last one but, as my computer is getting really slow with last filters, I resize the source directly in the zlib, such as:
z_ConvertFormat(width=1920, height=800, pixel_type="RGBP16", colorspace_op="2020:st2084:2020:limited=>rgb:st2084:2020:full", resample_filter_uv="Spline64", dither_type="error_diffusion", use_props=0)
DGCube("D:\Programmi\Media\AviSynth+\cube\1a_PQ1000_HLG_mode-nar_in-nar_out-nar_nocomp.cube", in="full", lut="full", out="full")
z_ConvertFormat(pixel_type="YUV420P10", colorspace_op="rgb:std-b67:2020:full=>2020:std-b67:2020:limited", resample_filter_uv="Spline64", dither_type="error_diffusion", use_props=0)
How will the subsequent filters will behave with something that is not even resembly linear?
DTL
21st October 2024, 13:27
Modern HDR transfer curvers are much more non-linear in comparison with gamma 2.2/0.45 of old SDR systems so making resize in HDR transfer domains may distort data more. But as we also do not have any standrard for display scaler - we can not say if resizing in linear or transfer domain is correct or not. With non-linear display scalers things may become even more complex and unpredictable.
"What could happen if we apply noise reduction that is not aware that the light part and the dark ones are not linearly represented?"
If noise deviation is not too large - the typical blocks blending process of MDegrain operates at close parts of transfer curve and possible distortions expected to be not very big. But if you try to process something like 4K-8K of 35mm film scan (silver black and white even worse) - it may be additional source of distortions. So it also depends on your source. But HDR linear require float32 samples to handle all range without too large quantization noise and mvtools may not work (or work good) with float32 samples. So maximum is 16bit integer and it is good only for SDR linear and partially for HLG HDR.
coolgit
30th December 2024, 22:36
Why is there a t missing in ConverXYZ_BT2446_C_HDRtoSDR when it should be ConvertXYZ_BT2446_C_HDRtoSD?
jpsdr
31st December 2024, 15:37
An error, maybe ? :D
jpsdr
20th July 2025, 10:18
New version, see first post.
jpsdr
25th August 2025, 12:29
Just for the record, as integer pictures (8 to 16 bits) use lookup tables, the AVX512 added has no effect.
I think there will be a small effect on float pictures with fastmode=true, and the most significant effect will be on float pictures with fastmode=false.
jpsdr
28th August 2025, 11:12
New version, see first post.
I made tests, but not intensive/exhaustive, so if any issue occurs, report here.
jpsdr
29th November 2025, 12:06
Update first page, minor changes.
AnonymousPeridot
21st February 2026, 04:18
Hi all, I've been playing around with this tool for sometime and I can't seem to accomplish what I want, so maybe you guys can help. I have a file that was incorrectly converted. The movie was already in bt.2020 but when the licensor brought it state side they incorrectly compressed it down to DCI.P3 inside a bit.2020 container, dulling the colors compared to foreign releases. Is there any way to convert the DCI.P3 back to the original bt.2020? I don't see DCI.P3 as an option in the color matrixes. Thank you for your consideration.
jpsdr
21st February 2026, 10:30
There is not direct named matrix option like "DCI.P3", you have to use the chromaticity coordinates parameters (check the readme) :
Rx,Ry,Gx,Gy,Bx,By,Wx,Wy -
These parameters allow to configure the chromaticity coordinates Red point, Green point, Blue point
and White point. If not set, the values defined in the BT.xxxx of the Color parameter are used.
So if you want to be sure of the proper (or specifix) matrix used, set these parameters.
AnonymousPeridot
22nd February 2026, 16:36
There is not direct named matrix option like "DCI.P3", you have to use the chromaticity coordinates parameters (check the readme) :
Rx,Ry,Gx,Gy,Bx,By,Wx,Wy -
These parameters allow to configure the chromaticity coordinates Red point, Green point, Blue point
and White point. If not set, the values defined in the BT.xxxx of the Color parameter are used.
So if you want to be sure of the proper (or specifix) matrix used, set these parameters.
Thank you so much that is exactly what I needed! After Googling the correct coordinates it fixed the colors. However it did show another issue with this film. It would appear as though they upped the brightness when converting it to Dolby Vision, and because of that it has effected the standard HDR 10 layer as well. Is there any way to possibly correct this also?
jpsdr
22nd February 2026, 17:55
Sorry, no idea, my tools are just for converting. For correcting, you have to use other filters i think.
AnonymousPeridot
23rd February 2026, 00:51
Sorry, no idea, my tools are just for converting. For correcting, you have to use other filters i think.
No worries it's all good your tool has already helped tremendously with just correcting the colors. Thank you.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.