View Full Version : FranceBB LUT Collection
FranceBB
8th February 2019, 19:15
Hi,
LUTs are generally used to grade contents, but they can be useful to do quick and dirt color space conversions, especially in this day and age.
Although a good color conversion has to be achieved manually and/or via algorithms, LUTs can still be helpful; unfortunately, I've seen people selling their LUTs for simple color conversion and it incredibly pissed me off 'cause they are supposed to be free, so today I'm gonna share my LUT collection, hoping that it can be useful to someone.
Before you apply any of my LUTs, remember that although you can apply them at any bit depth, I strongly suggest you to do that with 16bit precision, otherwise you'll get banding and other terrible issues.
LUTs are 65x65x65, which is supposed to be high precision, but some of them are 33x33x33 which is just about right. None of them are 17x17x17 'cause I don't consider it to be accurate enough.
LUTs: Link (https://github.com/FranceBB/LinearTransformation)
How to use my LUTs in Avisynth:
FFVideoSource("example.mxf")
ConvertBits(16)
ConvertToPlanarRGB()
Cube("C:\Programmi\AviSynth+\LUTs\example.cube")
How to use my LUTs in VapourSynth:
import vapoursynth as vs
core = vs.core
core.ffms2.Source(r'example.mxf')
vid = core.resize.Spline64(vid, format=vs.RGBS)
vid = core.timecube.Cube(vid, cube=r"C:\Programmi\AviSynth+\LUTs\example.cube")
vid.set_output ()
How to use my LUTs in FFMpeg:
ffmpeg.exe -i "source.m2ts" -vf lut3d='example.cube' -c:v whatever -c:a whatever -f mkv "output.mkv"
Alternatively, you can use my plugin "Linear Transformation": Link (https://github.com/FranceBB/LinearTransformation/blob/master/LinearTransformation.avsi)
Introducing LinearTransformation (https://github.com/FranceBB/LinearTransformation).
With the increasing number of matrices to do any kind of linear transformations, I kinda felt the need to make something more accessible for users, which is why I'm introducing now "LinearTransformation".
This plugin performs Linear Transformations based on a matrix conversion. Matrices are made by me and can be used independently from Avisynth as well.
Parameters
LinearTransformation(clip clp, string "Input", string "Output", string "Interpolation", string "LUT_Path")
clip = input clip
string Input = source input you're starting from
string Output = destination output you want to go to
string Interpolation = interpolation method to use (Trilinear or Tetrahedral)
string LUT_Path = path to the folder where the LUTs are ( e.g D:\MyLUTs\ while default is C:\Program Files (x86)\AviSynth+\LUTs\ )
The function has two mandatory parameters: Input and Output.
The function also has two optional parameters: Interpolation and LUT_Path.
The interpolation parameter can either be set to "Trilinear" or "Tetrahedral" and by default it's set to Tetrahedral as it achieves better results.
The LUT_Path allows you to specify a different path if you prefer to have the .cube files in a different place that isn't the default C:\Program Files (x86)\AviSynth+\LUTs.
Source (left) - Trilinear (center) - Tetrahedral (right):
https://images2.imgbox.com/ce/d3/lsm1LWs8_o.png
As you can see, in the right hand side waveform (tetrahedral) there are no ripples, unlike the ones you can see in the trilinear interpolation at the center.
Currently, only those conversions are supported:
LinearTransformation(Input="Linear_BT601_NTSC", Output="Linear_BT601_NTSC-J")
LinearTransformation(Input="Linear_BT601_NTSC-J", Output="Linear_BT601_NTSC")
LinearTransformation(Input="Linear_BT601_NTSC", Output="Linear_BT709")
LinearTransformation(Input="Linear_BT601_PAL", Output="Linear_BT709")
LinearTransformation(Input="Linear_BT709", Output="Linear_BT601_NTSC")
LinearTransformation(Input="Linear_BT709", Output="Linear_BT601_PAL")
LinearTransformation(Input="Linear_BT709", Output="Linear_BT2020")
LinearTransformation(Input="Linear_BT709", Output="BT2020_HLG")
LinearTransformation(Input="Linear_BT709", Output="BT2100_PQ")
LinearTransformation(Input="Linear_BT709", Output="DCI_XYZ")
LinearTransformation(Input="Linear_BT2020", Output="Linear_BT709")
LinearTransformation(Input="BT2100_PQ", Output="Linear_BT2020")
LinearTransformation(Input="BT2100_PQ", Output="Linear_BT709")
LinearTransformation(Input="BT2100_PQ", Output="BT2020_HLG")
LinearTransformation(Input="BT2100_PQ", Output="DCI_XYZ")
LinearTransformation(Input="ALog", Output="Linear_BT709")
LinearTransformation(Input="ALog", Output="BT2020_HLG")
LinearTransformation(Input="ALog", Output="BT2100_PQ")
LinearTransformation(Input="CLog3", Output="Linear_BT709")
LinearTransformation(Input="CLog3", Output="Linear_BT601_PAL")
LinearTransformation(Input="CLog3", Output="Linear_BT601_NTSC")
LinearTransformation(Input="CLog3", Output="BT2020_HLG")
LinearTransformation(Input="CLog3", Output="BT2100_PQ")
LinearTransformation(Input="SLog2", Output="Linear_BT709")
LinearTransformation(Input="SLog3", Output="Linear_BT709")
LinearTransformation(Input="SLog3", Output="Linear_BT601_PAL")
LinearTransformation(Input="SLog3", Output="Linear_BT601_NTSC")
LinearTransformation(Input="BT2020_HLG", Output="Linear_BT709")
LinearTransformation(Input="BT2020_HLG", Output="BT2100_PQ")
LinearTransformation(Input="BT2020_HLG", Output="DCI_XYZ")
LinearTransformation(Input="DCI_XYZ", Output="Linear_BT709")
LinearTransformation(Input="DCI_XYZ", Output="BT2020_HLG")
LinearTransformation(Input="DCI_XYZ", Output="BT2100_PQ")
LinearTransformation(Input="LogC", Output="Linear_BT709")
LinearTransformation(Input="LogC", Output="Linear_BT601_PAL")
LinearTransformation(Input="LogC", Output="Linear_BT601_NTSC")
LinearTransformation(Input="VLog", Output="Linear_BT709")
LinearTransformation(Input="VLog", Output="Linear_BT601_PAL")
LinearTransformation(Input="VLog", Output="Linear_BT601_NTSC")
LinearTransformation(Input="ZLog", Output="Linear_BT709")
LinearTransformation(Input="ZLog2", Output="Linear_BT709")
LinearTransformation(Input="dvhe0509", Output="Linear_BT709")
A Linear Transformation is essentially a matrix that maps all points of a certain space to another, which includes of course points belonging to a certain curve to other in order to get a different curve.
Of course, a linear transformation can be used in encoding to map some values to some other values and therefore have conversions from curves like PQ to HLG and so on.
The transformation is performed with 16bit precision, which means that if your input source is lower, let's say, 8bit planar yv12, it will be brought to 16bit planar RGB internally, the linear transformation will be applied with 16bit planar precision and then the result will be brought down to 8bit planar yv12.
Planar RGB 16bit is strongly suggested as your source as it's gonna be faster, in fact 4:2:0, 4:2:2, 4:4:4 planar up to 16bit will be converted back and forth internally.
Inside the plugin, the path specified for the matrices by default is: "C:\Program Files (x86)\AviSynth+\LUTs" which means that it's gonna look for my LUTs in a folder in such a location. It's not mandatory to have my LUTs there, you can have them in any location you want, provided that you do update that string via the LUT_Path parameter while calling the function.
A huge thanks to StainlessS and to the whole community for greatly improving the script and helping me writing it.
Plugin: https://github.com/FranceBB/LinearTransformation/blob/master/LinearTransformation.avsi
Matrices: https://github.com/FranceBB/LinearTransformation
Usage Example:
Example 1: From Slog3 to Linear BT709
FFVideoSource("mySlog3source.mxf")
LinearTransformation(Input="SLog3", Output="Linear_BT709")
Example 2: From PQ to HLG
FFVideoSource("myPQsource.mxf")
LinearTransformation(Input="BT2100_PQ", Output="BT2020_HLG")
Video:
https://i.ytimg.com/vi/XL8kkeEfQuk/hqdefault.jpg (https://www.youtube.com/watch?v=XL8kkeEfQuk&t=1s)
Images:
Slog3 pic1:
https://i.imgur.com/9E6yr7S.png
BT709 pic1:
https://i.imgur.com/7DHYloZ.png
-
Slog3 pic2:
https://i.imgur.com/glV6rHA.png
BT709 pic2:
https://i.imgur.com/icGXfbo.png
-
Slog3 pic3:
https://i.imgur.com/kYlmAet.png
BT709 pic3:
https://i.imgur.com/VaDIB0M.png
Slog3 to BT709
https://i.imgur.com/TIRdtG5.png
Who made those LUTs?
Those matrices are made by Francesco Bucciantini (FranceBB) (https://www.linkedin.com/in/francesco-bucciantini-3392b4ab/), computer science engineer and Linear Algebra lover and Livio Aloja (aligia) (https://www.linkedin.com/in/livio-aloja-9a287424/), former Senior Sky Editor and Encoder, using both free open source tools and closed source ones and cross-checking them with broadcast grade equipment (TVs, waveform monitors, scopes) provided by Sony, Canon and Tektronix.
Who uses those LUTs?
Those LUTs are used by everyone for free, from companies that deal with broadcasting video content in any way (Post-production, OTT, etc) like public and private broadcasters all around the world to regular people that want to convert their video archives.
Mentions in other programs:
These LUTs are officially shipped with
- FFASTrans - FFMpeg Avisynth Transcoder by Steinar Apalnes, Benjamin Dissoubret and Francesco Bucciantini (https://www.ffastrans.com/)
- Hybrid by Selur (https://www.selur.de/)
Compatibility with third party programs:
- Compatible with Avisynth+
- Compatible with VapourSynth
- Compatible with AVID Media Composer
- Compatible with Davinci Resolve
- Compatible with Adobe Premiere
- Compatible with Colorfront Transkoder
gonca
8th February 2019, 23:24
Thank you for this.
One question
Should it be fulldepth=true or false
since false would return 8 bit I believe
FranceBB
9th February 2019, 04:12
Should it be fulldepth=true or false
since false would return 8 bit I believe
Nope, they both return 16bit, but fullrange=true is for full range (PC Range) sources, while fullrange=false is for limited range (TV Range) sources.
Limited range for 8bit is 16-235, for 10bit is 64-940 and so on.
Full range for 8bit is 0-255, for 10bit is 0-1020 and so on.
It depends on your source, but keep in mind that the majority of sources are TV Range and if you encode something for the TV, it has to be Limited TV Range.
gonca
9th February 2019, 12:37
My mistake
I originally read fulldepth in your sample script, but after re reading it I realize that it actually says fullrange
StainlessS
9th February 2019, 14:56
Full range for 8bit is 0-255, for 10bit is 0-1024 and so on.
Nit Pick, 1023.
EDIT: Hmmm, I'm wrong too.
FranceBB
9th February 2019, 16:44
Sorry about that.
Actually, this is the right one, I think (from the Avisynth Wiki):
https://i.imgur.com/aZtIN8V.png
huhn
9th February 2019, 20:48
these "issues" come from the understanding that 10 bit is 4 times as big as 8 bit so we just have to multiply by 4.
8 bit RGB 255 255 255 as 10 bit is 1023 1023 1023 not 1020 1020 1020 has a very slightly lower brightness and is just 4x the original number.
the correct way to increase 8 bit to 10 bit is taking the first 2 bits from the 8 bit source and add them to the end.
or as an small example:
11111111=255 100 % brightness
1111111100=1020 ~99.7% brightness
1111111111= 1023 100% brightness
wonkey_monkey
9th February 2019, 21:41
the correct way
But according to whom? The wiki seems to indicate the other way - simple shifting - is correct. What's the broadcast standard?
And what's the correct way to go back down? Is there bit-ty way to do it, or do you have to divide by 4.0117647059?
And I thought 16-235 was a headache...
huhn
9th February 2019, 22:02
i just ask you a different question who stops you from creating a native 10 bit source with 1023 in it?
a bad way to go back to 8 bit is by removing the last too bits truncation. another one would be dithering.
wonkey_monkey
9th February 2019, 22:19
i just ask you a different question who stops you from creating a native 10 bit source with 1023 in it?
Umm, okay, but my questions weren't rhetorical. Nothing stops you from creating a native 8 bit source with 255 in it, but that is - according to broadcast standards - an "illegal" value.
a bad way to go back to 8 bit is by removing the last too bits truncation. another one would be dithering.
Dithering still needs a convention as to what values, integer of fractional, correspond between the bit depths.
huhn
9th February 2019, 22:39
Umm, okay, but my questions weren't rhetorical. Nothing stops you from creating a native 8 bit source with 255 in it, but that is - according to broadcast standards - an "illegal" value.
full range is a thing. computer games work in it it's part of display port and HDMI.
while BD source is all ways limited range this doesn't change that even full range encoding is a thing and totally supported by programs like x264.
and be aware that this is about RGB not YCbCr.
so clearly not illegal
Dithering still needs a convention as to what values, integer of fractional, correspond between the bit depths.
does it? how should i even know what an dithering algorithm is working internal. i know it using the "errors" truncated parts to spread noise if it is max 1023 or 1020 shouldn't matter. it will just use what it has available.
wonkey_monkey
9th February 2019, 22:49
Okay, we're getting off-track. The original point is: the Avisynth wiki says 8-bit 255 is equivalent to 10-bit 1020. You say it's 1023. Who's right?
silverwing
25th February 2019, 22:30
FranceBB, thank you!
So.
These are examples with your lut "PQ_to_HLG.cube".
I get a similar result only with the help of a long selection of curves in the plugin "SmoothCurve". Good work. :thanks:
FranceBB
19th March 2019, 05:59
FranceBB, thank you!
So.
These are examples with your lut "PQ_to_HLG.cube".
I get a similar result only with the help of a long selection of curves in the plugin "SmoothCurve". Good work.
Thanks, I tried to tweak things correctly.
Update: Added Slog3 to BT709 LUT
Whenever I work for the News channel or for our Sport channel, I receive footages shot normally, but whenever I work on TV Series, I receive footages shot in Slog3 and I always have to bring them to BT709 to encode everything in a standard old-fashioned FULL HD SDR.
I'm gonna share with you my Slog3 to BT709 LUT as well.
https://i.imgur.com/TIRdtG5.png
Slog3 first, BT709 second:
https://i.imgur.com/9E6yr7S.png
https://i.imgur.com/7DHYloZ.png
https://i.imgur.com/glV6rHA.png
https://i.imgur.com/icGXfbo.png
Some people may think that it's ok-ish, but slightly dark on some low-light scenes, but actually this is because I added a knee to the curve and there's a reason for that: trying to stay in the Limited Tv Range avoiding clipping.
Let's take a look at this example here with a strong light coming from behind.
Raw footage in Slog3:
https://i.imgur.com/kYlmAet.png
If I try to apply a transformation without using a knee, the white level gets too high and I get out of legal range, therefore everything over 235 gets clipped out:
https://i.imgur.com/c8ItGyB.png
By adding a knee, however, I manage to get thinks right in 16-235 without the need to clip so many details out:
https://i.imgur.com/VaDIB0M.png
If you take a look at the curve of the transformation you can see how the unclipped one gets so high that it almost looks like a function that reaches a vertical asymptote:
https://i.imgur.com/oT6Tw7B.png
While the knee manages to smooth things out and generates a proper curve:
https://i.imgur.com/8Q3DQBi.png
FranceBB
24th April 2019, 03:41
Update: Added C-Log3 to BT709 SDR / C-Log3 to PQ HDR / C-Log3 to HLG HDR
I added three new LUTs that are meant to be used by Canon C-300 Camera users.
It's a 4K professional camera that can record up to 12bit with the C-Log3 curve and it can definitely be used for HDR productions and SDR ones alike.
What's interesting about this curve with the C-300 is that it's possible to shoot and then grade it to HDR PQ and get approximately 3500 nits worth of data (I mean, real data).
When I created the LUTs, I tried to keep the BT709 SDR one in range and I applied a knee to get the right values.
As to the HDR PQ one, I left it "unclipped" to 10'000 nits, however you're not gonna get anything over 3500 nits. The reason why I left it unclipped up to 10'000 nits, though, is that Canon might release new cameras in the future that are gonna use the same curve and perhaps they'll be able to get more than 3500 nits worth of data.
As to the HDR HLG one, I had to make a very big compromise, 'cause as you know, HLG has been invented in order to display both HDR and SDR using the same file, which basically means that whenever you make a LUT you have two choices: 1) make it more HDR-like and sacrifice the view of the ones with an SDR TV or 2) make it more SDR-like and sacrifice the view of the ones with an HDR TV.
Since many people still have SDR TVs, my choice (as well as the one of other encoders working in broadcast) is to make it more SDR-like, 'cause this way no one is ever gonna complain.
In order to do so, I had to sacrifice the representation of the black values and of course since HLG is limited to 1'000 nits, I had to lower down the highlights as well.
The result looks good and it's definitely more natural than the SDR, but comparing it to the PQ is... like... you know... not quite good enough, but as broadcaster it's kinda acceptable.
Alright, let me show you the graphs.
Let's start with the C-Log3 to BT709 SDR:
https://i.imgur.com/IwzbKey.png
https://i.imgur.com/IwzbKey.png
https://i.imgur.com/NC0Qvik.png
As you can see, the C-Log3 curve is very different compared to the BT709 and it's a curve that it's meant for HDR productions as well, so although it can be used for SDR, the grading should really be done manually on a scene by scene basis, 'cause otherwise you might end up with oversaturated or wrong values.
C-Log 3 to BT2100 HDR PQ:
https://i.imgur.com/t7kdtcs.png
https://i.imgur.com/h3xyoPh.png
https://i.imgur.com/iF3h0BL.png
As you can see, the C-Log 3 curve pretty much resembles the PQ curve, this is also why it's actually pretty easy to map it to HDR PQ BT2100.
C-Log 3 to BT2100 HDR HLG:
https://i.imgur.com/FnUukXL.png
https://i.imgur.com/hEC7UbZ.png
https://i.imgur.com/2RS5aCl.png
As you can see, I tried to keep the HLG curve as tweaked as possible to SDR, which actually limited the quality of the blacks for the HDR viewers. As to the peak, HLG is limited to 1000 nits by definition.
FranceBB
24th April 2019, 03:41
Alright, let's crack on and view some examples.
You'll find the original C-Log3 footage, the BT709 SDR one, the HDR HLG one and the HDR PQ one.
I tried to keep the BT709 LUT as usable as possible, but limiting C-Log3 to BT709 SDR means that many details are really gonna be clipped out and you can definitely see it from the examples below.
As to the HDR HLG BT2100, it pretty much resembles the BT709 SDR version, but it does show more details, despite being still capped out.
Finally, the HDR PQ BT2100 is the best looking version, with a very natural look and it almost feel like as if you were there for real with 3500 nits worth of data.
C-Log3
https://i.imgur.com/OGsGwCC.jpg
BT709 SDR
https://i.imgur.com/PEf8dPS.png
BT2100 HDR HLG
https://i.imgur.com/Ty2R7go.png
BT2100 HDR PQ
https://i.imgur.com/3D4nNem.png
C-Log3
https://i.imgur.com/fwxqH16.jpg
BT709 SDR
https://i.imgur.com/hisJcBM.png
BT2100 HDR HLG
https://i.imgur.com/iycLYSo.png
BT2100 HDR PQ
https://i.imgur.com/bgXCnHn.png
C-Log3
https://i.imgur.com/u32LPm4.png
BT709 SDR
https://i.imgur.com/RV23zGM.png
BT2100 HDR HLG
https://i.imgur.com/GPV7Oqf.png
BT2100 HDR PQ
https://i.imgur.com/yyqGQ5S.png
C-Log3
https://i.imgur.com/Y5nHirT.png
BT709 SDR
https://i.imgur.com/8LGSkWj.png
BT2100 HDR HLG
https://i.imgur.com/64zMdVa.png
BT2100 HDR PQ
https://i.imgur.com/aAbjw8L.png
gonca
25th April 2019, 22:54
Once again, thank you for your contribution :thanks:
Perhaps a dumb question: How do people select the "correct" LUT? Is it a matter of personal taste, or do we need reference pictures for comparison?
FranceBB
1st May 2019, 14:08
Perhaps a dumb question: How do people select the "correct" LUT? Is it a matter of personal taste, or do we need reference pictures for comparison?
What do you mean?
Each LUT is a matrix of linear transformation that goes from a curve to the other, which basically means that, depending on your source color curve, you use the one to go from it to your target color curve.
For instance, if you have an HDR PQ video and you wanna go to HDR HLG, you are gonna use my PQ_to_HLG LUT.
If you are asking how to create a LUT yourself, then that's a whole different question and... no, it's not a matter of personal taste only, it's a matter of linear algebra, defined standards and personal taste.
You generally start with a linear conversion from a curve to the other and then tweak it trying to get into the right values according to the standard. After that, you can fine-tune it 'till you'll get something that looks best for your taste, as long as you are still respecting the standards.
Anyway, it really depends on your source and your target, 'cause if you have two curves that are really different one to the other, then you are gonna have to choose which parts of the input you wanna keep while you go to your desired output.
Let's suppose that you have a C-LOG3 in input and you wanna go to BT709 SDR in output; you can basically get the calculations right, but you still have to choose what you wanna sacrifice as the BT709 SDR is able to retain very little informations compared to the input and THAT is a personal choice according to what you think it's best.
When I make my LUTs, I always try to keep as many things as possible and make them usable for pretty much every scenario. Let's suppose that we have a scene with snow, a white dog and the sky: you are gonna have three different tonalities of white, one for the snow, one for the dog and one for the highlights (sky). If you originally shoot in BT709 SDR, you have one of those three tonalities of white clipped out, while if you shoot in C-LOG3 you are gonna have as many details as your camera can get, then, in encoding, you can decide to retain the desired part of the image, with the desired tonalities of white. In this specific case, you wouldn't be able to do it with my LUT, 'cause my LUT is gonna take a decision for you and clip what I thought it was supposed to be an acceptable compromise for every scenario, but it's better to do it manually, 'cause by doing it manually you can choose which things you are gonna preserve for that specific shot.
I hope this answer your question; if you want, I can get into more technical details.
Cheers,
Frank.
Thank you Frank for enlightening me. Your short tutorial answered my nebulous question about the LUTs nicely :)
FranceBB
10th May 2019, 10:17
Hello Frank,
Thanks a lot for this! It will be useful for sure.
I wonder if you work on Sony Slog 2? I must admit it will be useful for me :)
Slog 2 to rec 709.
Thanks again.
Cheers.
Benjamin
I don't use Slog2 anymore, but I do have some old contents shot using that curve, so it's gonna be useful to me as well.
Slog2 is the second revision of the old version of the Sony log, which is significantly different if you compare it to Slog3 as we can see from here:
https://i.imgur.com/Rl5Y0io.png
(The scale used in the graph is the same, so it's easier to spot the differences).
As you can see from the graph, Slog2 curve is pretty much the same (although slightly lower) on the low terms with a more gradual raise, while as it goes up it intersects with Slog3 and it ends up raising faster. If you take a look at this Slog2 shot, you can see the differences between the two curves:
This is the orignal Slog2 footage:
https://i.imgur.com/F09jiif.png
This is how it would have been if it was recorded in Slog3:
https://i.imgur.com/0h3sM4a.png
Keep in mind that this specific example is kinda "bogus" 'cause the content has been originally shot in Slog2, so a linear transformation matrix had to be applied in order to convert it to Slog3; luckily the transformation was 1 to 1, but it's not onto. The reason is that every element in Slog2 can be mapped to Slog3, however the contrary is not true: for instance, Slog2 is a 14 stop maximum curve, so the peak level is recorded right at the top of the recording range, while the S-Log3 curve is designed to go beyond 14 stops. In other words, an element that resides within the >14 area can't be mapped back, so the linear transformation is not onto which basically means that it's not an isomorphism, which is basically why I said that the example above is just to give you something else other than the graph.
Enough digression for Slog2 vs Slog3 and linear algebra lovers, so let's crack on and take a look at the graph that goes from Slog2 and then we'll take a look at some examples.
This is what I've got so far for Slog2 to BT709 SDR:
https://i.imgur.com/EOM31i6.png
Please note that it's not just the curve, but also the Gamut as we have S-Gamut with Slog2 (it would have been S-Gamut3 with Slog3), which is not exactly so straightforward to convert to BT709 SDR as the color science inside it's slightly different from the one we use to deal with.
Let's take a look at our first example here:
Slog2:
https://i.imgur.com/QDdGSDG.png
BT709 SDR:
https://i.imgur.com/XI9mCKc.png
This is exactly what I mean with "it's not exactly so straightforward". It's very easy to get the different tonalities of the leaves/ground wrong, especially on a general purpose LUT, which is why I tried to keep it as low as possible. For instance, when I tweaked it to a scene, I've got a red-ish colors on brown tonalities, so this is the compromise I managed to get.
Let's take a look at a normal shot you are usually going to get:
Slog2:
https://i.imgur.com/pNElEE7.png
BT709 SDR:
https://i.imgur.com/Dm9njIH.png
As you can see, skin tones are natural and chroma grading is in general kinda conservative, as well as levels.
Let's take a look at the last example here:
Slog2:
https://i.imgur.com/SHg1JY4.png
BT709 SDR:
https://i.imgur.com/CZur4ZT.png
In this case, although the overall picture appears fine, in the BT709 SDR output we've got combing in the hat. Don't get me wrong, it wasn't introduced as an artifact by the conversion, but it was on the Slog2 S-Gamut already, however while it looked like a fine gradient, it became a noticeable "artifact" once it has been converted to BT709, so in this case it might be worth doing it manually.
I'm gonna finish a few things and perhaps tweak it a little bit more and then I'm gonna upload it next week.
Cheers,
Frank.
FranceBB
27th May 2019, 16:14
When logarithmic curves are life, linear algebra is your passion and you can't start the day without using a matrix of linear transformation :P
https://i.imgur.com/0oUrdz3.jpg
ChaosKing
27th May 2019, 16:36
Nice and tasty results :D
FranceBB
16th June 2019, 05:04
Over the last few days I've been taking pictures of pretty much everything in LogC.
I'm gonna upload the LUT in a matter of hours, but right now I uploaded a few images here 'cause it's "educative" to show how linear transformations performed by the matrix created (my LUT) are ok, however there's always margin for manual adjustment: the so called "artistic-choice" which cannot be included in a LUT by default as it would produce a good result on some occasions and bad results on some others.
(Examples are in BT709 SDR as the sensor I used is very bad and with a ridiculously low amount of stops).
Example1:
Log-C:
https://i.imgur.com/T2AAJQM.png
Linear Transformation BT709 SDR:
https://i.imgur.com/qVRLFoF.png
Artistic Choice BT709 SDR:
https://i.imgur.com/nE8lgGK.png
Log-C:
https://i.imgur.com/9Hltiqk.png
Linear Transformation BT709 SDR:
https://i.imgur.com/PmAD6FR.png
Artistic Choice BT709 SDR:
https://i.imgur.com/SyauXJi.png
Log-C:
https://i.imgur.com/664H6mJ.png
Linear Transformation BT709 SDR:
https://i.imgur.com/9Fkg42y.png
Artistic Choice BT709 SDR:
https://i.imgur.com/ys19Czx.png
As you can see, the matrix cannot tell whether it's ok to raise the highlights or not 'cause in some occasions it is, in some others it's not, so it just sticks with a rather conservative linear transformation; after all, it is my personal choice to raise certain highlights.
For instance, the cat should be black 'cause it was completely black in the reality, but I wanted to raise the grass a little bit and give a bit more life to the fur at the expense of making it "dirty" a little bit.
Anyway, those are just examples, they are shot with a ridiculously crappy sensor and I literally spent 2 minutes to grade them, however I do believe that they were good examples of what I mean by "artistic adjustment".
This is the LUT I'm gonna upload this evening:
https://i.imgur.com/5iCRvdR.png
https://i.imgur.com/jkSeYRe.png
https://i.imgur.com/Mb1bFhA.png
FranceBB
9th July 2019, 23:50
Have you ever noticed that many of the latest music videos have been originally shot in Log? I just noticed that Rita Ora - Lonely Together, Ed Sheeran - Beautiful People and Ellie Goulding - Sixteen were all Log; you can tell by the way they have been graded and brought to BT709 linear with a matrix of linear transformation (LUT).
This is a frame from "Ed Sheeran - Beautiful People":
https://i.imgur.com/TVbfP9c.png
FranceBB
25th July 2019, 09:53
Here I am again, ready to play with matrices of linear transformation as I have a little bit more spare time.
A few days ago, a user, Gser (https://forum.doom9.org/member.php?u=148121) received a DCP package in M-JPEG2000 which contained an XYZ 4:4:4 12bit video.
He was trying to convert it to RGB and then YUV to encode it and I got interested in the subject as the very first thing I thought about was "we can do it with a matrix of linear transformation!" :D
Unfortunately, though, I didn't really have time to spend on that as I was both working and studying for my Calculus III exam (which I just passed; hurray! :)).
Anyway, in the mean time another encoder popped up to help Gser (https://forum.doom9.org/member.php?u=148121) and made his own matrix using Davinci Resolve; the encoder who made the matrix is Bradley Greer, founder of Kyotocolor and a very famous colorist who worked for several movie productions and who has been invited to speak on behalf of Kodak, Sony, and Avid multiple times...
I know what you are thinking: "C'mon Frank, I know you like matrices, but can't you just give us a link to his matrix and stop?"
Well, if you just wanna stop reading and you wanna use his LUT, you can download it from this website: Link (http://24p.com/wordpress/wp-content/uploads/2016/11/xyz-709-xyz.zip)
However, there are some interesting findings I made for what follows...
As an engineer who truly loves Linear Algebra and who likes math, I can't stop thinking about matrices of linear transformation and although there was already a matrix made by a really talented encoder, I really wanted to make my own matrix in order to see how far I was going to get, so first things first.
First of all, a DCI it's actually relatively easier to handle as we're gonna make our conversion in linear gamma, specifically from 2.60 to 1.90, as we're gonna have to bring it down to make use of it in our final BT709 target. The second think we need to do of course is to convert the XYZ colorspace. X, Y and Z are extrapolations of RGB created mathematically to avoid negative numbers and are called Tristimulus values: Y means luma (as we all know), Z is somewhat equal to blue, and X is a mix of cone response curves chosen to be orthogonal to the luma and non-negative.
In my attempt to make a decent-looking matrix, I used the monitor I have here at work to test it and I'm not very satisfied with the result as I think that the black level is too low and the white level has been compressed so much to avoid clipping that the final look actually greatly differs from what the original intent was, however it doesn't look bad and I think it can be used in production.
Anyway, before trying to spot the conversion differences, let's take a look at the graph of the curves first:
https://i.imgur.com/3HPo5aU.png
https://i.imgur.com/28Mav1M.png
If you remember how logaritmic curves behave, you can see that they're completely different.
Logaritmic curves generally use to start higher than the linear BT709 one and then they generally curve 'till they get almost straight as if they were y=x+3 in the first quadrant, crossing the linear BT709 curve two times, at the beginning after the non-so-black values are displayed and at the end right when the linear BT709 one gets a correction in order to avoid to get out of range values, therefore applying a sort of soft-clipping, which someone likes to call "knee". In the DCI case, however, there are no points in common whatsoever between the two curves and the DCI one is always above the BT709 one. We kinda expected this as we knew that it was going to be higher, but the interesting thing is that the difference between the two curves isn't constant as we expected in a linear scenario, on the contrary, it varies as there's less difference in the mid-tones than there's in the black-ish tones. As to the white tones, the DCI curve quickly peaks to high values while the BT709 one is smoothed to make sure to avoid out of range values (i.e clipped whites and so on), so it diverges but we expected this and it makes sense.
Alright, let's take a look at the comparison, shall we?
Original XYZ footage 1:
https://i.imgur.com/BgxWxda.png
BT709 Bradley Greer matrix of linear transformation:
https://i.imgur.com/l4RnUzO.png
BT709 FranceBB matrix of linear transformation:
https://i.imgur.com/KJRG26z.png
Original XYZ footage 2:
https://i.imgur.com/xPBe02t.png
BT709 Bradley Greer matrix of linear transformation:
https://i.imgur.com/Nzg3HYr.png
BT709 FranceBB matrix of linear transformation:
https://i.imgur.com/ERSyBwH.png
We can see how the Bradley Greer matrix has both luma and chroma right to the right level and it offers a more natural representation of how the scene should look like. As to the matrix I used, blacks are slightly too low I think and in order to have whites in range I ended up scaling everything down and getting perhaps too smoothed values. I'm gonna post the matrix by tomorrow, so feel free to use it anyway if you prefer it over the Bradley Greer one and you like a darker, more contrast-looking output with kinda saturated colors, or just use the Bradley one as many other people are.
When it comes to these things, it's really up to you and your eyes as both matrices are mathematically correct.
Temporary Link (I'll add it to the main link inside the folder soon): Link (https://wetransfer.com/downloads/3df66d4386679baca613270e8c2945d420190728155059/0c4977)
Cheers,
Frank.
FranceBB
1st September 2019, 20:22
A few days ago I was explaining how HLG is useful but it looks different for people who do have a BT2020 SDR capable TV but not an HLG HDR capable one.
I strongly invite you to read it here: Link (https://forum.doom9.org/showthread.php?t=176797)
As a follow up, I decided to do a few more comparisons to show you how it looks different across different TVs.
On the left hand side, you'll find the BT709 SDR footage.
In the middle, you'll find the HLG version as it should look like for people who have an HLG Capable TV.
On the right hand side, you'll find the HLG version as it should look like for people who have a BT2020 SDR capable TV.
https://i.imgur.com/0XEspy6.png
https://i.imgur.com/NMettmD.png
https://i.imgur.com/lMqVJEr.png
https://i.imgur.com/t2JQnRZ.png
https://i.imgur.com/X7wdfb3.png
https://i.imgur.com/wOpP2Ab.png
https://i.imgur.com/SImWPia.png
https://i.imgur.com/KxKJHuZ.png
https://i.imgur.com/y6oLnmT.png
https://i.imgur.com/t9UnEgl.png
https://i.imgur.com/Uu4SVJe.png
https://i.imgur.com/OzkEew4.png
https://i.imgur.com/Ih182V8.png
Link to sample files:
BT709 SDR & BT2020 HLG HDR: https://we.tl/t-cXvmayyONR
Comparison Video (BT709 SDR - HLG BT2020 - BT2020 SDR): https://we.tl/t-NkikWq8AwO
FranceBB
21st October 2019, 22:17
Hi there,
it's been a while.
Today I had to encode a few contents shot with a Nikon camera in Z-Log.
I gotta say that I was surprised 'cause I totally ignored the fact that Z-Log even existed, however it seems that it's really a thing and it has been developed around mid-2018 or so.
Anyway, since I didn't really want to get into HDR as I have no flipping clue about how many stops (nits) Nikon cameras have, I decided to go to Linear BT709 SDR 100 nits as target for my matrix of linear transformation.
To be fair, even though I don't know the exact amount of stops that those cameras have, from the tests I made, I don't really think that there are enough stops to get a decent amount of nits that would justify going to HDR (either HLG or PQ), so it's better to stick with BT709 SDR.
I'm about to show you some Z-Log 10bit footages before and after applying my matrix of linear transformation (LUT):
Z-Log Original 1
https://i.imgur.com/zW5r1yu.png
Linear Transformation to BT709 1
https://i.imgur.com/hDa8VXp.png
Z-Log Original 2
https://i.imgur.com/Ml03NR2.png
Linear Transformation to BT709 2
https://i.imgur.com/quH5HF4.png
Z-Log Original 3
https://i.imgur.com/NGPjVOv.png
Linear Transformation to BT709 3
https://i.imgur.com/PbYrWF3.png
I know what you're thinking "you generally plot the input and output curves in a graph and show the differences between the input and the output, why didn't you do it this time?".
Well, mathematical laziness at its finest I say, so I'm asking you to fire up your brain and picture a 2D plane in your mind.
https://i.imgur.com/aGX2DOk.png
You should be familiar by now with the classic BT709 curve, so let's focus now on the Z-Log one.
Well, Z-Log basically has the black level that starts higher than normal, however it quickly goes up with its highlights to the point it doesn't even look like a logarithmic curve anymore at the very top. This is because its main focus is to prioritize blacks and offer a better way to deal with situations that would otherwise be difficult to deal with and would get blacks crashed. So, if you're ever going to shoot in Z-Log, keep in mind that although it does a fine job in retaining the details of the blacks, it won't help you with highlights. In other words, if you are using Z-Log, don't expect to have skies not clipped out and a very wide dynamic range, it's not what it's meant for! The reason for that, I suppose, is that sensors used by Nikon cameras don't have many stops and although they do a relatively fine job with dark areas, they are not able to get bright areas and highlights.
I'm gonna add the .LUT file called "Z-Log_to_BT709.cube" tomorrow.
As a plus, this time it's gonna be compatible not just with Avisynth, but also with ffmpeg.
Cheers,
Frank.
anatol2002
18th December 2019, 14:39
Hi Frank
I tried to access the LUT's link, but it did not work for. Is it broken?
Actually I am looking for HLG to PQ conversion. Do u have that LUT?
Thanks,
Anatol
FranceBB
18th December 2019, 18:28
Hi Frank
I tried to access the LUT's link, but it did not work for. Is it broken?
Actually I am looking for HLG to PQ conversion. Do u have that LUT?
Thanks,
Anatol
It works fine on my end. https://i.imgur.com/ZqYl5I9.png
Please note that Mega is blocked by some ISP via DNS, so you might wanna try to change your DNS to the google ones or open dns ones or cloudflare ones.
FYI
Google DNS are 8.8.8.8, 8.8.4.4
Cloudflare one is 1.1.1.1
As to the LUTs, I did make a PQ to HLG but I didn't make an HLG to PQ. If you need it, I might take a look at that and make it. Ideally I would make a 1000 nits HLG to 1000 nits PQ, if that's alright. Would you be willing to test it if I send you a LUT?
anatol2002
22nd December 2019, 05:05
Hi Frank
Thanks for your advice - I succeeded to download the LUT's files from another connection.
And thanks again - I will surely test the HLG to PQ LUT! Much appreciated!
Anatol
FranceBB
22nd December 2019, 15:55
Ok, perfect. The reason why I use Mega as a host is because it's fast and I have 50 GB of space free of charge, but it's blocked in some countries.
Anyway I'm gonna be out of office 'till Christmas, so I won't be able to work on the LUT (heck I don't even have a 1000 nits capable display at home T_T), but I will as soon as I get back to work.
For those curious, I'm actually eating a delicious half roast chicken with a pig-in-blanket, roast potatoes, gingerbread stuff, red wine jus and of course two Yorkshire puddings.
As you probably figured out, I'm currently in the UK as there's hardly anything more British than a Sunday Roast. https://i.imgur.com/k0N36Cg.jpg
anatol2002
22nd December 2019, 18:31
Merry Christmas Frank!
Have a great time in UK!
P.S. - is it a roast chicken or broadcast chicken :)
FranceBB
26th December 2019, 21:55
Alright, before getting to HLG to PQ, I wanted to review my HDR PQ to HLG matrix and add a new one.
I gotta say though that making a PQ to HLG matrix is a bit tricky 'cause it's NOT an homomorphism 'cause the PQ input is so much wider than the HLG output, so I can't match each and every point of the input to a single point of the output (not 1-1) but every member of the input is mapped to all the output (so it is onto) but definitely not an homomorphism. In other words, you can't go from PQ to HLG without losing something.
A matrix of linear transformation is just... you know... a matrix, which basically means that can map some points of the input to some other points of the output, which is exactly what I'm doing here for PQ to HLG, however PQ can span from 0 to 10'000 nits while HLG can only span 0 to 1000 nits which is far less than PQ. The thing is that I can't make the LUT change on a scene-by-scene basis or anything, it's static, it's just a "mapping", therefore there's no magical matrix that works for any content in the world.
I started with the BBC White Paper as a good reference point for doing just this as I did last time for the other LUT, however I was trying to adapt this in order to be good with any kind of contents with many more nits than 1000 nits without brutally clipping them in my attempt to bring them down to 1000 in HLG, but I wasn't satisfied. The results were poor and my matrix only behaved correctly on not-so-bright contents. Fortunately, I noticed that NHK published a similar reference paper for HDR PQ to HLG which has been translated in English (thanks God as I don't really understand Japanese other than a few words I learned from watching anime in my younger age) and it was far different from the BBC one. After trying a few options, the curve I got has a much greater slope compared to what the BBC states and I gave a lot of importance to the black level. I sacrificed whites, but that's an acceptable compromise; after all, I gotta map everything to just 1000 nits, so I don't really have much choice, but I tried not to brutally clip whites, but to smooth them out a bit instead, although I do also sort of "clip" the very very high ones.
https://i.imgur.com/UKuw5lT.png
As you can see, blacks are preserved, but whites are smoothed out before eventually clipping them.
https://i.imgur.com/em86uxA.png
If you take a look at the nits of this HDR PQ test image, for instance, you can see that there's a lot in the low area with very low nits: the background is at about 200 nits, the sky is pretty low as it's evening so it's slightly over 500 nits at like 520 nits and the skin is between 240 to 500 nits, depending on the part of the face we're actually analyzing as some parts gets more photons from the light emitting source. Lastly, the power source peaks at 1000 nits and it's therefore clipped out as the PQ test file I used has just 1000 nits. Please note that the picture you're seeing is a PQ on an HDR Waveform Scope, which basically means that you're already seeing how it's supposed to look like, but for the sake of references, here's how you would see it if you open the raw pixel file without taking into account the curve (i.e NOT how is supposed to look):
https://i.imgur.com/DP7nBaG.png
From here we can see that the windows at the center pops up as it peaks at 1000 nits as well as each and every "candle" (heck, there are no candles anymore, just AC light bulbs getting a mono-phase current and emitting photons :( ).
Walls, chairs made out of wood and other things are at about 400 nits and so on.
https://i.imgur.com/IF78vur.png
Alright, enough waveforms, now I'm gonna post a few screenshot comparisons about HDR PQ (on the left) and HDR HLG (on the right).
As you can see, I couldn't quite match the same tones of the input, but I preserved as many things as possible while mapping.
I gotta say that all the test files I used have about 1300 nits but nothing more, so it was relatively easier to re-map to 1000 nits, but it should be fine for contents slightly higher than 1300 nits (although I didn't test it).
HDR PQ (left) vs HDR HLG (right):
https://i.imgur.com/8pADg58.jpg
https://i.imgur.com/u8wegI2.jpg
https://i.imgur.com/NKP1KIc.jpg
https://i.imgur.com/OIkrqHw.jpg
https://i.imgur.com/Eqq2gZm.jpg
https://i.imgur.com/SyJuLnV.jpg
https://i.imgur.com/FP9WMMk.jpg
https://i.imgur.com/20cLkOH.png
https://i.imgur.com/r6b2Wiw.png
https://i.imgur.com/MlYafZP.jpg
https://i.imgur.com/QBfbkpx.jpg
https://i.imgur.com/FwYPh9p.jpg
https://i.imgur.com/EqiSrN3.jpg
https://i.imgur.com/OwxpF4p.jpg
https://i.imgur.com/WPl3Ky7.jpg
FranceBB
26th December 2019, 22:01
https://i.imgur.com/NVFFakh.jpg
https://i.imgur.com/ISwHWj6.jpg
https://i.imgur.com/ByNJKiX.jpg
https://i.imgur.com/CrwDhOm.jpg
https://i.imgur.com/eKwPjqe.jpg
https://i.imgur.com/V42Q9l7.jpg
https://i.imgur.com/Ytrcldb.jpg
I added it to the list with the name "PQ_to_HLG_Nspec.cube" which stands for "NHK specifications based" + of course my modifications.
Now I'm finally ready to work on your LUT, which is the inverse: from HLG to PQ, which should be fairly easier as this time I can really map each and every point of the input space (HLG) to each and every point of the output space (PQ) without losing quality as HLG is less wide than PQ.
I decided to set them to scale in a linear fashion: in other words, if you have an HLG at 250 nits you'll get a PQ at 250 nits, if you have an HLG at 400 nits you'll get a PQ at 400 nits and if you have an HLG of 1000 nits you'll get a PQ at 1000 nits.
One of the common mistakes people make is to map the maximum of a certain input curve to the maximum of the output curve, 'cause generally when you're dealing with matrices of linear transformation and you have an input space and an output space, you tend to do it that way.
Think about BT709 to HLG: many people think that the correct way to do it is to map the whole linear BT709 to HLG thus getting the peak brightness of BT709 SDR to 1000 nits in HLG HDR, but that's a very doggy approach. As a matter of fact, in HLG to PQ I've done the same: they're both mapped in a linear fashioned so that instead of having the peak HLG be mapped to the peak PQ, they're mapped to get equal results on the output; in other words, instead of mapping the 1000 nits HLG to 10'000 nits PQ, I mapped it to 1000 nits PQ.
That's the way it should be done anyway in my opinion.
I'm doing it in this very moment, it should be ready soon!
Merry Christmas Frank!
Have a great time in UK!
P.S. - is it a roast chicken or broadcast chicken :)
I'm afraid that the canteen we have at work is way worse. :(
FranceBB
29th December 2019, 08:06
Alright, your LUT is ready now.
I mapped it out to 1000 nits in PQ in order to have the same amount of nits in both the resulting HDR, rather than remapping the maximum of HLG to the maximum of PQ.
This is the resulting curve:
https://i.imgur.com/p5FStgB.png
https://i.imgur.com/rJ0x8dP.png
https://i.imgur.com/NDsixAP.png
I know what you're thinking "hold on a second! You said that you were going to map it to 1000 nits but the resulting PQ curve is left unclipped 'till 10000 nits, why is that?"
Well, that's not gonna affect the results at all.
Yes, it's true, I left the curve unclipped 'till 10'000 nits, but since I mapped every point of the HLG to its reciprocal of PQ 'till 1000 nits, those other 9000 nits that are there left are NOT gonna be used at all.
I.e there isn't going to be any data in there.
As an example ('cause mine are just words), I'm gonna show you a frame.
This is how the waveform would look like if I clip the resulting curve of the matrix to 1000 nits by forcing it to be 1000 nits directly from the matrix:
https://i.imgur.com/msHqcM8.png
Now, look at what happens when I use the very same curve but I leave it unclipped to 10'000 nits:
https://i.imgur.com/AwRNkS8.png
Nothing, exactly. This is because although I left the curve unclipped to 10'000 nits, I mapped the resulting points in a way that NOTHING is gonna get mapped over 1000 nits.
Now, for the sake of knowledge, this is how it would be if I had to map the maximum of the HLG to the maximum of the PQ (i.e 10'000 nits):
https://i.imgur.com/Oa3uBrD.png
See the curve? See the waveform? Now I have a completely different slope and a completely different peak as points that were lower will be mapped to an higher point, but I don't really like it, I think it's wrong, 'cause essentially you're making something out of nowhere for apparently no reason at all, so...
It would be like when I see broadcasters mapping the 100 nits of the linear BT709 to the maximum of the HLG so that I get a "nice" 1000 nits of white and completely clipped out sky -.-
So, that's why I decided to take this other route.
I didn't actually manage to get it 100% the same, but I think I'm fairly close and it's gonna be fine for your needs.
A few screenshots (on the left the original HDR HLG 1000 nits and on the right the HDR PQ 1000 nits output from the matrix of linear transformation):
https://i.imgur.com/V2253FY.jpg
https://i.imgur.com/RbXFxGk.png
https://i.imgur.com/XC22HHi.jpg
https://i.imgur.com/uO7GEk2.png
https://i.imgur.com/GzPQLLW.png
https://i.imgur.com/VuuSHkl.png
https://i.imgur.com/ucWEDio.jpg
https://i.imgur.com/1Hc2frs.jpg
https://i.imgur.com/jeJQhAG.jpg
https://i.imgur.com/ckc4ZmH.jpg
As you can see, the very low dark levels are slightly different, but that it's really gonna depend on how low your monitor can go, so it's gonna be tricky to check, especially if you have an LCD, while you'll be perfectly able to see it if you have an OLED. This is because in HLG the low end of the curve resembles a sort of linear SDR one and the mid-high end part is more log-prone (so more inclined to the HDR), hence the reason why it's called Hybrid Log Gamma. When it's mapped to PQ, though, which is purely meant for HDR, the low end part is gonna be mapped to several completely different points that are way different from the HLG one and if your monitor isn't very good at displaying low lights it may seem as if they're not there, but really they are, 'cause I doubled checked with my waveform monitor. This is particularly "funny" 'cause I can see details in the shadows in the HLG one that get mapped to points in PQ that make them invisible to my monitor at home but they're still there and I can see them in the waveform (and I probably will be able to see them at work in one of the monitor we have there).
You should find the new LUT in the folder (Mega) in the afternoon.
I look forward for your reply.
Cheers,
Frank.
anatol2002
31st December 2019, 14:58
Hi Frank
Thanks for prompt response!
Unfortunately I did not time to get to test your new LUT. Just overloaded with lots of other stuff.
Hope that will get some time in couple of days.
Happy New Year!
Anatol
FranceBB
1st January 2020, 12:25
Unfortunately I did not time to get to test your new LUT. Just overloaded with lots of other stuff.
Hope that will get some time in couple of days.
Happy New Year!
Sure, no problem, happy new year! :)
FranceBB
24th January 2020, 22:08
Alright, so I've come across some Panasonic Cameras that shoot in V-Log.
I gotta say that I do not like Panasonic Cameras nor V-Log, however I had to quickly do something to get something out of this.
Please note that this is a very rough linear transformation from V-Log to Linear BT709 SDR.
Unfortunately although I've got the Luma right, I don't quite seem to understand the internal color science of Panasonic that much, that's why I didn't quite get the tone I wanted, anyway if you wanna use it feel free to use it (it will be added to the link in the first page soon). Temporary Link: Link (https://we.tl/t-YFng3JQUUY)
https://i.imgur.com/d3KOzw4.png
https://i.imgur.com/a92vFLj.png
https://i.imgur.com/KQisM8j.png
https://i.imgur.com/43E9jdJ.png
https://i.imgur.com/1vH8xd8.png
https://i.imgur.com/BijYyVt.png
https://i.imgur.com/z0s9wtl.png
https://i.imgur.com/r8p7dLp.png
https://i.imgur.com/q09TkaK.png
hydra3333
25th January 2020, 00:45
thank you
ClubM
26th January 2020, 23:17
Just wanted to say thank you FranceBB for sharing these!
FranceBB
31st January 2020, 17:51
New day, new matrix of linear transformation.
This matrix has been inspired by something that hello_hello was talking about here (https://forum.doom9.org/showthread.php?p=1897823&posted=1#post1897823) which is basically going from BT2100 HDR PQ not to BT709 SDR but rather to BT2020 SDR. Although, generally, whenever we have PQ contents we go to HLG to keep HDR compatibility as much as possible up to 1000 nits, however the more it gets closer to the original HDR source, the more it gets dull on BT2020 SDR monitors/TVs, so it does actually make sense to have such a matrix as it can come in handy.
So, the idea behind this is to make use of the wide BT2020 but limiting the nits to get an SDR material. In other words, this content will look far better on UHD SDR TV that can handle 4K but that don't interpret any curve and would just ignore information about HLG in an HLG source and would interpret the matrix correctly.
Since we're dealing with BT2100 PQ and our output is going to be a BT2020 it's very strongly suggested to work with 16bit and output either a 12bit or a 10bit file also 'cause 8bit BT2020 is not officially supported (although Sony likes to make weird files and I've seen cameras being able to encode an 8bit file with BT2020 which is a mediocre compromise).
Alright, enough talking, let's see the curve!
If you take a look at it, it basically bring an HDR BT2100 PQ and maps it in order to get a gamma 1.90 (which is something we expect from an SDR source) BUT making use of the wide BT2020 matrix.
The knee at the very top is to avoid hard clipping and its slope is kinda high 'cause the amount of nits we have in our output is gonna be extremely low compared to the input, so our linear transformation is "onto" which means that it maps different points of the input to a single point of the output. If we call our input PQ "X" and our output Linear BT2020 SDR gamma 1.90 "Y", then the function is "onto" because every element in the codomain is the value of f(x) for at least one element x in the domain.
https://i.imgur.com/XFlmosJ.png
https://i.imgur.com/hr9EFjF.png
https://i.imgur.com/mMnTvMJ.png
Screenshots are gonna be a little bit tricky though 'cause I have nothing to make you visualize them correctly if you have an old monitor which is not compatible with BT2020 SDR as I'm going to compare BT2100 HDR PQ with BT2020 SDR, none of which is supported by old monitors.
BT2100 HDR PQ (Top)
Linear BT2020 SDR (Bottom)
https://i.imgur.com/S8pJItb.png
https://i.imgur.com/jQHYj7A.png
https://i.imgur.com/FVHOeYz.png
https://i.imgur.com/pUAUNkb.png
https://i.imgur.com/XjCFmjT.png
https://i.imgur.com/DaruT1D.png
https://i.imgur.com/UhO0JTR.png
https://i.imgur.com/FjIceXn.png
Temporary Link to the LUT for testing (it will be added to the main repository soon): Link (https://we.tl/t-lxprs0qH6X)
DavidK_
7th February 2020, 07:56
Frank!
I am helping Anatol on this conversion issue and tested your HLG to PQ lut. Very close - nice work - just had a couple of notes/adjustments if possible.
We're trying to get FFMPEG to match a source file and an output from an non-FFMPEG encoder. I measured the source, the version from an adobe media encoder and your lut via ffmpeg. Here are some of the results/observations comparing the three outputs:
1) Histogram:
Source MXF: RGB values: 7.774 6.701 7.267
Adobe Media Encoder H265: RGB values: 5.829 5.803 6.125
FFMPEG HLG TO PQ LUT: RGB values: 1.554 1.459 1.512
It does feel too red still and you'll notice that yours has just slightly elevated Rs instead of G and B with Blue being too low compared to Source and Media Encoder.
2) RGB peaks stop well below what the source and Media Encoder. Yours are at around 80/.8 whereas the source and Adobe version hit 100/1.
3) It feels too contrasty and darker with the LUT compared to what is expected. But just a little.
FranceBB
8th February 2020, 21:04
Frank!
I am helping Anatol on this conversion issue and tested your HLG to PQ lut. Very close - nice work - just had a couple of notes/adjustments if possible.
We're trying to get FFMPEG to match a source file and an output from an non-FFMPEG encoder. I measured the source, the version from an adobe media encoder and your lut via ffmpeg. Here are some of the results/observations comparing the three outputs:
1) Histogram:
Source MXF: RGB values: 7.774 6.701 7.267
Adobe Media Encoder H265: RGB values: 5.829 5.803 6.125
FFMPEG HLG TO PQ LUT: RGB values: 1.554 1.459 1.512
It does feel too red still and you'll notice that yours has just slightly elevated Rs instead of G and B with Blue being too low compared to Source and Media Encoder.
2) RGB peaks stop well below what the source and Media Encoder. Yours are at around 80/.8 whereas the source and Adobe version hit 100/1.
3) It feels too contrasty and darker with the LUT compared to what is expected. But just a little.
A feedback is always welcome 'cause other people will always test more scenarios than I do on my own. I gotta say that I did notice a light dominance in red but that probably was because of my test source, so although the intent was to match it as much as possible, I think I "fixed" it when I was creating it so that the output was going to be ok, however that probably ended up with me matching the wrong points; the blue makes sense as it's the one that got compensated in favor of red. Anyway, I'll try to make another one but it would help to have a very short sample if you can provide one so that I can send you multiple outputs.
PatchWorKs
28th February 2020, 13:03
Hi there, just a question: do you think I need a "color conversion" lut for Canon HF100' shootings ?
I guess it *should* record in 4:2:0 8-bit AVCHD (.mts) Canon RGB...
FranceBB
28th February 2020, 17:48
Hi there, just a question: do you think I need a "color conversion" lut for Canon HF100' shootings ?
I guess it *should* record in 4:2:0 8-bit AVCHD (.mts) Canon RGB...
Uhm... so it's basically an H.264 yv12 (4:2:0 planar) 8bit muxed in an .mts container, but that tells me nothing, honestly.
I mean, I tried to google it up and it doesn't seem to be able to record in any logarithmic curve, so my guess is that it actually records in Linear BT709. If that's the case, then no, you don't need a matrix of linear transformation, however I don't really know your model. Just scroll through the settings and check whether it says anything about "C-Log" (since it's Canon) or HLG. If it doesn't, then you're probably fine and it should say somewhere "BT.709". If you're uncertain, just record a short sample and upload it here via WeTransfer.
PatchWorKs
28th February 2020, 20:19
Ok, i did some searches too and found this interesting article:
Video editing for scientific analysis (http://nerdfever.com/video-editing-for-scientific-analysis/)
That claims:
Color spaces – Studio RGB vs. Computer RGB vs. Canon RGB
One thing you may notice when using Vegas or viewing the output files after processing in Vegas is that the video looks “washed out” or too dark or contrasty. These problems come from color space conversion problems. Different video players use different color spaces, so the same video file might look fine in one player, and bad in another.
The brightness and color of pixels displayed on your computer screen is determined by three numbers, for the brightness of Red, Green, and Blue in each pixel. Each number can range from 0 (darkest) to 255 (brightest). If Red, Green, and Blue (RGB) are all 255, they combine to make bright white. This is the “Computer RGB” color space – each color has the range from 0 to 255.
The “Studio RGB” color space uses only the values from 16 to 235 to represent the RGB brightness. Values in the range of 0 to 15 are called “superblacks” and values 236-255 are “superwhites”. Standard televisions and video cameras are supposed to use the Studio RGB system. On a TV display, superblacks are all displayed as the same color of absolute black, and superwhites are all displayed as the same shade of whitest white, so 16 is as black as you can get, and 235 is as white as you can get.
But this is not true in the Computer RGB system. 16 is not pure black – it’s dark, but 0 is a lot darker. And 235 is not as bright as the computer display can get – full brightness comes at 255. So if you show a Studio RGB video (16-235) on a computer (0-255), it will look washed out, with low contrast. The blacks won’t be very black, and the whites will be grayish. And vice-versa; if you show a Computer RGB video on a TV, there will be too much contrast, with all the dark details (0 to 15) lost as black, and all the white highlights (236-255) “blown out” to pure white.
So a color space correction is needed when converting from one system to the other. Sony Vegas has the “Sony Color Corrector” video effect that you can use to do this conversion – it has presets for converting Computer to Studio RGB and another for the other direction.
But. If you look at the video files the Canon HF100 generates, you’ll find it uses the values 16-255, instead of either of the two standard systems. If you treat this as Studio RGB, the video will lose the bright highlights (236-255). If you treat it as Computer RGB, the black levels are wrong (16 instead of 0).
You can fix this by converting Canon RGB to Computer RGB (assuming you’ll view on a computer).
In the Sony Color Corrector, set Gain to 1.067 (this is (17+ 255)/255), and set an Offset of -17. The Color Corrector first multiplies all the color values by the Gain setting, so 16-255 becomes 17-272. Then it adds the Offset to all the values, so the range 17-272 becomes 0-255. I saved this setting as “Canon HFxxx to Comptuer RGB”.
...i still don't know if a lut is needed, but according to the article's author a "color shift" would be useful.
FranceBB
28th February 2020, 22:33
Ok so the first part is just talking about Limited TV Range and Full Range.
For 8bit:
Limited TV Range is 16-235 (0.0-0.7V)
Full PC Range is 0-255.
Your camera is behaving like some other Canon camera do while shooting in Linear BT709 8bit: they're set in Limited TV Range 16-235 however they leave the highlights unclipped so that they can go as high as 255.
In their mind, it's the cameraman that has to look at the waveform monitor and make sure that it doesn't overshoot and it's at the sweet spot instead (235).
This happens on professional productions while shooting live sports events as well, which is why I generally put a hard clipping to 16-235 at the very end of the chain just to be sure in case the cameraman goes mad and a player passes through a very strong light almost straight into the camera.
In your case, I would advise you to check your waveform monitor (if the camera has one built-in) and then make sure that your highlights never exceed 235 as you're gonna lose them.
Once in post-production, you can do a soft-clipping to bring what exceeded down to 235 and just be safe.
I don't really use Sony Vegas as NLE, I use AVID Media Composer instead (and sometimes Davinci Resolve for color-correction and masks), so I can't tell you how to do soft-clipping there, but if there's something called "Broadcast Safe" or "Broadcast colors" then go for it.
On Avisynth there are two ways of doing it as well:
#Indexing
FFMpegSource2("whatever.mts", atrack=-1)
#Clipping
Limiter(min_luma=16, max_luma=235, min_chroma=16, max_chroma=240)
OR
#Indexing
FFMpegSource2("whatever.mts", atrack=-1)
#Canon Levels to Limited TV Range
Levels(0, 16, 255, 16, 235, coring=false)
The latter will assume that you shot on Canon Levels 16-255 and that your white is left unclipped to 255, so it keeps the black level at 16 and lowers down all the white values from 255 to 235. It should work.
Please keep in mind that the reason why I'm suggesting you that you work in Limited TV Range instead of using the Full PC Range 0-255 by just lowering the black of your Canon from 16 to 0 is that although you can encode and flag a stream with Full Range, it would be correctly reproduced by a bunch of computers only and a very little number of TVs will be able to correctly reproduce it; besides, not even ALL the players for computer will read the flag correctly and respect it, so my suggestion is to play safe and go for Limited TV Range 16-235.
This is an example of what I mean:
https://i1.creativecow.net/u/19614/0_levels_vs_broadcast_colors.png
As you can see, clipping brutally "cuts" everything above 235 (which in that scale is 100% luma) while Levels just scales it down.
Oh, as a final remark, you don't really need a LUT for that; a LUT is a matrix of linear transformation, it maps a space into another and - in this case - points of a curve into points of another curve. In your case it would be from Linear BT709 with highs unclipped to Linear BT709 in limited TV Range, so it shouldn't really be needed considering that there are tons of other tools available for video levels that do a way better job. Anyway, just out of curiosity, a matrix of linear transformation from out of range Linear BT709 values to legal Linear BT709 values would look something like this (where 100% in this case means 255):
https://i.imgur.com/SPIRQ0B.png
https://i.imgur.com/CFbnkZD.png
Please note that there are tons of topics about this subject here on Doom9 if you're curious. ;)
I hope this clarifies your doubts.
Cheers,
Frank.
DavidK_
3rd March 2020, 06:20
A feedback is always welcome 'cause other people will always test more scenarios than I do on my own. I gotta say that I did notice a light dominance in red but that probably was because of my test source, so although the intent was to match it as much as possible, I think I "fixed" it when I was creating it so that the output was going to be ok, however that probably ended up with me matching the wrong points; the blue makes sense as it's the one that got compensated in favor of red. Anyway, I'll try to make another one but it would help to have a very short sample if you can provide one so that I can send you multiple outputs.
Okay I think you're right - we should reference something together. Here is a link to the file I used:
https://4kmedia.org/lg-new-york-hdr-uhd-4k-demo/
I'll reply back tomorrow with settings that I'm trying to match. And thank you!!!! You're insight has been very enlightening.
DavidK_
5th March 2020, 08:01
A feedback is always welcome 'cause other people will always test more scenarios than I do on my own. I gotta say that I did notice a light dominance in red but that probably was because of my test source, so although the intent was to match it as much as possible, I think I "fixed" it when I was creating it so that the output was going to be ok, however that probably ended up with me matching the wrong points; the blue makes sense as it's the one that got compensated in favor of red. Anyway, I'll try to make another one but it would help to have a very short sample if you can provide one so that I can send you multiple outputs.
Okay I think you're right - we should reference something together. Here is a link to the file I used:
https://4kmedia.org/lg-new-york-hdr-uhd-4k-demo/
I'll reply back tomorrow with settings that I'm trying to match. And thank you!!!! You're insight has been very enlightening.
And here are the settings to match:
LG Sample levels to match:
Source Timecode: 00:00:01:00
Source: R .802 G .672 B .795
Adobe Match: R 1.472 G 1.202 B 1.334
At least keep those proportions. And keep black levels a bit lower - the LUT feels a bit too contrasty/dark/inky I thought. Your lut currently is still too red - your lut levels were:R 2.877 G 2.654 B 2.56 - notice your's is too green and too red. Red and Blue should be more even etc.
DavidK_
9th March 2020, 03:29
A feedback is always welcome 'cause other people will always test more scenarios than I do on my own. I gotta say that I did notice a light dominance in red but that probably was because of my test source, so although the intent was to match it as much as possible, I think I "fixed" it when I was creating it so that the output was going to be ok, however that probably ended up with me matching the wrong points; the blue makes sense as it's the one that got compensated in favor of red. Anyway, I'll try to make another one but it would help to have a very short sample if you can provide one so that I can send you multiple outputs.
Did you see my note below? (I have a sample for us to share and settings to match etc)
FranceBB
9th March 2020, 11:31
Did you see my note below? (I have a sample for us to share and settings to match etc)
I did, but it's been 18 days since I left the office due to coronavirus and it seems like there's no plan for me to get back there AT LEAST 'till April. Right now I'm sitting at home waiting for this whole mess to calm down. Making a LUT with a crappy commercial 4K TV and monitor wouldn't be wise when I have a 50'000$ Sony monitor at work. Anyway, since this whole think is like a surreal situation, if you want me to try on my commercial TV and monitor, I will, it's just that I don't know how good the output will be.
PatchWorKs
9th March 2020, 19:23
#Indexing
FFMpegSource2("whatever.mts", atrack=-1)
#Clipping
Limiter(min_luma=16, max_luma=235, min_chroma=16, max_chroma=240)
OR
#Indexing
FFMpegSource2("whatever.mts", atrack=-1)
#Canon Levels to Limited TV Range
Levels(0, 16, 255, 16, 235, coring=false)
Ok, how to translate into FFMPEG ?
ffmpeg -i whatever.mts -vf "colorlevels=rimin=##/255:gimin=##/255:bimin=#/255:rimax=###/255:gimax=###/255:bimax=###/255, eq=gamma=#.##" -y out.mov
FranceBB
9th March 2020, 19:29
@PatchWorks... Clipping in ffmpeg is fairly easy:
ffmpeg -i "sample.mov" -vf lut=y=clipval:u=clipval:v=clipval
frank
9th March 2020, 21:59
There are only 3 BT... cubes in your download.
You have 6 BT... cubes at the first page.
I'm very missing the BT2100 HDR PQ to BT709 SDR cube.
FranceBB
10th March 2020, 01:20
There are only 3 BT... cubes in your download.
You have 6 BT... cubes at the first page.
I'm very missing the BT2100 HDR PQ to BT709 SDR cube.
Because it's called "PQ_to_BT709.cube" as file and there are two versions of it because one is the one I made at the very beginning when I first began to make matrices of this kind and the other one is my second attempt. The unusual name comes from the fact that at the very beginning I thought that nobody was ever going to be so mad to put a PQ curve into something else other than BT2100 with 10 or 12bit precision, so I just specified the curve and not the matrix in the name of the file only to find out later on that unfortunately there have been people doing weird thing so I changed the name of the post but I didn't change the name of the file (yet).
At the time of the creation whenever I wrote PQ I clearly meant a BT2100 with a PQ curve applied and when I wrote BT709 I clearly meant Linear BT709 with the plain old standard gamma. I hope this clarifies your doubts. Please try the two matrices and let me know.
frank
10th March 2020, 15:14
Thank you.
I have tested in Avisynth+ using avscube. The source was an UHD movie mkv:
LWLibavVideoSource(...)
z_ConvertFormat(pixel_type="RGBP16",colorspace_op="2020ncl:st2084:2020:l=>rgb:linear:2020:f",dither_type="none")
Cube("C:\Program Files (x86)\AviSynth+\LUT\PQ_to_BT709_v2.cube", cpu=2, fullrange=true)
z_ConvertFormat(pixel_type="YV12",colorspace_op="rgb:linear:709:f=>709:709:709:l",dither_type="ordered")
Sorry, results have too much contrast and clipping from midtones upward.
There must be a problem with the level. It's not usable.
The Cube function only works in RGBP16, maybe floating point like RGBPS is needed.
edit: linear is wrong.
PatchWorKs
10th March 2020, 18:15
@PatchWorks... Clipping in ffmpeg is fairly easy:
ffmpeg -i "sample.mov" -vf lut=y=clipval:u=clipval:v=clipval
I just found this interesting repository that explain how to generate a "measurement gif" of a clip with FFMPEG: https://github.com/dericed/ffmpeg-mpeg2video-clipping
This is the (33Mb !) GIF for 10s of my shooting:
http://www.forart.it/_priv/cultura/HF100_measurement.gif
As clearly viewable, the "Video editing for scientific analysis" was right: the Canon HF100 generates a "shifted" range files.
The "recalibration" of it with the clipval parameter generates this instead:
http://www.forart.it/_priv/cultura/recal_clipval.gif
So the next question is: is possible to "shift down" everything (and constrain inside broadcast range, of course) in order to preserve the maximum possible color quality ?
Thanks again and sorry if I'm too nagging.
frank
10th March 2020, 18:26
IFAIK Canon has a converter software for the HF100. Maybe they use 16-255.
You have to ask Canon.
FranceBB
11th March 2020, 03:05
So the next question is: is possible to "shift down" everything (and constrain inside broadcast range, of course) in order to preserve the maximum possible color quality ?
Thanks again and sorry if I'm too nagging.
Yes, absolutely. Since you're actually producing a non standard file with 16-255 you can also avoid clipping and just remap the highlights to 235 with levels in Avisynth as I pasted the code before
Levels(0, 16, 255, 16, 235, coring=false)
As it says that the input is 16-255 and the output is going to be 16-235. I'm pretty sure other thing that soft-clipping instead of hard-clipping can be done in ffmpeg as well, but I don't use it that much to post you a command line for that as well. Are you sure you don't wanna give Avisynth a try?
Sorry, results have too much contrast and clipping from midtones upward.
There must be a problem with the level. It's not usable.
The Cube function only works in RGBP16, maybe floating point like RGBPS is needed.
Did you try both the two .cube files for PQ to BT709? Do they have the same problem? 'cause that's really weird...
DavidK_
11th March 2020, 06:44
I did, but it's been 18 days since I left the office due to coronavirus and it seems like there's no plan for me to get back there AT LEAST 'till April. Right now I'm sitting at home waiting for this whole mess to calm down. Making a LUT with a crappy commercial 4K TV and monitor wouldn't be wise when I have a 50'000$ Sony monitor at work. Anyway, since this whole think is like a surreal situation, if you want me to try on my commercial TV and monitor, I will, it's just that I don't know how good the output will be.
WOW! Glad you are well but wow. I'm in US and we're still figuring out how to react but having some closures and cancellations too.
If you could go ahead and try from home if you can. It would be helpful and much appreciated. :) And it would give you something to occupy your time - ha ha? :) No matter what stay well.
frank
11th March 2020, 09:24
Did you try both the two .cube files for PQ to BT709? Do they have the same problem? 'cause that's really weird... Yes, I tested both. But the v2 works better.
Is there another Cube plugin available?
frank
11th March 2020, 12:22
Ok, I've got it!! :)
The color must not be linearized. The example in Donald's Cube plugin is wrong.
Here the correct Avisynth+ script:
LWLibavVideoSource(...)
z_ConvertFormat(pixel_type="RGBP16",colorspace_op="2020ncl:st2084:2020:l=>rgb:st2084:2020:f",dither_type="none")
Cube("C:\Program Files (x86)\AviSynth+\LUT\PQ_to_BT709_v1.cube", cpu=2, fullrange=true)
z_ConvertFormat(pixel_type="YV12",colorspace_op="rgb:709:709:f=>709:709:709:l",dither_type="ordered")
v1 has the right contrast.
v2 has lower contrast.
FranceBB
11th March 2020, 14:00
I'm glad it finally worked out for you.
WOW! Glad you are well but wow. I'm in US and we're still figuring out how to react but having some closures and cancellations too.
It's gonna be a mess, mark my word. People have been underestimating this so have some governments and they won't realize that until it's too late.
Look what happened in Italy! They are on their knees! And it's not even one of the worse European Health Service, on the contrary, it's kinda "ok" but it's been overwhelmed...
In the UK the government pushed 50 million pound in the research of a vaccine and their plan seems to be to contain and then delay the epidemic 'till this summer when hopefully there will be a cure (the vaccine) and hospitals will be slightly less busy because of the end of seasonal flu. Yet, it's March, it's a long way 'till June, so I truly hope they'll find the vaccine way sooner.
Please, please please, people, don't underestimate this, don't go out if it's not necessary.
DavidK_
18th March 2020, 23:02
I'm glad it finally worked out for you.
It's gonna be a mess, mark my word. People have been underestimating this so have some governments and they won't realize that until it's too late.
Look what happened in Italy! They are on their knees! And it's not even one of the worse European Health Service, on the contrary, it's kinda "ok" but it's been overwhelmed...
In the UK the government pushed 50 million pound in the research of a vaccine and their plan seems to be to contain and then delay the epidemic 'till this summer when hopefully there will be a cure (the vaccine) and hospitals will be slightly less busy because of the end of seasonal flu. Yet, it's March, it's a long way 'till June, so I truly hope they'll find the vaccine way sooner.
Please, please please, people, don't underestimate this, don't go out if it's not necessary.
Did you have a chance to make the adjustments to the LUT? I didn't see a new link but I'm still not use to this forum fully.
As for Corona - we are now on partial lockdown here in the US! Store shelfs are bare with everyone hoarding food - especially toilet paper.
But if you had a chance to do that last small adjustment on the LUT let me know and send me a link here!
wonkey_monkey
18th March 2020, 23:53
with everyone hoarding food - especially toilet paper.
You eat weird stuff.
Andouille
19th March 2020, 01:25
You eat weird stuff.
Fibers are good for digestive system.
DavidK_
22nd March 2020, 20:51
Fibers are good for digestive system.
And really tasty with a little hot sauce.
masterkivat
9th June 2020, 11:22
Hey FranceBB, thank you very much for your LUT collection! I'll give a try someday later on these :D
I wanna ask you something: while I understand the current situation with HDR and such, do you by any change know where to download or have plans to make an LUT file that converts BT.601 to BT.709? I didn't find anything related to this kind of conversion using an LUT file...
FranceBB
9th June 2020, 13:26
Well, to be fair I've been thinking about it for a while 'cause if I introduce linear BT601 and I get that right I could potentially get all the matrices that already have linear BT709 as either input or output and modify them to make them BT601 compatible.
The only "bad" thing with Linear BT601 is that there are actually two of them: one for PAL and one for NTSC which would double the work.
I would also like to cross check my results since I don't really trust myself getting the calculations right all the time...
I know that I can't use color matrix 'cause it only converts the matrix and not the primaries... Perhaps I can compare it with the one from "plugin_JPSDR" made by Jean Philippe as he probably got it right.
I might try in the next few days...
masterkivat
9th June 2020, 13:33
Well, to be fair I've been thinking about it for a while 'cause if I introduce linear BT601 and I get that right I could potentially get all the matrices that already have linear BT709 as either input or output and modify them to make them BT601 compatible.
The only "bad" thing with Linear BT601 is that there are actually two of them: one for PAL and one for NTSC which would double the work.
I would also like to cross check my results since I don't really trust myself getting the calculations right all the time...
I know that I can't use color matrix 'cause it only converts the matrix and not the primaries... Perhaps I can compare it with the one from "plugin_JPSDR" made by Jean Philippe as he probably got it right.
I might try in the next few days...
hmmm I see... But yeah, man... Take your time on these, I really hope you could provide these LUT files in the future, this kind of conversion would help me a lot with some personal projects that require such conversions :)
Thanks for answering me!
FranceBB
11th June 2020, 08:26
Ok, so I made a few tests.
I started with the PAL version of BT601 as you can see:
https://i.imgur.com/QdI7D4p.png
The curve is exactly the same and there's a reason: the difference between those two is so subtle that it can't really be noticed on this scale...
To test this, I indexed a BT709 file and I converted it to BT601 in three different ways:
1st Indexing only (my source file):
FFVideoSource("I:\temp\sample.ts")
Spline64Resize(848, 480)
2nd my LUT:
FFVideoSource("I:\temp\sample.ts")
Spline64Resize(848, 480)
ConvertBits(16)
ConvertToPlanarRGB()
Cube("C:\Programmi\AviSynth+\LUTs\test.cube", fullrange=true)
3rd the old good colormatrix:
FFVideoSource("I:\temp\sample.ts")
Spline64Resize(848, 480)
ColorMatrix(mode="Rec.709->Rec.601", interlaced=false, threads=0, thrdmthd=0)
4th Matrix from HDR Core:
FFVideoSource("I:\temp\sample.ts")
Spline64Resize(848, 480)
ConvertBits(16)
ConvertToDoubleWidth()
Matrix(from=709, to=601, rg=1.0, gg=1.0, bg=1.0, a=16, b=235, ao=16, bo=235, bitdepth=16)
ConvertFromDoubleWidth()
This is the original frame in Linear BT709:
https://i.imgur.com/5yXvUM2.png
This is the result of my linear Transformation:
https://i.imgur.com/6hO1JjQ.png
This is ColorMatrix:
https://i.imgur.com/CAjq1B6.png
This is Matrix from HDR Core:
https://i.imgur.com/cJyP0lg.png
A few frame-comparison, but honestly the difference is so small that it's barely noticeable:
https://i.imgur.com/9oLPtfJ.png
https://i.imgur.com/5kwNGCh.jpg
https://i.imgur.com/LzPRMqH.jpg
https://i.imgur.com/IUzo2aY.jpg
https://i.imgur.com/7RduBS2.jpg
https://i.imgur.com/PDRkzoJ.jpg
https://i.imgur.com/tVffwHp.jpg
https://i.imgur.com/qp8JVfE.jpg
https://i.imgur.com/CPFKXd4.jpg
Could you test it, please, and let me know?
Link: FranceBB LUT (https://mega.nz/file/yVVgDSAB#IFZhR6KfLCHQ9aoeFo56A6htrewYJKoKZ9JI1_zccnM)
This one instead is made by Adam Stanislav and his results are pretty much the same as mine with very little difference. Can you check this one as well, please?
Link: Stanislav LUT (http://www.pantarheon.org/601vs709luts.zip)
masterkivat
13th June 2020, 10:48
Your conversions looks pretty damn good! :)
But for my purpose, it would look "technically" wrong... My source file is listed as:
Color range : Limited
Color primaries : BT.601 NTSC
Transfer characteristics : BT.601
Matrix coefficients : BT.601
And since I'm working in this project (upscaling SD content to HD with the proper color conversion), my goal is to do a proper color conversion from BT.601 NTSC to BT.709.
I know this is just the beginning of your work on LUT files, so I'll be patiently waiting your LUT.
As for Adam Stanislav LUT files, I think his "conversion" looks way stronger... Check out this comparison chart (https://slow.pics/c/X9DRGTW2).
FranceBB
16th June 2020, 13:25
Ok, so I've done it.
This is the BT601 PAL to BT709:
https://i.imgur.com/NeYSIT8.png
And this is the NTSC one:
https://i.imgur.com/c0Aj8Yu.png
I then used the CIECAT02 module and its equations for calculating mathematical correlates for the six technically defined dimensions of color appearance: brightness (luminance), lightness, colorfulness, chroma, saturation, and hue.
I've got two matrices 274628 X 3, which are way too precise for such a simple calculation.
Nonetheless, here they are.
Take a look at them and let me know.
p.s of course I made the inverse as well.
Updated link in the 1st post.
FranceBB
25th June 2020, 13:50
Introducing LinearTransformation.
With the increasing number of matrices to do any kind of linear transformations, I kinda felt the need to make something more accessible for users, which is why I'm introducing now "LinearTransformation".
This plugin performs Linear Transformations based on a matrix conversion. Matrices are made by me and can be used independently from Avisynth as well.
The function has two parameters: Input and Output.
Currently, only those linear transformations are supported:
From "Linear_BT601_NTSC" to "Linear_BT709"
From "Linear_BT601_PAL" to "Linear_BT709"
From "Linear_BT709" to "Linear_BT601_NTSC"
From "Linear_BT709" to "Linear_BT601_PAL"
From "Linear_BT709" to "BT2020_HLG"
From "Linear_BT709" to "BT2100_PQ"
From "Linear_BT709" to "DCI_XYZ"
From "Linear_BT709" to "ZLog"
From "BT2100_PQ" to "Linear_BT2020"
From "BT2100_PQ" to "Linear_BT709"
From "BT2100_PQ" to "BT2020_HLG"
From "CLog3" to "Linear_BT709"
From "CLog3" to "BT2020_HLG"
From "CLog3" to "BT2100_PQ"
From "SLog2" to "Linear_BT709"
From "SLog3" to "Linear_BT709"
From "BT2020_HLG" to "Linear_BT709"
From "BT2020_HLG" to "BT2100_PQ"
From "DCI_XYZ" to "Linear_BT709"
From "LogC" to "Linear_BT709"
From "VLog" to "Linear_BT709"
A Linear Transformation is essentially a matrix that maps all points of a certain space to another, which includes of course points belonging to a certain curve to other in order to get a different curve.
Of course, a linear transformation can be used in encoding to map some values to some other values and therefore have conversions from curves like PQ to HLG and so on.
The transformation is performed with 16bit precision, which means that if your input source is lower, let's say, 8bit planar yv12, it will be brought to 16bit planar RGB internally, the linear transformation will be applied with 16bit planar precision and then the result will be brought down to 8bit planar yv12.
Planar RGB 16bit is strongly suggested as your source as it's gonna be faster, in fact 4:2:0, 4:2:2, 4:4:4 planar up to 16bit will be converted back and forth internally.
Inside the plugin, the path specified for the matrices is "mypath" and by default is: mypath = "C:\Program Files (x86)\AviSynth+\LUTs" which means that it's gonna look for my LUTs in a folder in such a location. It's not mandatory to have my LUTs there, you can have them in any location you want, provided that you do update that string.
A huge thanks to StainlessS and to the whole community for greatly improving the script and helping me writing it.
Plugin: https://github.com/FranceBB/LinearTransformation/blob/master/LinearTransformation.avsi
Matrices: https://github.com/FranceBB/LinearTransformation
Usage Example:
Example 1: From Slog3 to Linear BT709
FFVideoSource("mySlog3source.mxf")
LinearTransformation(Input="SLog3", Output="Linear_BT709")
Example 2: From PQ to HLG
FFVideoSource("myPQsource.mxf")
LinearTransformation(Input="BT2100_PQ", Output="BT2020_HLG")
Dogway
11th August 2020, 15:16
I'm curious about your LUTs, the reds are deeper using yours for matrix conversion, is this expected for the CIECAT chromatic adaptation? Can you choose Bradford or any other for comparison?
EDIT: Nevermind, you were comparing PAL. I got confused because those coefficients (https://forum.doom9.org/showthread.php?p=1915272#post1915272) are more in line with SMPTE
Also I think that adding an option for the chroma resample kernel should be a good idea, I always switch to spline36 since bicubic is a bit soft, not that I can't do myself but as a suggestion.
FranceBB
11th August 2020, 23:40
I'm curious about your LUTs, the reds are deeper using yours for matrix conversion, is this expected for the CIECAT chromatic adaptation? Can you choose Bradford or any other for comparison?
EDIT: Nevermind, you were comparing PAL. I got confused
Yeah, I was indeed comparing with BT601 PAL; anyway, technically I could switch and use the Bradford Chromatic Adaptation
https://i.imgur.com/n5Mjtnb.png
but unless there's a real need, I would personally stick with CIE 'cause the CAT02 provided is the international one that is expected to be used everywhere by everyone, which uses the following matrix:
https://i.imgur.com/aZirr2I.png
Also I think that adding an option for the chroma resample kernel should be a good idea, I always switch to spline36 since bicubic is a bit soft, not that I can't do myself but as a suggestion.
You mean in LinearTransformation() (https://github.com/FranceBB/LinearTransformation/blob/master/LinearTransformation.avsi)? Sure, I can do that, no problem, but in the meantime, if you want you can use the matrices manually like this:
ConvertBits(16)
ConvertToPlanarRGB()
Cube("C:\Programmi\AviSynth+\LUTs\whatever.cube")
Converttoyuv420(chromaresample="Spline64")
so this way you can specify the chroma resample yourself. Since all calculations are done in RGB 16bit Planar and then brought back to whatever you had in input. :)
That would be the same as:
ConvertBits(16)
ConvertToPlanarRGB()
LinearTransformation(Input="something", Output="something_else")
Converttoyuv420(chromaresample="Spline64")
as you're feeding it with RGBP16 and it will output RGBP16 thus allowing you to resize the chroma with your favorite kernel. :)
Dogway
12th August 2020, 09:08
Yes, CAT02 is meant to be an improved version but I was curious about why the red is so much deeper. I wanted to test this but couldn't find Linear_BT709 and 601 in your repo(?). I'm missing these LUTs:
BT601_NTSC_to_BT709
BT601_PAL_to_BT709
BT709_to_BT601_NTSC
BT709_to_BT601_PAL
I don't know how it behaves currently but the example in that post is wrong I think. Rec709 and Rec601_PAL only differ 0.010 in red. This is a test I did in Nuke.
Rec709/sRGB
0.640, 0.330, 0.030
0.300, 0.600, 0.100
0.150, 0.060, 0.790
Rec.601 PAL
0.640, 0.330, 0.030
0.290, 0.600, 0.110
0.150, 0.060, 0.790
P22-EBU - ColorMatch RGB (D50) (Radius PressView Monitors)
0.630, 0.340, 0.030
0.295, 0.605, 0.100
0.150, 0.075, 0.775
https://i.imgur.com/aRr71Nx.png
Now when I inverted the matrices M-1 (which is wrong) I get a match of your example.
https://i.imgur.com/jXc5t5M.png
FranceBB
12th August 2020, 10:11
Yes, CAT02 is meant to be an improved version but I was curious about why the red is so much deeper. I wanted to test this but couldn't find Linear_BT709 and 601 in your repo(?). I'm missing these LUTs:
BT601_NTSC_to_BT709
BT601_PAL_to_BT709
BT709_to_BT601_NTSC
BT709_to_BT601_PAL
Oh, dang... I forgot to upload them, now they're there.
Now when I inverted the matrices M-1 (which is wrong) I get a match of your example.
I see! I made a boo boo, but it's my fault, it's not the CAT02. I'll make a new one for PAL. NTSC should be ok I think, but now that they're uploaded, feel free to test it as well.
Dogway
12th August 2020, 12:40
Thanks, just tested also with SMPTE coefficients and it's working fine : D
frank
19th August 2020, 19:40
For transcoding you only need ffmpeg. It works faster and accurately. Here an example for conversion PQ HDR to SDR BT709 in Windows 10.
ffmpeg64.exe -i input.uhd.mkv ^
-vf scale=1920x1080:flags=bicubic,lut3d='D\:/INSTALL/LUT/PQ_to_BT709_v1.cube',format=yuv420p ^
-c:v libx264 -preset fast -crf 20 ^
-g 48 -bufsize 15M -maxrate 15M ^
-force_key_frames chapters -forced-idr 1 ^
-color_primaries bt709 -colorspace bt709 -color_trc bt709 ^
-c:a copy ^
movie.mkv The lut3d filter reads the 10 bit input into rgb48 and applies the matrix. You get about 12 fps speed on a notebook.
lut3d needs the absolute path to the LUT with slashes like in Linux. Path variables don't work.
No Avisynth 16 bit is needed. You can apply filters from ffmpeg.
Thanks for your great work, Frank!
FranceBB
19th August 2020, 20:00
Well, you're welcome.
As a side note: last time I tried, ffmpeg wasn't able to read large matrices like 64x64x64 but was working fine with 32x32x32 ones and 16x16x16 ones as well. As result, some of the most accurate LUTs were not applied and resulted in an error. I don't know whether someone updated the lut3dfilter or not, but in case they didn't, just keep in mind that it might not work. If you wanna try, try to use the PQ to HLG matrix (which is definitely a 64x64x64) and check whether ffmpeg complains about it being too large or not: if it does, then they didn't update it, if it doesn't, then they updated it and I'm gonna add it as an example of how to use my LUTs. ;)
wswartzendruber
21st August 2020, 02:32
I need to remember to compare your hand-tuned LUTs to my CLI utility.
EDIT: Actually, that would be stupid. I need to get a HLG display of some kind first.
frank
21st August 2020, 11:04
Test with Jaws (HDR10+) and PQ_to_HLG.cube - it works.
I used NVIDIA hevc_cuvid decoder to get rid of the annoying messages "hevc: Skipping NAL unit 62" and for quick resizing.
ffmpeg64.exe -v verbose ^
-c:v hevc_cuvid -resize 1920x1080 -r 24000/1001 -i "input.uhd.mkv" ^
-vf lut3d='D\:/INSTALL/ffmpeg/PQ_to_HLG.cube',format=yuv420p10le ^
-c:v libx265 -profile:v main10 -preset fast -crf 18 ^
[hevc_cuvid @ 000002ac571c6100] Formats: Original: nv12 | HW: p010le | SW: p010le
[graph 0 input from stream 0:0 @ 000002ac57402c80] w:1920 h:1080 pixfmt:p010le tb:1001/24000 fr:24000/1001 sar:1/1
[auto_scaler_0 @ 000002ac57403f80] w:iw h:ih flags:'bicubic' interl:0
[Parsed_lut3d_0 @ 000002ac57403e80] auto-inserting filter 'auto_scaler_0' between the filter 'graph 0 input from stream 0:0' and the filter 'Parsed_lut3d_0'
[auto_scaler_1 @ 000002ac57403780] w:iw h:ih flags:'bicubic' interl:0
[Parsed_format_1 @ 000002ac57403680] auto-inserting filter 'auto_scaler_1' between the filter 'Parsed_lut3d_0' and the filter 'Parsed_format_1'
[auto_scaler_0 @ 000002ac57403f80] w:1920 h:1080 fmt:p010le sar:1/1 -> w:1920 h:1080 fmt:rgb48le sar:1/1 flags:0x4
[auto_scaler_1 @ 000002ac57403780] w:1920 h:1080 fmt:rgb48le sar:1/1 -> w:1920 h:1080 fmt:yuv420p10le sar:1/1 flags:0x4
x265 [info]: HEVC encoder version 3.4+15-g45f1d01f8
x265 [info]: build info [Windows][GCC 10.2.0][64 bit] 10bitLatest ffmpeg self compiled (Zeranoe emulating) with media-autobuild suite. No errors but contrast is too high on SDR display. I have no HLG capable device.
FranceBB
21st August 2020, 11:18
Great, then they updated ffmpeg! :D
Good to know, the more the merrier.
I added the ffmpeg example in the first post. ;)
shph
21st September 2020, 16:36
Not sure why this info is so hidden by FranceBB, but looking to screenshots these LUTs are generated in well known LUTCalc https://cameramanben.github.io/LUTCalc/LUTCalc/index.html
FranceBB
21st September 2020, 22:38
Not sure why this info is so hidden by FranceBB, but looking to screenshots these LUTs are generated in well known LUTCalc https://cameramanben.github.io/LUTCalc/
Not hidden at all, LUT Calc is a great tool made by Ben Turley and I would recommend it to everyone, however it's not the only thing I use of course, as I manually make calculations and I check and modify them in Davinci Resolve with a Decklink card outputting the SDI to a broadcast 4K Sony reference monitor, its scope, Davinci's scope and a Tektronix. In other words, there's a lot of manual work involved 'till I get things right. If you feel like using LUT Calc yourself, feel free and I invite everyone who wants to try any LUT Calculation software to try it out, but again you gotta make sure to understand what you're doing and to make correct calculations as you can't really select an input curve and an output curve and expect a software to do its magic. Also 'cause it may or may not have some parameters or other things; for instance, when I made the Z-Log to Linear BT709 SDR matrix, it was completely from scratch as there was only the official documentation; after all it was a brand new color curve and many software haven't been updated for quite some time; for instance LUT Calc hasn't been updated since 2017 and has no clue about Z-log. That's why I said that there's a lot of manual work involved. I personally love Linear Algebra, it's literally my favorite subject and what I find fascinating is how a matrix gives you the feeling to almost morph the space you're working on and it can be applied to pretty much everything, from geometry to computer science. In this very case, a matrix basically maps points from an input space to some other points to the output and could actually be identified as a function; looking at it as a function, it indeed can be either an Homomorphism or not (in fact we can talk about surjective and bijective, also known as 1-1 and onto). So, depending on the input and output points you have different "mapping functions", i.e matrices with different properties. Of course, nobody writes each and every own value of a matrix individually in real life scenarios (unless they're very small matrices like the one you write in your class which generally don't go beyond 5x5 while in the real world we have thousands of coeffs.) as we all use models and this is where something to calculate LUTs can come in handy, either working in Matlab (https://uk.mathworks.com/downloads/), Julia (https://julialang.org/), LUT Calc (https://cameramanben.github.io/LUTCalc/) will do. ;)
To everyone who wants to try it out (if you didn't attend at least a linear algebra class), I definitely suggest MIT Lectures by Gilbert Strang (https://www.youtube.com/playlist?list=PL221E2BBF13BECF6C) on Julia (https://www.youtube.com/playlist?list=PLP8iPy9hna6Si2sjMkrPY-wt2mEouZgaZ) and Linear Algebra (https://www.youtube.com/playlist?list=PL221E2BBF13BECF6C), he's probably the best in his field. If you don't wanna take such a course and you wanna have only a "vague" idea of how these things work, then I suggest you to watch the "Essence of Linear Algebra (https://www.youtube.com/watch?v=fNk_zzaMoSs&list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab)" series by Grant Sanderson (3blue1brown) (https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw). As to my personal YT channel (https://www.youtube.com/channel/UCzhj_LmbAAm4bJfCWSeQ9bA/videos), unlike what I did with Electrical Engineering and Digital Electronics, I've posted things about Linear Algebra (https://www.youtube.com/playlist?list=PL7dD-bUWOf-qHymw_jHn9SusEf-H57QzF) but not as a course, but instead as solution to several exercises out of fun and 'cause I thought they might be useful for other engineering students, but I didn't really make it as a course with lectures, so it's NOT something a beginner should be watching.
By the way, if it pleases more people, Shph, I can write a more detailed process about how these things work (or at least, about what my understanding of these things is) and what I do, including all the tools I use to make my matrices, it's not a big deal. :)
The only reason I opened this topic a while ago was 'cause I had to make matrices myself for things I had to do (I work in broadcast) and I was amazed by how many companies were ripping off people by selling their matrices for a lot of money and I wanted to do something for other people by making all my matrices free. Again, while a company hires several engineers to make calculations and test matrices over and over again, the ones I make are only made by myself, so they may not be as accurate and studied as the ones done by Avid or Blackmagic or Adobe or the BBC etc, but I try to keep everything mathematically correct and most importantly free and open. I didn't even expect other people to use them, actually, this topic kinda had much more success than I expected which means that there's a genuine willingness by people to use them and, as long as other people or my company will ask me to make them or work at something, I'll keep making them and posting them here. So, all in all, I think it's an happy ending. In the meantime, I'll share some useful links.
Useful Links:
Matlab: https://uk.mathworks.com/downloads/
Julia: https://julialang.org/
BBC White Papers 283: https://www.bbc.co.uk/rd/publications/whitepaper283
BBC White Paper: http://downloads.bbc.co.uk/rd/pubs/papers/HDR/BBC_HDRTV_HLG_LUT_Implementation_Guide.pdf
LUT Calc: https://cameramanben.github.io/LUTCalc/
MIT Lectures by Gilbert Strang about Linear Algebra: https://www.youtube.com/playlist?list=PL221E2BBF13BECF6C
MIT Lectures about Julia: https://www.youtube.com/playlist?list=PLP8iPy9hna6Si2sjMkrPY-wt2mEouZgaZ
Essence of Linear Algebra by Grant Sanderson: https://www.youtube.com/watch?v=fNk_zzaMoSs&list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab
Other free alternatives to my LUTs:
HDRTools by Jean Philippe Scotto di Rinaldi: https://forum.doom9.org/showthread.php?t=175488
DGHDRtoSDR by Donald Graft: http://avisynth.nl/index.php/DGHDRtoSDR
shph
22nd September 2020, 11:46
Yes, LUTCalc is not a simple one click tool and may need some solid technical background especially when it goes to LUTs with custom options. Development was stopped in 2017, but In 2020 seems it back to life and hope we may see new options there. There are some discussions on GitHub and link to beta version was always here http://cameramanben.github.io/LUTCalc/testing/
By the way, your LUTs pack included in Hybrid.app, so i came to this thread to see if it may be further details.
FranceBB
22nd September 2020, 16:58
Yes, LUTCalc is not a simple one click tool and may need some solid technical background especially when it goes to LUTs with custom options. Development was stopped in 2017, but In 2020 seems it back to life and hope we may see new options there. There are some discussions on GitHub and link to beta version was always here http://cameramanben.github.io/LUTCalc/testing/
Ah, I didn't know about the beta version. It's good to know. It would be great to have an updated version up and running. :)
By the way, your LUTs pack included in Hybrid.app, so i came to this thread to see if it may be further details.
Hybrid? You mean the one developed by Selur? I didn't know 'cause I've never used it and I basically never go to the GUI dedicated section of Doom9, but I'm glad he found them worth to be included. :)
shph
24th September 2020, 11:42
Yes, it is Hybrid developed by Selur.
Small question. I notice BT709_to_HLG_400.cube and BT709_to_HLG_800.cube inside Hybrid, but seems those LUTs are excluded from your current Github package. Are those some sort of legacy outdated non recommended LUTs?
Also seems Hybrid use legacy naming for few LUTs probably taken from some early packages. I will notice Selur and ask to update those names.
FranceBB
24th September 2020, 12:05
Yes, it is Hybrid developed by Selur.
Small question. I notice BT709_to_HLG_400.cube and BT709_to_HLG_800.cube inside Hybrid, but seems those LUTs are excluded from your current Github package. Are those some sort of legacy outdated non recommended LUTs?
Also seems Hybrid use legacy naming for few LUTs probably taken from some early packages. I will notice Selur and ask to update those names.
Oh boy, they were experimental, targeting two different nits level within the BBC specification. In other words, I was trying to see the result by remapping the peak white in the SDR luma to 400 nits and to 800 nits. You can keep them inside the program, but I would of course advise anyone to use the updated version. As a matter of fact, I kinda opted out for 100 nits SDR to 400 nits HDR HLG as re-mapping it to 1000 nits or so was causing some unwanted effect, especially when I was watching it on a 1000 nits reference monitor. I mean, nobody wants a completely clipped out sky (due to the 100 nits limitation of the original content) to peak at 1000 nits 'cause while in SDR you wouldn't notice, in HDR it would be annoying as there would be too much light all caused by averaged out values that were originally 235 in the 100 nits version. This happened many times, especially when "backpacks" cameraman are sent to record interviews on live sports events, like on a football pitch or near the F1 track and so on. I've also used the "new" matrix to re-encode some old footages so that I was able to insert them inside a documentary I was making (which was clearly shot in Clog3 to get enough stops / nits to produce it in HDR): About Max (2019) (https://www.imdb.com/title/tt11462526/)
You can actually try to download the "new" version of the matrix and see the differences yourself.
Anyway, by uploading them on GitHub, it should allow people to be aware of each and every changes so that these kind of things don't happen, which is one of the reason why I wanted to ditch Megaupload.
Side note: I'm pretty busy with the remastering thing at work, but when I'm gonna have time, I wanna try to make two HLG and PQ to Linear BT601 matrices as they can actually be useful when downscaling to SD without making the intermediate step of going through Linear BT709. It's actually something I wanted to make long time ago, but I never had time...
FranceBB
19th November 2020, 11:45
A friend of mine asked me what I was thinking about his camera, a Canon EOS R.
I tried it and unfortunately for him my review wasn't flattering... heck, it was rather a more sweetened version of "it's ok for FULL HD, it sucks for UHD".
If you're curios, here's a sample (re-encoded by YT sadly 'cause I wouldn't know where to upload it to make it last as WeTransfer lasts for a week only) brought to BT709 SDR 100 nits with my LUT (it's a video, not an image, you have to click on it to see it as I can't embed it):
https://i.ytimg.com/vi/XL8kkeEfQuk/hqdefault.jpg (https://www.youtube.com/watch?v=XL8kkeEfQuk&t=1s)
Sample:
Canon EOS R 4K UHD 25p Sample in CLog1 brought to Linear BT709 4:2:0 (yv12) planar 8bit 100 nits using a matrix of linear transformation 65x65x65 with 16bit planar precision. The result has then been dithered down to 8bit planar with the Floyd Steinberg Error Diffusion using Avisynth.
MediaInfo of the original file:
General
Complete name : U:\temp\Raw Canon EOS R\1220_001.MP4
Format : MPEG-4
Format profile : Base Media / Version 2
Codec ID : mp42 (mp42/avc1/CAEP)
File size : 415 MiB
Duration : 7 s 600 ms
Overall bit rate mode : Variable
Overall bit rate : 458 Mb/s
Video
ID : 1
Format : AVC
Format/Info : Advanced Video Codec
Format profile : High@L6.1
Format settings : 1 Ref Frames
Format settings, CABAC : No
Format settings, Reference frames : 1 frame
Format settings, GOP : N=1
Codec ID : avc1
Codec ID/Info : Advanced Video Coding
Duration : 7 s 600 ms
Bit rate mode : Variable
Bit rate : 456 Mb/s
Width : 3 840 pixels
Height : 2 160 pixels
Display aspect ratio : 16:9
Frame rate mode : Constant
Frame rate : 25.000 FPS
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 2.201
Stream size : 413 MiB (100%)
Language : English
Color range : Full
Color primaries : BT.709
Transfer characteristics : BT.709
Matrix coefficients : BT.709
Codec configuration box : avcC
Audio
ID : 2
Format : PCM
Format settings : Big / Signed
Codec ID : twos
Duration : 7 s 600 ms
Bit rate mode : Constant
Bit rate : 1 536 kb/s
Channel(s) : 2 channels
Sampling rate : 48.0 kHz
Bit depth : 16 bits
Stream size : 1.39 MiB (0%)
Language : English
Other
ID : 3
Type : Time code
Format : QuickTime TC
Duration : 7 s 600 ms
Bit rate mode : Constant
Frame rate : 25.000 FPS
Time code of first frame : 00:43:38:13
Time code, striped : Yes
Language : English
Camera Review:
As to the Camera itself, it's limited to 25p or 29.970p in 4K and its sensor isn't really great, especially in UHD. Although this camera is capable of recording in UHD (3840x2160), it cannot record in 50p or 60p and on top of that it's limited to 8bit. As to HDR, its dynamic range is pretty much zero; this is because although it's capable of recording in CLog1, its sensor can record as little as 120 nits, of which 20 nits are just noise. Blacks are full of noise and they don't really benefit for the additional "range" (if we can call it that, considering that it's as little as 20 nits) and it's very hard not to clip out whites. If you close too much to save high frequencies (like the sky), then you're gonna get everything averaged out / crashed in the blacks. My review is simple: this is not a camera for UHD nor HDR and it can only work for FULL HD BT709 SDR 50p/60p as it's meant for these things. The fact that Canon added the ability to record in UHD and in CLog1 doesn't really mean that it should be used that way. One final remark goes to the autofocus which tries to get the objects in focus all the time making the stuttering of recording in 25p even more noticeable...
Codec: H.264, 3840x2160, 4:2:0 yv12 25p, 500 Mbit/s Linear BT709 8bit planar (--ref 1, all frames are encoded as Intra).
FranceBB
20th December 2020, 17:42
Greetings, everyone!
This year has hardly been a "year" as there were restrictions in place, mandatory face coverings, lockdowns, all due to this global pandemic.
Anyway, there's now an approved vaccine and there might be another one soon, so there's light at the end of the tunnel.
This is gonna be my last release of 2020 and it's gonna be with a 2020-related thing.
Linear Transformation v1.1 Released!!
- Added Linear BT2020 SDR 100 nits to HLG BT2020 HDR 200 nits support
Download Link (GitHub) (https://github.com/FranceBB/LinearTransformation/releases)
The reason for it is that, according to the ITU specifications, HLG defines graphics white as being 75% of code values and the common mapping of the original SDR 100 nits signal to fit as white for HLG is 3.18 of Y relative value, which leads to the magical number of 200 nits. I've cross-checked it with different sources, the math is correct and it also pleases the viewer (i.e me xD).
https://i.imgur.com/AUbkgG0.png
https://i.imgur.com/YqG7Xao.png
https://i.imgur.com/2zELI0v.png
https://i.imgur.com/wnPLunU.png
Disclaimer: screenshot are taken in HDR on an HDR monitor on Windows 10, the picture on the right has the HLG color curve applied and thus needs an HDR monitor to be displayed correctly, you won't see it displayed correctly on an SDR one.
FranceBB
22nd January 2021, 14:34
As you probably are aware, Iphone 12 can shoot in HDR HLG BT2020 Dolby Vision H.265 10bit planar.
The problem is that because of the tiny sensor, it doesn't have many stops, which in turns doesn't have many nits, however what Apple seems to be doing is very peculiar and requires a very dedicated matrix of linear transformation, hence this LUT.
This is the original picture shot by the Iphone 12: https://i.imgur.com/ubIAcsl.png
The reason why I had to make yet another matrix is that I wasn't really pleased with what the tonemapping algorithms were producing: on the left hand side, Reinhard, in the middle, Hable, on the right hand side the proper HDR HLG BT2020 interpreting both the color curve and color matrix correctly: https://i.imgur.com/nBNE3q5.png
they came straight from zscale of FFMpeg but similar results can be achieve in Avisynth with HDRTools.
After spending lots of time tweaking the parameters, I decided to make the LUT myself and this is what I've got:
https://i.imgur.com/wtWaiiv.png
It seems that Apple's interpretation of the HLG curve is not exactly based on the BBC specs as it has a black point that starts very high, way higher than it should. HLG is known to be an Hybrid curve which starts like a Linear BT2020 curve, so like SDR, but then changes and approaches its HDR nature, which is why it can be viewed both on SDR and HDR monitors. In Apple's implementation, however, this is NOT the case as the black starts way higher, as if it was a proper logarithmic curve. This creates problems as it's supposed to start lower and "confuses" tonemapping algorithms.
Not only that, it's also gonna look bad on SDR BT2020 displays! This is how it would look on SDR BT2020 displays if you interpret the color matrix correctly as BT2020 but you ignore the info about the color curve: https://i.imgur.com/3GoGKeM.png
See? It's wrong, it's really wrong, blacks are supposed to be displayed properly on SDR displays due to the nature of the curve which starts normally and THEN becomes logarithmic, but here it's not the case and the black point is far too high. What I think tried to achieve with this is to squeeze as much as they could from this curve by making it as logarithmic as possible and I could understand that if it wasn't for the fact that with such a tiny sensor it's not justified.
I mean, honestly, even cameras that shoot HLG don't do that, so why should Apple?
I have no words...
Anyway:
Updated Linear Transformation v1.2
- Added HLG BT2020 Apple to Linear BT709 SDR
Link: https://github.com/FranceBB/LinearTransformation/releases
frank
25th March 2021, 15:35
I have tested the BT709 to HLG conversion and got a dark result.
After some research in Avisynth+ and FFmpeg I found that the RGB input to BT709_to_HLG.cube must be limited 16-235 (TV). Then the output of Cube() will be full RGB with right black level 0. Maybe you tested with a TV RGB from your office?
Because the RGB range in ffmpeg and Avisynth is 0-255/2023 (PC) the LUT has to work with full range.
FranceBB
25th March 2021, 16:06
I found that the RGB input to BT709_to_HLG.cube must be limited 16-235 (TV).
Crap, you're right, I just checked.
It was outputting this:
https://i.imgur.com/KEORrBF.png
instead of this:
https://i.imgur.com/bnqFa7p.png
Maybe you tested with a TV RGB from your office?
Yes, it goes through a Blackmagic Decklink and then on to a Canon Broadcast Monitor via SDI.
Good catch.
Unfortunately I'm at Sky but I'm not in a 4K room to test right now, so I might have got it wrong but I tried to fix it.
Left (HLG) - Right (BT709): Img1 (https://i.imgur.com/oehCJIA.png) - Img2 (https://i.imgur.com/xEez643.png) - Img3 (https://i.imgur.com/ilndR9X.png)
Can you please test this and come back to me?
https://we.tl/t-GTfJ7q9P6n
p.s If I got it wrong, I'll book a 4K editing room for late this afternoon.
frank
25th March 2021, 19:17
My test is very simple. I only use VirtualDub to check the avs.
My Avisynth+ script:
# (LSMASHSource.dll)
LWLibavVideoSource("movie.mkv",cachefile="movie.lwi",format="",decoder="",prefer_hw=1) # cuvid
# Converting format (avsresize.dll)
z_ConvertFormat(pixel_type="RGBP16",colorspace_op="709:709:709:l=>rgb:709:709:f",dither_type="none")
# Apply LUT (vscube.dll)
Cube("BT709_to_HLG.cube",fullrange=true) # max-cll 1000
# Converting format (avsresize.dll)
z_ConvertFormat(pixel_type="YUV420P10",dither_type="error_diffusion")
# Enable MT
Prefetch(2)
This script is very fast! With ffmpeg x265 I get 36 fps (1080p) encoding speed on my notebook.
Your new cube works as far I can see. :)
FranceBB
25th March 2021, 23:08
Ah ok, a very simple yet effective test. :)
I'm glad it's working ok, I'll test it in a proper broadcast monitor tomorrow morning and if everything is alright, I'll swap it on GitHub and in the next version of FFAStrans. :)
frank
26th March 2021, 08:33
I tested a short sample of Das Boot (The Boat) with the cube. Encoded in HLG BT2020-10, not BT709.
Sorry, not good! Black level is good, but then colors get brighter too soon. So medium brightness of mid tones gets higher.
Looking on my LG CX (HDR HLG ready) I can compare with the original movie.
The original (BT709) looks much better.
FranceBB
26th March 2021, 10:00
Ok, I see. I tried to knee it down a bit, how about this one: https://we.tl/t-Drj48BMhpy
https://i.imgur.com/XDOydAG.png
Red is BT709 SDR, Blue is BT2020 HLG HDR
frank
26th March 2021, 12:37
Ok, BT709_to_HLG_v3 works better. But the color contrast is lower, I guess about 5%-10%.
My 3 test options:
- VirtualDub to control avs.
- A new Dell XPS 15 9500, it has a very good display with Windows HD color. I can watch HDR or HLG encoded streams using mpv, color mapping is awesome.
- TV LG OLED 48CX (neutrally calibrated) to show the end result.
In the mean time I encoded a SDR to HLG sample with color transfer functions of Avisynth+. The result was surprisingly good.
# Converting SDR to HLG (avsresize.dll)
z_ConvertFormat(colorspace_op="709:709:709:l=>2020:std-b67:2020:l", \
pixel_type="YUV420P10",dither_type="error_diffusion",nominal_luminance=150) But I had to set the nominal_luminance to 150 (default 100) to get the right brightness.
Very difficult to distinguish from the original on the LG OLED. :) But HEVC reencoding of long HD movies like Das Boot results in 1/5 size.
FranceBB
20th May 2021, 17:25
Linear Transformation v1.4 (https://github.com/FranceBB/LinearTransformation/releases)
Changelog:
- Improved BT2020 HLG to Linear BT709 SDR Conversion (I'm now following the EBU Tech 3373 specifications much more closely)
- From "BT601_NTSC" to "BT601_PAL"
- From "BT601_NTSC" to "BT2020"
- From "BT601_NTSC" to "BT2020_HLG"
- From "BT601_NTSC" to "BT2100_PQ"
- From "BT601_PAL" to "BT601_NTSC"
- From "BT601_PAL" to "BT2020"
- From "BT601_PAL" to "BT2020_HLG"
- From "BT601_PAL" to "BT2100_PQ"
- From "BT2020_HLG" to "BT601_PAL"
- From "BT2020_HLG" to "BT601_NTSC"
- From "BT2020" to "BT601_NTSC"
- From "BT2020" to "BT601_PAL"
- From "BT2100_PQ" to "BT601_NTSC"
- From "BT2100_PQ" to "BT601_PAL"
I'm looking for volunteers to test those new matrices 'cause my tests have all been done with color bars.
Please test those with real life contents and come back to me with the results!
gispos
21st May 2021, 23:07
Thank you FranceBB,
tried the BT2020 to SDR ( HLG_BT2020_to_Linear_BT709, PQ_to_BT709_v1) and the results are very good for me.
With DGHDRToSDR I sometimes needed more than half an hour for a slightly worse result (falsified colors).
Are variations also possible? like: normal, everything darker brighter
FranceBB
22nd May 2021, 07:30
Well not inside the matrix itself as I gotta respect the mapping points defined by the standard (any modification would be my personal choice and not the application of the documents from the regulators), anyway that is indeed possible, however, for a "normal" use case I would say that once you bring everything to BT709 SDR 100 nits, you can use any SDR-aware Color Correction filter like smooth adjust, tweaks, levels etc 'cause you're effectively just working in BT709 SDR without any Color curve applied ('cause the old fashioned resulting sigmoid in the transformation took care of it for you). For instance if you're in a NLE you can easily apply the matrix and then use the colour correction panel.
Anyway I'm glad that they're working as intended. :)
wswartzendruber
24th May 2021, 07:28
Hey FranceBB... It's me again and I'm up to my usual antics.
How does HLG_BT2020_to_Linear_BT709.cube work? Is it linear up to a certain point and then there's a knee like BT.2390 and Mobius? Or does it darken the overall image like Hable?
FranceBB
24th May 2021, 17:25
Hey FranceBB... It's me again and I'm up to my usual antics.
How does HLG_BT2020_to_Linear_BT709.cube work? Is it linear up to a certain point and then there's a knee like BT.2390 and Mobius? Or does it darken the overall image like Hable?
No worries. :)
You're right, it is linear at the very beginning and then it's "kneed" down following the EBU Tech 3373 reference (https://tech.ebu.ch/docs/tech/tech3373.pdf), in fact I used their v210 lossless color bars as reference along with the values included in their document. I gotta say, though, that I didn't follow them by the letter in the sense that if you're gonna check the bars with a scope after the transformation you won't see a straight line. The reason is that I started with that and then I adjusted myself 'cause I tried to preserve as many details as I could in the 400 nits range then I made a soft-rollback (soft-clip) of the 1000 nits highights. The reason is that while the vast majority of HLG movies peak at 1000 nits, I noticed that the vast majority of sporting events from 2017 onward 'till nowadays generally peak at 400 nits.
wswartzendruber
24th May 2021, 19:04
No worries. :)
You're right, it is linear at the very beginning and then it's "kneed" down following the EBU Tech 3373 reference (https://tech.ebu.ch/docs/tech/tech3373.pdf), in fact I used their v210 lossless color bars as reference along with the values included in their document. I gotta say, though, that I didn't follow them by the letter in the sense that if you're gonna check the bars with a scope after the transformation you won't see a straight line. The reason is that I started with that and then I adjusted myself 'cause I tried to preserve as many details as I could in the 400 nits range then I made a soft-rollback (soft-clip) of the 1000 nits highights. The reason is that while the vast majority of HLG movies peak at 1000 nits, I noticed that the vast majority of sporting events from 2017 onward 'till nowadays generally peak at 400 nits.
I think that would work for what I want. My idea is to convert a frame of a movie to HLG using pq2hlg, then downconvert that output using this LUT of yours. I should then compare it against a BT.709 Blu-ray screenshot of the same frame, in order to see if I need to increase or reduce the PQ's brightness.
Until now, I've just been using MPV and VLC to compare how they look on BT.709, but VLC's Hable implementation darkens the whole frame while MPV seems have shifting levels of brightness. So I'm looking for a more firm source of truth on what a HLG frame's BT.709 representation should really be.
FranceBB
26th May 2021, 13:02
I think that's gonna work.
On the other hand, I very much like the MPV approach and you can try to play with:
--target-peak=<auto|nits>
--tone-mapping=<value>
--tone-mapping-param=<value>
--tone-mapping-max-boost=<1.0..10.0>
--hdr-compute-peak=<auto|yes|no>
--hdr-peak-decay-rate=<1.0..1000.0>
--hdr-scene-threshold-low=<0.0..100.0>
--hdr-scene-threshold-high=<0.0..100.0>
--tone-mapping-desaturate=<0.0..1.0>
--tone-mapping-desaturate-exponent=<0.0..20.0>
in particular, you can easily tweak the dynamic tonemapping of MPV to also behave like a "normal" static mapper and have a more consistent result. I would do that for testing only 'cause I very much like the dynamic tonemapping of MPV and I'd very much like to see it implemented in FFMpeg one day 'cause the way it is implemented in FFMpeg right now is sort of unfinished 'cause the mapping is static and doesn't adjust itself on a scene-by-scene basis, which is a shame.
For me the real deal are those three parameters in particular:
--hdr-compute-peak=<auto|yes|no>
Compute the HDR peak and frame average brightness per-frame instead of relying on tagged metadata. These values are averaged over local regions as well as over several frames to prevent the value from jittering around too much. This option basically gives you dynamic, per-scene tone mapping.
--hdr-peak-decay-rate=<1.0..1000.0>
The decay rate used for the HDR peak detection algorithm (default: 100.0). This is only relevant when --hdr-compute-peak is enabled. Higher values make the peak decay more slowly, leading to more stable values at the cost of more "eye adaptation"-like effects (although this is mitigated somewhat by --hdr-scene-threshold). A value of 1.0 (the lowest possible) disables all averaging, meaning each frame's value is used directly as measured, but doing this is not recommended for "noisy" sources since it may lead to excessive flicker. (In signal theory terms, this controls the time constant "tau" of an IIR low pass filter)
--hdr-scene-threshold-low=<0.0..100.0>, --hdr-scene-threshold-high=<0.0..100.0>
The lower and upper thresholds (in dB) for a brightness difference to be considered a scene change (default: 5.5 low, 10.0 high). This is only relevant when --hdr-compute-peak is enabled. Normally, small fluctuations in the frame brightness are compensated for by the peak averaging mechanism, but for large jumps in the brightness this can result in the frame remaining too bright or too dark for up to several seconds, depending on the value of --hdr-peak-decay-rate. To counteract this, when the brightness between the running average and the current frame exceeds the low threshold, mpv will make the averaging filter more aggressive, up to the limit of the high threshold (at which point the filter becomes instant).
joearmstrong
21st June 2021, 20:22
I downloaded your LUT collection v1.4 and tested PQ to BT709. v1 is working but v2 cannot be loaded - tested with AviSynth+ and your LinearTransformation plugin. Error message: AVSCube - cannot open cube file.
My AviSynth command was: LinearTransformation(Input="BT2100_PQ", Output="BT709").
Edit: It seems to be a problem of the LinearTransform plugin. Using PQ_to_Bt709_v2.cube with Avsresize is working fine.
z_ConvertFormat(pixel_type="RGBP16",colorspace_op="2020ncl:st2084:2020:l=>rgb:st2084:2020:f",dither_type="none")
Cube("PQ_to_Bt709_v2.cube", fullrange=true)
z_ConvertFormat(pixel_type="YV12",colorspace_op="rgb:709:709:f=>709:709:709:l",dither_type="ordered")
FranceBB
22nd June 2021, 08:11
Only v1 is included in Linear Transformation, though (check the conditional at line 38):
Input=="BT2100_PQ" && Output=="BT709" ? "PQ_to_BT709_v1"
therefore there's no way to call v2 from within the plugin.
Shall I add v2 inside as well?
Besides, did you set mypath at the very beginning in line 6 of the script?
By default it's:
mypath = "C:\Program Files (x86)\AviSynth+\LUTs\"
which means that it's gonna look for the LUTs in a folder called "LUTs" inside the main Avisynth+ folder, however, if you have them in some other place, you gotta specify it
joearmstrong
22nd June 2021, 09:03
Yes, I specified the folder where I stored your cube-file. I found a solution: Renaming PQ_to_BT709_v2.cube to PQ_to_BT709_v1.cube fixed the issue.
Adding v2 to Linear Transformation would of course be better.
Do you prefer v1 or v2 for HDR to SDR?
chmars
8th July 2021, 14:08
Hi,
I'm trying to see how far I could grade without the use of Resolve.
My capture rushes are in Slog3 (Sony FS7 XAVC-I).
As starting point, I tried
s = FFVideoSource("D:\davinci_eric_folder\test_sources\490-christophe_010-XAVCI-4K-BLD-Trim_Crop.mov").KillAudio().assumefps(25)
s = s.trim(2528, 2578).crop(80,90,-70,-80)
s1 = s.convertbits(16).ConvertToYUV422()
s2 = s.LinearTransformation(Input="SLog3", Output="Linear_BT709")
return(stackhorizontal(s1, s2))
But I get a strange result (source/lineartransformed):
https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/vTjCG1D8RrILl2Y/download
https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/vTjCG1D8RrILl2Y/download
Here is the clip (https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/tRsJqj7kfndpdRm/download)
Where is my error?
FranceBB
8th July 2021, 15:03
Where is my error?
No error, the result is consistent with what I get by using:
FFVideoSource("Z:\490_trim_crop.mov")
ConvertBits(16)
ConverttoPlanarRGB()
Cube("C:\Program Files (x86)\AviSynth+\LUTs\Slog3_to_BT709.cube", fullrange=true)
So I assume that the blue shift is already in the very old source, you're not seeing it in the Slog3 file 'cause it's impossible to see it with a naked eye.
As an example, here's a real Slog3 image after the Linear Transformation:
https://i.imgur.com/8xxQEA4.png
Of course, in your specific case this can be easily fixed by playing with the ASC-CDL with a 0.66 slope reduction on the mapping of the blue values:
https://i.imgur.com/59PH90J.png
which leads to this:
https://i.imgur.com/iO9ZTsS.png
https://i.imgur.com/wuJ3qdq.png
https://i.imgur.com/z1767GX.png
Released Linear Transformation v1.5 (https://github.com/FranceBB/LinearTransformation/releases)
Changelog:
Updated LinearTransformation() for Super8 Slog3 captures:
LinearTransformation(Input="SLog3_Super8", Output="BT709")
https://github.com/FranceBB/LinearTransformation/releases
chmars
8th July 2021, 18:09
Whaaa, great, thanks for the work+explanation, one more Avi saint!:)
So I assume that the blue shift is already in the very old source, you're not seeing it in the Slog3 file 'cause it's impossible to see it with a naked eye.
Hmmm...wait... before concrete dries, maybe, this counts:
On the pro side, in the studio, we are used to shoot with cameras (Red...) which have daylight sensors. So we shoot with daylight sources. This allows not to increase the noise in post-production, noise which would appear mainly in the red, by lifting up the color temperature to compensate artificial CTT light sources (halogen...).
I followed the same logic here when I set up my contraption. Blue filter to convert the contraption halogen bulb from 3200°K to 5600°K. To be seen as white by the sensor.
But is the FS7 sensor daylight? I am 90%sure but don't find the official information about that. Sensor is an EXMOR R CMOS...
Anyway, I guess the LUT to be used for 8mm/S8mm conversion via Slog3 also depends on the light source of the scanner/projector. Some use fixed temp LEDs, others RGB LEDs, halogen...
Back to our case:
It's great to have a LUT that approaches me to the final image so much in one step. Resolve LUT also gave crazy results. So, till now, I had to manually correct the colors levels and curves.
If you are interested, here (https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/5tVHzmKspSdFQ3n/download) is a more complete test file.
It contains various scenes. Also some sea takes where blue (and miss of magenta?) still appear a bit excessive with the new LUT:
https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/9vi5uL5dFiGIHHg/download
https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/9vi5uL5dFiGIHHg/download
Detail:
LinearTransformation(Input="SLog3_Super8", Output="Linear_BT709")didn't work butLinearTransformation(Input="SLog3_Super8", Output="BT709")did. I think the new output name wasn't changed in the new avsi.
FranceBB
9th July 2021, 09:04
one more Avi saint!:)
lol
On the pro side, in the studio, we are used to shoot with cameras (Red...) which have daylight sensors. So we shoot with daylight sources. This allows not to increase the noise in post-production, noise which would appear mainly in the red, by lifting up the color temperature to compensate artificial CTT light sources (halogen...).
Yes, when shooting using a logarithmic curve you would end up getting much more noise than you would normally do otherwise 'cause the camera would save all the frequencies the sensor gets and especially in the blacks there are gonna be many more details than you would get with a classic SDR curve or even with an hybrid curve like HLG as the values are "lifted", making those completely logarithmic curves start much higher, so it's ok for you to try to compensate this on the camera side before getting to post-production just to play it safe.
I followed the same logic here when I set up my contraption. Blue filter to convert the contraption halogen bulb from 3200°K to 5600°K. To be seen as white by the sensor.
But is the FS7 sensor daylight? I am 90%sure but don't find the official information about that. Sensor is an EXMOR R CMOS...
Right. It should be correct, but could you try to record a bit without the blue filter just to see what the output is gonna look like? It might be that the camera is adjusting itself automatically, so we get the blue shift as the processing is applied twice.
Anyway, I guess the LUT to be used for 8mm/S8mm conversion via Slog3 also depends on the light source of the scanner/projector. Some use fixed temp LEDs, others RGB LEDs, halogen...
Absolutely.
Resolve LUT also gave crazy results. So, till now, I had to manually correct the colors levels and curves.
Yeah, I'm not surprised. The matrix created by the Blackmagic engineers is probably gonna follow the same logic as mine, so taking aside the personal taste, the basic mathematical implementation should be the same, so...
If you are interested, here (https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/5tVHzmKspSdFQ3n/download) is a more complete test file.
It contains various scenes.
I'm totally interested and I've seen that using Slog3 might be a bit of an overkill for those poor 8mm, 'cause there are no details whatsoever in the blacks and the whites are easily clipped out in the source. Especially in the blacks, in the scene where there's the rock in the water, underneath the rock, in the inner part of what looks like an inlet, there's... well... nothing, back then it was impossible for the camera sensor to record those frequencies (after all we're talking about analog technology from several years ago).
I'm gonna play with it a bit more, but not now 'cause I'm technically at work and I should really be working on our TV Series :P
'later ;)
chmars
9th July 2021, 15:55
It might be that the camera is adjusting itself automatically, so we get the blue shift as the processing is applied twice.
No. With Slog3 XAVC-I, the camera has no correction enabled.
Ok, I'll try to record the same footage with/without blue (asap but have few time atm).
I'm totally interested and I've seen that using Slog3 might be a bit of an overkill for those poor 8mm,
Great :-)
Yes Overkill, I know. My whole workflow is overkill also in resolution and compression terms, as I don't feel able to find the right limit. Afraid to miss something in tests to find the acceptable limit. Basically, I am a lighting guy, not a video freak :D
impossible for the camera sensor to record
IIRC, they were talking about...film...or something approaching :cool::p:D
I'm gonna play with it a bit more, but not now 'cause I'm technically at work and I should really be working on our TV Series :P
'later ;)
Great!
FranceBB
9th July 2021, 16:23
IIRC, they were talking about...film...or something approaching :cool::p:D
Yeah, it was shot on film, but I mean, it was impossible for the camera to capture enough nits and put them on that little piece of celluloid xD
I mean, I'm an engineer, but I'm still relatively young, so back when 8mm / Super 8 were a thing I wasn't even born and I don't really know much about their technology and how many stops the cameras had at the time, but I wouldn't be surprised if they turned out to have less than 6 stops (so less than the standard 100 nits SDR)...
chmars
9th July 2021, 18:13
Yeah, it was shot on film, but I mean, it was impossible for the camera to capture enough nits and put them on that little piece of celluloid xD
I mean, I'm an engineer, but I'm still relatively young, so back when 8mm / Super 8 were a thing I wasn't even born and I don't really know much about their technology and how many stops the cameras had at the time, but I wouldn't be surprised if they turned out to have less than 6 stops (so less than the standard 100 nits SDR)...
I was just teasing you :) you certainly know way more than me on those subjects.
Yes, the film was probably (almost) not exposed at this place.
I am capturing an image which dynamic is about half of the camera histogram. I pull it almost on the top of histogram as I understood there is more room to store information in the high light. Please correct me if I am wrong.
Anyways, film clips before the cam does. I mean, no details in shadows or light means it was clipped at exposure time (or, eventually because of under/over development).
chmars
10th July 2021, 11:28
... but could you try to record a bit without the blue filter just to see what the output is gonna look like?...
Done.
Quick and dirty color temp test only. (Whole capture setup stowed on a shelf cause dusty workshop ATM, might be not perfectly stable neither 100% sharp.)
But ok for light temp comparison.
https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/ziYXm4PgohyfkUd/download
https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/ziYXm4PgohyfkUd/download
Two captures of the same footage. S-Log3/S-Gamut3:
1. "daylight"
2. "tungsten"
Light correction made with 1/1 CTB filter.
I compensated the filter removal by closing the iris by approx 1 F-stop.
Here are the frame accurate trimed-croped mov files. (https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/tZ8DlfXGyP7AW0L/download)
Here are the original files, with side (metadata?) files. (https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/eZuOozvxyxwDnQF/download)
--------------------------------------------------------------
Here, fore reference, a X-Rite Munsell Color chart clip (https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/yUZihjNMrf8afvC/download).
I think this can be helpfull to verify LUT.
https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/yzPB4NLXgDUP3Dx/download
https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/yzPB4NLXgDUP3Dx/download
--------------------------------------------------------------
EDIT:
I tested your S8 and non S8 LUTs on all these.
Works perfectly on the chart. Or?
On the captured footages, it behaves very strangely. Like if it would exaggerate the saturation. Blue is excessive on the 5600°K capture, Yellow-green is excessive on the 3200°K one.
I don't know phenomenon happens here?
https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/t375pGdJZ3Uv47d/download
https://nmldqjct.preview.infomaniak.website/shared_files/index.php/s/t375pGdJZ3Uv47d/download
FranceBB
12th July 2021, 10:13
Alright, so I've grabbed the Tungsten one you made, namely MBGV0503.MXF and I tried to work my way around that.
I used both the PSST-CDL to reduce the blue and the ASC-CDL to bring the slope of the red from 1.00 to 1.63.
As to the knee, I made sure that the point in which is was going to be kneed down was Gray 18% + 8 stops to make it change concavity much more nicely, like so:
https://i.imgur.com/eXo5eGp.png
https://i.imgur.com/Qb1WMID.png
So I think I've got it right this time:
https://i.imgur.com/IRLKOll.png
https://i.imgur.com/x7gIQRL.png
https://i.imgur.com/LtvYUVr.png
https://i.imgur.com/UZNv189.png
https://i.imgur.com/DbyJiqe.png
however my fear is that it's gonna change and it's not gonna be static. I don't know if it's the nature of how things are in those kind of film or if it's the projector, but once it turns to another scene with another subject, like the trees, everything is different. I mean, it's really hard to get something done properly...
Try to apply it to the whole reel but I think it's not gonna be good (I mean the final result).
At this point I'm almost tempted to ask you one last attempt if the last LUT doesn't work: namely trying HLG, let the camera adjust itself dynamically and hope for the best. :(
Linear Transformation v1.6 Released! (https://github.com/FranceBB/LinearTransformation/releases)
- Fixed typo
- Improved Slog3 Super 8 to BT709
- Got rid of the "Linear" voice in front of the regular SDR curve like BT601, BT709 and BT2020
The new syntax is like:
LinearTransformation(Input="SLog3_Super8", Output="BT709")
chmars
12th July 2021, 15:43
At this point I'm almost tempted to ask you one last attempt if the last LUT doesn't work: namely trying HLG, let the camera adjust itself dynamically and hope for the best. :(
Yes, I could do what you need but I'm afraid camera auto-adjust will not work. The system will gonna turn crazy with this huge black borders and this flashing blue LED.
Too bad there is not yet an embedded version of Avisynth to allow treating only one part of the frame!
Film is always different.
Film was changing a lot. every batch of reels had its curve, colors (little changes, but still)... If you add exposure errors and age, you get a nightmare.
When we use to shoot in film for features, they always asked to get the same batch to avoid testing again and again to know exactly how to expose.
If some characteristics common to all films exist, the LUT must be limited to those (probably your original Slog3-LUT?). The rest is to be made by hand or automatic filters.
Maybe would VideoFred or JohnMeyer have some clever suggestions...
One point I don't get: why applying the LUT seems to turn to a so unstable result, exaggerating sometimes the yellow-green, sometimes the blue?
FranceBB
12th July 2021, 18:09
Yes, I could do what you need but I'm afraid camera auto-adjust will not work. The system will gonna turn crazy with this huge black borders and this flashing blue LED.
Right, there's also that LED that will screw things up... :(
Film is always different.
Film was changing a lot. every batch of reels had its curve, colors (little changes, but still)... If you add exposure errors and age, you get a nightmare.
I see...
If some characteristics common to all films exist, the LUT must be limited to those (probably your original Slog3-LUT?). The rest is to be made by hand or automatic filters.
Yeah, it's constantly changing, there isn't much I can do.
I was trying to make a comparison with this:
FFVideoSource("Super8_Slog3_AppleProRes.mov")
original=Subtitle("Original Analog Super8 film", size=60)
p0=FreezeFrame(0, 1, 0).Trim(0, 1).ConvertBits(16).ConverttoPlanarRGB().Cube("Slog3_to_BT709.cube").ConverttoYUV422().ConvertBits(bits=10, dither=1).Levels(64, 0.40, 940, 64, 940, coring=false)
p1=trim(1, 344).ConvertBits(16).ConverttoPlanarRGB().Cube("Slog3_to_BT709.cube").ConverttoYUV422().ConvertBits(bits=10, dither=1)
p2=trim(345, 717).ConvertBits(16).ConverttoPlanarRGB().Cube("Slog3_to_BT709.cube").ConverttoYUV422().ConvertBits(bits=10, dither=1).Levels(64, 0.20, 940, 64, 940, coring=false)
p3=trim(718, 1400).ConvertBits(16).ConverttoPlanarRGB().Cube("Slog3_to_BT709.cube").ConverttoYUV422().ConvertBits(bits=10, dither=1)
p4=trim(1401, 1451).ConvertBits(16).ConverttoPlanarRGB().Cube("Slog3_to_BT709.cube").ConverttoYUV422().tweak(hue=-4, dither=true).ConvertBits(bits=10, dither=1)
p5=trim(1452, 1599).ConvertBits(16).ConverttoPlanarRGB().Cube("Slog3_to_BT709.cube").ConverttoYUV422().ConvertBits(bits=10, dither=1).Levels(200, 1, 810, 64, 940, coring=false)
p6=trim(1600, 1772).ConvertBits(16).ConverttoPlanarRGB().Cube("Slog3_to_BT709.cube").ConverttoYUV422().ConvertBits(bits=10, dither=1).Levels(200, 1, 810, 64, 940, coring=false)
p7=trim(1773, 2344).ConvertBits(16).ConverttoPlanarRGB().Cube("Slog3_to_BT709.cube").ConverttoYUV422().ConvertBits(bits=10, dither=1).Levels(200, 1, 810, 64, 940, coring=false)
p8=trim(2345, 2504).ConvertBits(16).ConverttoPlanarRGB().Cube("Slog3_to_BT709.cube").ConverttoYUV422().ConvertBits(bits=10, dither=1).Levels(64, 0.40, 900, 64, 940, coring=false).tweak(sat=1.81, dither=true)
p9=trim(2505, 2634).ConvertBits(16).ConverttoPlanarRGB().Cube("Slog3_to_BT709.cube").ConverttoYUV422().ConvertBits(bits=10, dither=1).Levels(64, 1.0, 800, 64, 940, coring=false).tweak(hue=-24, dither=true)
p10=trim(2635, 3204).ConvertBits(16).ConverttoPlanarRGB().Cube("Slog3_to_BT709.cube").ConverttoYUV422().ConvertBits(bits=10, dither=1).Levels(64, 0.40, 940, 64, 940, coring=false).ColorYUV(autogain=true, autowhite=true).tweak(sat=1.81, dither=true)
p0++p1++p2++p3++p4++p5++p6++p7++p8++p9++p10
Crop(90, 20, -20, -0)
SpotLess(RadT=16, ThSAD=1000000, ThSAD2=1000000, pel=2, chroma=false, BlkSz=64, Olap=4, tm=false, glob=false, bBlur=0.0)
SpotLess()
super = MSuper(pel=2, sharp=1)
bv1 = MAnalyse(super, isb = true, delta = 1, overlap=4)
fv1 = MAnalyse(super, isb = false, delta = 1, overlap=4)
bv2 = MAnalyse(super, isb = true, delta = 2, overlap=4)
fv2 = MAnalyse(super, isb = false, delta = 2, overlap=4)
MDegrain2(super,bv1,fv1,bv2,fv2,thSADC=1400, thSAD=1400)
SpotLess()
dfttest(sigma=64, tbsize=1, lsb_in=false, lsb=false, Y=true, U=true, V=true, opt=0, dither=0)
FrostyBorders(1650, 1150, frosty=false)
Subtitle("Digital Avisynth Remaster", size=60)
filtered=last
StackHorizontal(original, filtered)
first=last
waveform=TurnRight.Histogram.TurnLeft.Crop(0, 0, -0, -1150).Spline64Resize(3300, 706)
StackVertical(waveform, first)
FrostyBorders(3840, 2160, frosty=false)
and it's encoding at the whopping speed of 0.04fps on a 56c/112th at 7% CPU usage.
1 Day and 2 hours remaining... DX
Maybe would VideoFred or JohnMeyer have some clever suggestions...
They're definitely more expert than me in terms of Remastering old reels. They're the masters of Remastering. They were doing this long before I was, so maybe they're gonna have a trick or two for us, I don't know. :P
One point I don't get: why applying the LUT seems to turn to a so unstable result, exaggerating sometimes the yellow-green, sometimes the blue?
'cause the input is unstable, it constantly changes, it's incredibly hard to work with!
It's really really hard when you have each "cut" different from the other. In your sample I had to divide it in 10 parts and threat each one of them individually in a different way 'cause otherwise I would have got some pretty bad results.
On top of that, the results I've got in the end are far from being great as I should have opened Davinci Resolve and played with them a bit, but I didn't want to and since I was doing everything in Avisynth I ended up with a compromise.
Anyway, I'll send you the results just for curiosity.
At least I'm happy about one thing, though: SpotLess() got rid of (almost) all the spots. :D
chmars
12th July 2021, 22:19
Yumy, rich answer!
If I dare: I am afraid we might spread our minds all over and loose our point if we talk about spot removal, stabilisation, denoising, etc.
However, I am very curious to see your results color-wise, sure, but also about your cleaning approach, frosty borders...
Only some words...
[Off topic parenthesis begin]
Just to explain: Alone, Spotless eats parts of moving subjects (balls, feet, hands...). It needs a colleague to bring them back.
A whole study was made in this thread (https://forum.doom9.org/showthread.php?t=182831) about spot removal (and, somehow, grain keeping).
Brilliant results thanks to Stainlesss with Spotless and Zorr with Delta Restore. Really efficient and impressing. The flavour I use and now tested a lot is here (https://forum.doom9.org/showthread.php?p=1946031#post1946031).
Here, you can see an example (Zorr) of what Spotless removed and what Delta Restore bought back:
https://i.postimg.cc/Gm826khp/dark-mask-v2.gifd
You know that place, don't you? ;)
[Off topic parenthesis end]
the results I've got in the end are far from being great as I should have opened Davinci Resolve and played with them a bit, but I didn't want to and since I was doing everything in Avisynth I ended up with a compromise.
Yes, I had great results with DR but it is totally anti-productive for such a task. I know John also uses an NLE to grade sometimes.
It would really be great having a tool that automates some part of the work like Fred/John scripts do but a bit further ifever possible.
I tried with Gammac and Autolevels.
Major problem is that Gammac will also correct the sky, sea or grass color when they fill the whole image.
Maybe, good approach would be to have one correction mixing all the scenes, plus one scene-by-scene correction. And percentages to balance these two corrections.
Well, off again....
Still: By looking at the scenes differences with the projector on a screen, differences are not so extreme as when LUT is applied on the capture. I am sure there is something to understand here.
Just intuition. No tools, no knowledge. Maybe you could see some moment in the process where colors go crazy?
FranceBB
15th September 2021, 11:05
Released Linear Transformation v1.7 (https://github.com/FranceBB/LinearTransformation/releases)
Changelog:
- Added support for ZLog2 HDR to BT709 SDR 100 nits
Full Screen Pictures: ZLog2 HDR (https://i.imgur.com/3OXYddV.png) - BT709 SDR (https://i.imgur.com/L9GU2QQ.png)
Comparison:
https://i.imgur.com/wOOdIb4.png
https://i.imgur.com/NzxlprK.png
Waveform:
https://i.imgur.com/morBVGB.png
Plotted matrix of transformation with In and Out:
https://i.imgur.com/pBC0YSQ.png
FranceBB
16th September 2021, 17:29
I'm gonna take the chance to post a conversation occurred in PM with a user.
So basically they've asked my opinion for a BT2020 UHD stream and I noticed that the color transfer was set to BT2020, which means BT2020 SDR 100 nits, however the user was concerned about the possibility that it could have been an HDR HLG stream.
Original Picture: https://i.imgur.com/NbxFvXN.jpg
So, I indexed the stream to take a look at it and... Oh my God, what a mess they've done...
I gotta say that I don't know SK 4K as a channel, but they've done a mess.
See here:
https://i.imgur.com/fcJpEQn.png
In the middle you see those "arcs" and then straight line. Those are in the middle, namely in the 3.18 Y HLG relative value. In other words, that's the peak for reference white in HLG, in fact if you look at the bottom, this should be white:
https://i.imgur.com/YODOSjl.png
So far so good, 'cause we would think that it's just a stream tagged wrongly and we can just easily tag it as arib-std-b67, so HLG in color transfer and that's it, right?
WRONG!
THIS is where they screwed up:
https://i.imgur.com/JI63qKF.png
They overlayed a BT2020 SDR 100 nits logo in a BT2020 HLG stream!!
You can't do that, of course, in fact the waveform skyrockets to 940 as it shouldn't...
Now, this is the original picture: https://i.imgur.com/NbxFvXN.jpg
This is what TVs get with the "wrong" BT2020 SDR 100 nits flag (as they're currently airing): https://i.imgur.com/3YfmBY9.jpg
And this is what you would get with the BT2020 HLG HDR flag (as they should be airing): https://i.imgur.com/WN9S2b0.jpg
Of course, by doing that the TV will have to compensate the logo as it's not HLG and has therefore the wrong values...
FranceBB
22nd October 2021, 09:14
2021, what a year we're living in: a year in which users are now responsible to set the right frame properties themselves ehehehehehe
https://i.imgur.com/KtaDiIi.png
FranceBB
23rd October 2021, 17:00
Linear Transformation v1.8 Released!!
Changelog:
- Introduced frame properties support for Avisynth 3.7.1
https://github.com/FranceBB/LinearTransformation/releases
MaxLt
5th November 2021, 20:40
Is this something I can use to "convert" HLG video to PQ?
Via some unusual events, I ended up with dozens of short HLG 10-bit videos that look exactly as needed on equipment that supports HLG correctly. So I do not need to colour grade them or edit them - the goal is to keep them looking as close to the way they do now but be compatible. I'd like to try to convert them to PQ because PQ videos display correctly on all equipment I have, and if that fails, convert them to SDR.
I tried doing it in Davinci Resolve with just one video (without these LUTs), and it seems to work very well. But ideally, I'd be able to do it in a batch with FFMpeg. I batch transcode them to the needed bitrate via FFMpeg anyway, so if I can also convert to PQ in that step, it would be ideal. Am I on the right track?
FranceBB
5th November 2021, 21:27
ideally, I'd be able to do it in a batch with FFMpeg. I batch transcode them to the needed bitrate via FFMpeg anyway, so if I can also convert to PQ in that step, it would be ideal. Am I on the right track?
Definitely. You can totally use my LUTs to go from HLG to PQ, either by using LinearTransformation() in Avisynth or by applying the LUT directly from FFMpeg. Additionally, if you need something that takes care of automatic encoding and works with both Avisynth and FFMpeg, you might wanna check our product: FFAStrans. It's free and available for everyone to use and it's the one that is handling the encoding of the overwhelming majority of contents here at Sky.
I think that FFAStrans is what you're looking for ;)
https://ffastrans.com/wp/
MaxLt
5th November 2021, 23:51
I think that FFAStrans is what you're looking for ;)
https://ffastrans.com/wp/
Thank you! Just tried it, and my mind is blown. It is exactly what I need if I can make it work. So far the PQ result is too dark for some reason (and I cannot figure out how to use CRF rather than fixed bit rate with HEVC output module there, which would be a good option to have but not critical).
I seem to have been able to localize the cause of dark image to the 2020 HLG -> 2100 PQ linear transform filter. Using all the same settings for PQ but BT709 source and BT709->PQ linear transform works fine. Similarly, using 2020 HLG source with HLG to BT709 transform works fine. Only 2020 HLG to 2100 PQ produces a very dark image but with correct colors (white is about the level of SDR white and shadows are all near black). Either there is a bug or I'm doing something wrong. I will try directly with FFMpeg, but I have difficulty figuring out the command line parameters there.
FranceBB
6th November 2021, 15:24
Thank you! Just tried it, and my mind is blown. It is exactly what I need if I can make it work.
Perfect. :)
So far the PQ result is too dark for some reason
This is weird.
I seem to have been able to localize the cause of dark image to the 2020 HLG -> 2100 PQ linear transform filter. Using all the same settings for PQ but BT709 source and BT709->PQ linear transform works fine. Similarly, using 2020 HLG source with HLG to BT709 transform works fine. Only 2020 HLG to 2100 PQ produces a very dark image but with correct colors (white is about the level of SDR white and shadows are all near black). Either there is a bug or I'm doing something wrong. I will try directly with FFMpeg, but I have difficulty figuring out the command line parameters there.
Perhaps you found a bug.
Can you please check this build: Link (https://onedrive.live.com/?authkey=%21AssQd1UcoAirKwU&id=A2FB73D8F2992944%21373799&cid=A2FB73D8F2992944)
and do a simple test with: Watch -> Encoder
and choose Auto LUT in the encoder?
If it still doesn't work correctly, then I'm gonna have to ask you to provide me privately a very small sample to work with.
MaxLt
6th November 2021, 21:08
I tried the new build and also tried with FFMpeg directly with just commend (to remove possible issues) and got the same result in every case. I'll upload the source and result samples and PM a link to it later today. Thanks for all your help!
MaxLt
7th November 2021, 22:23
I figured it out, I think. The LUT is for BBC HLG and what I had was "base HLG". I was able to generate a LUT that worked well with this tool: https://cameramanben.github.io/LUTCalc/LUTCalc/index.html
FranceBB
8th November 2021, 11:10
That's totally fine, no problem.
You can apply a custom Avisynth Script within FFAStrans and apply your custom LUT just as easily ;)
wswartzendruber
8th November 2021, 22:15
What is the difference between "BBC HLG" and "Base HLG?"
I know that in the early days, HLG had the reference white put at 0.5. Now the ITU has come along and put it at 0.75. Is that the difference between them?
MaxLt
9th November 2021, 04:19
What is the difference between "BBC HLG" and "Base HLG?"
I know that in the early days, HLG had the reference white put at 0.5. Now the ITU has come along and put it at 0.75. Is that the difference between them?
Yes, the "Spec Base/NHK HLG" white is 6 stops above neutral and "BBC HLG" is 4.5 stops above neutral. The red line here is Spec Base and the blue line is BBC. I'm surprised how few sources even mention this difference. Sony cameras seem to output the "Spec base/NHK HLG" with the brighter white point.
wswartzendruber
9th November 2021, 05:07
Yes, the "Spec Base/NHK HLG" white is 6 stops above neutral and "BBC HLG" is 4.5 stops above neutral. The red line here is Spec Base and the blue line is BBC. I'm surprised how few sources even mention this difference. Sony cameras seem to output the "Spec base/NHK HLG" with the brighter white point.
I think of these two as being labelled "ARIB STD-B67" (reference white = 0.5) and "ITU-R BT.2408" (reference white = 0.75).
Am I right in assuming that BT.2408 is the norm?
FranceBB
9th November 2021, 09:01
Sony cameras seem to output the "Spec base/NHK HLG" with the brighter white point.
Of course, Japanese people are playing at home with Sony Cameras ehehehehehe
I think of these two as being labelled "ARIB STD-B67" (reference white = 0.5) and "ITU-R BT.2408" (reference white = 0.75).
Am I right in assuming that BT.2408 is the norm?
Not here. Over here, we definitely use arib-std-b67 and we follow BBC Specs.
wswartzendruber
9th November 2021, 17:24
Not here. Over here, we definitely use arib-std-b67 and we follow BBC Specs.
You guys are putting reference white at 0.5? Because that's what ARIB STD-B67 calls for. At least on the copy I read.
FranceBB
9th November 2021, 17:54
You guys are putting reference white at 0.5? Because that's what ARIB STD-B67 calls for. At least on the copy I read.
Yes, definitely.
wswartzendruber
9th November 2021, 18:31
Oh for crying out loud!!!
I've got more to ask, but will do so in the that HDR10-to-HLG thread in this same forum.
FranceBB
6th January 2022, 12:18
Linear Transformation v1.9 Released! (https://github.com/FranceBB/LinearTransformation/releases)
- Following 75% ref white BBC Spec and assuming 1000 nits PQ all the time for PQ to HLG conversion
- Improved precision with 3D 65 size PQ to HLG conversion
In case you were wondering, it all came out from this: https://forum.doom9.org/showthread.php?p=1960698#post1960698
Selur
10th February 2022, 21:53
Small feedback:
I like the dvhe0509_to_BT709.cube, which works fine for some DV files,
using:
clip = core.resize.Bicubic(clip=clip, format=vs.RGB30, matrix_in_s="2020ncl", range_s="limited")
# color adjustment using TimeCube
clip = core.timecube.Cube(clip=clip, cube="I:/Hybrid/64bit/vsfilters/ColorFilter/TimeCube/dvhe0509_to_BT709.cube")
the color is off with the NASA file from https://www.demolandia.net/4k-video-test/dolby-vision/page-2.html which can be clearly seen when looking at the parts where the sun is shown.
It's identified by MediaInfo as "Dolby Vision, Version 1.0, dvhe.05.09, BL+RPU", same as the "LG Amaze Dolby Vision UHD 4K Demo" and the "LG Earth Dolby Vision UHD 4K Demo" files.
Since I don't really have DV content it's not really an issue for me, but I wanted to let you know that there is still room for improvement. ;)
Cu Selur
FranceBB
10th February 2022, 23:31
Yeah there's definitely room for improvement and I also promised you that I was gonna take a look at the colour bars, but I really didn't have time as I'm fighting against muxing .STL subtitles in .MXF as vbi_vanc_smpte_436m. If I can get that sorted tomorrow or in the coming days, I'll take a look at this again, I swear.
FranceBB
16th February 2022, 21:59
One of my retired colleagues named Livio Aloja (algie on Doom9) is working on it and he's getting closer, but not quite.
Top: original dvhe0509, Middle: LUT BT709 SDR, Bottom: Official Dolby Vision Decoder
https://i.imgur.com/Nk8kcju.png
https://i.imgur.com/NMf90Gj.png
https://i.imgur.com/mKa5vZc.png
quietvoid
16th February 2022, 23:07
Isn't it pointless unless the LUT is regenerated when the reshaping metadata changes?
Not sure what's currently being attempted, but a single LUT will never work properly.
The color mapping should be the same, though.
wswartzendruber
17th February 2022, 04:36
Isn't it pointless unless the LUT is regenerated when the reshaping metadata changes?
Not sure what's currently being attempted, but a single LUT will never work properly.
The color mapping should be the same, though.
Are you talking about the whole collection? There's plenty in here that makes sense to have in a LUT. Namely:
1. BT.601 to BT.709
2. BT.2100 HLG to BT.601
3. BT.2100 HLG to BT.709
...and the inverses of all of these.
EDIT: I have written a utility that generates a LUT for converting PQ to HLG based on reference white adjustment and MaxCLL.
https://github.com/wswartzendruber/hlg-tools
nevcairiel
17th February 2022, 10:09
Are you talking about the whole collection?
No, just Dolby Vision. It has a lot of metadata that impacts the image, which makes a single 3DLUT practically impossible, as those properties can change from scene to scene even.
FranceBB
17th February 2022, 10:43
No, just Dolby Vision. It has a lot of metadata that impacts the image, which makes a single 3DLUT practically impossible, as those properties can change from scene to scene even.
Yes but they affect luma not chroma.
The attempt is to get chroma right here, guys.
The user can then do whatever he wants with luma as I'm leaving it sort of flat.
wswartzendruber
17th February 2022, 17:07
Is there anything like a 4D LUT where we can define different tables for different durations?
Balling
18th February 2022, 15:17
Yes but they affect luma not chroma.
The attempt is to get chroma right here, guys.
The user can then do whatever he wants with luma as I'm leaving it sort of flat.
No, it affect all three channels. No chroma or luma, BTW.
Balling
18th February 2022, 15:19
Are you talking about the whole collection? There's plenty in here that makes sense to have in a LUT. Namely:
1. BT.601 to BT.709
2. BT.2100 HLG to BT.601
3. BT.2100 HLG to BT.709
...and the inverses of all of these.
EDIT: I have written a utility that generates a LUT for converting PQ to HLG based on reference white adjustment and MaxCLL.
https://github.com/wswartzendruber/hlg-tools
Neither of those should be done with a LUT. No, the implementation should be in HLSL in GPGPU. Like in mpv and like in Chrome. Full stop.
Balling
18th February 2022, 15:20
One of my retired colleagues named Livio Aloja (algie on Doom9) is working on it and he's getting closer, but not quite.
Top: original dvhe0509, Middle: LUT BT709 SDR, Bottom: Official Dolby Vision Decoder
You can get infinitely close to this, but without reshaper there will be jumps in the video luminance. You must parse the MMR or poly reshaping in the RPU using libdovi from quitevoid. And then synthesize stuff. The implementation is here https://code.videolan.org/videolan/libplacebo/-/merge_requests/207/diffs
wswartzendruber
18th February 2022, 15:23
Neither of those should be done with a LUT. No, the implementation should be in HLSL in GPGPU. Like in mpv and like in Chrome. Full stop.
Perhaps I could persuade you to elaborate?
Balling
18th February 2022, 15:28
Perhaps I could persuade you to elaborate?
Read this: https://photosauce.net/blog/post/what-makes-srgb-a-special-color-space
As you can see the lut is not good enough. The implementation must be done using para encoding.
wswartzendruber
18th February 2022, 16:11
Read this: https://photosauce.net/blog/post/what-makes-srgb-a-special-color-space
As you can see the lut is not good enough. The implementation must be done using para encoding.
A fascinating read, but it does absolutely nothing to address why a 3D LUT won't suffice for colorspace conversion.
Your behavior here is similar to what can be seen in my HDR10-to-HLG thread. You posted something way out there, and provided nothing of substance to demonstrate your claims.
From what I can see, you post here only to sow confusion and discord. It is my belief that the community is better served by simply ignoring you.
FranceBB
19th February 2022, 15:42
A fascinating read, but it does absolutely nothing to address why a 3D LUT won't suffice for colorspace conversion.
Exactly. @Balling, there's absolutely nothing wrong in using a LUT. You brought up the mpv implementation and I think we should differentiate the two things and then discuss Dolby Vision separately.
1) When we're dealing with dynamically changing metadata
2) when we're not
3) the special Dolby Vision Case
Now, let's start with the hard part. When we're dealing with dynamically changing metadata, the videos have been encoded with --repeat-headers but unlike HDR10, in HDR10+ we have info in the SEI message colour information changing on a scene by scene basis. (Of course, the thing is that you could technically change it with the GOP which incidentally is always 1 keyframe per second so --min-keyint 1 --keyint = framerate, so it's literally there every second and it could change every second of the authors really wanted to. For instance for 23,976 it's --keyint 24). Now, you might argue that if we want to convert it to whatever we might want to read those metadata and adjust our conversion every time according to the local maxcll info rather than using the global maxcll info. That approach would be tonemapping and it's sort of what MPV tries to accomplish, however it uses its own estimation rather than reading the info (although I haven't checked recently). Is it the de facto only correct possible way to do this? No. HDR10+ is backwards compatible with HDR10, so even a decoder which ignores the dynamically changing metadata is gonna be fine. This means that a conversion using global values rather than local values is gonna be just as fine. Hence, there's nothing wrong using a LUT. I also want to stress that none of this happens in HLG, in fact in HLG metadata is not required and it's always assumed in terms of both maxCll and reference white. What happens with HLG then? Well, there's literally no need to use the approach you depicted and using it to convert to, let's say, BT709 SDR 100 nits might even lead to unpleasant results. An example? Riviera. I've done many experiments with tonemapping and in HLG if you leave MPV with the default settings, it will try to use dynamically changing tonemapping on a pre-analysis basis. What happened with Riviera was that when a character was going walking under the light of the lightbulb, it was all incredibly lit and as it passed the light, it was all dark again. That is not ok and that's also a reason why that kind of technique shouldn't be always used, at least not for HLG which is backwards compatible with BT2020 SDR anyway and should be treated like that either by only converting the colormatrix or by using a static conversion with the proper maxcll and reference white info. Now, on to the Dolby Vision thing. First thing first, let's split the Dolby Vision in two as there are different profiles. The first one, the most common one, is the two layers Dolby Vision. Such a profile is essentially two video layers: one in HDR 10 so an H.265 3840x2160 10bit HDR PQ layer and then a metadata layer which is encoded as a 1920x1080 10bit H.265 stream. Such a stream cannot be decoded on its own as it's not really a stream, it's a metadata layer and when it's combined with the real stream, it creates a 12bit HDR PQ output with dynamically changing metadata. But guess what? When it's ignored by non Dolby Vision aware decoders, only layer 1 is decoded as a simple HDR PQ 10bit. So... Again, there's nothing wrong in using the global values and a LUT.
On to the last part, dvhe09, this is a completely new thing which is a new Dolby Vision profile. Such a profile has a completely different chroma and it has an RPU which gives information about the luma. Of course, a non Dolby Vision decoder won't be able to decode it correctly, but here's the thing: given that such a profile is supposed to use the resgaper to reshape the luma to have a common ground for HDR and SDR display, when you ignore the RPU and you get the right conversion, you can get the right chroma and... guess what? A common ground luma. Of course, it won't look pretty, but it's just as ok-ish on SDR displays, you're just gonna have the black value slightly higher on some scenes, big deal, nothing is stopping the user from modifying the thing himself.
The last thing I want to say is that you should encourage people to work in the community, not bring them down.
Your attitude is not helping anyone and I'm not talking about this topic, I'm talking about lots of other topics here on Doom9 that you replied to. Just let it go, man, live and let leave.
Balling
21st February 2022, 23:53
Mpv still does not support dynamic metadata of dolby vision. So...
>creates a 12bit HDR PQ output with dynamically changing metadata
That is called FEL. Also not supported.
>dvhe09
I think it is dvav.09 and that is avc, no?
>A fascinating read, but it does absolutely nothing to address why a 3D LUT won't suffice for colorspace conversion
It is not that it will not suffice, but it will be worse than complex SIMD by direct approach. And not bitperfect. And slower, because PQ is already optimised for 12 bit arithmetics, etc. Just like HLG. Anyway, the HW accel. in Vulkan and Directx 12/11 is even faster.
>you post here only to sow confusion and discord
Okay, sure. Whatever you say. You did read my answer here? https://forum.doom9.org/showthread.php?p=1953056#post1953056 are you still angry about it?
FranceBB
22nd February 2022, 00:14
And slower, because PQ is already optimised for 12 bit arithmetics, etc. Just like HLG.
What are you talking about?
PQ and HLG are colour curves, it doesn't make them any more feasible to 12bit than any other colour curve like LogC, Slog etc.
Besides, LUT-wise, everything is always done in RGB 16bit planar.
And not bitperfect.
You do realise that PQ to HLG is a non homomorphic transformation in linear algebra, right?
It's not 1-1 and onto, it will never be, so there's NOT such a thing as "bit perfect" no matter which algorithm you use to create your matrix. Please don't make me talk about how PQ is a real logarithmic curve so the black starts higher and HLG isn't so it starts lower similar to what you would have in an SDR curve and that when you're mapping from PQ to HLG you're gonna be mapping more input points into less output points from the input curve to output curve etc etc etc.
This topic is full of info about this, along with this one
https://forum.doom9.org/showthread.php?t=182499 and plenty others on Doom9...
Anyway, the HW accel. in Vulkan and Directx 12/11 is even faster.
So what? If Donald Graft will ever grant my wish to port Cube() to CUDA, it will be just as fast.
(Yes, it can be done and he's the perfect person to do it).
Balling
23rd February 2022, 15:32
>What are you talking about?
This: https://en.wikipedia.org/wiki/Perceptual_quantizer
4096 is everywhere as you can see (yes, it is not obvious but that is why I wrote the derivation in the wikipedia article).
Wow, ITU and SMPTE spend so many time on optimising it to 12 bit integer logic and you are not even aware of it.
HLG can also be optimised. And ICtCp HLG.
>Donald Graft will ever grant my wish to port Cube() to CUDA, it will be just as fast.
Yes, it is very well can be true. I think chrome already does it on a GPU. https://github.com/google/skia/commit/3d358fe2e533a6f25403397c36b626ec2dcc5116 (we are not using the code just yet). Also see the pull itself in skcms https://skia-review.googlesource.com/c/skcms/+/391136 and later https://skia-review.googlesource.com/c/skcms/+/388596/21
FranceBB
23rd February 2022, 18:26
Wow, ITU and SMPTE spend so many time on optimising it to 12 bit integer logic and you are not even aware of it.
HLG can also be optimised. And ICtCp HLG.
No. You're mixing oranges with apples.
12bit are used only because that's the recommendation to properly display a dynamic range of up to 10'000 nits. The reason it's mentioned is that the PQ implementation makes it so that instead of having to use 16bit to encode videos, it's possible to have 10'000 nits in as little as 12bit. On this regard, if you take HLG, 1000 nits can be easily reproduced in 10bits as you have enough precision. There's been an attempt by Sony to put HLG in 8bit by making use of the full range 255 but it was non standard and only allowed their cameras to have around 700 nits. Now here's the thing: it doesn't matter what the input bit depth is, nor what the output bit depth is, the important thing is how much precision you're using in the intermediate step.
You're talking about tonemapping. Fine. You're saying that since PQ is optimised for 12bit, we should use 12bit precision to make the calculations. This is BLATANTLY WRONG. Not only you can have more bits for better precision, but if you're doing the calculations in XYZ instead of YUV, you MUST have more than 12bits, otherwise you're gonna lose precision and your result is gonna be bad.
Generally tonemapping is done with 16bit planar or 32bit float precision and it's done like so: YUV 10bit (or 12bit) input -> 16bit YUV (or 32bit) -> Conversion to XYZ with 16bit (or 32bit) precision -> Tonemapping with 16bit (or 32bit) precision -> Conversion back to YUV with 16bit (or 32bit) precision -> Dithering to target bit depth.
Please read the PDF published by Jean Philippe Scotto di Rinaldi (also known as JPSDR) and you'll get why you need more than 12bit and also why the bit depth used to display something is very different from the one used in post processing.
wswartzendruber
23rd February 2022, 23:17
This: https://en.wikipedia.org/wiki/Perceptual_quantizer
4096 is everywhere as you can see (yes, it is not obvious but that is why I wrote the derivation in the wikipedia article).
The last person with any business editing Wikipedia articles is you. You are the reason I wasted hours trying to figure out how to convert between RGB and YCbCr. You, and your utterly wrong matrix implying that gamma correction could be applied through scalar multiplication.
Wow, ITU and SMPTE spend so many time on optimising it to 12 bit integer logic and you are not even aware of it.
Perceptual Quantizer is a curve that minimizes the human eye's ability to see banding at any bit depth. 10-bits is "good enough" for content distribution. If you need to do signal manipulation, well, you probably want 12-bits.
EDIT: If you are capturing a stream that will be manipulated, you will want a 12-bit capture at a minimum. To do the actual manipulation, you will want far more. FranceBB can correct me if I'm wrong.
HLG can also be optimised. And ICtCp HLG.
HLG is optimized (with BT.2408) to provide really good backwards compatibility with SDR such that the viewer is typically not even aware of the HDR encoding in the stream. That is what HLG is optimized for. And it can do this without metadata.
FranceBB
24th February 2022, 00:23
FranceBB can correct me if I'm wrong.
No need, you're absolutely correct. ;)
HLG is optimized (with BT.2408) to provide really good backwards compatibility with SDR such that the viewer is typically not even aware of the HDR encoding in the stream. That is what HLG is optimized for. And it can do this without metadata.
Precisely.
utterly wrong matrix implying that gamma correction could be applied through scalar multiplication.
@Balling, you see? Wswartzendruber is right. This is a problem. I noticed that you're trying to reply on almost every topic, but this is a serious community with experts in the field but also users that read those discussions and will read them for years to come. If you post something, make sure that you know what you're talking about, 'cause otherwise it's just misinformation. I read your posts several times and you write sentences as if they were absolutely true and you knew, but they're actually wrong and this can cause problems to users seeking help (and getting the wrong information) and also for developers like the poor Wswartzendruber who lost hours and hours of his time seeking your wrong hint before realising that it was wrong.
There's no shame in not fully knowing something and not replying or opening a post by saying that it should be taken with a pinch of salt etc. I myself don't know a lot of things and there are lots of topics I don't reply to. For instance, if I saw like DLT and Ferenc talking about porting a filter with inline assembly or perhaps having different results on different instructions, I wouldn't reply 'cause I wouldn't be of any use, I would just offer my help to test and that's it. That's because I can't read assembly proficiently and I would get lost in what the filter is doing, while they can. You on the other hand would probably read a few lines of assembly on Wikipedia and then try to read the code and reply to the topic. I'm not saying that it's wrong, it could be taken as a good initiative, but the fact that I know you would reply as if you understood all of it and you had the solution... well that's not ok and it can be confusing for lots of people.
Balling, I'm not telling you not to post ever again, but please, when you're about to write something, think twice or three times about how you're gonna phrase the answer, it's better for everyone, honestly.
FranceBB
25th February 2022, 20:34
Linear Transformation v2.0 Released! (https://github.com/FranceBB/LinearTransformation/releases)
- Introduced proper dvhe0509 (Dolby Vision Version 1.0 dvhe0509) support after 21 days of hard work together with algia (Livio Aloja), former Senior Sky Editor and Encoder.
Dolby Vision Version 1.0 dvhe0509 samples: https://we.tl/t-uyymdntXr6 (Link valid for 7 days)
Screenshot (left original - right BT709 SDR 100 nits):
https://i.imgur.com/2RSX7iQ.png
https://i.imgur.com/XaG01v4.png
https://i.imgur.com/d8wbwze.png
https://i.imgur.com/ewnF3yj.png
https://i.imgur.com/5z8ABGm.png
https://i.imgur.com/ZRZFgL4.png
https://i.imgur.com/WjBsrwG.png
https://i.imgur.com/1XuQzoU.png
https://i.imgur.com/IM1nuA2.png
https://i.imgur.com/PGtRZQm.png
https://i.imgur.com/cqRiSMw.png
https://i.imgur.com/EPurW3b.png
https://i.imgur.com/vZ5gIQV.png
https://i.imgur.com/4gFcdo8.png
https://i.imgur.com/ujP0HYp.png
Blue_MiSfit
25th February 2022, 22:37
How does this work? Does it basically use the RPUs to recover the original RGB from the dynamically shaped ITP and then tone map using the SDR trims in the metadata?
Also...
HLG is optimized (with BT.2408) to provide really good backwards compatibility with SDR such that the viewer is typically not even aware of the HDR encoding in the stream. That is what HLG is optimized for. And it can do this without metadata.
True, but in practice HLG with BT. 2020 will still look like crap on a legacy SDR display if the grading exceeds the gamut of BT. 709 in a meaningful way.
wswartzendruber
25th February 2022, 22:56
How does this work? Does it basically use the RPUs to recover the original RGB from the dynamically shaped ITP and then tone map using the SDR trims in the metadata?
Also...
True, but in practice HLG with BT. 2020 will still look like crap on a legacy SDR display if the grading exceeds the gamut of BT. 709 in a meaningful way.
I don't know what VLC on DirectX does, but it handles this amazingly well for everything I've thrown at it.
Blue_MiSfit
25th February 2022, 22:58
Well, sure when you've got a GPU doing smart stuff absolutely you can get pretty good results. That's also true for any PQ based HDR format.
You don't have that in the linear broadcast path where an HLG signal can and does get decoded and sent as-is to a legacy 1080p SDR BT. 709 display.
This has always been my biggest gripe with HLG. The "backwards compatible" branding is a bit disingenuous ;)
wswartzendruber
25th February 2022, 23:57
Well, it's doing wonders for me. I can watch my HLG encodes on Samsung TVs via thumbdrive. They play on my phone. My computers, family computers....
The project is doing exactly what i wanted it to do.
FranceBB
26th February 2022, 00:47
You don't have that in the linear broadcast path where an HLG signal can and does get decoded and sent as-is to a legacy 1080p SDR BT. 709 display.
To a legacy BT2020 SDR 100 nits display you mean eheheheh
I can't really send it to a BT709 one, it would be wrong.
This has always been my biggest gripe with HLG. The "backwards compatible" branding is a bit disingenuous ;)
Yes cause it's only backwards compatible with BT2020 capable TVs which can only interpret the colour matrix but not the colour curve.
As such, the FULL HD people who have a BT709 SDR display only will always get a real BT709 feed encoded from a different TX master ;)
Blue_MiSfit
26th February 2022, 01:12
Exactly. This is a critical nuance that a lot of people don't understand with HLG. I'm glad you guys do it right :)
wswartzendruber
26th February 2022, 01:58
To a legacy BT2020 SDR 100 nits display you mean eheheheh
I can't really send it to a BT709 one, it would be wrong.
Yes cause it's only backwards compatible with BT2020 capable TVs which can only interpret the colour matrix but not the colour curve.
As such, the FULL HD people who have a BT709 SDR display only will always get a real BT709 feed encoded from a different TX master ;)
Going by what VLC is able to do, I think the day will come when people with BT.709 TVs get a gamut-mapped HLG image from an external box connected via HDMI.
FranceBB
26th February 2022, 03:30
Going by what VLC is able to do, I think the day will come when people with BT.709 TVs get a gamut-mapped HLG image from an external box connected via HDMI.
Totally, that would be great 'cause encoding the same movie three times in UHD BT2020 HLG, FULL HD BT709 SDR and SD BT601 SDR really takes a lot of time. I hope one day boxes will be able to tonemap and downscale on the fly from the single UHD feed.
algia
2nd March 2022, 16:18
Hi all,
I'm working on a new version of the lut
In this version V_11 the blue and the green is better, the shades between colors are softer. but i'm not satisfied
I'll work on.
If you can try the new version, tell me about the issue.
Here the .cube and some image
https://we.tl/t-wOc9nnBeCF
rwill
2nd March 2022, 17:25
algia, FranceBB, I am confused.
Do you do
<Video Decode> -> [Pixels] -> <DV Composer and Color Conversion> -> [HDR Image] -> <LUT> -> [Final Image]
or
<Video Decode> -> [Pixels] -> <LUT> -> [Final Image]
?
FranceBB
2nd March 2022, 17:57
algia, FranceBB, I am confused.
Do you do
<Video Decode> -> [Pixels] -> <DV Composer and Color Conversion> -> [HDR Image] -> <LUT> -> [Final Image]
or
<Video Decode> -> [Pixels] -> <LUT> -> [Final Image]
The latter.
Unfortunately there isn't an official specification and/or SDK unless you pay Dolby, therefore what we've been doing was reverse engineering to get a proper result.
By we I mean me and algia (aka Livio Aloja, here in CC).
There's nothing too interesting in the dvhe LUT, it's literally just a 65x65x65 LUT and as such it maps values to other values. The thing is that we noticed that even though luma is affected by the RPU and should be reshaped accordingly, by default it follows a pseudo hybrid curve. As such, the black always starts low at the bottom as in SDR and the white peaks at 75% with some scenes having highlights overshooting, so it's literally almost just as good as watching an HLG on a BT2020 SDR display. As such, we only mapped the chroma values, hence our LUT. We still have a really sharp (too sharp) transition between red and yellow as result of the fact that we don't have many control points in that region. What I mean by that is that the LUT is done via control points. A control point is a value which is mapped to another value and from there all the neighbors are mapped accordingly. Of course, the more control points you have, the better. Anyway, we still have the issue of a light violet component and a light blue component in some shades of white that shouldn't be there, which is why Livio is working on a new version like the one he shared in the post above.
The result is achieved by comparing side by side several sources and their official dolby decoded version to which we tried to get as close as possible.
rwill
2nd March 2022, 18:25
That is not going to work.
How [Pixels] is to be interpreted is defined in the RPU which can change each picture. [Pixels] can be really anything, its not a fixed format.
FranceBB
2nd March 2022, 22:57
That is not going to work.
How [Pixels] is to be interpreted is defined in the RPU which can change each picture. [Pixels] can be really anything, its not a fixed format.
It worked for every sample we've tried so far.
Sure, reshaping would change the luma which in turn also affects the chroma, but so far we've been focusing on reversing the chroma and we've got it right.
I shared the sample, you can try yourself too. ;)
If you have more samples, feel free to share :)
rwill
3rd March 2022, 00:42
It worked for every sample we've tried so far.
Sure, reshaping would change the luma which in turn also affects the chroma, but so far we've been focusing on reversing the chroma and we've got it right.
I shared the sample, you can try yourself too. ;)
If you have more samples, feel free to share :)
Yes most Profile 5 content in the wild I have seen has reshaped IPTc2 as [Pixels] so your LUT will
somehow match these more or less. One could create streams with ITP PQ, Bt.2020 PQ or just something
made up as a base format, reshape that (optional) and just flag these as Profile 5 though.
Regarding no specification being available...
The ETSI Composer spec is here:
https://www.etsi.org/deliver/etsi_gs/CCM/001_099/001/01.01.01_60/gs_CCM001v010101p.pdf
And there is a partial spec of the syntax here in Annex F:
https://dashif.org/docs/DASH-IF-IOP-v4.1-clean.pdf
With a Composer + Color Conversion you could re-create the HDR stored in [Pixels].
Then create HDR tone mapping LUTs to get SDR ?
Maybe quietvoid here on the forum can help. I cant, I don't want to risk my job.
quietvoid
3rd March 2022, 00:52
I've already shared the relevant info here: https://forum.doom9.org/showthread.php?p=1963203#post1963203
There's also an implementation in libplacebo, which I think was also mentioned.
Reshaping: https://code.videolan.org/videolan/libplacebo/-/blob/master/src/shaders/colorspace.c#L120
Color decoding: https://code.videolan.org/videolan/libplacebo/-/blob/master/src/shaders/colorspace.c#L411
If you still need help you can probably come around the libplacebo IRC channel on Libera.
Balling
5th March 2022, 15:53
>You, and your utterly wrong matrix implying that gamma correction could be applied through scalar multiplication.
Linear algebra postulates that nonlinear operation cannot be done like that. Thus you and only you and your knowledge in linear algebra is at fault. I will also point out that you even managed to make a mistake by a) looking into YUV instead of YCbCr article, b) look into BT.709 YUV matrix that was never in use EVER and will never be in use. c) transfer function can be 1, i.e. linear and then YCbCr is also linear.
>You, and your utterly wrong matrix implying that gamma correction could be applied through scalar multiplication.
Maybe you should have fixed that on Wikipedia. I fixed it. You did not. Because YOU KNOW NOTHING about how it all worked in 1989. I do. The fact that I copy pasted the matrix style from above from 12 years ago which you can simply see from commit history also suggests you know nothing about how wikipedia editing works and THUS YOU JUST CANNOT edit it, while I at least can.
>HLG is optimized (with BT.2408) to provide really good backwards compatibility with SDR such that the viewer is typically not even aware of the HDR encoding in the stream. That is what HLG is optimized for. And it can do this without metadata.
This is not optimisation, quite the opposite. Also it is naive to think SDR compatibility will be perfect. There are all kinds of problems, like ATR SEI is broken in ffmpeg and that scene color managment is very dumb and complex. What I meant is optimisations in code. For example, ICtCp HLG matrix has two values that are the same when you invert.
>You are the reason I wasted hours trying to figure out how to convert between RGB and YCbCr.
People waste years to do that. I did. And there is still a high chance that the scheme in H.273 is not compatible with that. I am still analysing it.
>Perceptual Quantizer is a curve that minimizes the human eye's ability to see banding at any bit depth. 10-bits is "good enough" for content distribution. If you need to do signal manipulation, well, you probably want 12-bits.
No, you need 12 bits for it. Full stop. The fact that you propose the opposite suggests you know nothing about the topic. Anyway, 16 bit PQ is also possible. What I was talking about was just math optimisations, not any derivation optimisation.
quietvoid
16th July 2022, 22:40
There shouldn't be a need for the "dvhe0509" LUT anymore for AVS users: https://github.com/Asd-g/avslibplacebo
At least if you have a GPU. It also gives correct results, contrary to the LUT.
StvG
6th August 2022, 19:02
You should set the correct matrix for rgb->yuv here (https://github.com/FranceBB/LinearTransformation/blob/master/LinearTransformation.avsi#L116-L126) otherwise 601 is used. Can be verified by putting propshow() after LinearTransformation.
FranceBB
6th August 2022, 21:36
You should set the correct matrix for rgb->yuv here (https://github.com/FranceBB/LinearTransformation/blob/master/LinearTransformation.avsi#L116-L126) otherwise 601 is used. Can be verified by putting propshow() after LinearTransformation.
Nicely spotted.
Fixed and I mentioned your suggestion in the release notes. :)
Linear Transformation v2.1 Released! (https://github.com/FranceBB/LinearTransformation/releases)
Changelog:
- Improved conversion back to input sampling by correctly setting the output matrix as per StvG suggestion
Balling
10th August 2022, 17:09
Well, you're welcome.
As a side note: last time I tried, ffmpeg wasn't able to read large matrices like 64x64x64 but was working fine with 32x32x32 ones and 16x16x16 ones as well. As result, some of the most accurate LUTs were not applied and resulted in an error. I don't know whether someone updated the lut3dfilter or not, but in case they didn't, just keep in mind that it might not work. If you wanna try, try to use the PQ to HLG matrix (which is definitely a 64x64x64) and check whether ffmpeg complains about it being too large or not: if it does, then they didn't update it, if it doesn't, then they updated it and I'm gonna add it as an example of how to use my LUTs. ;)
You know, you are saing it like there may be no bugs that lead to e.g. using simplied Little CMS mode that is only 49^3 max. See https://github.com/mpv-player/mpv/issues/10400
After this fix you can finally do even 512^3.
frank
10th September 2022, 17:26
Hello Francesco,
there is a problem with your 3D 65 lut BT709_to_HLG.cube.
# BT709 SDR to BT2020 HLG with reference white 75% (Full Range in - Full Range out)
You'll get limited spikes with color errors (black/blue) on bright reflections. After many tests I found it is not working on full range. I know you work with limited range in the studio. May be you mismatched something?
This Avisynth+ script worked on this lut and the resulting colors are good.
# (dgDecodeNV)
dgSource("movie.dgi") # SDR AVC
# (avsresize.dll)
z_ConvertFormat(pixel_type="RGBP16", \
colorspace_op="709:709:709:l=>rgb:709:709:l", \
chromaloc_op="left=>top_left")
# Apply LUT (vscube.dll) RGBP16
Cube("BT709_to_HLG.cube")
# (avsresize.dll)
z_ConvertFormat(pixel_type="YUV420P10", \
colorspace_op="rgb:std-b67:2020:l=>2020:std-b67:2020:l", \
chromaloc_op="top_left=>top_left")
Usually the red marked l shoud be f (full) for full range lut.
The movie was Those Magnificient Men in their Flying Machines.
You can also try STUDIOCANAL's AVC intro. The white text is inverted to black.
-------------
Dell XPS 15, Win10 Pro
frank
10th September 2022, 19:43
New test without Avisynth+.
I used NVEncC64 from rigaya. Best and fastest converter for NVIDIA.
You only can use size 65 LUTs in this program.
The importent cmd lines:
-i "movie.mkv" ^
--vpp-colorspace matrix=bt709:bt2020nc,lut3d=BT709_to_HLG.cube,range=limited:limited ^
-c hevc --profile main10 -u p5 --qvbr 25 ^
...
--chromaloc 2 --colorprim bt2020 --colormatrix bt2020nc ^
--transfer bt2020-10 --atc-sei arib-std-b67 ^
The program log shows:
Vpp Filters colorspace: cspconv(nv12 -> yuv444(16bit))
matrix:bt709->GBR
lut3d: table=BT709_to_HLG.cube
size=65, interp=tetrahedral
matrix:GBR->bt2020nc
cspconv(yuv444(16bit) -> yv12(16bit))
cspconv(yv12(16bit) -> p010)
Working perfect with your LUT. And faster, 240 fps on my notebook.
No more limited spikes, nice colors.
So I think there must be a problem with Avisynth+ and the plugins, and levels.
EDIT
Possible cause.
Depends how the 3dLUT is integrated. I think Avisynth cube reads elements as integer and not float, or has issues. So some elements for high levels destroy the colors. NVEncC64 correctly reads and converts elements as float.
All LUTs from wswartzendruber are working well with my script, but PQ to HLG only.
spoRv
11th September 2022, 17:02
Bravo Francesco, ottimo lavoro!
I'm thinking if you can make two further LUTs:
XYZ to 2020 HLG
XYZ to 2020 PQ
- unless double conversion XYZ->SDR 709 then SDR-709->HDR (HLG or PQ) is equivalent, without too much loss.
OT: how is possible to open a DCP (and other sources like HEVC 10 bit for example) and NOT getting only 8 bit?
I tried ffvideosource, directshowsource, DSS2, but always only 8 bit...
FranceBB
20th September 2022, 10:18
Hello Francesco,
there is a problem with your 3D 65 lut BT709_to_HLG.cube.
You'll get limited spikes with color errors (black/blue) on bright reflections. After many tests I found it is not working on full range. I know you work with limited range in the studio. May be you mismatched something?
I cannot reproduce.
It works just fine in full range here.
This is from the movie Lucy, a BT709 XDCAM-50 SDR 100 nits masterfile:
FFVideoSource("D:\Masterfiles\Lucy MPEG-2 FULL HD SDR BT709 YUV422 25i TFF 8bit.mxf")
propClearAll()
VideoTek(Mode="SDR")
https://i.imgur.com/67V5Hwr.png
As you can see, it peaks at around 700mV, so 235 in Limited TV range.
This is what happens when I go to HLG using my LUT which closely follows the BBC specification of their white paper as I've been reviewing it over and over and over again:
FFVideoSource("D:\Masterfiles\Lucy MPEG-2 FULL HD SDR BT709 YUV422 25i TFF 8bit.mxf")
propClearAll()
#From 4:2:0 16bit planar Narrow Range to RGB Planar 16bit Full Range
z_ConvertFormat(pixel_type="RGBP16", colorspace_op="709:709:709:limited=>rgb:709:709:full", resample_filter_uv="spline64", dither_type="error_diffusion")
#From BT709 SDR to BT2020 HDR HLG with 16bit precision
Cube("C:\Program Files (x86)\AviSynth+\LUTs\BT709_to_HLG.cube", fullrange=true)
#From RGB 16bit planar Full Range to YUV422 10bit planar Narrow Range with dithering
z_ConvertFormat(pixel_type="YUV422P10", colorspace_op="rgb:std-b67:2020:full=>2020:std-b67:2020:limited", resample_filter_uv="spline64", dither_type="error_diffusion")
VideoTek(Mode="HLG")
https://i.imgur.com/FiMGK5P.png
As you can see, the value which was previously at 700mV (so 235, so 100% of the Limited TV Range SDR signal which corresponds to 100 nits in the BT709 SDR version) is now at 520mV, so we now have the reference white at 75% of the Limited TV Range HDR HLG signal.
In my view, there's nothing wrong with this.
I'm thinking if you can make two further LUTs:
XYZ to 2020 HLG
XYZ to 2020 PQ
No problem, but I'll need someone to test them too.
I'll put them on my "to do" list.
OT: how is possible to open a DCP (and other sources like HEVC 10 bit for example) and NOT getting only 8 bit?
I tried ffvideosource, directshowsource, DSS2, but always only 8 bit...
That is actually really weird.
Are you sure you're using the latest ffms2 and Avisynth+?
This is because on the old, legacy Avisynth 2.6, you would get 8bit planar all the time OR 16bit stacked or interleaved.
On the new Avisynth+, however, it will index high bit depth sources at their native bit depth, so if you have a 10bit planar source it will be 10bit etc.
There's one notable exception, though, and that is DCP.
If you have a DCP, it means that it's a MJPEG2000 4:4:4 XYZ 12bit, however XYZ isn't natively supported in Avisynth (despite my desperate requests to support it dating back to 2017 and which I included in my meme collection https://forum.doom9.org/showthread.php?p=1953469).
There are some people like Jean Philippe who had to work in XYZ, so what they did was to create a fake RGB64 output on his ConvertYUVtoXYZ() function with XYZ inside. Some other people like Hydra/HolyWu/Asd just recognized that XYZ isn't supported in Avisynth and therefore indexers like LWLibavVideoSource() won't output anything and report an error:
https://i.imgur.com/sq24AWJ.png
Other people like Myrsloyk instead added automatic conversion, which is the case for ffms2, which brings me to the final reply of your question: if you index an XYZ 12bit file with FFVideoSource(), it will automatically bring it to 16bit, convert it to YUV and output a YUV 16bit stream.
As you can see here, my input was a MJPEG2000 in UHD XYZ 4:4:4 12bit and after indexing with FFVideoSource() it has become a YUV 4:4:4 16bit planar:
https://i.imgur.com/6j88Bqt.png
This is the Mediainfo of the original file:
Video
ID : 2
Format : JPEG 2000
Format profile : D-Cinema 4k
Format settings, wrapping mode : Frame
Codec ID : 0D010301020C0100-0401020203010104
Duration : 1 h 15 min
Bit rate : 248 Mb/s
Width : 3 996 pixels
Height : 2 160 pixels
Display aspect ratio : 1.85:1
Frame rate : 25.000 FPS
Color space : XYZ
Chroma subsampling : 4:4:4
Bit depth : 12 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 1.147
Stream size : 130 GiB (100%)
Title : Picture Track
Color range : Full
XYZ seen as is through MPV: https://i.imgur.com/46XuSBi.jpg
XYZ indexed by FFVideoSource() in Avisynth which automatically converts to YUV 16bit: https://i.imgur.com/xi8pHH4.jpg
wswartzendruber
20th September 2022, 14:03
I cannot reproduce.
As you can see, the value which was previously at 700mV (so 235, so 100% of the Limited TV Range SDR signal which corresponds to 100 nits in the BT709 SDR version) is now at 520mV, so we now have the reference white at 75% of the Limited TV Range HDR HLG signal.
In my view, there's nothing wrong with this.
This is in agreement with BT.2408, so long as you are including SDR in a larger HLG presentation. If you are converting SDR to HLG outright, that is covered in BT.2446, which offers three methods.
frank
21st September 2022, 07:48
I used hardware decoding. I'll test again when I return from my trip. Weekend.
FranceBB
21st September 2022, 09:42
when I return from my trip. Weekend.
Vacation? Where are you chillaxing? :)
As to me, right now I wanna go nowhere. I've had enough of travelling after Amsterdam to attend IBC. Not just 'cause it was all over-expensive, but also 'cause I got caught in the Schipol airport strike and lost my flight after a 4h queue... :(
I had to get back and book another flight (with no refund) and it costed me 400€... Madness.
I've had enough.
This is in agreement with BT.2408, so long as you are including SDR in a larger HLG presentation. If you are converting SDR to HLG outright, that is covered in BT.2446, which offers three methods.
Yep, that's exactly right. The original BBC White Paper from 2017 specified mapping in which BT.709 SDR is "mapped" to HLG by making HLG act as its container. In other words, there's no "creative" intent whatsoever and it's not using any of the methods specified in ITU BT.2446 which will inevitably "try to be smart" to try to give an authentic HLG feel and will change the overall perceived contrast. In the original White Paper, in fact, the BBC suggested to use the hybrid nature of HLG to make it act as a container for BT709. In other words
"Conversions whereby SDR content is placed into an HDR container without changing the dynamic range"
in accordance with ITU BT.2390.
The reason for this method is strictly related to rights.
While when we're both producers and broadcaster we can do what we want (like with sports in which we can use scene-referred HLG conversion if we have some non HLG camera, like the small ones for replays inside the net in football games), for movies and tv series whose rights are not ours, we gotta use display-referred mapping with the method I mentioned above 'cause otherwise if we apply the methods highlighted in ITU BT.2446 the content provider might reject the conversion as it will inevitably change the content. (We had a few occasions in the past where this happened and our contents got rejected, which is why I reviewed this LUT several times in the past). :)
spoRv
21st September 2022, 21:19
So, I finally found a way to load >8bit sources with:
ffvideosource("filename.extension",enable10bithack=true)
it correctly see DCPs as 12 bit; it automatically converts XYZ color space, though.
FranceBB
21st September 2022, 22:01
I'll ask you again: which version of Avisynth are you on? Is it Avisynth 2.6.1 from 2016 or 3.7.2 from 2022?
If you're not on 3.7.2, you might wanna update https://github.com/AviSynth/AviSynthPlus/releases
And don't worry, the only OS that were dropped in the meantime are Windows 98SE and Windows 2000, so given that it's highly unlikely that you're dealing with MJPEG2000 12bit using any of them, you should really update.
The reason why I'm saying this is the line you wrote right here:
"enable10bithack=true"
This parameter here doesn't exist any longer in ffms2.
As a matter of fact it has been deprecated years ago.
The reason is that back in the days of 2.6.1, Avisynth was only working in 8bit planar, while the only high bit depth supported were 16bit stacked (Dither Tools) and interleaved (HDR Core).
Back in the days, FFVideoSource() outputted 10bit+ sources as 16bit stacked, while LWLibavVideoSource () outputted 10+ sources as 16bit interleaved.
Nowadays, they both output in planar, so 10bit planar sources are kept as 10bit planar etc.
Although there's nothing wrong in working in 16bit stacked as you're doing, you need to be careful about MSB and LSB and which filters support it etc.
Let me be very clear: when you work in stacked, you must tell each and every function you're gonna call later that you're working with that.
This is an updated build of ffms2
ffms2_6ad7738 (https://ppp.woelkli.com/s/NMk6MyD6LZR7nYH) (pass: u7Uezbh3fTHM):
- ffms2@90975ec;
- ffmpeg n5.1@1764a6887b;
- zlib 1.2.12;
- dav1d 1.0.0;
- AviSynth: set Dolby Vision RPU data in frame props.
I'm gonna quote myself:
HBD stands for "High Bit Depth" and it refers to the bit depth in which you're working with.
There are 3 possible ways to work with high bit depth in Avisynth:
- Planar
- Stacked
- Interleaved
Planar means regular high bit depth, namely you can work in 8bit, 10bit, 12bit, 14bit, 16bit planar and 32bit float. The picture is the way it is and has regular high bit depth.
In other words, 1920x1080 16bit planar is 1920x1080.
https://i.imgur.com/tsDIBBZ.png
Stacked means that MSB (most significant bit) and LSB (less significant bit) are "stacked" one on top of the other, so you end up with a picture which has double its height.
In other words, 1920x1080 16bit stacked becomes 1920x2160 as it has 8bit MSB + 8bit LSB stacked one on top of the other.
https://i.imgur.com/s4yznAb.png
Interleaved means that MSB and LSB are "interleaved" together one next to the other, so you end up with a picture which has twice its Width.
In other words, 1920x1080 16bit interleaved becomes 3840x1080 as it has 8bit MSB + 8bit LSB interleaved one next to the other.
https://i.imgur.com/s9g8ilr.png
spoRv
26th September 2022, 21:05
I'll ask you again: which version of Avisynth are you on? Is it Avisynth 2.6.1 from 2016 or 3.7.2 from 2022?
If you're not on 3.7.2, you might wanna update https://github.com/AviSynth/AviSynthPlus/releases
...
This is an updated build of ffms2
...
I run Avisynth+ 3.7.0 - by the way, "enable10bithack=true" works ONLY inside MP_Pipeline.
So, I've downloaded the updated ffms2 build: still 8 bit only, both with 10bit HEVC and 12bit DCP.
Then I've downloaded 3.7.2; the same; but now ffvideosource doesn't work inside MP_Pipeline anymore; dss2 doesn't work at all, directshowsource load everything at 640x480...
Reverting to 3.7.0 everything works as previously!
Back on topic:
shouldn't "BT2020_HLG" be "BT2100_HLG"?
And, if so, couldn't "BT2100_PQ" be "BT2084_PQ" to differentiate it more from "BT2100_HLG"?
FranceBB
26th September 2022, 22:34
I run Avisynth+ 3.7.0 - by the way, "enable10bithack=true" works ONLY inside MP_Pipeline.
Are you using Ferenc's version of MPPipeline()?
https://github.com/pinterf/MP_Pipeline/releases
So, I've downloaded the updated ffms2 build: still 8 bit only, both with 10bit HEVC and 12bit DCP.
But how...? O_O
I clearly get 4:4:4 16bit planar converted to YUV when using an updated build of ffms2 and Avisynth+...
Then I've downloaded 3.7.2; the same; but now ffvideosource doesn't work inside MP_Pipeline anymore; dss2 doesn't work at all, directshowsource load everything at 640x480...
Reverting to 3.7.0 everything works as previously!
Wait, so... changing Avisynth version affects the indexing? O_O
Are you using propclearall() right after indexing in modern version of Avisynth? (that's needed 'cause otherwise other plugins will misbehave)
This is a really really really strange behavior.
I'll test tomorrow again with MPPipeline()
shouldn't "BT2020_HLG" be "BT2100_HLG"?
And, if so, couldn't "BT2100_PQ" be "BT2084_PQ" to differentiate it more from "BT2100_HLG"?
Nah, with BT2020 I mean the SDR version of the BT2020 which is signalled in HLG streams.
Given that HLG is hybrid and backwards compatible with BT2020 SDR TVs, that is signalled as BT2020 and arib-std-b67, hence TVs which can read HLG will interpret the color curve in the transfer characteristics and will reproduce accordingly, while the ones that can't will ignore the color curve and just interpret it as BT2020 SDR, hence showing everything a bit dimmed (as the reference white is 75% instead of 100%) but still making use of the BT2020. When it comes to SMPTE2084, so PQ, on the other hand, such a color curve isn't backwards compatible with BT2020 SDR TVs 'cause it's totally logarithmic, therefore blacks are pushed higher and the waveform stays in the middle, which is why it's identified by the "BT2100" which is used for HDR.
Anyway, none of this affects anything, it's just a naming convention to make some rationale around those LUTs and inside the parameters of the function I made, but yeah, they can be changed eventually, so I'll stay open to suggestions. :)
wswartzendruber
27th September 2022, 00:07
I would offer that the BT.2020 SDR fallback capability of BT.2100 HLG is largely a mechanic of HEVC signaling. With AV1, for example, I can find no way to specify a fallback transfer function. Ergo, with AV1, BT.2100 HLG streams are signaled as that and only that.
After reviewing these specifications and how they're organized, I would have expected three different naming patterns to occur:
1. BT2020_SDR
2. BT2100_HLG
3. BT2100_PQ
frank
27th September 2022, 17:32
Vacation? Where are you chillaxing? I was driving to visit relatives in Leipzig.
You did the lut3d test with a file from your office.
Lucy MPEG-2 FULL HD SDR BT709 YUV422 25i TFF 8bit.mxfEh, you should use a normal Blu-ray with AVC YUV420.
The two known cube filters avsCube and dgCube have in Avisynth+ different issues with BT709_to_HLG.cube. The cause was the black level! If the source goes to black (0) or lower then avsCube inverts borders to white, and dgCube destroys colors, makes spikes. Also clearly visible in the vectorscope of VideoTek.
https://i.imgur.com/09Zj4z1.jpeg avsCube with BT709 to HLG
I was able to eliminate it by limiting the levels of the source.
Levels(16,1,235,17,235,coring=false)This line eliminates black 16 (0) in limited YUV space. So I think your test source .mxf never reached real black or super black.
Then I looked at your BT709_to_HLG.cube and dada...
the first filter line has small negative values. It corresponds to black 0. This generates errors in Avisynth+ in the multiplication. It must be a filter problem with floating/integer conversion. In ffmpeg and NVEncC the lut3D filter is working without issues.
I replaced this filter line with three zeroes and BT709_to_HLG.cube is working perfectly.
I don't know where the negative shift is coming from. First line must be zero, we don't want super blacks.
Please recalculate this LUT.
_________________________________________
Dell XPS 15 9510, Win10 Pro, Avisynth+ 3.7.2 (64)
FranceBB
30th September 2022, 15:12
You did the lut3d test with a file from your office.
Guilty :P
Eh, you should use a normal Blu-ray with AVC YUV420.
The two known cube filters avsCube and dgCube have in Avisynth+ different issues with BT709_to_HLG.cube. The cause was the black level! If the source goes to black (0) or lower then avsCube inverts borders to white, and dgCube destroys colors, makes spikes. Also clearly visible in the vectorscope of VideoTek.
Ouch.
I know what this is about: compression artifacts lead to overshooting.
Essentially, in consumer-tier stuff, you have values outside the limited tv range which were "created" from scratch. I.e they shouldn't be there, but they are as a result of compression.
In other words, once those values are taken into account, unexpected things can happen.
Generally in professional master files and TX Masters, we try to avoid those as much as possible 'cause having them would result in QC Fail as operators always play the files with a Tektronix Hardware Waveform Monitor at their left hand side, taking the input signal from the hardware playback port (carried via SDI).
I was able to eliminate it by limiting the levels of the source.
Levels(16,1,235,17,235,coring=false)This line eliminates black 16 (0) in limited YUV space. So I think your test source .mxf never reached real black or super black.
That's exactly right. By making sure all values are within the legal region, you basically created the exact same environment we work on as you got rid of compression overshooting. :)
p.s just FYI, what you did is really good and should be done all the time as illegal values won't be displayed anyway as all monitors are RGB Full Range and therefore if you feed a monitor with a 16-235 YUV limited signal, it will expand it to 0-255, therefore anything lower than 16 will be negative, thus not displayed (same goes for out of range whites).
Then I looked at your BT709_to_HLG.cube and dada...
the first filter line has small negative values. It corresponds to black 0. This generates errors in Avisynth+ in the multiplication. It must be a filter problem with floating/integer conversion. In ffmpeg and NVEncC the lut3D filter is working without issues.
I think the best thing to do would be to inform Donald Graft about this.
Since he rarely visits Doom9 any longer and he's staying on his own solitary ice castle ehm I mean his forum, I hope my fellow compatriot @Tormento will point him to this topic here. :)
frank
30th September 2022, 20:32
The best way is to zero out that first line.
You know a lut3d is mathematically a linear matrix, or table:
input vector x matrix = output vector
Input is full range 0..max, and output is is full 0... max.
All vector elements are greater or equal zero.
The filter works internally with a fast integer format. So negative table elements can generate overflow, depending on word length. You'll get overshuts that don't exist in the input, epecially around point 0.
FranceBB
1st October 2022, 11:36
The best way is to zero out that first line.
I finally had a bit of spare time to look at this and I can't believe what I found...
The values from the first three rows are:
-0.00086043 -0.00046653 -0.00063309
0.00905835 0.00289278 0.00107100
0.01858871 0.00607219 0.00265007
And you're absolutely right, the first row is negative.
How did it happen?
Easy.
I always create the LUTs at work in Studio RGB due to our requirements, then I perform a direct trilinear interpolation to convert the values to Full Range RGB and then post here publicly so that they can be used everywhere.
Simply put: trilinear interpolation got it wrong and mapped the Studio RGB values to non existing values in Full Range RGB.
This led to negative coefficients which mean absolutely nothing in this case and are wrong.
By zeroing the first line you've done the right thing 'cause you've removed the negative mapping. With a simple calculation, the actual value of the first row should be:
0.00819792 0.00242625 0.00043791
in other words, the first three rows are supposed to be:
0.00819792 0.00242625 0.00043791
0.00905835 0.00289278 0.00107100
0.01858871 0.00607219 0.00265007
You can replace them safely and make some tests, but they're gonna be right.
I will update the LUT on GitHub too and credit you in the pull request.
EDIT: Done - https://github.com/FranceBB/LinearTransformation/commit/8d54afc5eef07867d34b91366cfece62b7ea4c23
Thank you for pointing this out, very very very well done as I completely overlooked it.
frank
15th October 2022, 09:48
Ok, thanks as always. :)
But I found another wrong LUT: PQ_to_HLG.cube
There the first 4290 rows have wrong negative elements.
Well we can generate the LUT with William's generator but you shoult correct it. This LUT is very important.
And please update your github releases. I only found v2.1.
FranceBB
15th October 2022, 14:54
Linear Transformation v2.2 Released!! (https://github.com/FranceBB/LinearTransformation/releases/)
Changelog:
Re-interpolated and removed illegal negative values to avoid overflow in Avisynth Cube() and DGCube() implementation in both BT709 to BT2020 HLG and BT2100 PQ to BT2020 HLG. Credits to frank from Germany.
Tested on the .ts version of Army of the Dead (which is the closest thing I have to a low bitrate consumer version):
https://i.imgur.com/larhO01.png
Marsu42
21st October 2022, 18:11
Hi,
LUTs are generally used to grade contents, but they can be useful to do quick and dirt color space conversions, especially in this day and age.
Can I use any of these to to convert my Samsung HDR10+ phone vidoes to SDR for my regular PC montior? The mediainfo output of the source mp4 file is:
Color range: Limited
Color primaries: BT.2020
Transfer characteristics: PQ
Matrix coefficients: BT.2020 non-constant
Mastering display color primaries: Display P3
Mastering display luminance: min: 0.0050 cd/m2, max: 1000 cd/m2
The FFMpeg tonemap filter is very slow. I've been trying to use some of these .cube files, but now have to ask because I this is simply too confusing for me - the output of "PQ_to_BT709" looks ok-ish, and I've tried combination of others - but I'm really not understanding what I'm doing I'm afraid to say. Plus I don't know what set for the encoder output --color-primaries --matrix-coefficients --transfer-characteristics settings.
Edit: I could upload a short source file clip to some sharehoster.
FranceBB
21st October 2022, 18:41
Can I use any of these to to convert my Samsung HDR10+ phone vidoes to SDR for my regular PC montior?
Absolutely, however given that they're static LUTs, they won't benefit from the dynamic metadata of HDR10+ (i.e the transformation will be static).
If it's just to watch them, I strongly suggest you MPV as a player, which is open source, cross platform and it will perform dynamic tonemapping to BT709 automatically in a scene-by-scene fashion.
Anyway, if you want to re-encode them to BT709 SDR instead, then you're in the right place. :)
the output of "PQ_to_BT709" looks ok-ish
Good. :)
I don't know what set for the encoder output --color-primaries --matrix-coefficients --transfer-characteristics settings.
it's pretty easy, for x262, x264 and x265 it's just
--colormatrix bt709 --transfer bt709 --colorprim bt709
while for FFMpeg it's:
-color_primaries 1 -color_trc 1 -colorspace 1
I could upload a short source file clip to some sharehoster.
If you want, feel free. :)
Marsu42
21st October 2022, 22:48
Absolutely, however given that they're static LUTs, they won't benefit from the dynamic metadata of HDR10+ (i.e the transformation will be static).
Um, how bad is this?
Sorry, usually I'm not _that_ clueless, but this whole hdr stuff is news to me, I'm usually all about images (including color spaces like Adobe RGB or Photo Pro) and regular (sdr) video transcoding. However, now I've just got this fancy new phone and discovered the HDR10+ switch...
Use case: My desktop hardware (connected to the large monitor) is simply too slow to decode the 4k hevc clip, so I need to transcode. Plus I'd like to carry around my favorite clips with reduced bitrate and resolution.
If it's just to watch them, I strongly suggest you MPV as a player, which is open source, cross platform and it will perform dynamic tonemapping to BT709 automatically in a scene-by-scene fashion.
Thanks, I didn't realize mpv has that many options!
The --target-prim=bt.709 --tone-mapping=mobius combination seems to do what I've achieved with ffmpeg, but since even regular playback ls lagging...
MPV even has an option to use the .cube files, but the video playback is... very colorful :-) using --image-lut=PQ_to_BT709_v2.cube --vo=gpu-next. I've tried all options for --image-lut-type= so I'm probably missing something, or my GPU isn't "next" enough?
it's pretty easy, for x262, x264 and x265 it's just --colormatrix bt709 --transfer bt709 --colorprim bt709.
Right, thanks, I was wondering if all these three get changed to bt709 with the lut3d.
If you want, feel free. :)
Sample-SamsungS20-BT2020-HDR10+.mp4: https://www119.zippyshare.com/v/1xzay9yv/file.html
As you can see, it's a contrasty scene, and I'm really struggling to finde the "correct" .cube file (and/or ffmpeg/mpv video filter options). Even the difference between v1 and v2 PQ_to_BT709 seems tricky, and both look a bit washed-out and not colorful enough to me. However, while being inside in the winter I don't quite remember how it was like in the summer.
The exiftool output (mediainfo see above) says it's BT2100, too... which accordung to Wikipedia is same-ish as BT2020. Right, I'm really new to this, so any help is appreciated.
ColorProfiles: nclx
ColorPrimaries: BT.2020, BT.2100
TransferCharacteristics: SMPTE ST 2084, ITU BT.2100 PQ
MatrixCoefficients: BT.2020 non-constant luminance, BT.2100 YCbCr
wswartzendruber
21st October 2022, 23:01
BT.2100 (both PQ and HLG) use BT.2020 color values. "Transfer characteristics" is where BT.2100 emerges with its own take on things (either PQ or HLG).
To refer to BT.2100 color...is...strange...
FranceBB
22nd October 2022, 01:56
Um, how bad is this?
Not too bad, but let's just say that dynamic tonemapping would be better, however given that it's not a movie but rather a video shot by your mobile phone, it's gonna be fine. I'm actually surprised to see mobile phones shooting in PQ out there, I thought smartphones were all gonna implement HLG...
Sorry, usually I'm not _that_ clueless, but this whole hdr stuff is news to me,
no worries, we can't be expert in everything. I myself don't know lots of things. For instance, when people like Ferenc, Jean Philippe, Donald, ifb, DTL etc make use of intrinsics and write long complicated assembly stuff (or inline assembly code back in the days) I always have a big surprised face ('cause I can't).
now I've just got this fancy new phone and discovered the HDR10+ switch...
Eh, at least you've got PQ, I'm pretty angry at Google 'cause both my Google Pixel 5 and my Google Pixel 6 Pro got only LogV2 for HDR or the normal BT709 SDR 100 nits, but rumors say that Google engineers decided to introduce HLG with the new 7 (which I actually didn't want to buy straight away to be fair, but if rumors are true, then I guess I don't have any other choice)...
p.s for those wondering, I turn all my LogV2 into HLG
Use case: My desktop hardware (connected to the large monitor) is simply too slow to decode the 4k hevc clip, so I need to transcode. Plus I'd like to carry around my favorite clips with reduced bitrate and resolution.
Gotcha. No problem.
Thanks, I didn't realize mpv has that many options!
Yeah, it's one of the best players ever and for HDR I think it's the de facto best in terms of output results (but it's really really heavy in terms of processing).
MPV even has an option to use the .cube files, but the video playback is... very colorful :-)
Yeah, it's probably an internal planar RGB conversion screw-up, don't worry.
Sample-SamsungS20-BT2020-HDR10+.mp4: https://www119.zippyshare.com/v/1xzay9yv/file.html
Well, turns out ZippyShare is blocked everywhere. I even tried 3 different British VPN servers, but nothing, then I remembered that StainlessS (who actually lives in the UK) said that it was blocked over there, so switched to a US server and I've been finally able to access the file.
Unlocked in the US: https://i.imgur.com/JTnjr5N.png
Blocked in the UK: https://i.imgur.com/eRCXXrr.png
As you can see, it's a contrasty scene, and I'm really struggling to finde the "correct" .cube file (and/or ffmpeg/mpv video filter options). Even the difference between v1 and v2 PQ_to_BT709 seems tricky, and both look a bit washed-out and not colorful enough to me. However, while being inside in the winter I don't quite remember how it was like in the summer.
Well, the BT709 should look something like this (which is MPV with my settings): https://i.imgur.com/5GdDipi.jpg
For reference, VLC got it completely wrong (but still watchable): https://i.imgur.com/dwz9gaC.png
and this is the original image for comparison: https://i.imgur.com/Lt7ZyeT.jpg
Anyway, tomorrow I'll fire up Avisynth and I'll give it a shot. Right now it's late in the evening and I don't feel like booting Windows up as I'm on Linux and I'm about to brush my teeth and go to bed.
Marsu42
22nd October 2022, 03:42
Well, the BT709 should look something like this (which is MPV with my settings): https://i.imgur.com/5GdDipi.jpg
Thanks for your help so far! This is really bugging me, so I had another go at it.
I've found another software with built-in hdr to sdr mode: MPC Video Renderer is a dx filter and thus is usuable in about every video player. It's not as configurable as MPV, but it does have a GUI :-) ... the last release includes "Optimized PQ to SDR conversion using D3D11 video processor on Windows 10." (which doesn't help with my ancient desktop computer hardware, but still sounds useful). https://github.com/Aleksoid1978/VideoRenderer/releases
This is a reference screenshot of the original HDR10+ mp4 in hdr mode: https://i.imgur.com/oOvAPIN.jpg
This is with MPCVR sdr conversion enabled - I suppose this is about what it should look like: https://i.imgur.com/1nQI34y.jpg
Your screnshot from MPV is too dark imho - it was a glazing summer day, with harsh shadows but overall high brightness. I don't have a tv, but a computer monitor, so I suppose ymmv how it looks. For another reference, this is ffmpeg with "zscale=transfer=linear:npl=100,format=gbrpf32le,zscale=primaries=bt709,tonemap=tonemap=hable:desat=1.5,zscale=transfer=bt709:matrix=bt709:range=limited" which is still not as dark: https://i.imgur.com/X9qKLWE.jpg
It've tried to replicate the MPCVR result with your .cube files, and only succeeded by chaining lut3d='lut/PQ_to_HLG.cube',lut3d='HLG_BT2020_to_Linear_BT709.cube': https://i.imgur.com/kj7jh0t.jpg
The encoding time is a little longer with doing lut3d twice.
The 'PQ_to_BT709' .cube files sound about right, and the result looks nice, but it's a little too bright and/or the colours are a bit washed out:
PQ_to_BT709_v1.cube: https://i.imgur.com/eLRn35g.jpg
PQ_to_BT709_v2.cube: https://i.imgur.com/JQHV0bF.jpg
All screenshots from the ffmpeg trancodes are 8-bit (x264), thus the banding, but it's the only format my ancient desktop computer can decode in hardware.
Marsu42
22nd October 2022, 17:54
After using avisynth after all, I've found a better solution, because my ancient desktop computer happens to have an external nNvidia gpu - the CUDA plugin DGHDRtoSDR is ~100% faster than ffmpeg lut3d, ~50% faster than avs Cube and ~25% faster than avs DGCube.
z_ConvertFormat(width=2560, height=1440, resample_filter="bilinear", pixel_type="YUV420P16")
DGHDRtoSDR(mode="pq", fulldepth=true, white=1500)
http://avisynth.nl/index.php/Avsresize
http://avisynth.nl/index.php/DGHDRtoSDR
Plus DGHDRtoSDR configurable, solving any color or brightness issues I had with the PQ to SDR cube files.
I tried to use purely ffmpeg with lut3d because I can simply put the -vf filter comands in the av1an command line for the encoding stage - so a single .cube file delivering a MPCVR-ish output would still be welcome.
richardpl
22nd October 2022, 18:36
lut3d is CPU only, if you could get ffmpeg with libplacebo filter you could use GPU with .cube files.
wswartzendruber
22nd October 2022, 18:38
Here's the thing with going from PQ to either HLG or SDR: You have to know where reference white sits in the PQ source. So if your source content isn't specifically graded to a standard level, your results can appear either too bright or too dark when going to a relative brightness transfer function. This is true of converting to SDR, and when converting to HLG and viewing on SDR. As your phone is not controlling reference white, we need to determine this value.
First, let's get something else out of the way. The HDR10 metadata in your clip puts MaxCLL at 1,000 nits, but when fishing around for bright pixels, I'm finding them as high as 1,500 nits.
So then, what's the reference white level of your clip? Well, we don't really have any good way to determine this using things that are already white. There are the bird feathers, but they're not ever lit ideally. They're either under direct sunlight (overshoot), or in non-direct light (undershoot). So we have to use an alternative method. Like some of the grass that's visible. When in sunlight, grass should have a nominal luminance of 30 to 65 nits. We'll just use 48 nits as an average.
When blurring a grayscale of your image, some grass comes out to 35% signal strength. That comes out to just 18 nits. And we need to get it to 48 nits. 48 / 18 = 2.67. This is our luminosity scaling factor.
pq2hlg -s 65 -m 1500 -l 2.67 pq2hlg.cube
Here is the result: https://wswartzendruber.net/videos/Sample-SamsungS20-BT2020-HLG.mp4
And that HLG file has reference white much, much closer to where it should be. This should also let you take one of FranceBB's HLG to BT.709 LUTs and get a really good SDR result.
EDIT: And you won't need mpv to dynamically adjust brightness for you.
FranceBB
22nd October 2022, 22:50
Here's the thing with going from PQ to either HLG or SDR: You have to know where reference white sits in the PQ source. So if your source content isn't specifically graded to a standard level, your results can appear either too bright or too dark when going to a relative brightness transfer function.
William is exactly right, you must know the reference white, otherwise you have to calculate it yourself.
In your case, the clip says absolutely nothing, it puts the default values for the mastering display in as 1000 nits, but it doesn't give us MaxCLL nor MaxFALL which is of course a problem 'cause it means that we gotta calculate it ourselves.
Here are the results of the calculation:
MinCLL: 0
MaxCLL: 1854
MaxFALL: 150
https://i.imgur.com/SAc8hjO.png
Before we say anything, here's a comparison by using my original PQ_to_BT709_v1.cube
#Indexing
FFMpegSource2("D:\Sample-SamsungS20-BT2020-HDR10+.mp4", atrack=-1)
#Screw frame properties
propClearAll()
#Going to RGB 16bit planar full range
ConvertBits(16)
ConvertToPlanarRGB(matrix="Rec2020")
#Bringing everything to BT709 with 16bit precision
Cube("C:\Programmi\AviSynth+\LUTs\PQ_to_BT709_v1.cube")
#Going back to YUV 4:2:0 Limited TV Range
ConverttoYUV420(matrix="Rec709")
https://i.imgur.com/bhR4K7U.png
Now, taking 1854 nits into account as our peak, we're gonna use it to perform the right transformation.
Now, since I don't totally trust automatic detection tools ('cause there can be compression overshoots created by the consumer-bitrate encode of H.265) I generally like to take it a bit lower and/or adjust it myself rather than blindly trust the data. As a wild guess, taking outliers out, I think that it's probably gonna be around the 1600 nits region. In this case, we're going from this:
https://i.imgur.com/dzbbGnu.png
https://i.imgur.com/w5DvR6M.png
to this:
https://i.imgur.com/sc5yJ4k.png
https://i.imgur.com/vO1j29n.png
however we don't really have anything which is totally white as our reference, so it's hard to say what the real value is (and for those wondering, no, we can't take seagulls as white 'cause otherwise we clip the rocks and we can't take the rocks as white 'cause... well... everyone knows they're not!).
Now, if I received such a picture at work and I had to bring it to BT709 myself, I would do something like:
https://i.imgur.com/u9BaFyJ.png
https://i.imgur.com/JlsJrbE.png
here is your LUT (quick, it lasts 7 days only!): https://we.tl/t-9EyHeoZpC1
and you can apply it like so:
#Indexing
FFMpegSource2("D:\Sample-SamsungS20-BT2020-HDR10+.mp4", atrack=-1)
#Screw frame properties
propClearAll()
ConvertBits(16)
ConvertToPlanarRGB(matrix="Rec2020")
Cube("D:\Test.cube")
ConverttoYUV420(matrix="Rec709")
https://i.imgur.com/iOq5o2p.png
when fishing around for bright pixels, I'm finding them as high as 1,500 nits.
ehehehe it's nice to see that your calculations and mine sort of check out. :)
what's the reference white level? Well, we don't really have any good way to determine this using things that are already white. There are the bird feathers, but they're not ever lit ideally. They're either under direct sunlight (overshoot), or in non-direct light (undershoot).
I know the struggle. We generally have someone there holding a thing we use as reference with both white, black and colours. This is also why I'm pretty against mobile phones recording in PQ. I mean, with HLG none of this would have happened, so it would make much much much more sense for mobile phones to record in HLG. I mean, why Samsung, why...?! DX
So we have to use an alternative method. Like some of the grass that's visible. When in sunlight, grass should have a nominal luminance of 30 to 65 nits. We'll just use 48 nits as an average.
Oh, you used grass! That's a very interesting method!
Here is the result: https://wswartzendruber.net/videos/Sample-SamsungS20-BT2020-HLG.mp4
Your result also looks pretty good, William! ;)
Marsu42
23rd October 2022, 00:06
I know the struggle. We generally have someone there holding a thing we use as reference with both white, black and colours.
Amazing, thanks to both of you, I really have to digest all this information - but I've saved the custom .cube :-)
Concerning a PQ reference: I faintly remember that I've got a small color card lying around somewhere, I've used it for photography.
If I ever should get to a level when I handle this PQ-HLG and HDR-SDR issues: How large/... would a reference card have to be in the frame in the start of a video to fulfill its purpose?
Up until now I've just turned on the "HDR10+" switch and suspeced that the more data I record, the more I have to work with in postprocessing. I didn't think it would be this tricky without a reference.
This is also why I'm pretty against mobile phones recording in PQ. I mean, with HLG none of this would have happened, so it would make much much much more sense for mobile phones to record in HLG. I mean, why Samsung, why...?! DX
I'm using the older Galaxy S20, which uses PQ just like the S21. From what I googling the newer S22 has HLG...
FranceBB
23rd October 2022, 02:47
Amazing, thanks to both of you, I really have to digest all this information - but I've saved the custom .cube :-)
No problem. You'll always be in safe hands when William replies, you're lucky he's here and active and I'm glad he is given that we're friends. ;) (Well, virtual friends, but friends nevertheless. :P)
Concerning a PQ reference: I faintly remember that I've got a small color card lying around somewhere, I've used it for photography.
If I ever should get to a level when I handle this PQ-HLG and HDR-SDR issues: How large/... would a reference card have to be in the frame in the start of a video to fulfill its purpose?
Not much, really, but not smaller than this Link (https://camo.githubusercontent.com/7882b1eec263c3ed010e792b4d2c122e6831672d9e7fdc7e53f3f4ce36ee0ebb/68747470733a2f2f692e696d6775722e636f6d2f774f4f644962342e706e67) (i.e slightly larger in the frame would be better)
I didn't think it would be this tricky without a reference.
Welcome to HDR PQ XD
I'm using the older Galaxy S20, which uses PQ just like the S21. From what I googling the newer S22 has HLG...
Good to know, but this means that Samsung went in bold with PQ, realized its mistakes and eventually moved "back" to HLG instead of implementing HLG from the very beginning (which would have been the right thing to do)...
wswartzendruber
23rd October 2022, 05:45
No problem. You'll always be in safe hands when William replies, you're lucky he's here and active and I'm glad he is given that we're friends. ;) (Well, virtual friends, but friends nevertheless. :P)
You honor me, despite my stumbling and falling down. And there was much of that to get here.
Some things I still haven't solved. I continue to slowly evolve how I can reliably determine reference white.
Good to know, but this means that Samsung went in bold with PQ, realized its mistakes and eventually moved "back" to HLG instead of implementing HLG from the very beginning (which would have been the right thing to do)...
Is recording HLG a trend we're going to see with smart phones?
FranceBB
23rd October 2022, 14:02
Is recording HLG a trend we're going to see with smart phones?
I really hope so!
Google is getting there from Pixel 7 onwards, Samsung now moved to HLG, Apple uses a Dolby Vision profile but with HLG inside (although with arbitrarily set values), I think we're gonna see more and more of it in the next couple of years and that's a very good thing! :D
wswartzendruber
23rd October 2022, 15:47
Apple is using HLG?! That surprises me. And in a good way.
Can I get a sample somewhere?
FranceBB
23rd October 2022, 16:36
Apple is using HLG?! That surprises me. And in a good way.
Can I get a sample somewhere?
Yeah, I'm not a big fan of Apple as you can imagine. Anyway, don't get too excited, as far as I'm concerned, they made a mess out of it and I had to make a very special conditional in my workflows that checks for the Apple made videos and uses the particular "HLG_A" cube which adapts to their recordings (I couldn't call it "Apple" 'cause they would have sued me).
I'll check whether I saved some samples on Monday (so tomorrow) and I'll send them over via PM or maybe via FTP. (If I forget, remind me xD)
wswartzendruber
24th October 2022, 15:06
Then call it HLG_Crapple.cube :devil:
wswartzendruber
26th October 2022, 02:57
Psst! Remember that Apple sample...
FranceBB
26th October 2022, 12:43
Psst! Remember that Apple sample...
Damn, I knew I was gonna forget!
Check your PM
wswartzendruber
26th October 2022, 21:17
Cool! I'll grab it when I get home.
wswartzendruber
27th October 2022, 00:52
That's BT.709 with HLG being falsely signaled in the bitstream.
FranceBB
27th October 2022, 09:22
That's BT.709 with HLG being falsely signaled in the bitstream.
hahahahahahaha
Apple iPhone Pro? More like Apple screw up pro then!
But no, seriously, that cannot be.
It is indeed BT2020 with HLG in it in fact:
(disclaimer: the picture shows one of our F1 journalists doing a speech)
https://i.imgur.com/BhIOKMi.png
The problem is that the camera sensor of the iPhone has really just a bunch of stops, so the resulting HLG will be bad and with really bad overshooting over the 0.52V (i.e 75% reference).
So... although it actually really is BT2020 HLG, it really doesn't introduce any improvement over a standard BT709 SDR recording as I'm pretty sure iPhone sensors barely have 6 stops (which is what you need for 100 nits...)
Now, I clearly cannot share the """master""" of the speech, but here's a more public sample I can share about a landscape: Link (https://bit.ly/3pld586)
The same goes for this sample depicting Christmas Lights, which is indeed BT2020 HLG with overshooting ('cause lights would require many more stops than the ones currently available in the iPhone):
https://i.imgur.com/02X0591.png
https://i.imgur.com/1cQT6xC.png
On the left hand side, there's the displayed version assuming it as BT2020 HLG (correct) and on the right hand side there's the displayed version assuming it as BT709 SDR (not correct):
https://i.imgur.com/E3ZDkrp.png
Still, does it make sense to have HLG on such a puny sensor? Probably not...
But you know, it's Apple, if they have like 7 stops and can turn the BT709 SDR 100 nits into a 175 nits BT2020 HLG, they'll call it HDR and scream to the whole world that they're great... :P
Balling
28th October 2022, 19:34
I really hope so!
Google is getting there from Pixel 7 onwards, Samsung now moved to HLG, Apple uses a Dolby Vision profile but with HLG inside (although with arbitrarily set values), I think we're gonna see more and more of it in the next couple of years and that's a very good thing! :D
Samsung still uses PQ. My galaxy s22. Apple uses HLG with dolby vision meta to derive PQ.
Balling
31st October 2022, 06:09
>But you know, it's Apple, if they have like 7 stops and can turn the
iPhone 13 has 12 stops.
FranceBB
31st October 2022, 06:37
iPhone 13 has 12 stops.
For real or is it what they declared on paper like when they were fined for misleading info about their monitors?
It would be nice to see a sample.
The reason why I'm skeptical is that big sensors like the full frame one of the Sony A7 III have 15 stops, so it would really surprise me if Apple had 12 on their tiny sensors in their phones...
Majorlag
11th November 2022, 02:34
FranceBB,
I noticed that a few people where trying to get your wonderful LUT's to work better for them. I wanted to share the script I use to get HDR to SDR to work for me with PQ to SDR. This worked for Marsu42's sample clip without a custom LUT. This uses LaTo's SmoothAdjust 3.20 Avisynth plugin to change gamma, since HDR and SDR have different gamma levels. No need to figure out brightness levels of source. Tested on several clips with great results. Thanks again for your hard work in create those LUT's
#Bringing everything to 16bit
ConvertBits(16)
#Stack when working in 16bit precision for SmoothLevels
#HDR and SDR have different Levels, then unstack
#Lmode 3 to keep blacks from crushing, and white from greying
ConvertToStacked()
SmoothLevels16(HQ=true,preset="fullrange",gamma=0.8,Lmode=3)
ConvertFromStacked()
#Converting YUV to RGB with 16bit precision
ConvertToPlanarRGB()
#Tone-mapping HDR PQ to SDR LUT
Cube("C:\Program Files (x86)\AviSynth+\LUTs\PQ_to_BT709_v1.cube")
#Converting RGB to YUV 4:2:0 planar with 16bit precision
ConvertToYUV420()
Balling
15th November 2022, 13:41
Latest Davinci added profile 5 Dolby Vision decoder. Only MacOS.
FranceBB
15th November 2022, 19:35
Only MacOS.
bummer
wswartzendruber
16th November 2022, 02:18
This uses LaTo's SmoothAdjust 3.20 Avisynth plugin to change gamma, since HDR and SDR have different gamma levels.
If this is true, then my hlg-tools converter is doing things wrong. Ultimately, I can't figure out how to scale brightness.
1. BT.1886 implies that SDR->HDR brightness scaling requires no gamma adjustment.
2. BT.2100 implies that gamma adjustment is absolutely necessary, and the HLG EOTF handles this.
3. BT.2446 states that it's optional.
:confused:
Majorlag
16th November 2022, 05:48
I have not tested any HLG content. All the videos that I have dealt with are all PQ.
I could be wrong, I thought I read that HDR used a different gamma. Without changing the gamma, it looks a bit washed out, especially the sun and clouds in scenes using the LUTs. The gamma shift and LUTs are also much closer to SDR blu-ray of of the same UHD HDR clips that other plugins never seem to get close to.
I was mostly posting my script because I saw one of the previous posters wished it was a bit darker. I have never been a fan of the other scripts out there, so hopefully someone else finds it useful to them, or maybe have a starting point to run with it and improve. Again, never tested HDR HLG, at least with HDR PQ I get the results that is most pleasing to me after spending countless days trying to get HDR PQ sources to convert nicely
Majorlag
16th November 2022, 18:55
If this is true, then my hlg-tools converter is doing things wrong. Ultimately, I can't figure out how to scale brightness.
1. BT.1886 implies that SDR->HDR brightness scaling requires no gamma adjustment.
2. BT.2100 implies that gamma adjustment is absolutely necessary, and the HLG EOTF handles this.
3. BT.2446 states that it's optional.
:confused:
I found a recent article talking about different gamma at https://www.igorslab.de/en/all-around-the-topic-colors-part-2-monitor-basics/2/. With Rec.709 at 2.4 and Rec.2020 at 2.2. This is the same that I have read from several sources for the last few years. Interesting BT.1886 I thought was 2.35 for gamma and is mentioned in that article as being between 2.2 and 2.4.
Maybe my method of madness is way off, but the end result was close, but changing it by 0.2 by changing the plugin's gamma value 1.0 (do nothing) to 0.8 resulted in satisfactory results for me and my setup. Not sure why I have to shift the gamma before the LUT, but it worked better before then after the 3d colour volume change.
Balling
30th November 2022, 07:32
"Interesting BT.1886 I thought was 2.35 for gamma and is mentioned in that article as being between 2.2 and 2.4."
It is 2.35, as in CRT true curve. Sony just moved to 2.4 after their reference LCD got better black point. And anyway, 2.4 is correct rounding for 2.35.
https://mixinglight.com/color-grading-tutorials/gamma-2-2-vs-gamma-2-4-davinci-resolve/
https://referencehometheater.com/2014/commentary/gamma-correct/
The article is garbage. sRGB does not use pure gamma, in fact nothing uses pure gamma nowadays (only Adobe RGB 1998).
From the article "I use C1 BT.1886 at home with my LG OLED, I personally like it better than Gamma 2.4 (matter of taste)."
What is the difference? Is BT.1886 using the light sensor as it should per BT.1886?
"and Rec.2020 at 2.2."
It does not say that. BT.1886 is used for it too.
Majorlag
1st December 2022, 03:47
I should clarify. The metadata of PQ HDR files that I deal with has "Color primaries:BT.2020" "Mastering display color primaries:Display P3" While Display P3 (comes from Apple) uses D65 (6500 K as in sRGB and Adobe RGB) and Gamma 2.2 (like sRGB). The D65 white point is now used internationally as a standard
The opinion of the quality of the article can be debated, however this is not the only site that has the same information referencing gamma 2.2 for HDR and 2.4 for SDR. That was just the most recent article I could find. Not sure what all claims the rest of the article talks about, it was more of a simplified explanation of why I find reducing gamma seems to work for my needs in converting HDR to SDR.
Balling
1st December 2022, 17:02
"referencing gamma 2.2 for HDR and 2.4 for SDR"
The article only talks about SDR. What??
"Mastering display color primaries Display P3"
You do understand that still means color primaries are BT.2020? Also, this is typo in Mediainfo. Display P3 is sRGB transfer. It actually means P3-D65.
FranceBB
6th December 2022, 23:20
Bravo Francesco, ottimo lavoro!
I'm thinking if you can make two further LUTs:
XYZ to 2020 HLG
XYZ to 2020 PQ
Hey Sporv, I'm getting closer to satisfy your request.
I've added:
BT2020 HLG to DCI P3 D63 XYZ γ 2.6
BT2020 PQ to DCI P3 D63 XYZ γ 2.6
https://i.imgur.com/UFnVxN5.png
https://i.imgur.com/rW9gvoJ.png
also check this out: https://forum.doom9.org/showthread.php?p=1979435
FranceBB
8th December 2022, 11:24
Linear Transformation v2.3 Released!! (https://github.com/FranceBB/LinearTransformation/releases/tag/2.3)
Changelog:
- Introduced support to DCI P3 D63 XYZ conversion to/from BT2020 HLG & PQ as requested by Sporv.
LinearTransformation(Input="BT2100_PQ", Output="DCI_XYZ")
LinearTransformation(Input="BT2020_HLG", Output="DCI_XYZ")
LinearTransformation(Input="DCI_XYZ", Output="BT2020_HLG")
LinearTransformation(Input="DCI_XYZ", Output="BT2100_PQ")
https://github.com/FranceBB/LinearTransformation/releases/
Note:
Please note that going back from DCI P3 D63 XYZ to PQ RGB is particularly hard and although I tweaked it on a few titles, the end result is supposed to be manually checked, especially 'cause this is all based on "static" MaxCLL assumptions which may not fit each and every case and for this very reason I wouldn't trust the conversion in a totally automatic process.
As far as HLG is concerned, however, you can safely "turn the autopilot on" and trust the conversion.
Balling
20th December 2022, 07:53
Adobe just released Camera Raw 15.1, that properly supports PQ surface on windows 11 for 48 megapixel DNGs from iPhone 14. It has insane HDR. My Galaxy S22 Ultra Expert RAW has NO HDR. Not even a pixel. WTF. Fake RAW, bad Samsung.
See some samples: crazy HDR https://www.dropbox.com/s/kl764411n9jxr5c/iPhone14Pro_ProRAW48MP.DNG?dl=1
Simple HDR: https://www.dropbox.com/s/ormope1xmzysdwq/IMG_1138.DNG?dl=0
Almost no HDR: https://www.dropbox.com/s/rqyasvk2hwqhfc1/IMG_1151.DNG?dl=0
Dragon1981
26th December 2022, 16:27
Guys,
I like dolby vision profile v5 output converted through davinci resolve of the HDR (HLG) videos shot on my iPhone 12. Is it possible to have same kind of color output in SDR through some LUT?
Used FranceBB LUT for iPhone SDR export but it doesn't quite go near to DV v5 color matching.
FranceBB
26th December 2022, 16:51
Used FranceBB LUT for iPhone SDR export but it doesn't quite go near to DV v5 color matching.
Have you tried the standard HLG to BT709 LUTs too?
The thing is that a lut doesn't understand Dolby Vision metadata, it's just a matrix: numbers in, numbers out, so the results can change.
Post a sample and I'll see what I can do.
Oh, almost forgot: Merry Christmas! ;)
Dragon1981
28th December 2022, 13:58
Have you tried the standard HLG to BT709 LUTs too?
The thing is that a lut doesn't understand Dolby Vision metadata, it's just a matrix: numbers in, numbers out, so the results can change.
Post a sample and I'll see what I can do.
Oh, almost forgot: Merry Christmas! ;)
Merry Christmas!
Whenever I import "HLG_BT2020_to_Linear_BT709.cube " LUT in my resolve, it gives error". Attached is the screenshot.
Other LUTs import worked fine from your collection.
Below, I am giving original sample and processed videos as you asked.
Original HLG video from iPhone 12:
https://drive.google.com/file/d/1M_O50P0Rv0zzzB5ndSPxSx4IJ1kLj-8U/view?usp=share_link
Processed SDR video in resolve with your "HLG_A_to_LinearBT709" LUT:
https://drive.google.com/file/d/1RaNOOWqm7CvdSJUcSvB3I8hgYwq-1fC2/view?usp=share_link
Processed Dolby Vision Profile v5 video in Resolve:
https://drive.google.com/file/d/1L4z6VUNI6AQg8muxv5WBa9wcyd3kJgBh/view?usp=share_link
I am attaching project settings and export video settings of Resolve here for dolby vision export and SDR export for your information.
FranceBB
4th January 2023, 12:14
Happy New Year! :)
So... let's first take a look at what we have here.
The reference white of 75% has overshooting over 0.52V in what is supposed to be specular highlights like the reflections in the tiara and the other pieces of jewelry that the girl is wearing. Far from being an ideal shot, but I guess we can't expect much from a tiny sensor like the one we have in mobile phones (iPhones included):
https://i.imgur.com/dKP3Fn9.png
Although there's a great deal of motion blur at 29,970p, at least the real reference white is correctly positioned at 0.52V as we can see on the left hand side of the waveform monitor, so looks like Apple didn't screw this up completely after all:
https://i.imgur.com/Joetkw9.png
This is the conversion with the non public BBC LUT:
video=LWLibavVideoSource("\\mibctvan000.avid.mi.bc.sky.it\Ingest\MEDIA\temp\Sample.mov")
audio=LWLibavAudioSource("\\mibctvan000.avid.mi.bc.sky.it\Ingest\MEDIA\temp\Sample.mov")
AudioDub(video, audio)
ConvertBits(16)
ConvertToPlanarRGB(matrix="Rec2020")
Cube("C:\Program Files (x86)\AviSynth+\LUTs\8a_HLG_bt709_AC_mode-nar_in-nar_out-nar_nocomp.cube", fullrange=true)
ConverttoYUV420(matrix="Rec709")
https://i.imgur.com/4EZ2pfO.png
https://i.imgur.com/FSXMXKb.png
Now, I know that the BBC LUT is correct, which means that there's something deeply wrong in the way Apple's logic saved the BT.2020 colours as there's a huge shift towards the magenta and red.
As always, my HLG_A_to_LinearBT709 LUT was done in 2021 to address that and in fact the result is quite pleasing:
video=LWLibavVideoSource("\\mibctvan000.avid.mi.bc.sky.it\Ingest\MEDIA\temp\Sample.mov")
audio=LWLibavAudioSource("\\mibctvan000.avid.mi.bc.sky.it\Ingest\MEDIA\temp\Sample.mov")
AudioDub(video, audio)
ConvertBits(16)
ConvertToPlanarRGB(matrix="Rec2020")
Cube("C:\Program Files (x86)\AviSynth+\LUTs\HLG_A_to_LinearBT709.cube", fullrange=true)
ConverttoYUV420(matrix="Rec709")
https://i.imgur.com/xy37zdB.png
https://i.imgur.com/NYJJHrm.png
The magenta shift is still quite noticeable, though, in your case, so I would still consider color shifting a bit more or reduce the saturation in the magenta part only altogether.
I think something like this looks much more natural:
video=LWLibavVideoSource("\\mibctvan000.avid.mi.bc.sky.it\Ingest\MEDIA\temp\Sample.mov")
audio=LWLibavAudioSource("\\mibctvan000.avid.mi.bc.sky.it\Ingest\MEDIA\temp\Sample.mov")
AudioDub(video, audio)
ConvertBits(16)
ConvertToPlanarRGB(matrix="Rec2020")
Cube("C:\Program Files (x86)\AviSynth+\LUTs\HLG_A_to_LinearBT709.cube", fullrange=true)
ConverttoYUV420(matrix="Rec709")
tweak(StartHue=75, EndHue=135, sat=0.70, dither=true)
https://i.imgur.com/tuGLrIt.png
Dragon1981
5th January 2023, 10:06
Happy New Year! :)
Happy New Year. That's one hell of analysis which is certainly above my understanding and requirement. Thanks for the detailed reply though.
I shoot lots of home videos of my daughter. I normally convert them in Dolby Vision (for my TV) and Rec709 (for sharing).
Just wanted to have quick LUT which can give me Rec709 video in color grades like Dolby Vision.
I guess I will just use your LUT which gives decent colours in Rec709.
:thanks:
FranceBB
5th January 2023, 10:29
I shoot lots of home videos of my daughter.
Oh, I didn't know that she was your daughter.
It's nice that you get to spend some time with your family. :)
I guess I will just use your LUT which gives decent colours in Rec709.
Yeah, for home videos sharing is more than enough.
The "official" use we have of that LUT is for our News channel.
Essentially we get people/viewers sending us videos from all over the world 'cause everyone has a smartphone around these days and people started sending us videos in HLG shot with the iPhone in early 2021, so we needed to cope with those, especially given that the news channel is still in FULL HD BT709, hence the LUT. ;)
The other use we had for this LUT was during the America's Cup 'cause we couldn't send cameramen physically on the boats as they would slow them down, so we had the crew recording videos on their iPhone in HLG and sending those over (I talked about this early on in this topic if you're curious (https://forum.doom9.org/showthread.php?p=1934075#post1934075) :) )
Balling
17th February 2023, 20:32
There are now HDR10+ EETFs in libplacebo and in ffmpeg. https://github.com/FFmpeg/FFmpeg/commit/eabc304d123bb4193ae8dc7a602530c2e0d86450
So initial support for the base of Dolby Vision curves too, another part of ST2094
FranceBB
23rd February 2023, 17:29
Any chance of having a CPU only version of libplacebo in FFMpeg as well as the current GPU one?
I mean, currently it requires GPU acceleration, which is fine for on prem, but not very cloud friendly given the limits of most AWS EC2...
Ideally, if a GPU isn't available, it should be able to have a CPU only fallback instead of failing.
quietvoid
23rd February 2023, 18:36
Any chance of having a CPU only version of libplacebo in FFMpeg as well as the current GPU one?
I mean, currently it requires GPU acceleration, which is fine for on prem, but not very cloud friendly given the limits of most AWS EC2...
Ideally, if a GPU isn't available, it should be able to have a CPU only fallback instead of failing.
I've had no problem running it with "lavapipe" on Linux. Of course it comes from mesa.
https://archlinux.org/packages/extra/x86_64/vulkan-swrast/
Following the Arch Wiki example for "Software Vulkan: lavapipe" at: https://wiki.archlinux.org/title/Vulkan.
Environment vars: LIBGL_ALWAYS_SOFTWARE=1 __GLX_VENDOR_LIBRARY_NAME=mesa VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/lvp_icd.i686.json:/usr/share/vulkan/icd.d/lvp_icd.x86_64.json
Command: ffmpeg -i video.mkv -init_hw_device vulkan -vf hwupload,libplacebo=format=yuv420p,hwdownload,format=yuv420p test.mkv
[libplacebo @ 0x563979c887c0] Device Name: llvmpipe (LLVM 15.0.7, 256 bits)
I don't know if this method would work for your environment.
In FFmpeg, vf_libplacebo is currently only supported for Vulkan frames. It's a GPU library, after all.
OrangeColaJuice
1st April 2023, 19:13
... my ancient iGPU lacks Vulkan support, so sad that I can't make short videos of my favorite HDR movies to share on Mongolian basket waving forums/imageboards.
wswartzendruber
1st April 2023, 23:04
... my ancient iGPU lacks Vulkan support, so sad that I can't make short videos of my favorite HDR movies to share on Mongolian basket waving forums/imageboards.
I lived in Ulaanbaatar, Mongolia from 1995 to 2000.
I don't remember anything about basket weaving.
LouieChuckyMerry
17th June 2023, 21:46
Thank you for sharing your LUTs, FranceBB :) . I think I've wrapped my head around their use enough to run some tests, but I'm unsure which to use for a BT.2020 PQ source that I want to transform into BT.709 ??. I've a 4K source but no 4K TV, so I want to downscale to 2K but don't know all the technical language. Here's a Test Clip (https://www.mediafire.com/file/tjhzaxbdhkfaw7g/TestClip2%255B2160p%255D.7z/file).
_____________
Edit: Please ignore the above; I just remembered that the reason I'm even here is because you posted a link when helping me on the HDRTools Plugins thread (which has your script :o ).
FranceBB
17th June 2023, 23:31
I just remembered that the reason I'm even here is because you posted a link when helping me on the HDRTools Plugins thread (which has your script :o ).
LOL and you posted the same example clip with trees xD
I'm unsure which to use for a BT.2020 PQ source that I want to transform into BT.709 ?
It's as easy as it sounds: to go from BT2020 PQ to BT709 you need, quite intuitively, the PQ_to_BT709_v1.cube or the PQ_to_BT709_v2.cube.
In other words, if you were to run it manually in Avisynth, it would be:
#Indexing
FFVideoSource("D:\TestClip2[2160p].mkv")
#Bringng everything to 16bit planar
ConvertBits(16)
#Going from YUV limited tv range to RGB full range
ConverttoPlanarRGB(matrix="Rec2020")
#From BT2020 PQ to BT709 SDR
Cube("PQ_to_BT709_v2.cube", fullrange=true)
#Going back from RGB full Range to YUV limited tv range
Converttoyuv420(matrix="Rec709")
#Dithering down to 8bit planar with the Floyd Steinberg Error Diffusion
ConvertBits(bits=8, dither=1)
OR if you use my plugin, LinearTransformation(), you can easily just do:
FFVideoSource("D:\TestClip2[2160p].mkv")
LinearTransformation(Input="BT2100_PQ", Output="Linear_BT709")
as described here: https://github.com/FranceBB/LinearTransformation
LouieChuckyMerry
24th June 2023, 20:42
Happy Saturday! I finally found some time to figure things out and run some tests, and was curious for your learned opinion. I tried your LinearTransformation:
ConvertToPlanarRGB(Matrix="Rec2020",Interlaced=False)
ConvertBits(Bits=16)
Spline36Resize(1920,1080)
Cube("F:\InstalledPrograms\AviSynth+\LUTs\PQ_to_BT709_v2.cube",Fullrange=True)
ConvertToYUV420()
and Donald Graft"s "DGHDRToSDR()":
ConvertToYUV420()
ConvertBits(Bits=16)
Spline36Resize(1920,1080)
DGHDRToSDR()
and Avidemux's "HDR tone mapping" feature with the "RGB Hable" option and "Spline" resizing. All default values and encoded with UtVideo. Here are my results:
https://i.ibb.co/TYL9W0s/1-Test-Clip-2160p-F.jpg
and
https://i.ibb.co/MC8S74K/1-Test-Clip-2160p-D.jpg
and
https://i.ibb.co/6g26D0L/1-Test-Clip-2160p-A.jpg
and
https://i.ibb.co/4Nt4sBp/2-Test-Clip-2160p-F.jpg
and
https://i.ibb.co/p1kyB64/2-Test-Clip-2160p-D.jpg
and
https://i.ibb.co/gJH8LrQ/2-Test-Clip-2160p-A.jpg
I think the results with Avidemux look the best, but I'd prefer to use your LinearTransformation because it's faster and I can fine-tune the resizing and encoding options. Would you have a suggestion(s) how to tweak the settings to "brighten" the results?
Edit: Apologies for the massive images; not sure how fix that...
Emulgator
24th June 2023, 22:17
No apologies needed, nice comparison !
Judging from two panels (10bit-100%DCI-P3 + 8bit-100%NTSC) both France BB and Donald Grafts look fabulous,
France BB seems to match the hi-end panels, DG seems to match the majority of panels ATM (and AviDemux seems overdone).
LouieChuckyMerry
25th June 2023, 19:12
Emulgator: Thanks for your informative reply :) . I agree that the Avidemux results seem a bit overdone but, on both my laptops, they appear much less overdone than the other two appear underdone, at least to my eyes. Granted, both laptops are at least ten years old and have 1600x900 14" screens. By underdone I mean that they're slightly dark, with the FranceBB's looking a bit darker than the Donald Graft's; it's as if I'm wearing sunglasses relative to the Avidemux's, and with slightly darker lens when viewing the FranceBB's. I guess I'll check things out on my HDTV.
FranceBB
26th June 2023, 14:45
I noticed that you're using the v2 cube.
That version targets 50k$ Sony reference monitors for up to 4000 nits PQ contents (technically also above as it doesn't clip but rolls back to 100 nits all values 'till 10000 with a knee, but still).
Your content clearly has a much lower MaxCLL, therefore you should really use v1.
To put it in your own code:
ConvertToPlanarRGB(Matrix="Rec2020", Interlaced=False)
ConvertBits(Bits=16)
Spline36Resize(1920,1080)
Cube("F:\InstalledPrograms\AviSynth+\LUTs\PQ_to_BT709_v1.cube", Fullrange=True)
ConvertToYUV420(Matrix="Rec709")
Judging from two panels (10bit-100%DCI-P3 + 8bit-100%NTSC) both France BB and Donald Grafts look fabulous,
France BB seems to match the hi-end panels, DG seems to match the majority of panels ATM (and AviDemux seems overdone).
:D
Yeah, Avidemux is really off in this case.
And you're right, I did it targeting the professional broadcast monitors we have here at work while looking at the Tektronix Waveform Monitor connected via SDI, so not really surprising ehehehehehehe
But I'm glad it all checks out. :)
LouieChuckyMerry
26th June 2023, 17:40
Emulgator: Oooweeee! I'm glad I checked things out on my HDTV. And I admire your restraint, as "overdone" is very generous of you. Actually, "...France BB seems to match the hi-end panels, DG seems to match the majority of panels ATM..." seems spot on. Thanks again :) .
_____________
FranceBB: Thanks for the information and suggestion; I'll run new tests comparing The Donald Graft Method to The New, Improved FranceBB Technique then make a choice. Ahhh, and don't blame Avidemux; it was 100% operator error ;-) .
_____________
EDIT: Happy Friday! The results with PQ_to_BT709_v1.cube are excellent for color and black & white sources, and I thank you again for your kind help :) .
FranceBB
25th September 2023, 20:42
Linear Transformation v2.5 Released! (https://github.com/FranceBB/LinearTransformation/releases/)
- Introduced a new optional parameter "Interpolation" which is a string and can be set either to Trilinear or to Tetrahedral (default is Tetrahedral)
- Temporarily removed x86 support as version 1.4 of the main dependency, Donald Graft's avscube (http://avisynth.nl/index.php/AVSCube), is now x64 only :(
As an example, a new way to call the function is now:
LinearTransformation(Input="Linear_BT709", Output="DCI_XYZ", Interpolation="Tetrahedral")
The interpolation parameter can either be set to "Trilinear" or "Tetrahedral" and by default it's set to Tetrahedral as it achieves better results.
Source (left) - Trilinear (center) - Tetrahedral (right):
https://user-images.githubusercontent.com/18946343/270301165-f742fb52-e382-4317-abf4-342c55a1790c.png
As you can see, in the right hand side waveform (tetrahedral) there are no ripples, unlike the ones you can see in the trilinear interpolation at the center.
I've already ported the new parameters to FFAStrans 1.4 as well so that they can be selected from the GUI
https://i.imgur.com/MgNhTFJ.png
although FFAStrans 1.4 is still in beta so it's not public yet as we're testing it extensively.
spoRv
27th September 2023, 09:12
Great FranceBB, thanks!
ProWo
6th October 2023, 18:25
Hi FranceBB
can you tell me a working FFmpeg command line to apply your LUTs?
If I apply this:
ffmpeg -i input_HDR -vf lut3d=your_lut ...
I always get wrong colors (to much contrast, to much red).
TIA
prowo
EDIT:
Found it.
-colorspace -color_primaries -color_trc must be specified explicitly after the lut.
FranceBB
12th October 2023, 08:22
Hi FranceBB
can you tell me a working FFmpeg command line to apply your LUTs?
If I apply this:
ffmpeg -i input_HDR -vf lut3d=your_lut ...
I always get wrong colors (to much contrast, to much red).
All my LUTs work in RGB Full Range, which means that you should always convert to RGB Full Range, apply the LUT and convert back.
Such a conversion is trivial in Avisynth (and probably VapourSynth too) but it's slightly less so in FFMpeg.
Now, in theory, lut3d *should* do that for you anyway, so something as simple as this should, in theory, suffice:
ffmpeg.exe -hide_banner -i "Test.mov" -vf lut3d="test.cube" -vcodec v210 -color_range 1 -color_primaries bt2020 -color_trc arib-std-b67 -colorspace bt2020nc -c:a pcm_s32le -ar 48000 -y "Test_v210_HLG_BT2020.mov"
When I ran the test:
ffmpeg.exe -hide_banner -i "Test.mov" -vf lut3d="test.cube" -vcodec v210 -color_range 1 -color_primaries bt2020 -color_trc arib-std-b67 -colorspace bt2020nc -c:a pcm_s32le -ar 48000 -y "Test_v210_HLG_BT2020.mov"
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'Test.mov':
Metadata:
major_brand : qt
minor_version : 512
compatible_brands: qt
encoder : Lavf58.76.100
Duration: 00:00:01.28, start: 0.000000, bitrate: 4423685 kb/s
Stream #0:0[0x1]: Video: v210 (v210 / 0x30313276), yuv422p10le, 3840x2160, 4423680 kb/s, 25 fps, 25 tbr, 12800 tbn (default)
Metadata:
handler_name : VideoHandler
vendor_id : FFMP
Stream mapping:
Stream #0:0 -> #0:0 (v210 (native) -> v210 (native))
Press [q] to stop, [?] for help
Output #0, mov, to 'Test_v210_HLG_BT2020.mov':
Metadata:
major_brand : qt
minor_version : 512
compatible_brands: qt
encoder : Lavf59.35.100
Stream #0:0: Video: v210 (v210 / 0x30313276), yuv422p10le(tv, bt2020nc/bt2020/arib-std-b67, progressive), 3840x2160, q=2-31, 4423680 kb/s, 25 fps, 12800 tbn (default)
Metadata:
handler_name : VideoHandler
vendor_id : FFMP
encoder : Lavc59.56.100 v210
frame= 32 fps=2.2 q=-0.0 Lsize= 691201kB time=00:00:01.24 bitrate=4566385.2kbits/s speed=0.0852x
video:691200kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000128%
In this case I'm going from BT709 SDR to BT2020 HLG HDR and indeed mediainfo shows the right info in the container:
General
Complete name : Test_v210_HLG_BT2020.mov
Format profile : QuickTime
Codec ID : qt 0000.02 (qt )
File size : 675 MiB
Duration : 1 s 280 ms
Overall bit rate mode : Constant
Overall bit rate : 4 424 Mb/s
Frame rate : 25.000 FPS
Writing application : Lavf59.35.100
Video
ID : 1
Format : YUV
Codec ID : v210
Codec ID/Hint : AJA Video Systems Xena
Duration : 1 s 280 ms
Bit rate mode : Constant
Bit rate : 4 424 Mb/s
Width : 3 840 pixels
Clean aperture width : 3 840 pixels
Height : 2 160 pixels
Clean aperture height : 2 160 pixels
Display aspect ratio : 16:9
Frame rate mode : Constant
Frame rate : 25.000 FPS
Color space : YUV
Chroma subsampling : 4:2:2
Bit depth : 10 bits
Scan type : Progressive
Compression mode : Lossless
Bits/(Pixel*Frame) : 21.333
Stream size : 675 MiB (100%)
Color primaries : BT.2020
Transfer characteristics : HLG
Matrix coefficients : BT.2020 non-constant
When I index the newly created version with ffmpeg and I compare it to the Avisynth one I can see that lut3d in FFMpeg did convert to RGB Full Range, applied the LUT and converted back to YUV Limited TV Range correctly:
LWLibavVideoSource("T3_LUT_IB_UHD_BT709_v210.mov")
#From 4:2:0 16bit planar Narrow Range to RGB Planar 16bit Full Range
z_ConvertFormat(pixel_type="RGBP16", colorspace_op="709:709:709:limited=>rgb:709:709:full", resample_filter_uv="spline64", dither_type="error_diffusion", use_props=0)
#From BT709 SDR to BT2020 HDR HLG with 16bit precision
Cube("C:\Program Files (x86)\AviSynth+\LUTs\5a_BT709_HLG_UPCONVERT_DISPLAY_mode-nar_in-nar_out-nar_nocomp.cube", fullrange=1, interp=1)
#From RGB 16bit planar Full Range to YUV422 10bit planar Narrow Range with dithering
z_ConvertFormat(pixel_type="YUV422P10", colorspace_op="rgb:std-b67:2020:full=>2020:std-b67:2020:limited", resample_filter_uv="spline64", dither_type="error_diffusion", use_props=0)
VideoTek()
avisynth=last
ffmpeg=LWLibavVideoSource("Test_v210_HLG_BT2020.mov").VideoTek()
StackVertical(avisynth, ffmpeg)
Avisynth top, FFMpeg bottom:
https://i.imgur.com/ncaoDaq.png
https://i.imgur.com/JcHt2hX.png
Found it.
-colorspace -color_primaries -color_trc must be specified explicitly after the lut.
Yes of course, when you perform any kind of conversion you need to tell the encoder and container what changed so that the right header is gonna be written.
I also recommend -map_metadata -1 if you're doing it in FFMpeg directly to completely get rid of the original info before replacing it with the new one.
By the way, this needs to be done regardless of the encoder you're using; I mean, even with Avisynth + x264 for instance you still need to specify the output to make decoders interpret it correctly, for instance in x264 it would have been something like:
x264-10b.exe "Test.avs" --preset medium --profile high422 --level 5.2 --keyint 1 --no-cabac --slices 8 --bitrate 500000 --vbv-maxrate 500000 --vbv-bufsize 100000 --deblock -1:-1 --overscan show --colormatrix bt2020nc --range tv --log-level info --thread-input --transfer arib-std-b67 --colorprim bt2020 --videoformat component --nal-hrd cbr --aud --output-csp i422 --output-depth 10 --output "raw_video.h264"
ProWo
12th October 2023, 21:28
Thanks FranceBB for the detailed info.
ProWo
FranceBB
14th November 2023, 18:12
Linear Transformation v2.6 Released! (https://github.com/FranceBB/LinearTransformation/releases/)
- Added preliminary RGB32 support (clips with alpha channels will be subject to the very same transformation on both the 24bit video and the 8bit alpha channel before being recomposed back to the output)
Now, as an example, let's take a look at the following fake RGB32 input:
ColorBars(848, 480, pixel_type="RGB32")
pippo=last
pluto=pippo.ConverttoY()
AddAlphaPlane(pippo, pluto)
This creates an RGB32 stream in which the first 24bit are RGB (i.e 8+8+8=24):
https://i.imgur.com/hicOV8a.png
and the last 8 are the alpha channel (+8 = 32):
https://i.imgur.com/OemhDyz.png
This is in BT709 SDR.
When we apply:
LinearTransformation(Input="Linear_BT709", Output="BT2100_PQ", Interpolation="Tetrahedral")
what's gonna happen is that the stream will be divided in two parts: the normal part and the alpha channel and both will be subject to the very same transformation (in this case from BT709 to BT2020 PQ) before being added back to create a proper RGB32 output:
https://i.imgur.com/92chDr2.png
https://i.imgur.com/Y7iiCBA.png
as per mojie126's request (https://github.com/FranceBB/LinearTransformation/issues/3). ;)
coolgit
1st December 2023, 21:54
LinearTransformation(Input="dvhe0509", Output="Linear_BT709")
Is there a way to convert from 709 to dvhe0509?
FranceBB
2nd December 2023, 00:25
Currently no, we can only go from dvhe0509 to BT709 SDR and even that took quite a lot of work for me and algia (Livio Aloja) one of my former colleagues, also an encoder, a senior editor and great friend of mine at Sky before he retired.
Nowadays he mostly goes fishing on the river in summer and fetching mushrooms in winter.
That being said, going from dvhe0509 was extremely difficult due to the lack of openness from Dolby about the proprietary metadata in the pixel shader, so much so that the result of that conversion comes from using the official Harmonic reference encodes in both dvhe0509 and BT709 and reverse engineering the transformation matrix used, which is why it's less than perfect as it's not based on an official spec, but it's "good enough".
Specifically, it applies to IPTc2 dvhe0509 inputs specifically, so it won't work with other kind of inputs.
This is because, on a normal pipeline, you should have:
Source dvhe0509 -> IPTc2 -> Proprietary Metadata interpreter (RPU) -> standard HDR image -> LUT -> BT709 SDR
however what we've done is this:
Source dvhe0509 -> IPTc2 -> LUT -> BT709 SDR
The fact is that nothing tells us that the input is always going to be IPTc2, for instance if the input is dvhe0509 with ITP PQ, that LUT can't be used.
Going the other way round, so from BT709 to dvhe0509 is impossible 'cause although the transformation could, in theory, be inverted, I would have no way to insert the proprietary metadata in the file so you would be left with something that no decoder could decode properly.
In other words, you could, in theory, invert and do:
BT709 SDR -> LUT -> IPTc2
then what?
You're left with IPTc2 that needs to be encoded and flagged as such with the relative metadata (RPU) so that an official decoder will be able to decode it, but we have no way to do that I'm afraid, so all you're left with is an uncompressed A/V stream living in RAM coming out from Avisynth with no metadata at all and that any decoder would interpret wrongly.
Out of curiosity, why are you trying to do this?
coolgit
2nd December 2023, 15:47
Is dvhe0509 (dvhe.05.09) the HDR format as my video has dvhe.08.06, so doesn't work?
Out of curiosity, why are you trying to do this?
I am just curious to why you have dvhe to 709 but not the other way around. I am sure some computer geek will crack the Dolby metadata one day.
I have just bought a new 4k tv with HLG, HDR10, HDR10+, dolby vision after the last tv went kaput last week just before Black Friday... perfect timing. I have been using different HDR versions of a film to see one is best. There isn't much different between HDR10, +, dolby. Dolby is slighty better when dealing with white levels as both HDR10 and + brightness tend to stick out like a sore thumb sometimes. Dolby is more subtle.
FranceBB
2nd December 2023, 17:33
Is dvhe0509 (dvhe.05.09) the HDR format as my video has dvhe.08.06, so doesn't work?
That's correct, you can't use the dvhe0509 LUT on dvhe0806, it's not gonna work.
There isn't much different between HDR10, +, dolby. Dolby is slighty better when dealing with white levels as both HDR10 and + brightness tend to stick out like a sore thumb sometimes. Dolby is more subtle.
Well the difference between HDR10 and 10+ is literally just dynamically changing metadata in the header so you would benefit from it only if your TV has less nits than the actual ones the content was mastered for.
This is because if the content was mastered on more nits than the ones of your actual TV, your TV would have to read the maxCLL value declared in the header and remap it to its own maximum (HDR10) however if we have something extreme like with lots of computer generated graphics that skyrockets to 5000 nits (I'm saying this 'cause afaik there's no camera with enough stops to capture more than 3300 nits currently, so it has to be computer generated content) and your TV is, let's say, an 880 nits OLED TV, it would have a really hard time with all the other scenes as they would have to be remapped much lower. This is where HDR10+ comes in to help with dynamically changing metadata in the header, the maxCLL value now refers to the scene so that you don't have the global one only. There's still the global one to be backwards compatible with normal HDR10 devices, however for those that can read the metadata in the header they're gonna be able to adapt and remap the peak dynamically thus achieving a far better result.
Last but not least is Dolby Vision which has so many flavors right now unfortunately that it's hard to compare them all.
IPTc2 dvhe0509 has no technological advancement over HDR10 and HDR10+ 'cause those two are PQ based while IPTc2 is more on the SDR side. It's still considered HDR but the luma is shaped to peak at around 80% turning pseduo-logarithmically to preserve the highlights while the blacks start lower as in SDR. The idea being that the shader interpreting the IPTc2 and the metadata can produce either an HDR version close to what HLG would look like on an HDR display and output a very good SDR version on an SDR display.
PQ on the other hand is a totally logarithmic curve which yields far better results on the HDR side as it preserves both blacks and highlights (but HDR10/10+ can't be displayed on an SDR display as a drawback).
Now going to what Dolby Vision should have actually sticked to, the dual layer profile, that one makes sense and does have some technological advancement over HDR10 and 10+. This is because it's literally two layers, so one layer with a normal UHD H.265 10bit HDR PQ encoded video and the second layer carrying dynamically changing metadata (you're gonna see it as a "fake" FULL HD stream that is completely green if you try to play it on a normal device). That thing there is the metadata layer and with that not only you have dynamically changing metadata like in HDR10+ but a proper Dolby Vision Dual Layer decoder would use it to display a perfect 12bit output and that's where Dolby Vision makes sense.
I have been using different HDR versions of a film to see one is best. There isn't much difference
Charles Poynton, the inventor of luma, once told me: "once the director signs a version off, no art should occur in the encoding process".
In other words, the goal of an encoder at that point is to make the different versions a movie is encoded to look as close as possible to each other while retaining the director's view and exploiting the advancement of one technology while compensating for the lack on another and so on.
The fact that you haven't been able to see major differences between the different versions of a movie means that such a job was done right by the person who encoded the movies. :)
For instance, when you target a DCI P3 XYZ theatrical release, you have to keep in mind that the peak is gonna be 48 nits but that the cinema room is gonna be completely dark and given that human vision separates in Photopic, Mesopic, Scotopic according to whether you're using rods, cones or both and that the less photons there are the less chroma you see, to make it look more "natural" you have to compensate for that on the chroma side. This is just one of the several things that encoders take into account when producing the final encoded output.
I'm just a guy who works on TV, so I haven't made many movies that ended up in the cinemas in my life (just a couple of documentaries, really) but, to a very lesser extent, I face those challenges too when producing the different TX Ready versions starting from the same master that need to then go on air. ;)
coolgit
3rd December 2023, 18:11
Charles Poynton, the inventor of luma, once told me: "once the director signs a version off, no art should occur in the encoding process".
That would obviously be the standard policy. Makes sense too. I think the slight differences is that Dolby, hdr10+, adjusts the brightness and tone mapping per scene, so in some darkish scene the shadows on the face are subtle and better than hdr10, 709. In normal day brightness there is hardly anything. But if i watch it normally, instead of pausing, one doesn't see any differences unless one knows where to look and concentrate on finding the differences. In the real world no one going to do that, they just accept the marvellous quality output of colours. Having said that is there really any need for Dolby when hdr10+ does the same but better? When streaming and if the tv doesn't have hdr10+, it can default to hdr10. With Dolby it would default to SDR.
second layer carrying dynamically changing metadata
This is similar to overlay isn't it?
Here the thing that got me thinking for ages now. When you watch the Lord of the Ring, there is a lot of action/violence but given 12 rating, but a film with less violence is given 18 rating, simply because there is blood, whereas there isn't any in the Lord of the Ring. But in terms of cinema and dvds sales, the 18 rated film would earn less than a 12 rated film. What if the blood parts of any films is on the 2nd layer. There would be 2 versions, 12 and 18. In the cinema, especially most are multiplex, one room would be 12 rated so adult can dump their children in and squeamish people in, in another room 18 rated for adults only. The same for dvds. The menu can at the beginning would show 12 or 18 and the parents can decide which version they want. Surely this way could maximise the income/sales/ by not excluding a large share of the market. For me i wouldn't mind seeing blood squirting out of the chopped head in the Return of the King. The same would go for swear words not appropriate for under 18 by having 12 rated sounds and 18 rated sounds.
FranceBB
3rd December 2023, 19:06
What if the blood parts of any films is on the 2nd layer. There would be 2 versions, 12 and 18
That ain't gonna work, unfortunately. One thing is adding an LSB kind of metadata to create a 12bit output, another is having a completely different version of the same movie (TL;DR you can't just add VFX).
Anyway it's an interesting idea, but it can't be done the way it currently is implemented.
is there really any need for Dolby when hdr10+ does the same but better?
dvhe? Nope, no advantage at all.
Dolby Vision dual layer? Yes, it would still default to 10bit HDR10 when watched on a standard decoder, but when watched on a proper Dolby Vision decoder it would not just have dynamically changing metadata like HDR10+ but it would also deliver 12bit and that's very important 'cause by standard on a totally logarithmic curve like PQ if you use only 10bit limited tv range code values you don't have enough bits to go all the way up to 10'000 nits, while with 12bit you do. Of course currently is a bit overkill 'cause there are no movies whatsoever graded at 10k nits, there are no monitors that can get to 10k nits and there are no cameras that can record enough stops to get to 10k nits, but eventually, in the future, we'll get there and that's where 12bit is gonna make a difference.
coolgit
3rd December 2023, 19:25
That ain't gonna work, unfortunately. One thing is adding an LSB kind of metadata to create a 12bit output, another is having a completely different version of the same movie (TL;DR you can't just add VFX).
Anyway it's an interesting idea, but it can't be done the way it currently is implemented.
Maybe not 2nd layer but some sort of overlay like subtitles do in a separate file. If there can be many sub files and audio files then why not many video files?
Theoretically it should be possible.
StainlessS
4th December 2023, 13:45
That ain't gonna work, unfortunately. One thing is adding an LSB kind of metadata to create a 12bit output, another is having a completely different version of the same movie (TL;DR you can't just add VFX).
Maybe alternate 'angle' like DVD (I assume BD also has alternate angle capability).
spoRv
20th August 2024, 12:49
I know that conversion from(to) rec709 to(from) rec2020 is not lossless, but I assume (wrongly, perhaps?) that after a dual conversion, result should look *mostly* similar to the original clip.
I mean, given the clip as original source, then
clip
LinearTransformation(Input="Linear_BT709", Output="BT2100_PQ")
LinearTransformation(Input="BT2100_PQ", Output="Linear_BT709")
should look similar to untouched clip, right?
If so, why the dual conversion result is brighter than the original clip? There may be three options:
1) conversion from 709 to 2020 makes the clip brighter
2) conversion from 2020 to 709 makes the clip brighter
3) both of the previous ones
France, please help!
P.S. using the default PQ_to_BT709_v1.cube
FranceBB
23rd August 2024, 19:52
The real answer is: "is complicated".
Let me explain.
What you said is absolutely true, you can't go to BT709 SDR and go back to BT2020 PQ losslessly as for such a transformation to be lossless you would need to map as many points to the output as the ones you have in the input (i.e a 1:1 and onto transformation). I'm not gonna say the word "isomorphism" 'cause otherwise mathematicians will scream at me saying that you can have lossless conversions even if they're not isomorphism 'cause an isomorphism is also preserving the structure, but anyway, that minor detail aside, you're right, such a conversion is not lossless.
The reason why you're seeing two very different results, however, has nothing to do with linear algebra in this sense, but rather to how those LUTs were made.
Essentially, the two LUTs you used were made with 2 very different inputs in mind.
Let's start with BT709.
As we can see, this peaks at 100 nits:
ColorBars(1920, 1080, pixel_type="YV24")
VideoTek(Mode="SDR", Type="nits")
https://i.imgur.com/1O7ClT2.png
Now, let's bring everything to BT2020 PQ:
ColorBars(1920, 1080, pixel_type="YV24")
ConvertBits(16)
ConvertToPlanarRGB()
Cube("C:\Program Files (x86)\AviSynth+\LUTs\BT709_to_PQ.cube", fullrange=1, interp=1)
ConverttoYUV444(matrix="Rec2020")
VideoTek(Mode="PQ", Type="nits")
https://i.imgur.com/juASK3O.png
As you can see, we went to around 400 nits.
This is because when we have BT709 SDR signals those might have completely white and clipped out stuff, especially for outside footages, so you don't really want to map the white too high to PQ otherwise you're gonna blind people at home. Remember that a completely clipped out sky at 100 nits is tolerable but if you bring it to 1000 nits or more, it can literally make the person sitting at home watching it very uncomfortable, especially if it's in a transition from a darker scene.
Anyway, if we apply the LUT to go back to BT709 SDR we're gonna be in trouble 'cause that LUT assumes a much higher MaxCll (not 1000 nits but it definitely something around that), while our content (the fake BT2020 HDR PQ we just converted from BT709 SDR) only really has 400 nits.
So... what's gonna happen?
Well, everything will be dimmer.
ColorBars(1920, 1080, pixel_type="YV24")
ConvertBits(16)
ConvertToPlanarRGB()
Cube("C:\Program Files (x86)\AviSynth+\LUTs\BT709_to_PQ.cube", fullrange=1, interp=1)
Cube("C:\Program Files (x86)\AviSynth+\LUTs\PQ_to_BT709_v1.cube", fullrange=1, interp=1)
ConverttoYUV444(matrix="Rec709")
VideoTek(Mode="SDR", Type="nits")
https://i.imgur.com/eSyxMyl.png
As you can see, the peak brightness (i.e the white) isn't at 100 nits any longer once we got back to BT709 SDR but it's actually lower.
If we use PQ_to_BT709_v2.cube then things will get even worse as that one is gonna assume an even higher MaxCll (more than 1000 nits) thus lowering the peak brightness of the BT709 SDR clip even further at the end of the roundtrip:
ColorBars(1920, 1080, pixel_type="YV24")
ConvertBits(16)
ConvertToPlanarRGB()
Cube("C:\Program Files (x86)\AviSynth+\LUTs\BT709_to_PQ.cube", fullrange=1, interp=1)
Cube("C:\Program Files (x86)\AviSynth+\LUTs\PQ_to_BT709_v2.cube", fullrange=1, interp=1)
ConverttoYUV444(matrix="Rec709")
VideoTek(Mode="SDR", Type="nits")
https://i.imgur.com/AKZlpki.png
By the way, apologies for the late reply.
I didn't really have that much time these days as I spent from 08.30AM to 10.00PM in the office with 30 minutes lunch and dinner breaks in between.
Once I got home I couldn't do anything other than getting undressed, brushing my teeth and crumbling to bed.
Then it was just a matter of opening my eyes and doing this all over again.
wswartzendruber
27th August 2024, 01:26
By the way, apologies for the late reply.
I didn't really have that much time these days as I spent from 08.30AM to 10.00PM in the office with 30 minutes lunch and dinner breaks in between.
Once I got home I couldn't do anything other than getting undressed, brushing my teeth and crumbling to bed.
Then it was just a matter of opening my eyes and doing this all over again.
Everyone here is happy about your community involvement and benefits from it, but don't forget to take care of yourself.
spoRv
29th August 2024, 16:01
France, thanks for the answer; worry not about late replies... and again, thanks for your efforts and time!
By the way, full screen white at around 900 nits or so (like in The Matrix) is painfully good! :D Those were good times when colourists DID NOT use OLED TVs as their reference monitors, with their meager 150/200 nits full screen... but I digress.
Just another question: diffuse white should be set at 100 nits for SDR; and at 203 nits in PQ, right? If so, why your LUT puts it around 400 nits?
FranceBB
29th August 2024, 22:04
Well, once again, the answer is complicated. In SDR you have a maximum of 0.7V, which correspond to 100 nits and that's absolutely fine. In PQ, you have the reference white at 0.40V, which is indeed 203 nits. Then, of course, you have specular highlights of different things inside the scene that exceed that and can go as high as you want them to be. So far so good. The problem, however, is that here we're using an SDR content as our source and unfortunately in SDR there aren't things like specular highlights, there are just... highlights. If we map our peak brightness (i.e 100 nits) to be the reference white in PQ (i.e 203 nits) then we would technically be correct and that's what a lot of software do, however we wouldn't have any kind of "HDR" at all. In other words, if you were to see such a movie, you would immediately spot that it originated from an SDR master and that it was just a very simple conversion. I know that we're talking about BT709 to BT2020 PQ, but the BBC offers the 5a LUT to go from BT709 to BT2020 HLG in order to make the content "look close to the original SDR when watched in an HDR 1000 nits monitor" and those sure enough go to 400 nits.
BT709 SDR 100 nits (source)
BT2020 HDR HLG 400 nits (BBC LUT 5a)
https://i.imgur.com/vO1AAoh.png
So, not only I've done the same thing in my BT709 SDR to BT2020 HDR HLG LUT, but I've also applied the very same logic in my BT709 SDR to BT2020 HDR PQ LUT as in both cases I'm mapping 100 nits SDR to 400 nits in HDR (it's actually 420 as I did the original math wrong a long time ago, but I left it as is as nobody ever complained).
BT2020 HDR PQ content after my LUT has been applied to the BT709 SDR source:
https://i.imgur.com/ibkcItW.png
As I mentioned last time round, however, for a roundtrip you would need a LUT that brings everything to 1000 nits PQ and then go back to 100 nits BT709, but that's risky as you might end up with very undesirable results, which is why I settled on 400 nits (yes, fine, 420, but whatever). As to why 400 nits and not higher, it's because in SDR you might indeed get nicely graded movies that can pop and look very nice in the HDR conversion, but you can also get clipped out whites. Take a look at this scene:
https://i.imgur.com/x2ovo7H.png
The outside of the window is completely clipped out and that's 100 nits in SDR. If we were to bring it to 1000 nits in HDR PQ, then we would make the viewer feel uncomfortable, especially if he's watching the movie during the evening, after dinner, in a pitch dark living room. At 400 nits, however, it's not gonna make the user uncomfortable.
spoRv
2nd September 2024, 16:50
Thanks for the explanation, France!
Now for the next release, SDR->PQ 400/420 nits correction! :p
asarian
4th November 2024, 02:10
Absolutely brilliant stuff! Got it all to work nicely.
Now, for re-encoding with x265, dgdecodenv always handily gives me this type of info on existing HDR movies:
--colorprim 9 --transfer 16 --colormatrix 9 --master-display "G(8500,39850)B(6550,2300)R(35400,14600)WP(15635,16450)L(10000000,1)" --max-cll "203,21" --frames 222217 --chromaloc 2
When I do a SDR2HDR conversion myself, with these LUTs, where can I get this info from? Especially the --master-display parameters, so I can actually write the output correctly to disk, using x265. Thanks.
FranceBB
4th November 2024, 14:06
Absolutely brilliant stuff! Got it all to work nicely.
I'm glad to hear that. :)
I started this project back in 2019 'cause lots of companies were offering .cube files to perform various kind of conversions for a pretty penny ($150 or even $300) and I thought it wasn't fair as those are really just matrices that take map some values in an input to some other values in output and were supposed to be free and open source for everyone. Since then, lots of people started using them and they've been included in several projects the likes of FFAStrans and Hybrik to name a few, which actually made me happy. So, the more people use them, the better. :D
When I do a SDR2HDR conversion myself, with these LUTs, where can I get this info from? Especially the --master-display parameters, so I can actually write the output correctly to disk, using x265.
Well, in SDR we can always expect the input to peak at 0.7V i.e 100 nits in Limited TV Range which corresponds to 235 in 8bit and 940 in 10bit.
The conversion takes that and maps it to 400 nits in both HLG and PQ (they correspond to different millivolt levels due to the difference in nature between those two curves), so you can set the following values in your x265 command line.
For HLG:
--min-luma 64 --max-luma 940 --chromaloc 2 --range limited --videoformat component --colorprim bt2020 --transfer arib-std-b67 --colormatrix bt2020nc --atc-sei 18 --overscan show
This is not a mistake, in HLG you don't need to specify the mastering display, nor the MaxCll as they're not mandatory and the TV will adjust automatically anyway. If the TV is BT2020 SDR 100 nits, it will ignore the HLG transfer and it will display it as-is by only interpreting the colormatrix and primaries. Sure, whites will be dimmer compared to an SDR signal, but it will look ok-ish and that's the intended output and the whole reason why HLG was invented (i.e to have one single linear channel which allows people with HDR and BT2020 SDR TVs to see it without having to air two channels for the same content and waste bandwidth on the already overcrowded satellites like Hotbird, Astra etc).
For PQ:
--min-luma 64 --max-luma 940 --chromaloc 2 --range limited --videoformat component --colorprim bt2020 --transfer smpte2084 --colormatrix bt2020nc --master-display "G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,0.0050)" --max-cll 400,200 --overscan show
In PQ the metadata are mandatory, so you can include them as per the section above given that the conversion from SDR will output 400 nits.
In both cases, I'm assuming that you're encoding in 10bit limited tv range, hence the min-luma max-luma, but you can either change those (if you're targeting 12bit) or remove them if you don't want them there as they're not mandatory anyway. Last but not least, I included --chromaloc 2 as 4:2:0 Type 2 'cause I noticed that you were targeting it, however keep in mind that Cube() will perform all the calculations in RGBPS (i.e RGB 16bit), so when you then go back to YUV 4:2:0 you need to convert the chroma placement yourself.
I know that you're using VapourSynth and not AviSynth, so I'm afraid I can't help you with that. I'm sure that there are plenty of people who can help you in the VapourSynth section with a conversion from RGBPS (i.e RGB 16bit which doesn't have a chroma placement 'cause chroma is the same resolution as luma given that they're one and the same) to YUV 4:2:0 Type 2 (chroma placement top left), but as a safety net if you can't find a way to do that in VapourSynth, you could always output YUV 4:2:0 16bit with the left chroma placement (i.e the old standard MPEG-2 placement) and then perform the conversion to top left (i.e coordinates 0-0) within FFMpeg before piping it to x265 like this:
ffmpeg.exe -i "AVS Script.avs" -vf scale=out_color_matrix=bt2020nc:out_h_chr_pos=0:out_v_chr_pos=0 -pix_fmt yuv420p16le -strict -1 -an -f yuv4mpegpipe - | x265.exe --y4m - --dither (other encoding options) -o "raw_video.hevc"
(again, it says AVS Script.avs but I would imagine the same applies to VPS Script.vpy).
In this example below (apologies, it's Avisynth again) I've grouped the results of the HLG and PQ conversions starting from the BT709 SDR 100 nits source:
video=LWLibavVideoSource("V:\fs0\clip.dir\UAT11887.mxf")
audio=LWLibavAudioSource("V:\fs0\clip.dir\UAT11887.mxf", stream_index=4)
AudioDub(video, audio)
ConvertBits(16)
ConvertToPlanarRGB()
source=last
Cube(source, "C:\Program Files (x86)\AviSynth+\LUTs\BT709_to_HLG.cube", interp=1, fullrange=1)
Converttoyuv420()
VideoTek(Mode="HLG", Type="nits")
Crop(0, 0, -0, -520)
Subtitle("BT2020 HDR HLG")
my_hlg=last
Cube(source, "C:\Program Files (x86)\AviSynth+\LUTs\BT709_to_PQ.cube", interp=1, fullrange=1)
Converttoyuv420()
VideoTek(Mode="PQ", Type="nits")
Crop(0, 0, -0, -520)
Subtitle("BT2020 HDR PQ")
my_pq=last
Converttoyuv420(source)
VideoTek(Mode="SDR", Type="nits")
Crop(0, 0, -0, -520)
Subtitle("BT709 SDR")
my_bt709=last
StackVertical(my_bt709, my_hlg, my_pq)
and as you can see the conversion is proportional, so if things peak at 100 nits in SDR, they're gonna peak at 400 nits in both HDR HLG and HDR PQ:
https://i.imgur.com/qXIfDh4.png
however if they peak lower in the SDR version, they're also gonna peak lower in the HDR HLG and HDR PQ versions (in this case around 80 nits in SDR correspond to 200 nits in HDR HLG and HDR PQ in the conversion:
https://i.imgur.com/QTRacir.png
asarian
4th November 2024, 15:06
I'm glad to hear that. :)
You are a brilliant man, in whatever thread I find you.:goodpost:
Thank you again, profusely for this very extensive info! Can't believe you went out of of your way like this, with so much invaluable information! I shall all eagerly take it to heart! :thanks:
asarian
4th November 2024, 19:50
--min-luma 64 --max-luma 940 --chromaloc 2 --range limited --videoformat component --colorprim bt2020 --transfer arib-std-b67 --colormatrix bt2020nc --atc-sei 18 --overscan show
I'm gettimg dangerously close to a valid HDR output. :) I used this line:
VSPipe -c y4m "f:\jobs\hdr.vpy" - | x265-new --y4m --input - --preset medium --input-depth 10 --output-depth 10 --crf 13 --hdr --min-luma 64 --max-luma 940 --chromaloc 2 --range limited --videoformat component --colorprim bt2020 --transfer 16 --colormatrix bt2020nc --atc-sei 18 --overscan show --output "i:\video\hdr.hevc"
And this script:
import vapoursynth as vs
core = vs.core
core.max_cache_size = 65535
vid = core.lsmas.LibavSMASHSource(r"f:\veai\alientest_iris2-00.11.57.773-00.12.46.554.mov")
vid = core.resize.Bicubic(vid, matrix_in_s="709", format=vs.RGBS)
vid = core.timecube.Cube(vid, cube=r"C:\VS\plugins\BT709_to_HLG.cube")
vid = core.resize.Point(vid, matrix = 1, format = vs.YUV422P10)
vid = core.neo_f3kdb.Deband (vid, preset="veryhigh", dither_algo=2)
vid.set_output ()
Not getting an 'HDR10 compatible' notice in MediaInfo, though. I reckon I either import from wrong colorspace, or convert erroneously. Movie is .mov, 422 HQ (the only lossless option TVAI offers). So, probably doing something wrong. But output is 422 BT 2020 (10-bit), so I can't be all that far off.
FranceBB
4th November 2024, 23:12
Not getting an 'HDR10 compatible' notice in MediaInfo, though.
Mediainfo is right, HDR10 means PQ 10bit, while you're encoding in HLG 10bit. It's still HDR, but not HDR10, it's a different standard. ;)
asarian
5th November 2024, 07:29
Mediainfo is right, HDR10 means PQ 10bit, while you're encoding in HLG 10bit. It's still HDR, but not HDR10, it's a different standard. ;)
And that shows my ignorance. :sly: Thanks for your patience.
N.B. 422 effectively produces an unplayable movie for me (like at 2 fps). I know of no media player that can do this, btw, so 420 it will have to be.
The colors and brightness were excellent, btw! :thanks:
FranceBB
5th November 2024, 07:40
N.B. 422 effectively produces an unplayable movie for me (like at 2 fps). I know of no media player that can do this, btw, so 420 it will have to be.
Yeah, that's probably because with 4:2:2 it goes all into software decoding putting all the load on the CPU, while with 4:2:0 it uses hardware decoding and it's therefore smooth during the playback. :)
The colors and brightness were excellent, btw! :thanks:
Nice! I've used it in production for a while so it would have been a problem if it was otherwise eheheheh
On that, if you're going to 4:2:0, remember to either convert to top left the chroma location or remove the --chromaloc 2.
As for the chroma resizing, don't use BilinearResize and PointResize. Especially the latter it's based on nearest neighbours and should never be used in practice. At work I generally use Spline64Resize, but I guess a windowed Sinc resizer like LanczosResize or BlackmanResize would also do.
Z2697
5th November 2024, 08:30
--master-display "G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,0.0050)"
That last value, 0.0050, might be wrong?
asarian
5th November 2024, 08:57
On that, if you're going to 4:2:0, remember to either convert to top left the chroma location or remove the --chromaloc 2.
Another bit of valuable information!
So, just remove --chromaloc 2 altogether? Good thing I caught your reply in time, as I was aready 10 minutes in, reencoding the movie. :)
Should I perchance remove --hdr too? (as it's not HDR10).
As for the chroma resizing, don't use BilinearResize and PointResize. Especially the latter it's based on nearest neighbours and should never be used in practice. At work I generally use Spline64Resize, but I guess a windowed Sinc resizer like LanczosResize or BlackmanResize would also do.
Awesome! Using core.resize.Spline64 now.
Z2697
5th November 2024, 10:53
Another bit of valuable information!
So, just remove --chromaloc 2 altogether? Good thing I caught your reply in time, as I was aready 10 minutes in, reencoding the movie. :)
Should I perchance remove --hdr too? (as it's not HDR10).
Awesome! Using core.resize.Spline64 now.
Remove chromaloc, yes, or since other HDR materials are chromaloc=2, designate the chromaloc when you converting RGBS back to YUV420P10. Use the chromaloc argument of core.resize. Conveniently the same name and same meaning of values.
Z2697
5th November 2024, 16:02
You can even do it at playback ;)
mpv --target-colorspace-hint=yes --vf=format=gbrpf32le,lut3d=file=BT709_to_PQ.cube,zscale=p=bt2020:t=smpte2084:pin=bt2020:tin=smpte2084
zscale is for "tagging" the video as PQ + Rec.2020 but perhaps there's filter for the specific job, I'm just more familiar with zscale
FranceBB
6th November 2024, 20:01
That last value, 0.0050, might be wrong?
"au contraire", I would say, it's actually correct.
--master-display "G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,0.0050)"
means
Mastering display color primaries: Display P3
Mastering display luminance: min 0.0050 cd/m², max: 1000 cd/m²
You can try yourself by using that in x265 and then checking Mediainfo on the newly produced raw_video.h265 file. ;)
Z2697
6th November 2024, 20:17
"au contraire", I would say, it's actually correct.
means
You can try yourself by using that in x265 and then checking Mediainfo on the newly produced raw_video.h265 file. ;)
I thought you mean 0.0050 cd/m^2 which should be 50 in the command.
But the reason of it "means" 0.0000 cd/m^2 is that it is parsed as unsigned integer in x265.
https://bitbucket.org/multicoreware/x265_git/src/7b5332d9df9a26204861009a9d68f28a2898e3ea/source/encoder/sei.h#lines-596:609
Anyway, that will not produce error in practice, and there's no use of the master-display information... that I know of. Do you happen to know some of the use case?
FranceBB
6th November 2024, 21:55
I thought you mean 0.0050 cd/m^2 which should be 50 in the command.
But the reason of it "means" 0.0000 cd/m^2 is that it is parsed as unsigned integer in x265.
https://bitbucket.org/multicoreware/x265_git/src/7b5332d9df9a26204861009a9d68f28a2898e3ea/source/encoder/sei.h#lines-596:609
Ah crap, you're absolutely right.
there's no use of the master-display information... that I know of. Do you happen to know some of the use case?
It's ignored by literally every player as it has no real use, so yeah it won't make any difference.
By the way, good catch, but now I'll just put it to 0 to be safe. Something like:
--master-display "G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,0.0000)"
should be just as safe. :)
ProWo
21st November 2024, 15:01
Hi FranceBB
I'm using your LinearTransformation.avsi script with Avisynth64+ with this setting:
LinearTransformation(Input="Linear_BT709", Output="BT2100_PQ")
Encoding the resulting avs with FFmpeg gives (as input):
Stream #0:0: Video: rawvideo (I420 / 0x30323449), yuv420p(tv, bt2020nc/bt709/smpte2084, progressive)
Should bt2020nc/bt709/smpte2084 not be bt2020nc/bt2020/smpte2084?
The mediainfo from the resulting video shows:
Color primaries : BT.709
Transfer characteristics : PQ
Matrix coefficients : BT.2020 non-constant
Color primaries should be BT.2020
Maybe the error in the script is here:
output_Matrix =
\ : Input=="Linear_BT709" && Output=="BT2100_PQ" ? ("Rec2020")
Thx for your help.
FranceBB
21st November 2024, 23:49
Oh crap. I'm correctly overriding the matrix and transfer but I'm not setting the primaries at all.
If you need a quick and dirty fix, add this in your Avisynth script after the LinearTransformation() call:
propset("_Primaries", 9)
Anyway, aside from that, can you please test this new version and let me know if it works?
https://github.com/FranceBB/LinearTransformation/blob/master/LinearTransformation.avsi
If it does, then I'll make a release tomorrow morning. ;)
asarian
22nd November 2024, 08:32
Oh crap. I'm correctly overriding the matrix and transfer but I'm not setting the primaries at all.
Oh crap, does this go for the VapourSynth 'cube' too?
ProWo
22nd November 2024, 11:01
Oh crap. I'm correctly overriding the matrix and transfer but I'm not setting the primaries at all.
Anyway, aside from that, can you please test this new version and let me know if it works?
https://github.com/FranceBB/LinearTransformation/blob/master/LinearTransformation.avsi
If it does, then I'll make a release tomorrow morning. ;)
Success, it works fine now. Thanks. :)
Z2697
22nd November 2024, 11:22
Oh crap, does this go for the VapourSynth 'cube' too?
This is just metadata, if you specified the right one when you use resize to convert RGB back to YUV it should be fine, actually if you don't specify or used wrong one, the actual colors shouln't be altered at all, you can easily fix the metadata in encoding parameters or even encoded bitstream.
asarian
22nd November 2024, 16:50
This is just metadata, if you specified the right one when you use resize to convert RGB back to YUV it should be fine, actually if you don't specify or used wrong one, the actual colors shouln't be altered at all, you can easily fix the metadata in encoding parameters or even encoded bitstream.
Thank you! You got me worried there for a moment. :D
MediaInfo always reported the right colorspace; juat wanted to be sure.
Z2697
22nd November 2024, 17:11
Thank you! You got me worried there for a moment. :D
MediaInfo always reported the right colorspace; juat wanted to be sure.
Actually, there's a little caveat: because core.resize read and use colorspace information from frame props if they exist, if your frame is flagged as "bt709" and you specify primaries_s when converting, it might perform bt709 -> bt2020 conversion rather than setting the property only.
I'd suggest clear the related frame properties when using core.resize to perform "colorimetric" conversion.
(What's the collective name for matrix, transfer and primaries conversion?)
asarian
23rd November 2024, 21:15
Actually, there's a little caveat: because core.resize read and use colorspace information from frame props if they exist, if your frame is flagged as "bt709" and you specify primaries_s when converting, it might perform bt709 -> bt2020 conversion rather than setting the property only.
I'd suggest clear the related frame properties when using core.resize to perform "colorimetric" conversion.
(What's the collective name for matrix, transfer and primaries conversion?)
Well, did a small test:
import vapoursynth as vs
core = vs.core
core.max_cache_size = 65535
import havsfunc as haf
vid = core.dgdecodenv.DGSource (r'c:\jobs\repo-00.01.16.497-00.02.09.085.dgi')
vid = core.resize.Spline64(vid, matrix_in_s="709", format=vs.RGBS)
vid = core.timecube.Cube(vid, cube=r"C:\VS\plugins\BT709_to_HLG.cube")
vid = core.resize.Spline64(vid, matrix=9, format = vs.YUV420P10)
vid.set_output ()
MediaInfo says 'Color prmaries BT.2020' on output.
But that may be because of setting (mandatory) 'matrix' in core.resize.Spline64, so I can't really tell what comes out of the BT709_to_HLG line (though it should be BT.2020).
So, should I change something?
VoodooFX
23rd November 2024, 23:32
@FranceBB Maybe you would want to add LUts for videos from DJI drones?
Because I looked at your thread first when I needed them. :D
https://forum.videohelp.com/threads/416286-DLog-video
FranceBB
24th November 2024, 04:55
MediaInfo says 'Color prmaries BT.2020' on output.
But that may be because of setting (mandatory) 'matrix' in core.resize.Spline64
Yes, that's exactly right, it is because you're setting the right matrix on the RGB to YUV conversion which isn't optional in VapourSynth. That will also set the frame properties.
I can't really tell what comes out of the BT709_to_HLG line (though it should be BT.2020).
It is absolutely and positively BT2020 in terms of the mapped points in the output after the transformation, but in terms of frame properties the answer is: nothing. The frame properties values are just not set in the RGB roundtrip.
The "good news" however is that VapourSynth - unlike Avisynth - expects the user to set them in the function so that they can also be set in the frame properties.
This means that up until this point as long as you set them correctly in the YUV->RGB->YUV roundtrip, then you're good to go. ;)
So, should I change something?
Nope, you're doing everything right already, the "issue" is limited to Avisynth in which we have to use PropSet().
In general, we can use this rule of thumb after going back to YUV.
For BT601 PAL outputs:
propSet("_ColorRange", 1) #Limited TV Range
propSet("_Matrix", 5) #BT601 PAL
propSet("_Transfer", 6) #BT601 PAL
propSet("_Primaries", 5) #BT601 PAL
For BT601 NTSC outputs:
propSet("_ColorRange", 1) #Limited TV Range
propSet("_Matrix", 6) #BT601 NTSC
propSet("_Transfer", 6) #BT601 NTSC
propSet("_Primaries", 6) #BT601 NTSC
For BT709 outputs:
propSet("_ColorRange", 1) #Limited TV Range
propSet("_Matrix", 1) #BT709
propSet("_Transfer", 1) #BT709
propSet("_Primaries", 1) #BT709
For BT2020 outputs:
propSet("_ColorRange", 1) #Limited TV Range
propSet("_Matrix", 9) #BT2020
propSet("_Transfer", 14) #BT2020
propSet("_Primaries", 9) #BT2020
For BT2020 HLG outputs:
propSet("_ColorRange", 1) #Limited TV Range
propSet("_Matrix", 9) #BT2020
propSet("_Transfer", 18) #HLG
propSet("_Primaries", 9) #BT2020
For BT2020 PQ outputs:
propSet("_ColorRange", 1) #Limited TV Range
propSet("_Matrix", 9) #BT2020
propSet("_Transfer", 16) #PQ
propSet("_Primaries", 9) #BT2020
For DCI P3 outputs:
propSet("_ColorRange", 1) #Limited TV Range
propSet("_Matrix", 2)
propSet("_Transfer", 17) #DCI P3
propSet("_Primaries", 11) #DCI P3
Tested and working as expected in AVSPmod mod:
https://i.imgur.com/aH9t1F2.png
https://i.imgur.com/FdfjADj.png
https://i.imgur.com/P30dqzs.png
https://i.imgur.com/ZUGWJ6j.png
https://i.imgur.com/vyAZhoQ.png
https://i.imgur.com/KYPV65Y.png
Maybe you would want to add LUts for videos from DJI drones?
Yeah, that's actually something I wanted to do for quite some time now. I did actually make a first implementation of D-Log to BT709, however I didn't particularly like the results that came out of it. On that note, most of the log conversions I made were targeting BT709, however nowadays log is mostly used to produce BT2020 HLG outputs, at least internally, so I should really start updating those. Anyway, I have a few samples of D-Log footage, so perhaps if I get enough samples of D-Log M footage as well I can make both D-Log to BT709 and D-Log M to BT709.
Hopefully come next year I'll have a bit more time to make things like Slog3 to HLG and to PQ which is kinda important right now as more and more productions shot in Slog3 are then graded and converted in either HLG or PQ for the final release (in our case, it's always HLG but we're a broadcasting company, so we're biased).
asarian
24th November 2024, 06:13
Nope, you're doing everything right already, the "issue" is limited to Avisynth in which we have to use PropSet().
In general, we can use this rule of thumb after going back to YUV.
I cannot thank you enough for your, once again, very extensive and helpful post! :thanks:
FranceBB
24th December 2024, 12:29
Linear Transformation v2.7 Released! (https://github.com/FranceBB/LinearTransformation/releases)
Changelog:
- Added Frame Properties support for Primaries
- BT601 transfer frame properties are now correctly signaled as smpte170m
- Introduced correct signalling of smpte432 primaries and smpte428 transfer for the DCI P3 XYZ Gamma 2.6 conversion
Merry Christmas!
FranceBB
20th February 2025, 22:00
In the next release we're gonna have two new conversions that are gonna be added:
- BT2020 SDR to BT709 SDR
- BT709 SDR to BT2020 SDR
Let's start from the first one and let's start by saying that other people have been working on this before me, in fact William (the creator and maintainer of HLG Tools) released a version based on Oklab (https://bottosson.github.io/posts/oklab/) here: Link (https://forum.doom9.net/showthread.php?t=182499&page=22). There's absolutely nothing wrong with his LUTs and you can go ahead and use them. What I'm doing is something much more simplistic, in fact the BT2020 SDR to BT709 SDR conversion is actually based on the most simple calculation illustrated in the ITU recommendation 2407.
The conversion is performed as follows:
[0.4124 0.3576 0.1805]^-1 [0.6370 0.1446 0.1689]
[0.2126 0.7152 0.0722] [0.2627 0.6780 0.0593] =
[0.0193 0.1192 0.9505] [0.0000 0.0281 1.0610]
Let's take the matrix for which we have to calculate the inverse and let's create the augmented matrix
[0.4124 0.3576 0.1805 1.0000 0.0000 0.0000]
[0.2126 0.7152 0.0722 0.0000 1.0000 0.0000]
[0.0193 0.1192 0.9505 0.0000 0.0000 1.0000]
Now that we have the identity matrix on the right, we have to perform the operations to "bring it to the left" so that what we're gonna be left with is gonna be the inverse.
We make the pivot in the 1° column by dividing the first row by 0.4124
[1.0000 0.8671 0.4376 2.4248 0.0000 0.0000]
[0.2126 0.7152 0.0722 0.0000 1.0000 0.0000]
[0.0193 0.1192 0.9505 0.0000 0.0000 1.0000]
we can eliminate the first column
[1.0000 0.8671 0.4376 2.4248 0.0000 0.0000]
[0.0000 0.5308 -0.0208 -0.5155 1.0000 0.0000]
[0.0000 0.1024 0.9420 -0.0467 0.0000 1.0000]
we can make the pivot in the 2° column by dividing the second row by 0.5308
[1.0000 0.8671 0.4376 2.4248 0.0000 0.0000]
[0.0000 1.0000 -0.0392 -0.9711 1.8837 0.0000]
[0.0000 0.1024 0.9420 -0.0467 0.0000 1.0000]
we can eliminate the second column:
[1.0000 0.0000 0.4717 3.2669 -1.6334 0.0000]
[0.0000 1.0000 -0.0392 -0.9711 1.8837 0.0000]
[0.0000 0.0000 0.9460 0.0527 -0.1930 1.0000]
at this point, we're almost there, we make the pivot in the 3° column by dividing the third row by 0.9460
[1.0000 0.0000 0.4717 3.2669 -1.6334 0.0000]
[0.0000 1.0000 -0.0392 -0.9711 1.8837 0.0000]
[0.0000 0.0000 1.0000 0.0557 -0.2040 1.0569]
we can therefore eliminate third column and we're gonna be left with the inverse matrix on the right as we brought the identity to the left:
[1.0000 0.0000 0.0000 3.2408 -1.5372 -0.4986]
[0.0000 1.0000 0.0000 -0.9689 1.8757 0.0415]
[0.0000 0.0000 1.0000 0.0557 -0.2040 1.0569]
so the inverse is:
[3.2408 -1.5372 -0.4986]
[-0.9689 1.8757 0.0415]
[0.0557 -0.2040 1.0569]
we still have to multiply it with the other matrix, though:
[3.2408 -1.5372 -0.4986] [0.6370 0.1446 0.1689]
[-0.9689 1.8757 0.0415] [0.2627 0.6780 0.0593] =
[0.0557 -0.2040 1.0569] [0.0000 0.0281 1.0610]
we can label the output as:
[A B C]
[D E F]
[G H I]
and they're calculated as:
A= 3.2408 x 0.637 + (-1.5372) x 0.2627 + (-0.4986) x 0 = 1.6605
B= 3.2408 x 0.1446 + (-1.5372) x 0.678 + (-0.4986) x 0.0281 = -0.5876
C= 3.2408 x 0.1689 + (-1.5372) x 0.0593 + (-0.4986) x 1.061 = -0.0727
D= -0.9689 x 0.637 + 1.8757 x 0.2627 + 0.0415 x 0 = -0.1244
E= -0.9689 x 0.1446 + 1.8757 x 0.678 + 0.0415 x 0.0281 = 1.1327
F= -0.9689 x 0.1689 + 1.8757 x 0.0593 + 0.0415 x 1.061 = -0.0083
G= 0.0557 x 0.637 + (-0.204) x 0.2627 + 1.0569 x 0 = -0.0181
H= 0.0557 x 0.1446 + (-0.204) x 0.678 + 1.0569 x 0.0281 = -0.1005
I= 0.0557 x 0.1689 + (-0.204) x 0.0593 + 1.0569 x 1.061 = 1.1186
so our final matrix is:
[ 1.6605 -0.5876 -0.0727]
[-0.1244 1.1327 -0.0083]
[-0.0181 -0.1005 1.1186]
Let's put this theory to the test and compare it against HDRTools:
test1=LWLibavVideoSource("Source1.mxf")
test2=LWLibavVideoSource("Source2.mxf")
test3=LWLibavVideoSource("Source3.mxf")
test4=LWLibavVideoSource("Source4.mxf")
test1++test2++test3++test4
propClearAll()
ConvertBits(16)
bt2020=Subtitle("BT2020 SDR")
bt2020_sdr=last
ConvertToPlanarRGB(bt2020_sdr)
Cube("A:\Ingest\MEDIA\temp\BT2020_to_BT709.cube", interp=1, fullrange=1)
ConverttoYUV444(matrix="Rec709")
Subtitle("BT709 SDR LUT")
bt709_cube=last
ConvertYUVtoXYZ(bt2020_sdr, Color=1)
ConvertXYZtoYUV(pColor=1)
Subtitle("BT709 SDR HDRTools")
bt709_hdrtools=last
StackHorizontal(bt2020, bt709_cube, bt709_hdrtools)
https://i.imgur.com/ChCa5iB.png
Looks fine.
To spot the actual differences between this method and the XYZ roundtrip made by HDRTools we have to check solid colors like in those commercials in which the clipping of values outside the BT709 realm done by the LUT becomes very apparent:
https://i.imgur.com/13xNDx8.png
https://i.imgur.com/toQXUX5.png
The difference is pretty clear and it can be seen in both the Colgate and EE backgrounds, with HDRTools actually performing a much better approximation, while the LUT is clipping several values out as it's a simple onto conversion (as every element in the range has at least one corresponding element in the domain) but clearly not one to one (because more elements map to the same destinations). This is also due to the normalizations of value above 1 and below 0. Speaking of values below 0, inside the LUT you're gonna be able to see a bunch of zeroes, that's to avoid issues with non legal values, in fact everything negative has been normalized to 0 to avoid a repetition of frank's issue and more specifically the lut3d implementation (https://forum.doom9.org/showthread.php?t=176091&page=10).
When we test with real life examples, however, the difference becomes much more slim:
https://i.imgur.com/zsKrc5w.png
https://i.imgur.com/yieRpH4.png
https://i.imgur.com/KjfscKN.png
https://i.imgur.com/hUdc4ya.png
https://i.imgur.com/SEhEj3h.png
https://i.imgur.com/hwbX1t7.png
For those who wanna start testing:
BT2020_to_BT709.cube (https://github.com/FranceBB/LinearTransformation/blob/master/BT2020_to_BT709.cube)
wswartzendruber
21st February 2025, 04:34
Regarding my BT.2020-to-BT.709 conversion LUT he mentioned, I have a new one I just generated:
https://wswartzendruber.net/uploads/bt2020to709-2.cube
It should be very similar, but the math is a little tighter. It still uses Oklab/Oklch, so it's as perceptually accurate as that is.
EDIT: I mainly use it for viewing HLG on BT.709 SDR. I may as well include screenshots and peddle my wares!
https://wswartzendruber.net/images/bt2020to709-2/0.jpg
https://wswartzendruber.net/images/bt2020to709-2/1.jpg
https://wswartzendruber.net/images/bt2020to709-2/2.jpg
https://wswartzendruber.net/images/bt2020to709-2/3.jpg
https://wswartzendruber.net/images/bt2020to709-2/4.jpg
https://wswartzendruber.net/images/bt2020to709-2/5.jpg
wswartzendruber
21st February 2025, 17:17
And now I learn that Google has a colorspace called HCT which is supposed to be even better than Oklab. It's based on CAM16, though, so it may be a bit of a doozie to compute.
FranceBB
8th March 2025, 18:02
It feels like a good time to make a release, so... here we are.
Linear Transformation v2.8 Released! (https://github.com/FranceBB/LinearTransformation/releases)
Changelog:
- Implemented a new BT2020 SDR to BT709 SDR conversion.
- Implemented a new BT709 SDR to BT2020 SDR conversion.
To apply those, simply use:
LinearTransformation(Input="Linear_BT2020", Output="Linear_BT709", Interpolation="Tetrahedral")
and
LinearTransformation(Input="Linear_BT709", Output="Linear_BT2020", Interpolation="Tetrahedral")
Or just apply the individual LUTs as always. :)
The roundtrip was also tested (https://i.imgur.com/tRE4Tea.png) and it should work.
Oh and before anyone says anything, yes, I did actually check to make sure we're populating frame properties correctly eheheheh
LWLibavVideoSource("test.mxf")
https://i.imgur.com/9m8K9KY.png
LinearTransformation(Input="Linear_BT2020", Output="Linear_BT709", Interpolation="Tetrahedral"))
https://i.imgur.com/nVq98HN.png
(and I've just realized that I screwed up the screenshot but whatever).
FranceBB
6th April 2025, 14:40
wh0phd pointed out some less than optimal results when performing the conversions to and from BT601 (both PAL and NTSC). Being little used nowadays, the original conversions from 4 years ago didn't quite achieve the expected results, especially for the conversions to and from BT2020 as well as the HLG (arib-std-b67) and PQ (smpte2084) conversions. A review of those was long overdue and as I'm trying to tidy things up I decided to finally spend time on those.
I recreated the matrices by inserting the BT601 PAL, BT601 NTSC, BT709 and BT2020 SDR primaries:
https://i.imgur.com/pOXnOCW.png
https://i.imgur.com/10Nwcqp.png
https://i.imgur.com/hnhrbtd.png
https://i.imgur.com/zmDTG7j.png
The white point stays the same for all of them, so BT601 PAL and BT601 NTSC as well as BT709 and BT2020 SDR, namely
x white = 0.3127
y white = 0.3290
The values for red, green and blue however change.
BT601 PAL has
x red = 0.640
y red = 0.330
x green = 0.290
y green = 0.600
x blue = 0.150
y blue = 0.060
BT601 NTSC has
x red = 0.630
y red = 0.340
x green = 0.310
y green = 0.595
x blue = 0.155
y blue = 0.070
BT709 has
x red = 0.640
y red = 0.330
x green = 0.300
y green = 0.600
x blue = 0.150
y blue = 0.060
BT2020 has
x red = 0.708
y red = 0.292
x green = 0.170
y green = 0.797
x blue = 0.131
y blue = 0.046
The idea here is to repurpose the BT709 conversions that have been created a long time ago and that have been tested over and over again by the community to produce the BT601 ones by just changing the primaries. Let's take for instance the old BT2020 HLG to BT601 PAL conversion: it was remapping the 75% reference white in the luma to 100% and clipping the rest. As to the chroma, it was converting the primaries from the BT2020 ones to the BT601 PAL ones. Now, this is NOT what we're doing in the BT2020 HLG to BT709 SDR conversion as we're keeping the luma in place and only converting the primaries (which is the whole purpose behind HLG given that it would be what a user would see if he bought a BT2020 UHD TV that can't interpret the transfer). So, in the new BT2020 HLG to BT601 PAL conversion we're using the same logic as the BT2020 HLG to BT709 SDR conversion, namely keeping the luma in place and converting the primaries.
This is the old BT2020 HLG to BT601 PAL conversion:
https://i.imgur.com/uejdLUN.png
and this is the new one:
https://i.imgur.com/nkQovET.png
Using the same logic, I could now fill the gap and add the missing BT601 conversions for Slog3, Vlog, LogC and Clog3 as well.
LWLibavVideoSource("C9128.MP4")
ConvertBits(16)
ConvertToPlanarRGB()
Cube("A:\MEDIA\temp\Slog3_to_BT601_PAL", interp=1, fullrange=1)
ConverttoYUV444(matrix="Rec601")
VideoTek()
https://i.imgur.com/jXoAexp.png
LWLibavVideoSource("A002C001_200527_RNMK.mxf")
ConvertBits(16)
ConvertToPlanarRGB()
Cube("A:\MEDIA\temp\LogC_to_BT601_PAL.cube", interp=1, fullrange=1)
ConverttoYUV444(matrix="Rec601")
VideoTek()
https://i.imgur.com/w754Q1J.png
LWLibavVideoSource("A006C002_191214R7_CANON.MXF")
ConvertBits(16)
ConvertToPlanarRGB()
Cube("A:\MEDIA\temp\Clog3_to_BT601_PAL.cube", interp=1, fullrange=1)
ConverttoYUV444(matrix="Rec601")
VideoTek()
https://i.imgur.com/ymJiCMY.png
I also fixed an issue in the old BT601 NTSC to BT601 PAL conversion as well as BT601 PAL to BT601 NTSC. Both LUTs have been regenerated using CIECAT02 instead of the Bradford Chromatic Adaptation. Taking z_ConvertFormat() as a safe reference point (i.e avsresize), I started testing the two conversions.
#BT601 PAL to BT601 NTSC
ColorBars(848, 480, pixel_type="YUV444P16")
SinPowerResize(848, 480)
bt601_pal=z_ConvertFormat(colorspace_op="709:709:709=>470bg:601:470bg", resample_filter_uv="spline64", dither_type="error_diffusion")
bt601_ntsc=z_ConvertFormat(colorspace_op="709:709:709=>170m:240m:240m", resample_filter_uv="spline64", dither_type="error_diffusion")
ConvertBits(bt601_pal, 16)
ConvertToPlanarRGB()
Cube("A:\MEDIA\temp\BT601_PAL_to_BT601_NTSC.cube", interp=1, fullrange=1)
ConverttoYUV444(matrix="Rec601")
Histogram("color2")
ntsc_cube=last
ConvertBits(bt601_pal, 16)
z_ConvertFormat(colorspace_op="470bg:601:470bg=>170m:240m:240m", resample_filter_uv="spline64", dither_type="error_diffusion")
ConverttoYUV444(matrix="Rec601")
Histogram("color2")
ntsc_avsresize=last
StackVertical(ntsc_cube, ntsc_avsresize)
https://i.imgur.com/k35wjJU.png
and the other way round as well
#BT601 NTSC to BT601 PAL
ColorBars(848, 480, pixel_type="YUV444P16")
SinPowerResize(848, 480)
bt601_pal=z_ConvertFormat(colorspace_op="709:709:709=>470bg:601:470bg", resample_filter_uv="spline64", dither_type="error_diffusion")
bt601_ntsc=z_ConvertFormat(colorspace_op="709:709:709=>170m:240m:240m", resample_filter_uv="spline64", dither_type="error_diffusion")
ConvertBits(bt601_ntsc, 16)
ConvertToPlanarRGB()
Cube("A:\MEDIA\temp\BT601_NTSC_to_BT601_PAL.cube", interp=1, fullrange=1)
ConverttoYUV444(matrix="Rec601")
Histogram("color2")
pal_cube=last
ConvertBits(bt601_ntsc, 16)
z_ConvertFormat(colorspace_op="170m:240m:240m=>470bg:601:470bg", resample_filter_uv="spline64", dither_type="error_diffusion")
ConverttoYUV444(matrix="Rec601")
Histogram("color2")
pal_avsresize=last
StackVertical(pal_cube, pal_avsresize)
https://i.imgur.com/ag4PxAW.png
You can already test the new versions on Github, but I'm planning to make a new release next week.
FranceBB
27th April 2025, 18:31
Linear Transformation v2.9 Released! (https://github.com/FranceBB/LinearTransformation/releases/)
Changelog:
- Introduced the new conversions
#Slog3 to BT601 PAL
LinearTransformation(Input="SLog3", Output="Linear_BT601_PAL")
#Slog3 to BT601 NTSC
LinearTransformation(Input="SLog3", Output="Linear_BT601_NTSC")
#Vlog to BT601 PAL
LinearTransformation(Input="VLog", Output="Linear_BT601_PAL")
#Vlog to BT601 NTSC
LinearTransformation(Input="VLog", Output="Linear_BT601_NTSC")
#LogC to BT601 PAL
LinearTransformation(Input="LogC", Output="Linear_BT601_PAL")
#LogC to BT601 NTSC
LinearTransformation(Input="LogC", Output="Linear_BT601_NTSC")
#Clog3 to BT601 PAL
LinearTransformation(Input="CLog3", Output="Linear_BT601_PAL")
#Clog3 to BT601 NTSC
LinearTransformation(Input="CLog3", Output="Linear_BT601_NTSC")
- Improved the existing BT601 conversions (both PAL and NTSC).
- Fixed an issue in the old BT601 NTSC to BT601 PAL conversion as well as BT601 PAL to BT601 NTSC. Both have been regenerated using CIECAT02 instead of the Bradford Chromatic Adaptation.
FranceBB
15th May 2025, 13:56
Linear Transformation v3.0 Released!! (https://github.com/FranceBB/LinearTransformation/releases)
Changelog:
- Added new conversions between the normal BT601 NTSC SMPTE C (1987, smpte170m) and the old BT601 NTSC Japan (1953, bt470m)
#BT601 NTSC SMPTE C (1987) to BT601 NTSC Japan (1953)
LinearTransformation(Input="Linear_BT601_NTSC", Output="Linear_BT601_NTSC-J", Interpolation="Tetrahedral")
#BT601 NTSC Japan (1953) to BT601 NTSC SMPTE C (1987)
LinearTransformation(Input="Linear_BT601_NTSC-J", Output="Linear_BT601_NTSC", Interpolation="Tetrahedral")
- Primaries are now correctly updated in the Avisynth frame properties even for inputs that have an Alpha Channel
This feature was requested by ossnorry.
As a bit of history, in 1953 the NTSC version of BT601 was born, however the tube phosphors originally used by the TVs of the time had issues displaying those values and the standard was later changed (reduced) in 1987 to make life easier for the hardware of the time, however one country never stopped using the original NTSC version and that country is Japan, which is why the original NTSC version has become known as "NTSC-J" which stands for "Japan".
Anyway, the old BT601 NTSC Japan (1953) is based on the following values:
x white = 0.3100
y white = 0.3160
x red = 0.670
y red = 0.330
x green = 0.210
y green = 0.710
x blue = 0.140
y blue = 0.080
and is indicated with
--colormatrix smpte170m --transfer bt470m --colorprim bt470m
while the normal BT601 NTSC SMPTE C (1987) that all other NTSC countries adopted has the following values:
x white = 0.3127
y white = 0.3290
x red = 0.630
y red = 0.340
x green = 0.310
y green = 0.595
x blue = 0.155
y blue = 0.070
and is indicated with:
--colormatrix smpte170m --transfer smpte170m --colorprim smpte170m
As you can see, all values are different, including the white point.
All the LUTs created up until this point that referred to BT601 NTSC were targeting the normal BT601 NTSC SMPTE C (1987), namely smpte170m.
This release allows the conversion between the two BT601 NTSC standards: the old BT601 NTSC Japan (1953), namely bt470m, and the normal BT601 NTSC SMPTE C (1987), namely smpte170m.
Left is BT601 NTSC SMPTE C (1987) - Right is BT601 NTSC-Japan (1953):
https://i.imgur.com/XDTVFAU.png
mojie126
18th May 2025, 07:27
May I ask why there is no conversion from SDR (BT709) to Dolby Vision (DV)?
that's simple what even is DV?
it's just PQ bt 2020.
DV is the same as HDR10+ just encoded with licensing stuff and custom meta data representing the same stuff.
FranceBB
18th May 2025, 22:55
it's just PQ bt 2020.
The one you're referring to is the dual layer, the most common version of Dolby Vision. You're right, in the dual layer you have the first layer as a normal H.265 3840x2160 4:2:0 HDR PQ 10bit planar track and the second layer as a fake H.265 1920x1080 4:2:0 10bit which is actually carrying metadata (it would look green if you tried to decode it on its own). Normal players ignore the second layer and just play the first one as a normal HDR10. Dolby Vision players can read the metadata track and combine it with the first to output 12bit HDR PQ with dynamically changing metadata.
Now, obviously making a LUT for such a thing wouldn't make sense, which is why I'm pretty sure that mojie126 is actually referring to dvhe0509. You see, dvhe0509 is actually a proprietary Dolby space (IPTc2) and the videos encoded with it are not supposed to be played back by normal devices. If you were to playback such a file, you would see the luma resemble a pseudo SDR curve and the chroma being with totally different values.
See here: https://forum.doom9.org/showthread.php?p=1964646
And here in this thread: https://forum.doom9.org/showthread.php?p=1964642#post1964642
May I ask why there is no conversion from SDR (BT709) to Dolby Vision (DV)?
I should actually give you a bit more context over how we made the dvhe0509 to BT709 LUT. Essentially, that dates back to February 2022 when algia (Livio Aloja, one of my colleagues, now retired) and I worked on it. Essentially, given that there was no documentation whatsoever, we couldn't really properly revert it and get an appropriate output in BT709. I mean, sure, we knew how things like the grass or the sky should roughly look like but it was really mostly guesswork and we were not really going anywhere. That changed when we got our hands on the Harmonic samples. You see, Harmonic published a few videos encoded in both dvhe0509 and BT709 so, with a lot of patience, armed with a lot of dedication and good will, we went through those one by one and we essentially mapped each and every value found in the dvhe0509 IPTc2 samples to the corresponding value in the BT709 SDR samples and from there we got the LUT. As to the luma, given that it resembled an SDR curve, we left it alone. The results were actually pretty decent even if we were ignoring the Dolby metadata alongside that.
LinearTransformation(Input="dvhe0509", Output="Linear_BT709")
https://i.imgur.com/PGtRZQm.png
Now, surely we could just reverse it so that we could potentially use the same logic to go from BT709 to a "fake" dvhe0509 IPTc2 and we could probably even get the values somewhat right but we would have no way of writing the correct metadata as we still wouldn't be able to generate the appropriate RPU. I'm pretty sure that no Dolby Vision decoder would accept a stream without the relevant metadata, so I guess we're stuck with this... :(
Z2697
18th May 2025, 23:13
The essential part is dynamic metadata and the colormatrix. (the latter is less essential)
Both are not under the charge of this LUT collection.
Z2697
18th May 2025, 23:29
The one you're referring to is the dual layer, the most common version of Dolby Vision. You're right, in the dual layer you have the first layer as a normal H.265 3840x2160 4:2:0 HDR PQ 10bit planar track and the second layer as a fake H.265 1920x1080 4:2:0 10bit which is actually carrying metadata (it would look green if you tried to decode it on its own). Normal players ignore the second layer and just play the first one as a normal HDR10. Dolby Vision players can read the metadata track and combine it with the first to output 12bit HDR PQ with dynamically changing metadata.
Now, obviously making a LUT for such a thing wouldn't make sense, which is why I'm pretty sure that mojie126 is actually referring to dvhe0509. You see, dvhe0509 is actually a proprietary Dolby space (IPTc2) and the videos encoded with it are not supposed to be played back by normal devices. If you were to playback such a file, you would see the luma resemble a pseudo SDR curve and the chroma being with totally different values.
See here: https://forum.doom9.org/showthread.php?p=1964646
And here in this thread: https://forum.doom9.org/showthread.php?p=1964642#post1964642
I should actually give you a bit more context over how we made the dvhe0509 to BT709 LUT. Essentially, that dates back to February 2022 when algia (Livio Aloja, one of my colleagues, now retired) and I worked on it. Essentially, given that there was no documentation whatsoever, we couldn't really properly revert it and get an appropriate output in BT709. I mean, sure, we knew how things like the grass or the sky should roughly look like but it was really mostly guesswork and we were not really going anywhere. That changed when we got our hands on the Harmonic samples. You see, Harmonic published a few videos encoded in both dvhe0509 and BT709 so, with a lot of patience, armed with a lot of dedication and good will, we went through those one by one and we essentially mapped each and every value found in the dvhe0509 IPTc2 samples to the corresponding value in the BT709 SDR samples and from there we got the LUT. As to the luma, given that it resembled an SDR curve, we left it alone. The results were actually pretty decent even if we were ignoring the Dolby metadata alongside that.
LinearTransformation(Input="dvhe0509", Output="Linear_BT709")
Now, surely we could just reverse it so that we could potentially use the same logic to go from BT709 to a "fake" dvhe0509 IPTc2 and we could probably even get the values somewhat right but we would have no way of writing the correct metadata as we still wouldn't be able to generate the appropriate RPU. I'm pretty sure that no Dolby Vision decoder would accept a stream without the relevant metadata, so I guess we're stuck with this... :(
Some discs have full enhance layer and the track contain some kind of diff of I guess 12bit to the 10bit of main track.
Which probably look like some noise. The track has low bitrate still, so it will look terrible, but at least it still does something I guess...
Is that dvhe0506 conversion works as converting it to RGB using Rec.709 matrix then "correct" the wrong RGB?
FranceBB
19th May 2025, 07:52
Is that dvhe0506 conversion works as converting it to RGB using Rec.709 matrix then "correct" the wrong RGB?
Pretty much, yes. Far from ideal, but it gets the job done.
The one you're referring to is the dual layer, the most common version of Dolby Vision. You're right, in the dual layer you have the first layer as a normal H.265 3840x2160 4:2:0 HDR PQ 10bit planar track and the second layer as a fake H.265 1920x1080 4:2:0 10bit which is actually carrying metadata (it would look green if you tried to decode it on its own). Normal players ignore the second layer and just play the first one as a normal HDR10. Dolby Vision players can read the metadata track and combine it with the first to output 12bit HDR PQ with dynamically changing metadata.
glad to say we are past that and on the fly none LUT DV to HDR10 is a pretty default feature now. pretty much LLDV or what the name was DV handling at the source. this was done with a 3D LUT ion the past
the DV encoder got bt 2020 PQ to eat and the display is presenting bt 2020 PQ at the end.
itp instead of ycbcr a meta data lever or what ever does not change that. how many types of DV are there 12?
Some discs have full enhance layer and the track contain some kind of diff of I guess 12bit to the 10bit of main track.
Which probably look like some noise. The track has low bitrate still, so it will look terrible, but at least it still does something I guess...
Is that dvhe0506 conversion works as converting it to RGB using Rec.709 matrix then "correct" the wrong RGB?
there was a DV level that had highlights encoded in a 2 bit level that is 1080p it's so insanely useless it is still 10000 nits PQ bt 2020 just in a different container and yes a DV file can look quite different from a normal HDR10+ because it was mastered differently.
rwill
19th May 2025, 18:15
there was a DV level that had highlights encoded in a 2 bit level that is 1080p it's so insanely useless it is still 10000 nits PQ bt 2020 just in a different container and yes a DV file can look quite different from a normal HDR10+ because it was mastered differently.
So which TV's panel supports 10000nits so that you can watch that 10000 nits PQ10 without having to downmap it to the display guided by metadata?
So which TV's panel supports 10000nits so that you can watch that 10000 nits PQ10 without having to downmap it to the display guided by metadata?
none and you don't use meta data to do so. any device is measuring peak nit by a frame by frame basin meta data is really just there.
even SDR screen are doing that for decades.
rwill
20th May 2025, 04:19
none and you don't use meta data to do so.
The non Dolby Vision TVs maybe don't use metadata to do so... but there the content looks different from TV to TV which has its downsides too...
Z2697
20th May 2025, 17:00
there was a DV level that had highlights encoded in a 2 bit level that is 1080p it's so insanely useless it is still 10000 nits PQ bt 2020 just in a different container and yes a DV file can look quite different from a normal HDR10+ because it was mastered differently.
Do you mean the "disappeared" profile 4? There's no much info about it, but seems like it uses an SDR base layer, so you mean it's then using the EL to encode all the highlights?
Profile 7 is different, it looks like some sort of difference between bit depths. Being low resolution and low bitrate it should only improve "effective bit depth" marginally. And yeah being a "gradient enhancer" it technically shouldn't look much difference, if any.
LouieChuckyMerry
4th August 2025, 22:12
FranceBB: I hope you've been well :) . A couple years ago you were kind enough to help me come to a (barely, ha ha) functional enough understanding of your LUT Collection (v2.3 at the time) to tone map from BT2020 PQ to BT709 using your "PQ_to_BT709_v1.cube". Recently I attacked my 4K UHD Blu-ray of Stanley Kubrick's 1975 masterpiece Barry Lyndon and, upon comparing it to my 2K Blu-ray I discovered that the colors seem off a bit. Here's a frame of the 2K and the 4K to compare:
https://www.mediafire.com/file/peazbv8wgve8zez/BLyndon{2KVs4K]..7z/file (https://www.mediafire.com/file/ndez1is0otfwypx/BLyndon{2KVs4K]..7z/file)
To my eyes the original 2K looks better than the tone mapped 4K, so I'm wondering if you had a(ny) suggestion(s). I've downloaded your latest v3, but perhaps that's not the issue. Anyway, thanks for any input.
FranceBB
4th August 2025, 23:08
Hey Louie, I'm doing well, but I'm in the middle of changing flat as I'm moving closer to my workplace, namely at a 10 minutes walk from the office, which is always nice.
I took a quick look at the two versions, but if you could upload the same frame in PQ it would definitely help.
LouieChuckyMerry
5th August 2025, 00:07
I've updated the link to include your request and, please, I'm in absolutely zero hurry, so focus on your move (congratulations!).
FranceBB
24th August 2025, 01:19
I've updated the link to include your request and, please, I'm in absolutely zero hurry, so focus on your move (congratulations!).
I looked at the 4K screenshot, but that isn't really a BT2020 PQ screenshot. Some kind of conversion happened before it got captured, I'm afraid.
In other words, this isn't BT2020 PQ:
https://i.imgur.com/lG2hIap.png
If you manage to get the actual original BT2020 PQ screenshot out I can actually try to play with it and see what I'm dealing with. I can also use other tonemapping algorithms eventually like Reinhard and provide an actual script or indeed play with the sample and generate a different LUT. A way to do this would be to index via LWLibavVideoSource() in Avisynth and then grab the screenshot of the PQ source by right clicking and saving as PNG lossless via AVSPmod mod.
Given that 203 nits looks suspiciously familiar, what I think happened here is that *something* converted the screenshot from BT2020 to BT709 in terms of colormatrix, but it didn't deal with the transfer (i.e the color curve) at all.
Anyway, when it comes to the difference between the output from the LUT and the official BT709 version, the first thing that we can notice is the difference in luma:
https://i.imgur.com/wQjY469.png
The official version almost peaks at 0.70V which is 100 nits in BT709 SDR (it actually peaks at 90 nits a tiny bit below) while the output from the LUT peaks much lower at around 0.5V which is around 70 nits. If we take the sky as our reference to reach 100 nits and we assume that we're gonna stay consistently at that level through the movie (which is almost definitely the case given that it's a re-scan and grade of a 1975 film) I'm sure we can get something better out of it.
LouieChuckyMerry
27th August 2025, 02:50
FranceBB: Thank you so much for your reply :) . I won't be able to do as you request until the weekend but, off the top of my head, I'm wondering if taking a frame from the resultant UtVideo file, after using your LUT to tone map, is the issue. When I've the time this weekend I'll re(rere..., ha ha)read your above post and attack. Thanks again, and I hope your move went as well as possible.
LouieChuckyMerry
31st August 2025, 19:31
Thanks for your patience. Here's an(other) updated link:
https://www.mediafire.com/file/vi0qlbqunuue683/BarryLyndon%255B2KVs4K%255D.zip/file
The .png file is a screenshot from MPC-BE from the Criterion 4K video; I hope this is what you want.
FranceBB
9th September 2025, 15:20
It's still not PQ. At this point if you could just trim a tiny bit of that scene it will probably be better.
Either that, or if you wanna keep going with the image just index the file and then save the png using AVSPmod mod.
For reference, the picture you sent was:
https://i.imgur.com/aGSIKEo.png
while it should have been something like:
https://i.imgur.com/qv3ZBaW.png
In this second example I'm taking the BT709 SDR tonemapped version and I'm converting it back to BT2020 HDR PQ just to show you how a totally logarithmic curve is supposed to look like.
The waveform is mostly in the middle, the black is supposed to start high.
LouieChuckyMerry
11th September 2025, 01:04
Roger, Roger. Here's a link to a three-second clip from the Criterion UHD Blu-ray: TestClipBarryLyndon4K (https://www.mediafire.com/file/xw4i3ec91z7sy33/TestClipBarryLyndon4K.zip/file)
FranceBB
11th September 2025, 21:50
Alright, now we're talking.
The scene is perfect as it also has the clouds in the sky and from the official BT709 SDR version we know that those are supposed to almost peak at 0.7V or 100 nits, so we can adjust with that in mind. The reason why the whole thing is much dimmer than the official version is that the PQ is peaking at around 180 nits as we can see from here:
https://i.imgur.com/eTTmuz0.png
Using Reinhard tonemapping with appropriate tweaking the result isn't that bad and still maintains a rather soft look, but it is still relatively different from the official source:
LWLibavVideoSource("TestClipBarryLyndon4K.mkv")
ConvertBits(16)
ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=8.5, contrast_X=0.9, exposure_Y=8.5, contrast_Y=0.9, exposure_Z=8.5, contrast_Z=0.9)
ConvertXYZtoYUV(pColor=0)
Converttoyuv420()
https://i.imgur.com/jp3XwJo.png
The one that gets us much closer to the official version in this case is Mobius that allows us to make it peak exactly at the same point as the official SDR source. In this case, we can see that the highlights of the sky on the left have the same brightness, however there's a non insignificant deviation on the chroma which is visible on the grass on the right.
LWLibavVideoSource("TestClipBarryLyndon4K.mkv")
ConvertBits(16)
ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)
ConvertXYZ_Mobius_HDRtoSDR(exposure_X=58.5, exposure_Y=58.5, exposure_Z=58.5)
ConvertXYZtoYUV(pColor=0)
Converttoyuv420()
https://i.imgur.com/i3KhArC.png
Lastly here's the same output using Hable:
LWLibavVideoSource("TestClipBarryLyndon4K.mkv")
ConvertBits(16)
ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)
ConvertXYZ_Hable_HDRtoSDR(exposure_X=20, exposure_Y=20, exposure_Z=20)
ConvertXYZtoYUV(pColor=0)
Converttoyuv420()
https://i.imgur.com/fZ13MRr.png
Keep in mind that in my new location I still don't have a proper monitor, so I might even be talking rubbish here, but from the waveform and the tiny and relatively crappy laptop display on the Suckdows 11 Enterprise x64 computer I'm writing from I would suggest you to go with Mobius tonemapping and the 16bit planar precision XYZ roundtrip.
LouieChuckyMerry
14th September 2025, 22:05
"...I would suggest you to go with Mobius tonemapping and the 16bit planar precision XYZ roundtrip."
_____________
As an enthusiastic-if-somewhat-clueless, semi-dedicated video encoding hobbyist, I quote Professor Farnsworth: A wha...?
Seriously, I have a reasonable clue but want to make certain. The original script I used (that didn't look quite right; and, thanks again, you helped me sort this out several years ago) was:
LWLibavVideoSource("Path")
ConvertToPlanarRGB(Matrix="Rec2020",Interlaced=False)
ConvertBits(Bits=16)
Spline36Resize(1920,1080).Sharpen(0.2)
Cube("F:\InstalledPrograms\AviSynth+\LUTs\PQ_to_BT709_v1.cube",Fullrange=True)
ConvertToYUV420(Matrix="Rec709")
Now, you're suggesting I use:
LWLibavVideoSource("Path")
ConvertBits(16)
Spline36Resize(1920,1080).Sharpen(0.2)
ConvertYUVToXYZ(Color=0,OutputMode=1,HDRMode=0,Fullrange=False)
ConvertXYZ_Mobius_HDRToSDR(Exposure_X=58.5,Exposure_Y=58.5,Exposure_Z=58.5)
ConvertXYZtoYUV(pColor=0)
ConvertToYUV420()
instead?
A couple sub-questions:
1) Does the order of "ConvertToPlanar.../ConvertYUVToXYZ..." and "ConvertBits(Bits=16)" matter?
2) Do I need to change "ConvertToYUV420()" in your new suggestion to "ConvertToYUV420(Matrix="Rec709")" as in the original script?
EDIT: And I understand your monitor dilemma; I've a fifteen-year-old ThinkPad with a 1600x900 display that's rather lacking.
FranceBB
17th September 2025, 21:07
1) Does the order of "ConvertToPlanar.../ConvertYUVToXYZ..." and "ConvertBits(Bits=16)" matter?
Yep. There's nothing stopping you from doing the conversion with 8bit planar precision, obviously, but the result would be full of banding and other artifacts. Unlike YUV, when you're working in XYZ you're dealing with a very big space, which means that the effect of working with 8bit precision would be so high that the result would be terrible. It's not just subtle banding problems, you're gonna notice the rounding introduced artifacts, which is why I recommend working with at least 16bit planar precision, but you could totally go with 32bit float instead if you wanna play it safe. So, yes, the order matters 'cause we're first converting to high bit depth, so we have a bunch of zeroes (if you were to look at the values) and then we perform the conversion to XYZ by making use of this new precision all the way through the entire processing.
2) Do I need to change "ConvertToYUV420()" in your new suggestion to "ConvertToYUV420(Matrix="Rec709")" as in the original script?
Oh yes, absolutely. Also, if we wanna be pedantic, given that we're sadly living in a world in which frame properties are a thing, the final output would be:
#Indexing
LWLibavVideoSource("Path")
#Screw frame properties
PropClearAll()
#Bringing everything to 16bit planar
ConvertBits(16)
#Upscale with 16bit precision
Spline64ResizeMT(1920, 1080)
#Bringing everything to XYZ with 16bit precision
ConvertYUVToXYZ(Color=0, OutputMode=1, HDRMode=0, Fullrange=False)
#BT709 SDR Tonemapping with 16bit precision
ConvertXYZ_Mobius_HDRToSDR(Exposure_X=58.5, Exposure_Y=58.5, Exposure_Z=58.5)
#Bringing everything back to YUV with 16bit precision
ConvertXYZtoYUV(pColor=0)
#Converting to 4:2:0 with 16bit precision
ConvertToYUV420(Matrix="Rec709")
#Dithering with Floyd Steinberg Error Diffusion
ConvertBits(bits=8, dither=1)
#Populate frame properties
propSet("_ColorRange", 1) #Limited TV Range
propSet("_Matrix", 1) #BT709
propSet("_Transfer", 1) #BT709
propSet("_Primaries", 1) #BT709
In this case I used the "MT" version of the resizers rather than the internal Avisynth version as the multithreaded version not only is faster but it also if you use plugins_JPSDR.dll there will be a common threadpool between the resizers, the tonemapper and the conversion to and from XYZ. :)
By the way, you can still use my LUT to perform the conversion instead of a tonemapper, obviously. When it comes to performing this kind of conversion, there isn't a generic way to do it, you're gonna have to try and adjust on a content-by-content basis. Effectively, you can use my VideoTek() to check the source and then find a point in which there's something white, so something that "peaks" and then use that one as your reference to bring it to 100 nits in BT709 SDR, so 0.7V in the graph. Of course, when it comes to HDR PQ, it's not exactly this simple in the sense that you might have some scenes skyrocketing high while some others are relatively low, so you may not always wanna use the MaxCLL as your reference. A simple example is the remastered version of the Harry Potter movies. Harry Potter and the Prisoner of Azkaban peaks at 1838 nits while Harry Potter and the Goblet of Fire peaks at a whopping 2848, but this is only due to the special effects (i.e the magic spells) which are computer rendered anyway and were brought extremely high to enhance their visual effect. The rest of the scenes of the movies were much lower as those were shot in 2005 with SDR in mind, so by bringing 2848 nits down to 100 with a static LUT would make all the other scenes pitch dark and it would be very hard to distinguish what's going on. This is to say that there isn't something you can copy-paste and that it's gonna work all the time for every content. In my LUTs I tried to get the best compromise so that it's gonna be good enough for the vast majority of contents. Even in this peculiar case, for instance, the result was too dim but it wasn't bad and that's the whole point. :)
Ideally one would use a dynamically changing tonemapping like the one in MPV that automatically adapts on a scene by scene basis to bring the peak brightness back to 100 nits and you have thresholds that you can adjust based on the differences in blocks on what is considered a scene, however even that might lead to undesirable results like in Riviera when Georgina was walking and she was lit by the light and then in the dark and then lit and then in the dark and the dynamically adjusting tonemapper tried to bring everything up, then down, then up, then down, then up, then down etc and the result wasn't pleasant as it was more distracting than watching the output of a static LUT. Once again, there's no perfect solution.
I understand your monitor dilemma; I've a fifteen-year-old ThinkPad with a 1600x900 display that's rather lacking.
True, but I'm spoiled because at work in the old office I used to watch contents on the Sony BVM-HX310. It's quite old now, but it was amazing back in 2018.
LouieChuckyMerry
25th September 2025, 00:17
By the way, you can still use my LUT to perform the conversion instead of a tonemapper, obviously.
Thanks for your patience, FranceBB :) .
Since you helped me settle on it several years ago (https://forum.doom9.org/showpost.php?p=1988873&postcount=256), I've been happily using the script
LWLibavVideoSource("PATH")
ConvertToPlanarRGB(Matrix="Rec2020",Interlaced=False)
ConvertBits(Bits=16)
Spline36Resize(1920,1080)
Cube("F:\InstalledPrograms\AviSynth+\LUTs\PQ_to_BT709_v1.cube",Fullrange=True)
ConvertToYUV420(Matrix="Rec709")
PreFetch(8)
to downscale and convert my 4K sources to 2K before sprucing them up (with vsDeblockPP7, TemporalDegrain2, and CAS) then shrivelling them (with 10bit x264). The only reason I returned with more questions, is because I noticed that the sky in the upper-left of the duelling scene--one of my favo(no "u"!)rite shots ever; the clouds, the tree branches, the rock wall, the figures on a landscape, endless brilliance--after using your above LUT to convert the 4K Criterion to 2K, was lacking the slightly pinkish hue present in the 2K Criterion.
Anyway, your source-specific script
LWLibavVideoSource("Barry Lyndon PATH")
PropClearAll()
ConvertBits(Bits=16)
Spline64ResizeMT(1920,1080)
ConvertYUVToXYZ(Color=0,OutputMode=1,HDRMode=0,Fullrange=False)
ConvertXYZ_Mobius_HDRToSDR(Exposure_X=58.5,Exposure_Y=58.5,Exposure_Z=58.5)
ConvertXYZtoYUV(pColor=0)
ConvertToYUV420(Matrix="Rec709")
ConvertBits(Bits=8,Dither=1)
PropSet("_ColorRange",1)
PropSet("_Matrix",1)
PropSet("_Transfer",1)
PropSet("_Primaries",1)
PreFetch(8)
seems to have rectified this but, of course of course, it's also led to several (more) questions:
1) Why, exactly, would I want to start the script with "PropClearAll()"?
2) Is it always best to have "ConvertBits(16)" before converting, I think, the colorspace?
3) What's the difference, and is it important, between "ConvertToPlanarRGB(Matrix="Rec2020",Interlaced=False)" from the original script and "ConvertYUVToXYZ(Color=0,OutputMode=1,HDRMode=0,Fullrange=False)" from the "updated" script?
4) I'm pretty sure that "ConvertXYZ_Mobius_HDRToSDR(Exposure_X=58.5,Exposure_Y=58.5,Exposure_Z=58.5)" is specific to Barry Lyndon; but, what about "ConvertXYZtoYUV(pColor=0)"?
5) Do I really need "ConvertBits(Bits=8,Dither=1)" if I'm going to use the resultant lossless video file from downscaling-converting to then deblock-denoise-sharpen in 10bit x264?
6) Do I really need "PropSet("_ColorRange",1), PropSet("_Matrix",1), PropSet("_Transfer",1), PropSet("_Primaries",1)" at the end of the script if my 10bit x264 command line contains "--colorprim bt709 --transfer bt709 --colormatrix bt709"?
I reckon that what I'm truly wondering is how best to combine the two above scripts, given my usage, into a single, generally functional script that's an improvement on the original script you helped me settle on two-plus years ago. And, I realize that you're a busy person with a busy life, so no need for any chop-chop response. Some day I might actually be able to retire and devote myself to video encoding. A man can dream...
Z2697
26th September 2025, 05:58
Oh yes, absolutely. Also, if we wanna be pedantic, given that we're sadly living in a world in which frame properties are a thing, the final output would be:
Why is it sad?
roccomarco
26th September 2025, 21:54
Hi,
I try to apply a lut in avisynth into my Dji mini 4 drone file that produce HLG mp4 files
I wonder: is there a suitable lut for it? in avisynth, I think input is HLG and output is bt709
thanks
FranceBB
27th September 2025, 01:09
1) Why, exactly, would I want to start the script with "PropClearAll()"?
It really depends, but I personally use it in every encode I make because I'm used to the "old" way of managing things within Avisynth.
Let me explain.
Up until a few years ago there were only clip properties within the frameserver. This was the way things were and how people were used to do things. This basically meant that after indexing the clip properties were gonna be populated with some extremely basic information and then when you called a function if you actually specified the parameters then the function would use those, otherwise it would use the default ones. This basically meant that you knew exactly which parameter a function would be using if you didn't specify them as those were the default ones. This worked beautifully for years and years for the internal needs of this community as the overwhelming majority of people were literally indexing, filtering stuff out and then manually re-encoding with x262, xvid, x264, x265 and so on. In those cli encoders you can specify the various options to populate the metadata like --colorprim bt709 --transfer bt709 --colormatrix bt709 --range tv anyway so everything was fine, but what about automation? What about interacting seamlessly with other software? For that, you needed something better, which is why frame properties were introduced. Effectively frame properites are some "properties" that get populated for every frame and can change within those. This allowed lots of new possibilities like managing changing live streams in NDI as the transition from SDI with hardware routing to actual IP packets is happening or indeed it allowed automated filterchains to integrate with the users.
For instance, if you were to have a system perform some kind of operations but you also wanted to perform some modifications in Avisynth you would need to tell the system what exactly you've done to the stream. With frame properties the software getting the uncompressed A/V output from Avisynth (be it another frameserver and collection of tools like FFMpeg or a player like MPV etc) it would immediately know what it's dealing with and treat it correctly.
In FFAStrans (FFMpeg Avisnth Transcoder) (https://forum.doom9.org/showthread.php?t=176655) for instance, there's something called the filter_builder. Essentially, when you build an encoding workflow, the filter_builder is the one responsible to analyze the source (Mediainfo, ffprobe, exiftool, ffms2 etc), check the destination you want to create in terms of encoding, and then "build" the "filterchain" (hence the name) to create a path between the source and the destination so that the uncompressed A/V stream coming out is already ready to be encoded by the actual encoder (like x264) as it has already taken care of converting everything from the framerate to the chroma location to the sampling to the bit depth to the colormatrix, transfer and primaries etc. Now, if the user wanted to make some modifications using a custom avisynth script, he could, however back when only the clip properties were available, he couldn't tell the filter_builder what he had changed, so either he was gonna write a bunch of conditionals and take care of all the possible input combinations to then just tell the filter_builder "hey, don't do anything, just pass this through to the encoder, I got this" or he could just perform filtering like denoise, debanding etc but not change any of the properties of the stream to then allow the filter_builder to still build the filterchain. When the frame properties have been introduced, the user had - for the first time - the ability to actually tell the filter_builder what he has done and what it's gonna get, thus unlocking lots of different possibilities.
So... all is good and frame properties are good, right? Well, not quite. You see, unfortunately Avisynth has been without frame properties for quite some time which means that when they've been introduced there were lots of filters that didn't really support them. Some of them started interpreting them and changing them after they're called, some others kept using the same default parameters without changing the frame properties but preserved them as they basically passed them through to the next filter, while some other again just didn't support them at all and nuked them after they were invoked. This led to some unfortunate issues.
Take your example with my original script with Cube() for instance: the function "cube" is performing the conversion as it's applying my values to map BT2020 PQ to BT709 SDR, however such a function has no clue about what it's doing, all it knows is that it's taking some values in input and it's applying a transformation to map those in an output according to what is defined in the file using either trilinear or tetrahedral interpolation.
This means that it cannot and does not change the frame properties which means that if your source had smpte2084 with bt2020nc, it will still say that after the conversion which in turn means that every filter you call after that will still think that it's dealing with a PQ stream while actually it's dealing with a BT709 SDR one.
This is why I'm using PropClearAll() all the time in my manual encodes as I know what I'm doing given that this isn't an automatically generated script but I'm writing it and therefore I'm happy to pass the parameters I require while letting the other unspecified ones as default.
At work, however, basically all the 304 Avisynth workflows I made have frame properties correctly preserved / modified / populated to tell either the filter_builder or the other systems that come next what they're getting. :)
Why is it sad?
Basically everything I said above. ;)
The sad thing is that not everything supports it and with some plugins being abandoned they never will, so we're currently in a state in which we have to add a bunch of PropSet() in the scripts and be extra careful about what's going on.
2) Is it always best to have "ConvertBits(16)" before converting, I think, the colorspace?
Yep, it's always nice to have more precision and it shows.
3) What's the difference, and is it important, between "ConvertToPlanarRGB(Matrix="Rec2020",Interlaced=False)" from the original script and "ConvertYUVToXYZ(Color=0,OutputMode=1,HDRMode=0,Fullrange=False)" from the "updated" script?
In the first case you're going to 16bit planar RGB which is a relatively normal space and it's the one required to perform the transformation as the values described in the LUT are actually RGB values (either full pc range or limited tv range according to who created it, but in mine it's always full pc range and never limited / narrow range / studio rgb). I know that the guys at Warner Bros for instance have all their LUTs working in Studio RGB (i.e Narrow Range / Limited TV Range RGB). Anyway, we're digressing. The point is that it's what you require to perform the conversion. When it comes to tonemapping, instead, this could be done in RGB as well, however it's generally performed in a much wider space, namely XYZ. You see, XYZ is way bigger and allows for far better precision, especially if you use 32bit float. If you've ever watched a movie at the cinema, those are played from a DCP (Digital Cinema Package) (https://forum.doom9.org/showthread.php?p=1979437) which is in DCI P3 XYZ 4:4:4 12bit. Anyway in your case, with tonemapping, going through an XYZ roundtrip rather than an RGB roundtrip allows us to work in a much wider space with far better precision.
4) I'm pretty sure that "ConvertXYZ_Mobius_HDRToSDR(Exposure_X=58.5,Exposure_Y=58.5,Exposure_Z=58.5)" is specific to Barry Lyndon; but, what about "ConvertXYZtoYUV(pColor=0)"?
Correct, the tonemapping with Mobius is specific to Barry Lyndon and can't be applied generally to every content all the time without checking the actual waveform and where it peaks in terms of nits. On the other hand ConvertXYZtoYUV(pColor=0) is simply a conversion from XYZ to YUV that specifies BT709. By the way I first started experimenting with those back in 2018 (https://forum.doom9.org/showthread.php?t=175488&page=4) when Jean Philippe Scotto di Rinaldi (i.e JPSDR) implemented them in HDRTools. We're friends and back then we even shared test builds, a few experiments and several test files. We still are to this very day. :)
5) Do I really need "ConvertBits(Bits=8,Dither=1)" if I'm going to use the resultant lossless video file from downscaling-converting to then deblock-denoise-sharpen in 10bit x264?
Oh, no, feed x264 with the 16bit planar output from Avisynth and it will perform the dithering to 10bit at the very end in a very efficient way using the Sierra A2-4 Error Diffusion, which is the way it's intended. I do that all the time when I encode XAVC Intra Class 300 files in BT709 and BT2020 HLG at work :)
6) Do I really need "PropSet("_ColorRange",1), PropSet("_Matrix",1), PropSet("_Transfer",1), PropSet("_Primaries",1)" at the end of the script if my 10bit x264 command line contains "--colorprim bt709 --transfer bt709 --colormatrix bt709"?
You're fine, x264 doesn't care at all about frame properties, it only reads the good old clip properties, so you're fine. Oh, don't forget --range tv, though. ;)
I reckon that what I'm truly wondering is how best to combine the two above scripts, given my usage, into a single, generally functional script that's an improvement on the original script you helped me settle on two-plus years ago.
No need, you can keep using the original script. Consider this as a "one off", however if you have a bit of time and wanna experiment a bit, you can use my function VideoTek() (https://forum.doom9.org/showthread.php?t=175249) to check the waveform of the inputs and see where they peak and based on that use the appropriate values in the tonemapping function to get the best result. Other than that, if you want a fire-and-forget approach, you're gonna be more than fine with my initial script.
By the way, it uses trilinear by default and you should update to the latest version and use
Cube("test.cube", fullrange=1, interp=1)
instead. I wrote a paragraph on the wiki (http://avisynth.nl/index.php/AVSCube) about trilinear vs tetrahedral interpolation. Here's a snipped from it:
Trilinear interpolation is used by default only for historical reasons.
When Cube() was first developed it only had one interpolation method, namely trilinear.
Although this was far from ideal as it can produce ripples, plenty of people used it (as they were using this function), therefore when tetrahedral was introduced it was agreed to leave trilinear as default to allow people to still obtain the same results when upgrading the version.
However, in practice, tetrahedral should always be used and it's the suggested method.
Source (left) - Trilinear (center) - Tetrahedral (right):
https://i.imgur.com/qlu1T2X.png
Keep in mind that if you were to send a test pattern back to Sony after encoding and applying trilinear interpolation, they would refuse it as the plot in 3D space would show a deviation of the actual values from the expected ones.
https://i.imgur.com/IxxdXGT.pnghttps://i.imgur.com/2nKitu4.png
however they would pass the same file when encoded using the tetrahedral interpolation.
And, I realize that you're a busy person with a busy life, so no need for any chop-chop response.
No worries, I'm mostly busy with my job at the moment, but - and this is related to the reason why I moved - we're actually doing something amazing which is building a group platform under Comcast for all the Sky across the world, streamlining all the various processes. This led to several challenges but it's also particularly rewarding and the team even got a public award for this. Obviously Avisynth is (and will continue to be) an instrumental part of all of this. After all, it's the best frameserver in the world. :D
Some day I might actually be able to retire and devote myself to video encoding. A man can dream...
I honestly and seriously consider myself one of the luckiest guys alive as I'm literally doing this day in and day out at work. Nowadays it kinda shifted from manually encoding files, filtering them to get the perfect compositing etc for the production department to actually code and write supply chains, workflow integrations etc. Still, I've had my fun with a few Sky Original Productions in the past. :)
Ironically, the day I retire, I will miss the Avisynth servers I set up and the code I wrote to make it all work and glue together with the other systems. People at the office often joke that I'm "married to this company" but seriously those servers are the closest thing I have to "children" eheheheheheheheh
Jokes aside, we'll see what the future holds as I won't be able to retire for at least another 27 years anyway, so who knows what we're gonna be talking about in so many years and who knows if the servers are forever gonna be there. Time will tell.
is there a suitable lut for it? in avisynth, I think input is HLG and output is bt709
If the input is HLG and the output you want is BT709 SDR then you can totally use the HLG_BT2020_to_Linear_BT709.cube either directly using the Cube() function
ConvertBits(16)
ConvertToPlanarRGB()
Cube("C:\Programmi\AviSynth+\LUTs\HLG_to_BT709.cube", fullrange=1, interp=1)
Converttoyuv420()
or using my LinearTransformation (https://github.com/FranceBB/LinearTransformation) like this:
LinearTransformation(Input="BT2020_HLG", Output="Linear_BT709")
roccomarco
30th September 2025, 16:14
Hi for kindness this is my todays example footage from d*i o*mo 3 pocket
https://www.swisstransfer.com/d/3aab4bc1-fb45-4c63-b851-2336621fb68c
that contain the same scene using normal profile and hlg
(1Normal.MP4 / 1HLG.MP4 - 2Normal.MP4 / 2HLG.MP4 - 3Normal.MP4 - 3HLG.MP4)
I try to do a batch that process this camera that when retrieve the arib-std-b67 (if "%color_transferA%"=="arib-std-b67" ...) do the correct avisynth script that generate the rec.709 output
so I wonder: what can it be the correct script to process the source, for example 1HLG.MP4?
can I process all HLG sources in batch mode with an acceptable output result or or do I have to manually do some sort of color correction on parameters that can be evaluated by eye
I try something like this my maybe need correctios
Import("v:\avisynth\plugins\IResize.avsi")
Import("V:\AviSynth\plugins\smoothFPS2.avsi")
Import("V:\AviSynth\plugins\smoothFPS3.avsi")
Import("v:\AviSynth\plugins\CropResizedic2017.avsi")
Import("V:\AviSynth\FrameRateConverter2021\FrameRateConverter.avsi")
Import("V:\AviSynth\LinearTransformation-3.0\LinearTransformation.avsi")
LoadPlugin("V:\AviSynth\LinearTransformation-3.0\vscube.dll")
LoadPlugin("v:\AviSynth\FrameRateConverter2021\X64\FrameRateConverter.dll")
LoadPlugin("v:\AviSynth\FFMS2_23_64bit\ffms2-2.23.1-msvc\x64\ffms2.dll")
Import("V:\AviSynth\FFMS2_AVSI_2019\ffms2.avsi")
LoadPlugin("v:\AviSynth\LSMASH_AGO_2023\x64\LSMASHSource.dll")
LoadCPlugin("v:\avisynth\plugins64\yadif.dll")
LoadPlugin("V:\AviSynth\MaskTool2\X64\masktools2.dll")
LoadPlugin("V:\AviSynth\Santiag\ResampleMT.dll")
LoadPlugin("V:\AviSynth\Santiag\nnedi3.dll")
LoadPlugin("V:\AviSynth\Santiag\aWarpsharpMT.dll")
LoadPlugin("V:\AviSynth\Santiag\eedi3.dll")
LoadPlugin("V:\AviSynth\Santiag\EEDI2.dll")
LoadPlugin("V:\AviSynth\Santiag\GScript_26_64.dll")
LoadPlugin("V:\AviSynth\Santiag\SangNom2.dll")
Import("V:\AviSynth\Santiag\santiag.avsi")
Import("V:\AviSynth\QTGMC2025\QTGMC.avsi")
Import("V:\AviSynth\QTGMC2025\Zs_RF_Shared.avsi")
LoadPlugin("V:\AviSynth\QTGMC2025\mvtools2.dll")
LoadPlugin("V:\AviSynth\QTGMC2025\RgTools.dll")
LoadPlugin("v:\AviSynth\BestSource\BestSource.dll")
LoadPlugin("V:\AviSynth\RIFE\RIFE.dll")
LoadPlugin("V:\AviSynth\RIFE\avsresize.dll")
LoadPlugin("V:\AviSynth\RIFE\PlanarTools.dll")
LoadPlugin("V:\AviSynth\HDRTools\x64\Release_W7_AVX2\HDRTools.dll")
vid=BSVideoSource("C:\Users\Administrator\Desktop\Nuova cartella (37)\HLG DJI_20250928173444_0024_D.MP4")
aud=LWLibavAudioSource("C:\Users\Administrator\Desktop\Nuova cartella (37)\HLG DJI_20250928173444_0024_D.MP4",stream_index=1 )
left=GetChannel(aud, 1)
right=GetChannel(aud, 2)
both=mergechannels(left, right)
audiodub(vid, both)
ConvertAudioTo16Bit()
#TurnRight()
#Turn180()
#TurnLeft()
ConvertBits(16)
ConvertYUVtoXYZ(Color=0, HDRmode=2)
ConvertXYZ_Hable_HDRtoSDR(exposure_X=8.0, whitescale_X=8.0)
ConvertBits(bits=8, dither=1)
Convertbits(8)
assumeFPS(50)
Prefetch(8)
FranceBB
4th October 2025, 22:53
I try to do a batch that process this camera that when retrieve the arib-std-b67 (if "%color_transferA%"=="arib-std-b67" ...) do the correct avisynth script that generate the rec.709 output
For those things what you actually need is FFAStrans (FFMpeg Avisynth Transcoder) (https://forum.doom9.org/showthread.php?t=176655). There's no need to write conditionals, unless you want to apply a different conversion yourself with a Custom Avisynth Script. In other words, you can just use an "encoding" node and set either Auto (LUT) or Auto (Tonemapping) to get the BT709 output and the filter_builder will create the appropriate filterchain for you automatically based on the Mediainfo/FFProbe/ExifTool of the input source and the destination you picked. ;)
can I process all HLG sources in batch mode with an acceptable output result or or do I have to manually do some sort of color correction on parameters that can be evaluated by eye
It really depends on what you deem "acceptable".
Generally speaking, in HLG the output will be ok in most circumstances even if you were to just convert the colormatrix and primaries but not the transfer. Namely doing something like this:
ConvertYUVtoXYZ(Color=1)
ConvertXYZtoYUV(pColor=1)
thus pretending that the input is BT2020 SDR 100 nits instead and converting it to BT709 SDR. This would tecnically simulate what a user with a UHD BT2020 SDR TV would see if he was to play an HLG video as it cannot interpret the arib-std-b67 transfer.
If we did that with your samples, we would have got:
https://i.imgur.com/xiHaMTi.png
https://i.imgur.com/JkPQbD7.png
which is "acceptable" nonetheless. The problem arises from when you want to actually tonemap to bring the peak brightness of the HLG source to 100 nits in SDR because you gotta know the MaxCLL for this to happen. Sure, one could try to calculate it, but in compressed sources there might be outliers that need to be filtered out, so it's a whole different can of worms. Obviously, if you have a, let's say, 203 nits stream and you're not doing tonemapping, then the SDR output will look awful as it's way too dim.
In other words, there's no quick and easy way to always process something.
I try something like this my maybe need correctios
In your script you're missing the conversion back from XYZ to YUV.
After you performed tonemapping with Hable, you've now gone from BT2020 HLG to BT709 SDR, however you're still in XYZ, not in YUV.
Avisynth doesn't unfortunately support XYZ directly (even though I actually asked Ferenc about this a few times and it will, one day), so we're spoofing XYZ as YUV even though it's not.
If you were to look down at the bottom right in AVSPmod mod you would indeed see YUV but actually it's XYZ.
In other words, your script here:
ConvertBits(16)
ConvertYUVtoXYZ(Color=0, HDRmode=2)
ConvertXYZ_Hable_HDRtoSDR(exposure_X=8.0, whitescale_X=8.0)
ConvertBits(bits=8, dither=1)
should actually be:
ConvertBits(16)
ConvertYUVtoXYZ(Color=0, HDRmode=2)
ConvertXYZ_Hable_HDRtoSDR(exposure_X=8.0, whitescale_X=8.0)
ConvertXYZtoYUV(pColor=0)
ConvertBits(bits=8, dither=1)
note the "ConvertXYZtoYUV(pColor=0)" there.
Anyway, I've downloaded the package and I took a look at the source. It looks like it's peaking at 600 nits, which seems to be consistent through the entire video for the two shots:
https://i.imgur.com/LWdipNR.png
https://i.imgur.com/DtchbPv.png
The third one was different, though, probably due to some automatic compensation inside, but it's actually a rather terrible shot. It's going all the way through to 1000 nits but we can see white and clipped out portions of the sky, which is a bit of a problem.
https://i.imgur.com/LnXup1g.png
Using my LUTs either via LinearTransformation
LinearTransformation(Input="BT2020_HLG", Output="Linear_BT709")
or directly via
ConvertBits(16)
ConvertToPlanarRGB()
Cube("C:\Programmi\AviSynth+\LUTs\HLG_to_BT709.cube", fullrange=1, interp=1)
Converttoyuv420()
for the first shot achieves a slightly overexposed result:
https://i.imgur.com/LocZMKH.png
We can do much better via manual tonemapping using Reinhard:
ConvertYUVtoXYZ(Color=0, HDRmode=2)
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=1.6)
ConvertXYZtoYUV(pColor=0)
https://i.imgur.com/UI9tHI4.png
About the last picture, the one of the flowers, given that it's peaking at 1000 nits, I would go with:
ConvertYUVtoXYZ(Color=0, HDRmode=2)
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=1.0)
ConvertXYZtoYUV(pColor=0)
https://i.imgur.com/j8inJX6.png
p.s for those in the UK, if you can't see the images, it's because of Captain Hindsight's online safety bill as imgur is no longer available and yet another service caught in the crossfire. Say thanks to Labours and Sir Keir Starmer I guess.
LouieChuckyMerry
13th October 2025, 05:49
Thanks, again, for your patience, and my apologies for temporarily crashing Doom9 with my last batch of inane questions :p .
Seriously, thank you so so much for your reply :) ; it really helped me gain a better understanding of things (like the fact that "converting" and "tone mapping" are different beasts. D'oh! And --range tv is already sorted).
After re(rererererere)reading your reply, I think I can finally wrap my head around everything. I've updated to AVSCube 1.4, and added ",Interp=1" to my tone mapping, er, conversion script. Is this such a massive change that I'd actually notice a difference if I redid encodes I did earlier based on a trilinearly interpreted conversion? If the answer is yes, then please lie, ha ha.
I'll absolutely attempt to put your VideoTek function to use when I have a long enough stretch of free time (a man can dream...).
Congratulations on your team's award, and it makes me happy that you love your job because good people deserve happiness :) .
FranceBB
13th October 2025, 23:25
Thanks, again
No worries, happy to help, as always. :)
Is this such a massive change that I'd actually notice a difference if I redid encodes I did earlier based on a trilinearly interpreted conversion?
My personal position on this is no. I gotta be honest: I've never really seen any noticeable difference aside from synthetic benchmarks. Sure, the waveform is different and sure if you plot the deviation of the points in space you're gonna get the vectors, but when it comes to blind tests looking at a monitor, you're never gonna notice, like, there's no way.
Now that I've said that, I know two of my colleagues (one of which who is also a member of the SMPTE) who would take away my fictional "license to encode" and would absolutely say "yes" and the same goes for some of the folks at Warner and Sony, however, I've never really noticed a difference, so it's not like day and night. To be fair, I've been encoding some titles with trilinear interpolation ages ago and I'm not going to re-encode them.
In other words, you're gonna be fine. ;)
it makes me happy that you love your job because good people deserve happiness :) .
Awwww. :')
roccomarco
16th October 2025, 23:08
thank you very much for your help: I need to do some implementation in my batch routine.
Fracesco Be patient, for kindness, if possibile. or if you want: in this site sometimes I need some interesting thing I need - FOR example - to do a batch that process single photo files to adjust the frame with the fuzzy blur when is portrait
So I wonder: i need to buld a batch procedure that ingest my source photo files and the processing should do some movement in video at different speed inputted.
A sort of "AutoPhoto" (moves and pan,zoom on photo ---> preferable with avisynth ---> export on mxf 1920x1080@50i (interlaced)
can be done this? or can FFAStrans do some "autozoom" on static image photos? thank you very very much
and can FFAStrans transcode to 50P. If I need to transcode to xdcamhd422 25i I use ffmbc but is seem not longer developed so I need to use a similar
Tlen
16th November 2025, 10:15
Hi FranceBB,
thank you for your work.
I'm pretty new to the HDR environment and SDR downconversion (wich I'm interested in).
Atm I don't even try to understand all the math behind the color spaces and I dully play the end user role who see the results (eheh).
So, in my initial round test to manage conversion to SDR I encountered your luts and I promptly tested them.
The initial result of the first try i did, which purposely I did without seeing any reference comparison, to base it on purely reaction, appeared to me a little (not much) "dull". Good colors, but something off.
So first I went to capshaolic just to have an initial alternative source
and the impression of dullness of the lut was confirmed.
The capshaolic screen was more "correct" for me.
I did at this point another round with DGHDRtoSDR and although the default was a bit too bright playing with the white level I was able to obtain a result that I found pretty good and that incidentally matched with capshaolic conversion (I don't know wich method they used to do it).
So, going to data, here's the info from Mediainfo (it's Karate Kid Film)
Video #1
ID : 4113 (0x1011)
Menu ID : 1 (0x1)
Format : HEVC
Format/Info : High Efficiency Video Coding
Format profile : Main 10@L5.1@High
HDR format : SMPTE ST 2086, HDR10 compatible
Codec ID : 36
Duration : 2 h 6 min
Width : 3 840 pixels
Height : 2 160 pixels
Display aspect ratio : 16:9
Frame rate : 23.976 (24000/1001) FPS
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
Maximum Content Light Level : 4010 cd/m2
Maximum Frame-Average Light Level : 268 cd/m2
This it the Raw image
https://thumbs4.imagebam.com/78/af/02/ME17SLFF_t.png (https://www.imagebam.com/view/ME17SLFF)
This it the Lut
ConvertBits(16)
ConvertToPlanarRGB()
Cube(eng,"PQ_to_BT709_v2.cube",interp=1,cpu=3)
https://thumbs4.imagebam.com/77/85/ad/ME17SLHN_t.png (https://www.imagebam.com/view/ME17SLHN)
This it DGHDRtoSDR
ConvertBits(16)
DGHDRtoSDR(mode="pq",impl="sw",white=1830)
https://thumbs4.imagebam.com/af/52/28/ME17SLIV_t.png (https://www.imagebam.com/view/ME17SLIV)
This is another frame adding capshaolic screen
Raw -> Lut -> DGHDRtoSDR -> caps
https://thumbs4.imagebam.com/09/6b/89/ME17SLLQ_t.png (https://www.imagebam.com/view/ME17SLLQ)https://thumbs4.imagebam.com/80/d5/5e/ME17SLLN_t.png (https://www.imagebam.com/view/ME17SLLN)https://thumbs4.imagebam.com/8e/cb/d3/ME17SLLM_t.png (https://www.imagebam.com/view/ME17SLLM)https://thumbs4.imagebam.com/8f/42/67/ME17SLLL_t.png (https://www.imagebam.com/view/ME17SLLL)
Why is your lut different?
Thank you :)
Emulgator
19th November 2025, 19:08
Safety ? If one source responds well to one or the other algo this does not mean that one is more correct than the other.
You would need a bouquet of reference material to judge any such conversion, there is no auto-improvement involved.
FranceBBs LUTs have passed his own, SKY practics and other testings well, provided that the source's grading/histogram population was somehow correct/useful in the first place.
Remember: MUST NOT CLIP, and this source needs to place 4000nits within SD.
Somebody's taste wants to keep highlight/shadow details and sacrifices some brightness/crunchyness and otherbody's taste may command his S-curve to be bent further up/down,
and later with availabilty of a brighter monitor regretting just that because these details/values are lost.
Looking at FranceBB LUT the girl/boy scene could use a bit more S-curve (but this scene came in with too flat exposure to begin with), the boy's shirt sat well.
Looking at DG/caps the girl/boy scene did well here, the boy's shirt came out blown out a bit.
Maybe this particular source should not have been mastered aiming for 4000nits, such negative stock would have been nicely bedded inside 1000 maybe.
Don't know that movie, are there huge explosions that need it ?
I would maybe regrade/re"time" (reexpose) that in source gamut, then downconvert.
DMD
30th November 2025, 09:40
Good morning.
I am trying to perform some shooting tests with the iPhone 17 Promax, generating a file in ProRes 422 HQ BT2020.
I would like to ask where I can find a conversion LUT from Apple Log2 HDR.
Thank you.
FranceBB
20th December 2025, 21:46
A sort of "AutoPhoto" (moves and pan,zoom on photo ---> preferable with avisynth ---> export on mxf 1920x1080@50i (interlaced)
can be done this? or can FFAStrans do some "autozoom" on static image photos?
I need to transcode to xdcamhd422 25i
Yes, of course it can be done, there's a reason why Avisynth is the best frameserver in the world.
What you need is the zoom function http://avisynth.nl/index.php/Zoom
#Indexing
ImageSource("PXL_20251118_190701454.jpg")
#Bringing everything to RGB
ConverttoRGB32()
#Pan from right to left
zoom(dstx="n", angle="0", width=1920, height=1080)
#Produce 25fps
AssumeFPS(25)
#Go back to YUV
Converttoyv16()
After which you can pass it to the encoder.
I use ffmbc but is seem not longer developed so I need to use a similar
There's no need, you can create a perfectly valid XDCAM-50 in the normal open source MPEG-2 encoder within FFMpeg. After all, what you need is just a normal FULL HD 1920x1080 MPEG-2 High 4:2:2 Profile, Level High 50 Mbit/s yv16 25i TFF BT709 SDR, so you can use
ffmpeg.exe -hide_banner -i "AVS Script.avs" -pix_fmt yuv422p -vcodec mpeg2video -s 1920:1080 -aspect 16:9 -vf setfield=tff -flags +ildct+ilme+cgop -b_strategy 0 -mpv_flags +strict_gop -sc_threshold 1000000000 -r 25 -b:v 50000k -minrate 50000k -maxrate 50000k -bufsize 36408333 -qmin 5 -qmax 28 -qsquish 99 -g 12 -bf 2 -profile:v 0 -level:v 2 -color_range 1 -color_primaries 1 -color_trc 1 -colorspace 1 -an -f mxf -y "raw_video.mxf"
bmxtranswrap.exe -p -y 00:00:00:00 -t op1a -o "final_output.mxf" "raw_video.mxf"
pause
In this example, here's the original picture (downscaled but it would be 4080x3072 so 1.328
https://i.postimg.cc/TPS0n528/image.png
and here's the output from Avisynth being a video that goes from left to right cropped in 1920x1080 to create the usual FULL HD 1.77 FF
https://i.postimg.cc/J4qQP27q/image.png
panning from right to left
https://i.postimg.cc/y88y5ykS/image.png
Once again the video is 25fps progressive flagged as interlaced and encoded as interlaced, however if you prefer the panning to be faster and the output to be truly interlaced 25i TFF then nothing stops you from using
AssumeFPS(50)
and then dividing in fields with
assumeTFF()
separatefields()
selectevery(4,0,3)
weave()
instead.
Obviously this entire thing can be easily inserted in a Custom AVS Script within FFAStrans and it can be automated, just make sure to use LoadPlugin() to load the appropriate zoom.dll if you're running it on hosts in which Avisynth isn't installed and make sure that the last thing you return is m_clip.
In other words, given that the indexing is already handled by the A/V Decoder node, in FFAStrans you would have the Custom AVS Script node set like
#Loading dependencies
LoadPlugin("%s_ffastrans_dir%\Processors\avs_plugins\zoom.dll")
#Bringing everything to RGB
ConverttoRGB32(m_clip)
#Pan from right to left
zoom(dstx="n", angle="0", width=1920, height=1080)
#Produce 25fps
AssumeFPS(25)
#Go back to YUV
Converttoyv16()
m_clip=last
return m_clip
followed by an XDCAM Encoding node and a delivery node. :)
https://i.postimg.cc/Twfw7C3z/image.png
thank you very very much
No problem at all. Once again, open source for the win. :D
Merry Christmas.
So, going to data, here's the info from Mediainfo (it's Karate Kid Film)
Video #1
ID : 4113 (0x1011)
Menu ID : 1 (0x1)
Format : HEVC
Format/Info : High Efficiency Video Coding
Format profile : Main 10@L5.1@High
HDR format : SMPTE ST 2086, HDR10 compatible
Codec ID : 36
Duration : 2 h 6 min
Width : 3 840 pixels
Height : 2 160 pixels
Display aspect ratio : 16:9
Frame rate : 23.976 (24000/1001) FPS
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
Maximum Content Light Level : 4010 cd/m2
Maximum Frame-Average Light Level : 268 cd/m2
The Mediainfo puts the MaxCLL value to a whopping 4010 nits, however if we take a look at the MaxFALL we can see that the average is 268 nits. This means that we're gonna have a few very bright moments through the movie but overall it's not gonna be very bright outside of those. This also means that if we were to blindly trust the MaxCLL and put the 4010 nits peak back down to 100 nits of the BT709 SDR we would have a problem as the entire content would look dark.
This is unfortunately due to the nature of HDR and in particular in a totally logarithmic curve like PQ that can go all the way up to 10000 nits, potentially. In other words, while a dynamic tonemapping algorithm can be set to analyze the scenes and adjust itself based on the peak of the scene (this is what MPV does for instance when it performs this kind of conversion), when using a static LUT you're essentially mapping the points from an input curve to an output curve based on the values you defined in the 65x65x65 matrix. In other words, those are gonna be static and they won't adjust on a scene by scene basis. In this case, if you were to take the MaxCLL of 4010 nits and map it to 100 nits, you would be preserving the highlights in that particular scene, but everything else would be pushed down accordingly so the overwhelming majority of the scenes would be far too dark. In the same way, if you were to take 1000 nits as your reference and map it down to 100 nits of the BT709 SDR, you would have everything above 1000 completely clipped out which of course includes many highlights. In other words, the higher you set your reference, the more highlights you're going to preserve, but the "dimmer" it will look in an SDR display. The lower you set your reference, the brighter it will look on an SDR display, but the more details you're gonna lose as they can't be mapped to anything above 100 nits (i.e 235 in 8bit values or 0.7V).
Why is your lut different?
Well, let's take a look at the picture you just posted.
https://i.postimg.cc/kG7T6WsK/image.png
We can easily see that there aren't really many highlights and the sky on the right peaks at around 500 nits.
Using the PQ_to_BT709_v1.cube makes the BT709 SDR version peak at around 80 nits.
https://i.postimg.cc/zXKnZyFc/image.png
while using the PQ_to_BT709_v2.cube - which has a higher reference in terms of nits - makes it peak lower and the result is much dimmer at around 70 nits.
https://i.postimg.cc/8PS7vtLw/image.png
You used this second version of the LUT but for a content like yours in which the average is as low as barely 250 nits, I would suggest using v1 instead. Please note that the v1 v2 nomenclature doesn't make one better than the other and actually the reason why they're both there is exactly the one I explained above. In other words, there's no perfect way to perform this conversion, so according to the kind of content you have you may wanna use one rather than the other. If the content is very modern with lots of bright scenes and the average is also high, then use v2, while if the content is older or if it doesn't have many bright elements and you don't want it to look too dim, then use v1 instead.
Using Reinhard as a tonemapping algorithm the result is slightly different but we can get it to produce a decent output while still preserving the highlights for the scene:
ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=12.5, contrast_X=0.8, exposure_Y=12.5, contrast_Y=0.8, exposure_Z=12.5, contrast_Z=0.8)
ConvertXYZtoYUV(pColor=0)
https://i.postimg.cc/nhPxZhk3/image.png
Safety ?
Yep. Pretty much. I would generally always prefer not to clip. Outside of my personal taste, internally at Sky we had a long conversation with the various parties involved. For instance, even when we make the PQ to HLG conversions, we use the MaxCLL of the source to bring everything down to 1000 nits in HLG up until 4000 nits with literally 1 LUT per nit from 1000 to 4000, while anything above that will be clipped.
I would like to ask where I can find a conversion LUT from Apple Log2 HDR.
Oh...! I didn't know Apple started creating its own logs instead of choosing anything which has already been standardized. If you can record a few samples and share them here I'll try to take a look and create something to produce a BT709 SDR output, but mapping to PQ will take me a bit longer because when I google around to find official specs about Apple Log and Apple Log2 I can't find anything which means that I'll have to reverse it by looking at the waveform and it will take time.
If you can, try to make your samples as diverse as possible with clear peak highlights and dark elements so that I can use them as a reference for my white and black.
DMD
20th December 2025, 21:57
..
Oh...! I didn't know Apple started creating its own logs instead of choosing anything which has already been standardized. If you can record a few samples and share them here I'll try to take a look and create something to produce a BT709 SDR output, but mapping to PQ will take me a bit longer because when I google around to find official specs about Apple Log and Apple Log2 I can't find anything which means that I'll have to reverse it by looking at the waveform and it will take time.
If you can, try to make your samples as diverse as possible with clear peak highlights and dark elements so that I can use them as a reference for my white and black.
If you're interested, in the meantime I found this link with free LUTs for iPhone 17 Pro Max Apple Log2. I don't know if they're suitable for obtaining the BT2020 color space for HDR.
https://gamut.io/product/free-apple-conversion-luts-iphone/
FranceBB
20th December 2025, 22:18
I don't know if they're suitable for obtaining the BT2020
The files produced by the iPhone are in BT2020 in terms of colormatrix, but what you want is the smpte2084, so basically to go from the Apple Log / Apple Log2 transfer to the PQ transfer and this needs work. A friend of mine, Peter, has ordered an iPhone 17 Pro for Christmas (bad choice, but hey, the world is great 'cause it's various) so he will be able to provide some samples. In the meantime, if you have some samples recorded in BT2020 Apple Log and Apple Log2 please share them and I'll start working on it.
manolito
23rd December 2025, 20:32
Video #1
ID : 4113 (0x1011)
Menu ID : 1 (0x1)
Format : HEVC
Format/Info : High Efficiency Video Coding
Format profile : Main 10@L5.1@High
HDR format : SMPTE ST 2086, HDR10 compatible
Codec ID : 36
Duration : 2 h 6 min
Width : 3 840 pixels
Height : 2 160 pixels
Display aspect ratio : 16:9
Frame rate : 23.976 (24000/1001) FPS
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
Maximum Content Light Level : 4010 cd/m2
Maximum Frame-Average Light Level : 268 cd/m2
Why is your lut different?
Thank you :)
Hi Tlen and FranceBB,
since my display hardware does not handle HDR sources I always have to convert such sources to SDR. I have old hardware which can handle DGHDRToSDR and Zimg, but not LibPlacebo. So my options to convert HDR to SDR are a little limited. But I never use LUTs because I do not like the concept... :devil:
You can find my current conversion scripts here:
https://forum.doom9.org/showthread.php?p=2014617#post2014617
My goal is to just convert HDR sources to SDR without any creative tweaks to correct source characteristics. I just want a conversion without any improvement of the source. Just like a basic PAL to NTSC (or vice versa) conversion without trying to improve the result from flaws of the source. No improvement of the source, just a dumb standards conversion.
To test my scripts with this source I need a short section of the original source clip which preserves all of the original source characteristics. Would it be possible for Tlen to upload such a clip?
Cheers
manolipo
FranceBB
24th December 2025, 15:26
I can see that you're using mobius tonemapping within FFMpeg
______________________________________________________________________________________
FFmpeg Fast (Slightly edited script by GeoffreyA)
Half HD target (1280x720):
--------------------------
PQ:
===
zscale=1280:-2,zscale=m=gbr:t=linear:dither=none:npl=225,format=gbrpf32le,tonemap=mobius:desat=3.0,zscale=m=709:t=709:p=709:r=limited:c=left:dither=error_diffusion,format=yuv420p,sidedata=delete
HLG:
====
zscale=1280:-2,zscale=m=gbr:t=linear:dither=none:npl=203,format=gbrpf32le,tonemap=mobius:desat=0,zscale=m=709:t=709:p=709:r=limited:c=left:dither=error_diffusion,format=yuv420p,sidedata=delete
I generally prefer Reinhard, so my FFMpeg equivalent of your command line would be:
#BT2020 PQ
ffmpeg -i "my_input.mxf" -map 0:v -c:v libx264 -profile:v high -level:v 4.1 -refs 4 -crf 25 -ignore_chapters 1 -ignore_unknown -write_tmcd 0 -movflags faststart -vf "sidedata=delete,metadata=delete,scale=w=1920:h=1080:flags=lanczos:sws_dither=ed,zscale=tin=smpte2084:min=bt2020nc:pin=bt2020:rin=tv:t=smpte2084:m=bt2020nc:p=bt2020:r=tv,zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=reinhard:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv422p10,scale=sws_dither=x_dither,format=yuv420p,setfield=prog,setdar=16/9,setsar=1,fps=25" -x264opts "opencl:keyint=50:force_cfr=1:deblock=-1,-1:aud=1:overscan=show:colorprim=bt709:fullrange=off:transfer=bt709:colormatrix=bt709" -color_primaries bt709 -color_trc bt709 -colorspace bt709 -color_range tv -field_order progressive -brand mp42 -max_muxing_queue_size 700 -map_metadata -1 -metadata creation_time=now -an -f mp4 -y "Video_Only.mp4"
#BT2020 HLG
ffmpeg -i "my_input.mxf" -map 0:v -c:v libx264 -profile:v high -level:v 4.1 -refs 4 -crf 25 -ignore_chapters 1 -ignore_unknown -write_tmcd 0 -movflags faststart -vf "sidedata=delete,metadata=delete,scale=w=1920:h=1080:flags=lanczos:sws_dither=ed,zscale=tin=arib-std-b67:min=bt2020nc:pin=bt2020:rin=tv:t=arib-std-b67:m=bt2020nc:p=bt2020:r=tv,zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=reinhard:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv422p10,scale=sws_dither=x_dither,format=yuv420p,setfield=prog,setdar=16/9,setsar=1,fps=25" -x264opts "opencl:keyint=25:force_cfr=1:deblock=-1,-1:aud=1:overscan=show:colorprim=bt709:fullrange=off:transfer=bt709:colormatrix=bt709" -color_primaries bt709 -color_trc bt709 -colorspace bt709 -color_range tv -field_order progressive -brand mp42 -max_muxing_queue_size 700 -map_metadata -1 -metadata creation_time=now -an -f mp4 -y "Video_Only.mp4"
I'm also going to FULL HD instead of HD.
That being said, it's very rare for me to use FFMpeg directly for those kind of things, in fact when I have to perform tonemapping I always use Avisynth.
The equivalent of your Avisynth part
AviSynth + (Script by Donald Graft. Separate parameters for PQ and HLG source files)
ConvertBits(16)
#PQ
DGHDRToSDR(mode="pq", white=1460, black=0, gamma=0.42, hue=0.00, r=1.00, g=1.00, b=1.15, tm=0.90, roll=0.70, fulldepth=false, impl="255")
#HLG
DGHDRtoSDR(mode="hlg", white=2820, gamma=0.50, r=1.10, g=1.07, b=1.12, roll=0.70)
for me it would be done via HDRTools made by Jean Philippe Scotto di Rinaldi, namely:
#PQ
ConvertBits(16)
ConvertYUVtoXYZ(Color=0, OutputMode=1, HDRMode=0, fullrange=false)
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=2.5, contrast_X=0.9, exposure_Y=2.5, contrast_Y=0.9, exposure_Z=2.5, contrast_Z=0.9)
ConvertXYZtoYUV(pColor=0)
Converttoyuv420()
ConvertBits(bits=8, dither=1)
#HLG
ConvertBits(16)
ConvertYUVtoXYZ(Color=0, HDRmode=2)
ConvertXYZ_Reinhard_HDRtoSDR(exposure_X=2.1, exposure_Y=2.1, exposure_Z=2.1)
ConvertXYZtoYUV(pColor=0)
Converttoyuv420()
ConvertBits(bits=8, dither=1)
I never use LUTs because I do not like the concept...
Predictability vs efficiency. In a perfect world with a perfect dynamic tonemapping algorithm that never fails and automatically adjusts on a scene by scene basis there would be no need for static matrices (i.e LUT). Unfortunately, we don't live in such a world, even though libplacebo (what MPV is using) is very close.
GeoffreyA
24th December 2025, 19:43
Here's my final version of the FFmpeg conversion. But I don't use it, libplacebo being much better.
-vf zscale=min=bt2020nc:tin=smpte2084:pin=2020:rin=limited:m=gbr:t=linear:p=2020:dither=none:npl=203:f=spline36,format=gbrpf32le,
tonemap=reinhard:desat=0,zscale=-1:1080:f=spline36,
crop=%crop%:exact=true,
zscale=m=709:t=709:p=709:r=limited:c=left:dither=error_diffusion:f=spline36,format=yuv420p,sidedata=delete
You can move the 1080p downscaling earlier so that tone mapping goes quicker, whilst keeping within the linear RGB stage.
manolito
25th December 2025, 02:16
Hi Geoffrey,
looks like in this post:
https://forum.doom9.org/showthread.php?p=2014494#post2014494
you still thought that mobius was better than reinhard? I switched to mobius at that time, liked it better than reinhard and kept it there.
Cheers
manolito
GeoffreyA
25th December 2025, 07:32
Hi manolito,
I think I put Reinhard there because it tends to be the "default" when it comes to tone mapping, but you can of course use Mobius if you prefer. Between the two, I haven't tested them for almost a year, so not sure which I'd pick right now. Mobius can give better contrast; Reinhard can be gentler on the eyes. I use Spline in libplacebo, which, when coupled with peak detection, gives a superior result to both Reinhard and Mobius.
wonkey_monkey
24th January 2026, 02:51
FFVideoSource("example.mxf")
ConvertBits(16)
ConvertToPlanarRGB()
Cube("C:\Programmi\AviSynth+\LUTs\example.cube")
Should I infer from the lack of a specified matrix that the input is assumed to be RGB to start with? If I wanted to apply, say, PQ_to_BT709_v2 to a 10-bit YUV HDR video, Should I include matrix = "Rec2020" as a parameter to ConvertToPlanarRGB? Or have I completely misunderstood? :confused:
FranceBB
24th January 2026, 22:35
Should I infer from the lack of a specified matrix that the input is assumed to be RGB to start with? If I wanted to apply, say, PQ_to_BT709_v2 to a 10-bit YUV HDR video, Should I include matrix = "Rec2020" as a parameter to ConvertToPlanarRGB? Or have I completely misunderstood? :confused:
Yes, ConverttoPlanarRGB("matrix="Rec2020") will convert from the YUV limited tv range BT2020 HDR PQ input to RGB Full PC Range BT2020 HDR PQ output. There are two reasons why I didn't specify the matrix in the example:
1) It serves a lot of purposes, so it's not just for people wanting to go from HDR PQ to BT709 SDR
2) For better or worse, we live in an age in which frame properties are a thing, so in theory the indexer (LWLibavVideoSource or FFVideoSource) is supposed to populate the frame properties with the right value and this value will be used automatically by the Convertto functions.
In your case:
FFVideoSource("example.mxf")
ConvertBits(16)
ConvertToPlanarRGB(matrix="Rec2020")
Cube("C:\Programmi\AviSynth+\LUTs\PQ_to_BT709_v2.cube", interp=1, fullrange=1)
ConverttoYUV420(matrix="Rec709")
propSet("_ColorRange", 1) #Limited TV Range
propSet("_Matrix", 1) #BT709
propSet("_Transfer", 1) #BT709
propSet("_Primaries", 1) #BT709
If your source also has MaxCLL and MaxFALL as well as the mastering display, it might be a good idea to get rid of those too, either directly or via a simple propclearall(). In the case of encoders like x264 and x265, you're fine as they won't be interpreting those frame properties anyway as they only really care about the good old clip properties, but if you're using something else like FFMpeg or if your frameserving to players like MPV etc, you might wanna get rid of them.
DMD
2nd February 2026, 16:04
@FranceBB
I sent you a PM.
Thanks.
mojie126
25th February 2026, 05:13
"HDR format : Dolby Vision, Version 1.0, Profile 5, dvhe.05.06, BL+RPU, no metadata compression"
The color is not stable when converting from DV to SDR. Is it due to an issue with the RPU?
FranceBB
15th March 2026, 20:29
"HDR format : Dolby Vision, Version 1.0, Profile 5, dvhe.05.06, BL+RPU, no metadata compression"
The color is not stable when converting from DV to SDR. Is it due to an issue with the RPU?
What do you mean with "not stable"?
LUTs are simple matrices that map values from the input curve to values on the output curve, which means that they're gonna be as stable as the input is.
@FranceBB
I sent you a PM.
Thanks.
Thanks for the footage, it took me a while to get it right.
The Apple Log curve is totally logarithmic: the black starts high and the reference white is at 0.55V in the 0.0-0.7V interval.
For reference, in PQ the reference white is 0.40V while in HLG it's 0.52V.
A reference of 0.55V for a logarithmic curve is very very high, which means that although it will do a good job in preserving the blacks, it won't do much in showing highlights.
It also raises faster than Slog3 and Slog2 and much faster than PQ which confirms that the number of available stops is relatively low, so don't expect many nits in output.
The colormatrix is the normal BT2020 in this case, so we can use the values we know.
In terms of mapping, I've mapped the reference to 0.70V because I sincerely doubt such tiny sensors are gonna have any true highlights. The result is the following:
https://images2.imgbox.com/2c/4a/xhJVkOXg_o.png
https://images2.imgbox.com/ea/14/ueAftI7L_o.png
https://images2.imgbox.com/ed/70/CuL2EDNi_o.png
https://images2.imgbox.com/b7/06/k2LygjlY_o.png
Although there aren't many details in the highlights, it would be a bit of a waste to convert the BT2020 to BT709 so I've created a BT2020 HDR HLG version as well.
https://images2.imgbox.com/c9/63/NAgFM7IN_o.png
I'll add them to the repository, but I won't make an official release just yet, so consider them "experimental", but please do play with them and let me know how it goes.
As usual, the more samples the better. :)
DMD
15th March 2026, 20:37
Thanks for the footage, it took me a while to get it right.
The Apple Log curve is totally logarithmic: the black starts high and the reference white is at 0.55V in the 0.0-0.7V interval.......
Thank you for conducting the test.
FranceBB
15th March 2026, 23:19
https://github.com/FranceBB/LinearTransformation/blob/master/LinearTransformation.avsi
https://github.com/FranceBB/LinearTransformation/blob/master/ALog_to_BT709.cube
https://github.com/FranceBB/LinearTransformation/blob/master/ALog_to_HLG.cube
https://github.com/FranceBB/LinearTransformation/blob/master/ALog_to_PQ.cube
Test them out with:
LinearTransformation(Input="ALog", Output="Linear_BT709")
LinearTransformation(Input="ALog", Output="BT2020_HLG")
LinearTransformation(Input="ALog", Output="BT2100_PQ")
mojie126
16th March 2026, 06:14
What do you mean with "not stable"?
LUTs are simple matrices that map values from the input curve to values on the output curve, which means that they're gonna be as stable as the input is.
I see. I perform LUT mapping through DV videos, and the colors suddenly change. It's likely due to inconsistent inter-frame curves in the DV videos
FranceBB
1st April 2026, 21:07
Linear Transformation v3.1 Released! (https://github.com/FranceBB/LinearTransformation/releases)
Changelog:
- Introduced support to convert Apple Log to BT709 SDR, BT2020 HDR HLG and BT2020 HDR PQ
# Apple Log to BT709 SDR
LinearTransformation(Input="ALog", Output="Linear_BT709")
# Apple Log to BT2020 HDR HLG
LinearTransformation(Input="ALog", Output="BT2020_HLG")
# Apple Log to BT2020 HDR PQ
LinearTransformation(Input="ALog", Output="BT2100_PQ")
Linear Transformation v3.1 Released! (https://github.com/FranceBB/LinearTransformation/releases)
Changelog:
Great FranceBB
Sorry for asking two questions, since I’m importing the files into Resolve.
1- Do I need to consider the LUT that converts the DWG intermediate color space to BT.2020?
2- As for the AppleLog2 color space, is it handled the same way, or do I need to wait for another LUT for that?
Thanks
FranceBB
2nd April 2026, 21:52
Great FranceBB
Sorry for asking two questions, since I’m importing the files into Resolve.
1- Do I need to consider the LUT that converts the DWG intermediate color space to BT.2020?
2- As for the AppleLog2 color space, is it handled the same way, or do I need to wait for another LUT for that?
Thanks
They're handled in the same way and you don't have to go any intermediate: just import the LUT, use it in a node and you're in your target. :)
And by the way, thank you for providing the samples, they've been what made this possible. ;)
FranceBB
10th May 2026, 20:33
Linear Transformation v3.2 Released! (https://github.com/FranceBB/LinearTransformation/releases/tag/3.2)
Changelog:
- Allow the user to specify a custom path for the .cube files directly from the function via the LUT_Path parameter.
By default the function expects the .cube file to be in C:\Program Files (x86)\AviSynth+\LUTs\ however it's not mandatory to have them in that position. Prior to this update, this was specified by myPath which was a local variable. It was possible to overwrite it but every update would have overridden it again. This is now exposed in the main function as a parameter LUT_Path.
Example:
LinearTransformation(Input="Linear_BT709", Output="Linear_BT2020", Interpolation="Tetrahedral", LUT_Path="D:\LUTs\")
By default, if not specified, it will still default to C:\Program Files (x86)\AviSynth+\LUTs\ for backwards compatibility.
wonkey_monkey
11th May 2026, 00:23
A while ago I asked about whether a matrix should be applied when doing the initial convert to RGB before calling Cube.
But now I look at LinearTransformation.avsi, I see it doesn't use one:
clp = clp.ConvertBits(bits=16).ConvertToPlanarRGB() # If already PlanarRGB 16 bit then should do nearly nothing
But it does pick and use a suitable matrix when converting back to YUV. Why is that?
And isn't there some loss in converting down to the original bitdepth first (still in RGB?) and then back to the original colour space? If I've understood the script correctly, that is.
Also (sorry, I keep being curious):
#If the input has the alpha channel it needs to be converted too
Isn't alpha usually meant to be linear? And so not in need of conversion?
FranceBB
11th May 2026, 08:54
A while ago I asked about whether a matrix should be applied when doing the initial convert to RGB before calling Cube.
But now I look at LinearTransformation.avsi, I see it doesn't use one
But it does pick and use a suitable matrix when converting back to YUV. Why is that?
That's very simple: the original idea behind this was that when converting to RGB it was gonna use the matrix specified by the frame properties thus using what was specified in the input, however when converting back from RGB to YUV Avisynth wouldn't know what was done because from the Cube() perspective it's just a set of values, so it really wouldn't know, which is why I had to specify one and set the frame properties manually.
Now that I think about it, given that we can't always trust the input, it would probably be a good idea to be explicit on the first conversion as well. I have to think this through for a little bit longer (I'm currently reading this while drinking my usual morning cappuccino) but I guess you're right and it's probably sensible to do so explicitly rather than leaving it up to the frame properties.
And isn't there some loss in converting down to the original bitdepth first (still in RGB?) and then back to the original colour space?
Yep, but that's basically user controlled in the sense that the user could, theoretically, convert to, let's say, RGB Planar 16bit before calling the function and it would work. I don't think it needs changing, but I could, potentially, add an option to allow the user to specify what to get as an output so that if, let's say, YUV 4:4:4 16bit is required, it would be possible to output it straight away. Not in my current plans but it's probably a sensible thing to do.
Isn't alpha usually meant to be linear? And so not in need of conversion?
Nope, the alpha channel must follow the other channels. I've learned this the hard way a few years back when we started broadcasting in BT2020 HLG. Our graphics department didn't have a way to output anything other than BT709 SDR and we had a bunch of logos to convert, namely the various channel logo, the logo of each football team for Sky Sport etc. I've then created a workflow that takes the input, separates the YUVA in YUV + A individually, converts them to RGBA individually as RGB (Normal) and RGB (Alpha only), then applies the conversion to both individually, then it reconstructs it to a proper RGBA and finally converts back to YUVA.
This is done because Cube() only supports normal RGB without the alpha channel, so I had to work around this by doing that "trick" before reconstructing the RGBA. It tested and it works as we've been using this for a very long time.
So... yeah, if you have YUVA with YUV in BT2020 HLG, then A must also be BT2020 HLG. Same goes for RGBA.
Here I'm checking if we have the alpha channel, so RGBA (in this case RGB32) and I'm separating the alpha from the normal image so that I have:
RGB24 with just the image
RGB24 with just the alpha
#Check if the input has the alpha channel
if (Original == "RGB32") {
my_alpha = clp.ShowAlpha(pixel_type="RGB24")
clp = clp.RemoveAlphaPlane()
has_alpha_plane = true
}
else
{
has_alpha_plane = false
}
and here I'm bringing both the RGB24 with the normal image and the RGB24 with just the alpha channel to 16bit planar RGB, converting them and then using them to recreate the RGBA.
#If the input has the alpha channel it needs to be converted too
if (has_alpha_plane == true) {
#Alpha channel conversion
ConvertBits(my_alpha, 16)
ConvertToPlanarRGB()
Cube(LUT_Path + CubeStr + ".cube", interp=Interpolation, fullrange=1)
ConverttoY()
my_alpha=last
#Normal channel conversion
Cube(clp, LUT_Path + CubeStr + ".cube", interp=Interpolation, fullrange=1)
my_video=last
#Merge converted normal channel with converted alpha channel
AddAlphaPlane(my_video, my_alpha)
#Set frame properties
propset("_Matrix", my_Matrix)
propset("_Transfer", my_transfer)
propset("_Primaries", my_primaries)
out=last
}
wonkey_monkey
12th May 2026, 00:37
Thanks for the teachings.
which is why I had to specify one and set the frame properties manually.
Since you set the frame properties, couldn't you leave the matrix unspecified in the final ConvertTo... calls as well? Seems a bit redundant, unless I've misunderstood.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.