FranceBB/VideoTek

nits type for PQ mode not working

Closed this issue · 11 comments

As far as I can see, the new nits type does not work for the PQ mode.

That's correct and that's essentially because I don't yet have a proper way of calculating it. Do you have a pattern / reference I can use to include it in VideoTek?

What exactly would you need for calculating that? I mean I guess you are aware of Rec. ITU-R BT.2100, or what else would be needed?

Yep, the thing is that I wanna absolutely avoid repeating the screw up I made with HLG last time before you came around to point it out (thank you for that by the way). Instead of just putting the values there willy nilly I'll create a synthetic test pattern this time with a 1000 nits increase at each frame so that I can cross check with the AVID reference waveform monitor. The problem is that I have to do this when I have a bit of spare time, but unfortunately these days it's not much encoding and it's more general purpose programming at work along with meetings, so it's very hard to find time... :(
If you already happen to have a test pattern with a 1000 nits increase on each frame like 1000 - 2000 - 3000 - 4000 etc all the way up to 10,000 then it would speed things up, otherwise it's not a big deal, I'll create it but unfortunately it will take a bit of time.

Sure, I can create such a clip. I assume that H265 in a MKV container is fine, or do you need something exotic?

That's absolutely fine, thank you! :D

So here you are. I thought that the mkv container is probably unnecessary, so here are raw h265 files.
One is Main10 and the other is Main12.
brightness-ramp-1k-nits.zip

Please test.

Function VideoTek(clip clp, String "Mode", String "Type") {
    
    #Check if frame properties are there
    my_frame_properties = propGetAll(clp)
    
    #Getting info
    #Resolution
    x=Width(clp)
    y=Height(clp)
    #Framerate
    fps=FrameRate(clp)
    #ColorSpace
    colorspace=PixelType(clp)
    
    #If there are no frame properties, let's do what we can
        if (Int(my_frame_properties.ArraySize()) == 0) {
        
            #Check Frame Size to set matrix
            if (clp.Height() <= 576) {
                    clp = ConvertToYUV444(clp, matrix="PC.601")           
            }

            else {
                    clp = ConvertToYUV444(clp, matrix="PC.709")             
                }
        }
                
        #If there are SOME frame properties, let's try
        else if (Int(my_frame_properties.ArraySize()) > 0) {
         
                #Check if we have Matrix
                try {
                        if (propGetInt(clp, "_Matrix") >= 0) {
        
                        my_matrix = propGetInt(clp, "_Matrix")
                        }
                }
        
                catch (property) {
                       my_matrix = Undefined()
                       }

                #If we have matrix, we're good
                if (Defined(my_matrix) == true) {
             
                          #BT601 PAL  or BT601 NTSC 
                          if (my_matrix == 5 || my_matrix == 6) {
            
                              clp = ConvertToYUV444(clp, matrix="PC.601")
                              }
                          #BT2020   
                          else if (my_matrix == 9) {
                          
                              clp = ConvertToYUV444(clp, matrix="PC.2020")
                              }
                              
                          #if none of the above, we assume BT709
                          else {
                              clp = ConvertToYUV444(clp, matrix="PC.709")
                              }      
                }                              

                #If we have no matrix
                else if (Defined(my_matrix) == false) {

                          #Check Frame Size to set matrix
                          #If SD - BT601
                          if (clp.Height() <= 576) {
                                clp = ConvertToYUV444(clp, matrix="PC.601")           
                              }
                              
                          #Otherwise we assume BT709
                           else if (clp.Height() > 576) {
                               clp = ConvertToYUV444(clp, matrix="PC.709")             
                              }
                }
          }
    
    clp
    nChannels=(HasAudio)?AudioChannels:0                        # HasAudio = audio_samples_per_second!=0
    
    #Mode
    Mode = Default(Mode, "SDR")
    #Type
    Type = Default(Type, "volts")

    #Errors checking                                            # ssS: Might as well do at beginning (after errchk, known Planar YUV & < 9 channels)
    Assert(nChannels<9,"VideoTek: sources with more than 8 audio channels are not supported")
    
    
    #Taking care of High bit Depth
    Bpc = BitsPerComponent
    
    (HasAlpha) ? RemoveAlphaPlane : NOP          # ssS: Avoid eg YUVA444 error in VirtualDub2 (OK in PotPlayer but grey screen in VD2 if YUVA)
    ConvertBits(bits=8)                          # ssS: Convert To YUV444, 8 bit, NO ALPHA, support all colorspace input

    #Main
    CSZ = 480                 # Chroma Size box (W & H)
    A_W = 320                 # Audio Box Width
    A_H = 460                 # Audio Box Height (Audio & Lissajoua)
    L_W = (704+704+6)-700-A_W # Lissajous Width
    SilentStereo=Last.BlankClip(width=1480, height=920,audio_rate=48000,channels=2,sample_type="Float")
    myBlack= (nChannels>0)  ? SilentStereo.AudioDubEx(Last) : SilentStereo.Killaudio
    Stereo = (nChannels>=2) ? Last.GetChannels(1,2) : (nChannels==1) ? MergeChannels(GetChannels(1),GetChannels(1)) : SilentStereo
    Stereoclip = Last.BlankClip(width=16,height=16).AudioDub(Stereo)  # Histogram(mode="StereoOverlay") requires 2 channel only clp.
    Picture   = BicubicResize(704, 396)
    chroma    = Histogram("color2").Crop(Width, 0, 0,256).BilinearResize(CSZ,CSZ)
    Audio     = myBlack.Crop(0,0,A_W,A_H).Histogram(Mode="audiolevels")
    lissajous = Stereoclip.Histogram(mode="StereoOverlay").BicubicResize(L_W,A_H)
    
    #Check whether we should put markers on or not
    if (Mode=="HLG" && Type=="nits" || Mode=="PQ" && Type=="nits") {
    
    luma      = TurnRight.Histogram(mode="classic", markers=false).TurnLeft.Crop(0,0,0,256).BiCubicResize(704, 396)
    
    }
    else {
    
    luma      = TurnRight.Histogram(mode="classic", markers=true).TurnLeft.Crop(0,0,0,256).BiCubicResize(704, 396)
    }
    

    #Putting the 4 blocks together with a black background
    MyBlack
    Overlay(Picture,   x=0,                   y=0)
    Overlay(luma,      x=704+6,               y=0)
    Overlay(chroma,    x=(704-chroma.Width)/2,y=396 + (920-396-chroma.height)/2)
    Overlay(Audio,     x=704-4,               y=396 + (920-396-audio.height) /2)
    Overlay(lissajous, x=700+Audio.Width,     y=396 + (920-396-lissajous.height)  /2)


    if (Mode=="HLG" && Type=="nits") {
    
    #Displaying Values for Luma (top right)
    #0 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=359.0, size=15, text_color=$0E7F84, utf8=true)
    Text("0 nits", x=1415.0, y=365.0, size=17)
    #100 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=166.0, size=15, text_color=$0E7F84, utf8=true)
    Text("100 nits", x=1415.0, y=173.0, size=17)
    #200 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=103.0, size=15, text_color=$0E7F84, utf8=true)
    Text("200 nits", x=1415.0, y=110.0, size=17)
    #400 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=77.0, size=15, text_color=$0E7F84, utf8=true)
    Text("400 nits", x=1415.0, y=84.0, size=17)
    #600 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=51.0, size=15, text_color=$0E7F84, utf8=true)
    Text("600 nits", x=1415.0, y=58.0, size=17)
    #1000 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=15.0, size=15, text_color=$0E7F84, utf8=true)
    Text("1000nits", x=1415.0, y=21.0, size=17)
  
    }
    else if (Mode=="HLG" && Type=="volts") {
    
    #Displaying Values for Luma (top right)
    #Reference bottom 0%
    Text("0.00V", x=1430.0, y=362.0, size=18)
    #Reference middle 50%
    Text("0.35V", x=1430.0, y=192.0, size=18)
    #Reference White 75%
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=103.0, size=15, text_color=$0E7F84, utf8=true)
    Text("0.52V", x=1430.0, y=107.0, size=18)
    #Reference top 100%
    Text("0.70V", x=1430.0, y=20.0, size=18)
    
    }
    else if (Mode=="PQ" && Type=="nits") {
    
    #Displaying Values for Luma (top right)
    #0 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=359.0, size=15, text_color=$0E7F84, utf8=true)
    Subtitle("0 nits", x=1415.0, y=369.0, size=8)
    #203 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=159.0, size=15, text_color=$0E7F84, utf8=true)
    Subtitle("203 nits", x=1415.0, y=169.0, size=8)
    #1000 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=101.0, size=15, text_color=$0E7F84, utf8=true)
    Subtitle("1000nits", x=1415.0, y=111.0, size=8)
    #2000 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=76.0, size=15, text_color=$0E7F84, utf8=true)
    Subtitle("2000nits", x=1415.0, y=86.0, size=8)
    #3000 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=61.0, size=15, text_color=$0E7F84, utf8=true)
    Subtitle("3000nits", x=1415.0, y=71.0, size=8)
    #4000 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=50.0, size=15, text_color=$0E7F84, utf8=true)
    Subtitle("4000nits", x=1415.0, y=60.0, size=8)
    #5000 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=42.0, size=15, text_color=$0E7F84, utf8=true)
    Subtitle("5000nits", x=1415.0, y=52.0, size=8)
    #6000 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=36.0, size=15, text_color=$0E7F84, utf8=true)
    Subtitle("6000nits", x=1415.0, y=46.0, size=8)
    #7000 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=30.0, size=15, text_color=$0E7F84, utf8=true)
    Subtitle("7000nits", x=1415.0, y=40.0, size=8)
    #8000 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=25.0, size=15, text_color=$0E7F84, utf8=true)
    Subtitle("8000nits", x=1415.0, y=34.0, size=8)
    #9000 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=20.0, size=15, text_color=$0E7F84, utf8=true)
    Subtitle("9000nits", x=1415.0, y=28.0, size=8)
    #10000 nits
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=15.0, size=15, text_color=$0E7F84, utf8=true)
    Subtitle("10000nits", x=1415.0, y=22.0, size=8)
    
    }
    
    else if (Mode=="PQ" && Type=="volts") {
    
    #Displaying Values for Luma (top right)
    #Reference bottom 0%
    Text("0.00V", x=1430.0, y=362.0, size=18)
    #Reference middle 50%
    Text("0.35V", x=1430.0, y=192.0, size=18)
    #Reference White 58%
    Subtitle("_________________________________________________________________________________________________", x=710.0, y=159.0, size=15, text_color=$0E7F84, utf8=true)
    Text("0.40V", x=1430.0, y=159.0, size=18)
    #Reference top 100%
    Text("0.70V", x=1430.0, y=20.0, size=18)
    
    }
    
    else if (Mode=="SDR" && Type=="volts") {
    
    #Displaying Values for Luma (top right)
    #Reference bottom 0%
    Text("0.00V", x=1430.0, y=362.0, size=18)
    #Reference top 50%
    Text("0.35V", x=1430.0, y=192.0, size=18)
    #Reference middle 100%
    Text("0.70V", x=1430.0, y=20.0, size=18)
    
    }
    
    else if (Mode=="SDR" && Type=="nits") {
    
    #Displaying Values for Luma (top right)
    #Reference bottom 0%
    Text("0 nits", x=1415.0, y=365.0, size=17)
    #Reference middle 50%
    Text("50 nits", x=1415.0, y=195.0, size=17)
    #Reference top 100%
    Text("100 nits", x=1415.0, y=23.0, size=17)
    
    }

    #Displaying TimeCode (bottom right), BitDepth and ColorSpace (bottom left)
    Subtitle("TC:", size=18, x=1309, y=896)
    #Adding workaround for fractional framerates
    Try{
    ShowSMPTE(size=18, x=1383, y=910)
    my_tc=last
    }
    catch(my_tc) {
    ShowTime(size=18, x=1383, y=910)
    }
    
    Subtitle(String(x) + "x" + String(y) + " " + String(fps) + "fps" + " " + String(colorspace) + " " + String(Bpc) + "Bit", size=18, x=11, y=896)

    return Last
}

I still have to polish it a bit but it should work

Updated version: https://github.com/FranceBB/VideoTek/blob/master/VideoTek.avsi

VideoTek(Mode="PQ", Type="nits")

Once you give me the go ahead, I'll release version 1.9 publically.

In my tests it looks good:
New File (3)000000
New File (3)2796800000
New File (80)007953
New File (80)031218

Yeah, it seems fine. For the final release I would guess it is not necessary to have all 1000 nits divisions. Just link in HLG mode not all 100 nits divisions are shown.

Yep, I agree. I picked 0 nits, 203 nits, 1000 nits, 5000 nits and 10000 nits as a reference, however I added an additional parameter: "detailed" which is a boolean and by default is set to false.
The idea here is to basically display only the 5 values above to avoid making the waveform very crowded (especially at the very top given that PQ is logarithmic and the space available gets smaller and smaller), however, if someone does actually want to see all the 1000 nits steps (i.e 0 nits, 203 nits, 1000 nits, 2000 nits, 3000 nits, 4000 nits, 5000 nits, 6000 nits, 7000 nits, 8000 nits, 9000 nits, 10000 nits) he can by using Detailed=true.

In other words:

VideoTek(Mode="PQ", Type="nits", Detailed=true)

shows all 1k increments, while

VideoTek(Mode="PQ", Type="nits", Detailed=false)

only shows the 5 values above.
By default (when omitted) it's set to "false".

This should make everyone happy. :)
Thank you for everything, I'm gonna close the issue and create a new release. :D
See you on Doom9 if you'll ever manage to recover the account (fingers crossed).