Log in

View Full Version : AviSynth+ thread Vol.2


Pages : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 [51] 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75

flossy_cake
21st May 2023, 12:24
http://avisynth.nl/index.php/Internal_functions#FunctionExists


Thanks - and sorry for not seeing it in avisynth.nl wiki - at the time I was using the offline documentation html files that come with Avisynth which is out of date and doesn't mention those ones like VarExist and FunctionExists.

gispos
21st May 2023, 13:22
New version - https://github.com/DTL2020/ConvertYUVtoRGB/releases/tag/0.3.0

Now can take also 10..16bits YUV planar and convert to 8bit YV12 internally before processing.

With skipping ConvertBits(8) before YUV to RGB with one more full frame scan it also adds performance at out-of-cache frame sizes. If AVS can either have lots of ready to use SIMD functions inside for different conversions with single source scan or can dynamically compile required SIMD program for requested format conversion it can save from several host RAM read/writes for sequence of formats conversion and adds to performance.

That's great, the new version runs faster even with YUV420P16 than the previous one with only YUV420P8.
With the previous one I had to put a ConvertBits(8) in front.

Thanks for the new version!
A big improvement would be if the mod 64 could be scaled down.

I have a new Pre-Release that works with both DLL versions.
https://drive.google.com/drive/folders/1I7yNkFLoYmOush5Olx-jT799GphKcSwX?usp=share_link

DTL
21st May 2023, 15:00
Here is attempt to process all widths - https://github.com/DTL2020/ConvertYUVtoRGB/releases/tag/0.3.1

It looks with 64 samples per pass it is not compatible with max mod64 bytes rows strides ? So the last columns up to 63 are processed with simple C-scalar program. At UHD frame 3840+60 width and at i3-9100T CPU it looks not add significant penalty -
3840 width 313 fps
3840+60 width 308 fps.

It is not tested with all possible frame widths so some bugs may happen.

"the new version runs faster even with YUV420P16 than the previous one with only YUV420P8. "

From ver 0.3.0 I set cs default to false as I see it typically make storing data faster and users may be lazy to test best setting of true/false at current host.

gispos
21st May 2023, 20:41
Here is attempt to process all widths - https://github.com/DTL2020/ConvertYUVtoRGB/releases/tag/0.3.1
.
Wow! Wow! Wow! I can hardly believe it, excellently done!

Tried all dimensions and no error received so far.
4K ColorBar YUV420P10 with AvsPmod 'Resample Filter' and option 'Prefetch display conversion' resized to 1980 x 1080
runs in playback with ~153 fps shrunk to 1280 x 720 it is ~189 fps

ColorBar 1920 x 1080 YUV420P10 ~196 fps in the playback with display drawing.

I've spent a few hours optimizing everything, at least it was worth it.

Thanks!

flossy_cake
27th May 2023, 11:46
And see Gavino stuff here [try move as much code as you can out of Scriptclip script and into function].

string (as a whole) is created only once when the containing script is loaded. However, that string itself is parsed afresh on every frame, which means that any identifiers and string literals within it are repeatedly added to the string heap...this was the source of a memory leak in SRestore

The solution is to move the code inside the run-time script to another function, reducing the run-time script itself to a simple function call. This effectively eliminates memory problems, and also gives a speed increase.

In other words, instead of
ScriptClip("""
... very long script ...
""")
use
function f(... some params ...) {
... previous script code ...
}
...
ScriptClip("f(...)")



Unfortunately it appears the solution above requires ScriptClip(local=true) which doesn't allow messaging between frames, which I absolutely need.

So I am stuck with a huge memory leak - around 2MB/sec in my case :o

Is there perhaps some way to manually "clear the string heap"?

StainlessS
27th May 2023, 12:50
Is there perhaps some way to manually "clear the string heap"?
Nope, nuttin' at all, no mem is garbage collectable.

What are you trying to do, post what you attempted.

EDIT: You can still use globals even when Local = true.
Must use eg

Global SomeVar = WhateverVar

Trying to pass a 'Stored Frame", will fail after a few (hundred or thousand) frames, ie Huge mem usage.
(You are calcing current frame, based on previous frame, which is also based on frame before it, etc.
Not possible to just "throw away" prev temp frames as re-seek requires every frame before it to be available.)

EDIT:
I have tried many times (and find hard to accept the futility) to try find solution for what it is I think that you are trying to do,
even this attempt at solution failed.
FrameStore v0.03 - Avs+ x86/x64 - 15 Jan 2019
https://forum.doom9.org/showthread.php?t=175212

flossy_cake
27th May 2023, 13:29
What are you trying to do, post what you attempted.

This is leaking around 1.3MB/sec for 30fps video on my system (too big to paste on forum): https://pastebin.com/raw/pKfBJ26Q

This however produces no leak: https://pastebin.com/raw/PGWtzubz

But it won't allow runtime funcs like this:


ScriptClip( last,
\ function [] (c) {

diff = YDifferenceToNext(c, -1) # requires local=true, else error message
c

} , after_frame=true, local=false)


If I set local=true then I lose the ability to message between frames:


global PrevFrameNumber = 0

ScriptClip( last,
\ function [] (c) {

global PrevFrameNumber = PrevFrameNumber + 1 # doesn't work, just stays at 1
c.SubTitle(String(PrevFrameNumber))

} , after_frame=true, local=true)


Perhaps messaging could be done through frame properties instead.

StainlessS
27th May 2023, 13:43
Sorry, I aint got a clue about that new fangled "Function [] (c)" stuff, old dog and new trick thingy.

Perhaps messaging could be done through frame properties instead.
Same, old dog, new tricks.

StainlessS
27th May 2023, 13:52
Is this what you are tryin' to do with that there new fangled stuff ?


/*
ScriptClip( last,
\ function [] (c) {
# EDIT: "Plane Difference: this filter can only be used within run-time filters.
diff = YDifferenceToNext(c, -1) # requires local=true, else error message
c

} , after_frame=true, local=false)
*/

Colorbars.Killaudio.ConvertToYV12

Function func(clip c) {
diff = YDifferenceToNext(c, -1) # EDIT: Works. Does NOT require local=true
c.Subtitle(String(diff))
}

SSS = """
func()
"""

ScriptClip( SSS , after_frame=true, local=false)

And

/*
ScriptClip( last, function [] (c) {
global PrevFrameNumber = PrevFrameNumber + 1 # doesn't work, just stays at 1
c.SubTitle(String(PrevFrameNumber))
} , after_frame=true, local=true)
*/


Colorbars.Killaudio.ConvertToYV12

Global PrevFrameNumber = 0

Function func(clip c) {
Global PrevFrameNumber = PrevFrameNumber + 1 # EDIT: Works, Does NOT stay at 1
c.SubTitle(String(PrevFrameNumber))
}

SSS = """
func()
"""

ScriptClip( SSS , after_frame=true, local=true)


EDIT: Both above WORK OK.

Rob105
27th May 2023, 21:01
path = "C:\Video\"

v0 = FFmpegSource(path + "video.mp4")

v1 = ImageSource(path + "Colors Gradient Horizontal 1920x1080.jpg", fps=50, end = 299).crop(0,980,0,0)
v2 = ImageSource(path + "BW Gradient Horizontal 1920x1080.jpg", fps=50, end = 299).crop(0,980,0,0)

StackVertical(v0, v1, v2)
Avisynth open failure: StackVertical: image formats don't match

How do i make it work?

Source files https://www.upload.ee/files/15277223/video.zip.html

flossy_cake
27th May 2023, 23:27
EDIT: Both above WORK OK.

Hmm neither are working for me - I'm getting the same result as the previous samples. I copy pasted your exact code so I'm not sure what's going on. What version Avisynth are you using? I've got 3.7.3 (r3936, 3.7, x86_64).

FranceBB
27th May 2023, 23:36
How do i make it work?


Easy peasy lemon squeezy: a simple Converttoyv12() after you index the images will do it. ;)


FFMPEGSource2("D:\video\video.mp4", fpsnum=50000, fpsden=1000, atrack=-1)

img1=ImageSource("D:\video\Colors Gradient Horizontal 1920x1080.jpg", fps=50, end=212).crop(0, 980, 0, 0).Converttoyv12()

img2=ImageSource("D:\video\BW Gradient Horizontal 1920x1080.jpg", fps=50, end=212).crop(0, 980, 0, 0).Converttoyv12()


StackVertical(last, img1, img2)



https://i.imgur.com/go5QX1Y.png


Explanation:

when you stack together different clips, they must all be the same, so you need to convert either the original video file you're indexing to reflect the two jpg you're trying to add on OR the other way around. In the example, I've done the opposite, so I've converted the two images to yv12 (4:2:0 planar 8bit).


I can now shut down my computer and go to bed :P

StainlessS
28th May 2023, 05:37
Hmm neither are working for me - I'm getting the same result as the previous samples. I copy pasted your exact code so I'm not sure what's going on. What version Avisynth are you using? I've got 3.7.3 (r3936, 3.7, x86_64).

v3.7.3(r3825,master, x86_64)

EDIT: Re-checked and both do work OK here.
Perhaps others with either version could verify results.

flossy_cake
28th May 2023, 06:11
v3.7.3(r3825,master, x86_64)

EDIT: Re-checked and both do work OK here.
Perhaps others with either version could verify results.

Thanks, I tried a few other versions without luck. In the end I got it working by copying exactly what Gavino's SRestore does:


global count = 0

ScriptClip(last, "MyFunc(last, current_frame)", after_frame=true, local=false)

function MyFunc(clip c, int current_frame) {

global count = count + 1
diff = YDifferenceToNext(c, -1)
c.SubTitle(string(diff) + ", " + string(count))
}


Passing current_frame to MyFunc is what makes it work for me, otherwise I get "this filter can only be used within run-time filters".

Hopefully there is no other weird side effect of doing it this way, but I've got a feeling it's going to be weird about something.

StainlessS
28th May 2023, 11:17
Also, the first of the scripts [works for me, not for you], kinda surprised me,
I was under the impression that current_frame did not survive when calling a function,
stangely it worked for me in that script where I might have expected it not to.
[perhaps something strange in the version I'm currently using].

Passing current_frame to MyFunc is what makes it work for me, otherwise I get "this filter can only be used within run-time filters".

Yep, I posted similar in Usage a little while ago.
https://forum.doom9.org/showthread.php?p=1986042#post1986042
Current_frame is not available outside of the runtime environment, and dont make much sense there either.
But, (probably not of use in required case) you can hack a one time use (on a single frame) just by setting
it to that frame number, eg


blankclip(length=100,pixel_type="YV12")
C = Last.BlankClip(length=0) # zero len clip, same characteristics as Last clip
For(n=0,FrameCount-1) {
current_frame = n # HACK for below AverageLuma
Y = AverageLuma # access frame n
T = Trim(n,-1)
T = T.Subtitle(String(n) + String(Y," : %f"),align=5)
C = C ++ T # add single frame n, to clip so far
}

C # Play C


current_frame is set only for use within runtime (eg by ScriptClip) where it is initialised before each frame that is processed by
the script arg of Scriptclip. Hacking current_frame to some number just allows to use some runtime func (eg AverageLuma), on that SINGLE frame.

EDIT:
Nuther script of limited use

blankclip(length=100,pixel_type="YV12")

Function SomeFunc(clip c, int n) { # Dont think current_frame is visible within this func, but can be provided by caller in n
current_frame = n
Y = c.AverageLuma
Return Y
}

SSS="""
Y = SomeFunc(Last,current_frame)
return Subtitle(String(current_frame) + String(Y," : %f"))
"""

ScriptClip(SSS)


# ...



EDIT:
Function SomeFunc(clip c, int current_frame)
Does not taste quite right to me, so I used an int n then assigned to current_frame internal to function.

Gavino
28th May 2023, 17:06
Also, the first of the scripts [works for me, not for you], kinda surprised me,
I was under the impression that current_frame did not survive when calling a function,
stangely it worked for me in that script where I might have expected it not to.
[perhaps something strange in the version I'm currently using].
Are you using GRunT's ScriptClip()?
In GRunT (unlike vanilla Avisynth 2.x), current_frame is a global variable (though still of course only visible inside the run-time environment).
Avs+ has incorporated some functions of GRunT, but I'm not sure if this one applies there.

StainlessS
28th May 2023, 22:31
Are you using GRunT's ScriptClip()?
Yep, renaming Grunt.dll so as not to use it,

1st script produces error report.

2nd script, shows subtitle '1' for all frames.

Cheers Gavin. [nice Welsh name].

DTL
28th May 2023, 23:26
Made new version of converter to RGB32 - https://github.com/DTL2020/ConvertYUVtoRGB/releases/tag/0.4.0

It is finally more correct processing in 16bit intermediates and in narrow range the resudual error only about +1LSB. After gained to Full range - at some colours may reach error of 2LSB.

Also when compared to ConvertToRGB32(matrix="PC.709") it was found that matrix (coefficients ?) in AVS core is somehow broken:

At script:

ColorBarsHD(640, 480, pixel_type="YV24")
ConvertToYV12()

ConvertToRGB32(chromaresample="point", matrix="PC.709")


Output for colours (R,G,B):
Yellow 181, 180, 12
Cyan 12, 181, 180
Green 13, 181, 12
Magenta 183, 15, 184
Red 184, 15, 16
Blue 15, 16, 184

The DecodeYUVtoRGB with narrow range mapping (gain=64 and offset=16) keep output in 15..17 and 179..181 range. It was found with math simulation the 8bit YUV can not be decoded to ideal 16 and 180 RGB at all colours because or already rounding errors in 8bit YUV. So only with 10bit and more it can be reach ideal 16 and 180 levels output.

Also added 32bit immediates processing mode - it run 2+ times slower at AVX2 and provide only slightly better precision in the Full range mapping (error looks like +-1LSB). And close to no better in narrow range. So it looks 32bit immediate processing only required for >8bit sources and results. And can make a bit better precision with 8bit output only if input is >8bit.

For some possible future of fastest 16bit immediate processing engine for YV12 to RGB32 it is possible to play with coefficients tweaking and rounders tweaking and may be reduce average error over all possible range of YUV input 8bit values - using some math simulator engine. But it require programmer of such optimizing engine.

Also added x86_32 build if someone still use 32bit Windows. It runs only slightly slower (register file size in 32bit CPU mode is 1/2 of size and compiler make more data temporal store/load from cache).

kedautinh12
29th May 2023, 01:08
First time for 32 bit from DTL :D

poisondeathray
29th May 2023, 03:00
Note that "PC matrices" are not quite the same thing as "Studio RGB", or "limited range RGB" used in broadcast or some NLE's

The equivalent way in avisynth as what's used a Studio RGB NLE (like vegas) for 8bit for that example above would be


ColorBarsHD(640, 480, pixel_type="YV24")
ConvertToYV12()
Levels(0,1,255,16,235, coring=false)
ConvertToRGB32(chromaresample="point", matrix="rec709")


Y 180,179,16
C 16,181,179
G 16,179,14
M 179,16,181
R 180,16,17
B 15,16,180

There was an old dedicated "studio RGB" function by "trevlac" for avisynth


EDIT:
It should be coring=false . Limiting (for example 0,255) is separate . Nominal Black to white is defined as 16 to 235 for studio RGB, but you can have superblack, superwhite . If you clip it in the levels (coring=true), you never get superblack or superwhite

DTL
29th May 2023, 06:56
What was the reason for such strange matrix ? Wiki says PC-matrix keep range unchanged. But ColorBarsHD already create levels in standard (industry ITU-R/ARIB) narrow range. Additional Levels of 0,255 to 16,235 looks like compress range even more ? Also aditional Levels() make precision and performance lower - may be add one more single-filter 'matrix' to ConvertToRGB() to create 16..235 RGB from 16..235 standard YUV ?

Also using Levels() for >8bit create additional nightmare for users to compute correct params because it is not autoscale.

Also it is good to add into documentation (wiki ?) about PC-matrix only in Convert() do not keep range in 16..235 (as input) but create some distorted RGB decode (above possible compute errors for 8bit in/out) in narrow-like levels if input standard narrow range not additionally compressed with Levels() processing.

"First time for 32 bit"

I see avspmod still release 32bit builds and require 32bit .dll for it. But I think at AVX2 chips users mostly running x64 OS so 32bit builds a not very required. With intrinsics-based SIMD program 32bit builds are easily possible (mostly all instructions have 32bit versions) but may have somehow lower performance because in 32bit mode addressable by instructions register file space is 1/2 of total.

Rob105
29th May 2023, 07:31
When opening Avisynth script is there command to get windows open file window to populate variable with the video.

Purpose is i have script that do not change at all, but file i apply script to changes a a lot, i don't want to type file name in script, i want to use windows open file dialog to populate it.

How i apply Avisynth script to all video files in folder, batch?

FranceBB
29th May 2023, 07:53
How i apply Avisynth script to all video files in folder, batch?

Let me introduce you to the fantastic world of FFAStrans: https://forum.doom9.org/showthread.php?t=176655
It does exactly what you want in terms of automation.
Just add a watchfolder -> A/V Decoder -> Custom Avisynth Script (doing whatever you want) -> Encoder -> Delivery
works every time. ;)

DTL
29th May 2023, 09:11
Note that "PC matrices" are not quite the same thing as "Studio RGB", or "limited range RGB" used in broadcast or some NLE's

The equivalent way in avisynth as what's used a Studio RGB NLE (like vegas) for 8bit for that example above would be


ColorBarsHD(640, 480, pixel_type="YV24")
ConvertToYV12()
Levels(0,1,255,16,235)
ConvertToRGB32(chromaresample="point", matrix="rec709")


Y 180,179,16
C 16,181,179
G 16,179,14
M 179,16,181
R 180,16,17
B 15,16,180

There was an old dedicated "studio RGB" function by "trevlac" for avisynth

I tried 2 more plugins for convert: avsresize and fmtc - they both output equal RGB in narrow range and can accept feed from ColorBarsHD directly:

Y 180, 180, 16
C 16, 180, 179
G 16, 180, 15
M 180, 16, 181
R 180, 16, 17
B 16, 16, 180

So it looks only AVS internal 'narrow' matrix is something special and of lowest precision if even feed by 'double-narrow' 8bit YV24.

poisondeathray
29th May 2023, 15:29
What was the reason for such strange matrix ?

Not sure what the "PC matrix" was originally for. Back then, people didn't know what "studio RGB"/"limited range RGB" was.

I tried 2 more plugins for convert: avsresize and fmtc - they both output equal RGB in narrow range and can accept feed from ColorBarsHD directly:

Y 180, 180, 16
C 16, 180, 179
G 16, 180, 15
M 180, 16, 181
R 180, 16, 17
B 16, 16, 180


zimg/avsresize seems better/faster for just about everything in terms of pixel format conversions than internal functions.

Rob105
30th May 2023, 12:08
Subtitle() (http://avisynth.nl/index.php/Subtitle) problem.

Subtitle("Hello World!", font="Arial", size=34, text_color=color_gold, halo_color=color_black, align=1, x=20)

Shows text in bottom left corner, if i add y=-20 to move text 20 pixels up from bottom left corner, text disappears.

I have to use frame height 1080 minus 20 = 1060 in y value.

Subtitle("Hello World!", font="Arial", size=34, text_color=color_gold, halo_color=color_black, align=1, x=20, y 1060)

this is major annoyance that whenever i set y value for Subtitle() function it starts to move text from top rather than its current position, am i doing something wrong or its a bug? I use AviSynthPlus_3.7.2_20220317_vcredist.exe


Let me introduce you to the fantastic world of FFAStrans: https://forum.doom9.org/showthread.php?t=176655
It does exactly what you want in terms of automation.
Just add a watchfolder -> A/V Decoder -> Custom Avisynth Script (doing whatever you want) -> Encoder -> Delivery
works every time. ;)

Thanks will give it a try.


Easy peasy lemon squeezy: a simple Converttoyv12() after you index the images will do it. ;)

Explanation:

when you stack together different clips, they must all be the same, so you need to convert either the original video file you're indexing to reflect the two jpg you're trying to add on OR the other way around. In the example, I've done the opposite, so I've converted the two images to yv12 (4:2:0 planar 8bit).



Thx for explaining.

StainlessS
30th May 2023, 12:45
When opening Avisynth script is there command to get windows open file window to populate variable with the video.

Purpose is i have script that do not change at all, but file i apply script to changes a a lot, i don't want to type file name in script, i want to use windows open file dialog to populate it.

How i apply Avisynth script to all video files in folder, batch?

1) Not exactly what you want but might like to know if its existence.
From RT_Stats plugin. https://forum.doom9.org/showthread.php?t=165479

RT_FSelOpen(string "title"="Open",string "dir"="",string "filt",string "fn="",bool "multi"=false,bool "debug"=false)

Function to select EXISTING filename using GUI FileSelector.

Title = Title bar text.
Dir = Directory, "" = Current
Filt = Lots, eg "All Files (*.*)|*.*"
[Displayed text | wildcard] [| more pairs of Displayed text and wildcard, in pairs ONLY].
first one is default.
fn = Initially presented filename (if any).
multi = Multiply Select filenames. Allows selection of more than one filename at once.
debug = Send error info to DebugView window.

Returns
int, 0, user CANCELLED.
int, non zero is error (error sent to DebugView window).
String, Filename selected, Chr(10) separated multiline string if MULTI==true (and multiple files selected).

Example, to prompt for an AVI file and play it.
avi=RT_FSelOpen("I MUST have an AVI",filt="Avi files|*.avi")
Assert(avi.IsString,"RT_FSelOpen: Error="+String(avi))
AviSource(avi)

***
***
***

Function RT_FSelSaveAs(string "title"="Open",string "dir"="",string "filt",string "fn="",bool "debug"=false)

Function to select filename for Save using GUI.

Title = Title bar text.
Dir = Directory, "" = Current
Filt = Lots, eg "All Files (*.*)|*.*"
[Displayed text | wildcard] [| more pairs of Displayed text and wildcard, in pairs ONLY].
first one is default.
fn = Initially presented filename (if any).
debug = send errors to DebugView window.

Returns
int, 0, user CANCELLED.
int, non zero is error (error sent to DebugView window).
String, Filename selected.
Will prompt to overwrite if file already exists.

***
***
***

Function RT_FSelFolder(string "title"="",string "dir"=".",bool "debug"=false)

Function to select Folder using GUI.

Title = UNDERNEATH the title bar text, for instructions.
Dir = Directory, Default "." = Current, ""=Root.
debug = Send errors to DebugView window.

Returns
int, 0, user CANCELLED.
int, non zero is error (ie -1, error sent to DebugView window, usually selecting non Folder object eg 'My Computer').
String, Folder selected (minus trailing BackSlash).


2) Avisynthesizer_Mod
A SendTo App that allows Windows Explorer selection of video files and fills in a user supplied Template with the filenames.
Can concatenate (join/splice) selected files (default as original non mod version) and create a single output AVS file OR,
batch create multiple AVS files, one for each input source file (MOD version only).
Has a GUI to select required template and sort input files if multiple input files selected.

https://forum.doom9.org/showthread.php?t=166820

Also, This thread is Avisynth Development thread, not really for asking questions on Usage, Avisynth Usage forum appropriate place for that.

Do not reply in this thread to this post, thanx.

Rob105
31st May 2023, 04:19
Do not reply in this thread to this post, thanx.
Do not tell others what to do, thanks.

kedautinh12
31st May 2023, 04:31
Do not tell others what to do, thanks.

StainlessS right, you ask wrong thread, you need create a thread in avisynth usage

gispos
31st May 2023, 17:05
Made new version of converter to RGB32 - https://github.com/DTL2020/ConvertYUVtoRGB/releases/tag/0.4.0

It is finally more correct processing in 16bit intermediates and in narrow range the resudual error only about +1LSB. After gained to Full range - at some colours may reach error of 2LSB.

Yes, the colors are even better (more accurate) and I am glad that there is also a 32bit dll.
Thanks again for your work. I hope you don't mind because I deliver the dll with AvsPmod.

Edit:
I think you have something mixed up

Full range - gain=74, offset=0,
narrow range - gain=64, offset=16,
zero black and non-clipping superwhited - gain=69, offset=0.

should be

Full range - gain=64, offset=16
narrow range - gain=74, offset=0

DTL
31st May 2023, 21:09
"should be

Full range - gain=64, offset=16
narrow range - gain=74, offset=0"

No. In latest version the computing of R,G,B changed significantly (the 16 is subtracted from Y at first). So in old versions (not correct) the computing make R,G,B in 16..235 range, and in latest version it is in 0..219 range (with signed integer 16bit format so underblacks are negative).

0..219 range with negative underblacks is not standard to either narrow or full range in 8bit output. So to make it narrow - addition of 16 only required and to make it full - multiplication to (255/219)*64=74.5 only. So to output narrrow range it is now required gain=64 (no gain), offset=16. So to output full range - gain=74, offset=0 (no offset). To make computing a bit faster I even thing about templating main processing function even more so it can skip multiplication and addition of rounder and shifting if only addition of offset of 16 is required or skip addition if only range scaling is required. But it still not implemented because may not make significant difference in performance and make program text even more complex. And I think multiplication to 64 with addition of rounder of 32 and integer shift to 6 bits to the right (/64) not make precision lower in compare with skipping this operation (may be I not correct here because addition of rounder 32 may somehow change output in worse precision ?) in case of outputting narrow range with gain=64 and offset=16. So currently 'proc-amp' of gain+offset always full active. Also it may be some research if the sequence of operations of multiplication (range scale) and addition may make residual errors less - may be it is more better to make addition of offset first and next is scale. The total performance may be not any depend of the sequence of operations but residual error over all RGB range may change somehow. So current version have some internal features not completely optimized for case of gain only (no offset) and offset only (no gain) operations. Also the non-clipping superwhites monitoring setting of gain=69, offset=0 also required no offset so do-nothing addition of 0 may be skipped with some very small performance gain. Though most of expected operations with output full-RGB and non-superwhites clipping RGB both require full scale operation (of 3 stages - integer multiplication, addition of rounder and div-shifting). So only may be currently rare-needed narrow-RGB output may possibly benefit a bit in precision and performance if the scale/gain 3 operations may be skipped in completely template-based if-then new version. But it require even more complex selector of processing function (if gain=64 - select no-gain proc function version and if gain !=64 - select gain-proc function version). It may finally require redesign all large number of combinations params selector to 'tuple-type' like was implemented in mvtools by pinterf and not large and very complex set of if-else statements (they can also eat some performance and make program text harder to design and understand). May be will try it in some next versions.

Also about possible precision optimizations: Current computing of RGB performed not with 3x3 matrix multiplication and additions but with 'classic' RGB equations and with 16bit signed immediates:

R = (Y-16) + (Kr * (V-128) + 32) >> 6;
B = (Y-16) + (Kb * (U-128) + 32) >> 6;
G = (Y-16) - (Kgu * (U-128) + 32) >> 6 - (Kgv * (V-128) + 32)>>6;

this produce RGB in 0..219 range.

and proc-amp to make required range mapping
Val = ((Val * gain) + 32) >> 6) + offset;

So it have internally 16, 128 and 32 lots of hidden constants and matrix-dependent Kr, Kb, Kgu, Kgv coefficients and may be using some optimizing software (like zopti ?) there constants and coefficients may be tweaked so the absolute mean error over possible RGB output values may be reduced to minimum (in both or separate narrow-range RGB output mode and/or full-range RGB). But it require to run optimizer software with about 18 input variables (of 16bit signed short each) to optimize - may be long to run and I still not know this ready to use optimizer software (with brute-force search for example in +-defined range for each variable). May be some simple C-program may be designed to make this optimizing search.

16bit immediate computing allow to about double performance of AVX-engine in compare with 32bit immediate but not allow to accumulate several multiplication results before addition of rounder and div-shifting.
With 32bit immediate the possible computing is like

R = (R (Y, Kr, V, gain, offset) + rounder(4096)) >> 13; so it possibly have less rounder addition operations and div-shifts but total compute performance in 32bit IOPS is only 1/2 of 16bit IOPS for AVX-engine. Also the total workunit size for 32bit immediate only 1/2 of 16bit immediate computing (32 or 64 RGB triplets per 1 SIMD pass for AVX2). So the 32bit immediate computing mode can be also checked for performance in 3x3-matrix way of computing (as in AVS core now). The simple redesign of non-matrix computing to 32bit immediate shows it is about 2+x times slower.

gispos
1st June 2023, 16:33
"should be

Full range - gain=64, offset=16
narrow range - gain=74, offset=0"

No. In latest version the computing of R,G,B changed significantly (the 16 is subtracted from Y at first). So in old versions (not correct) the computing make R,G,B in 16..235 range, and in latest version it is in 0..219 range (with signed integer 16bit format so underblacks are negative).

Then I'll probably mess something up. I asezoate 'narrow range' with TV-levels 16-235 and 'full range' with PC-levels 0-255

Is that correct?
But I just saw that if I look at a YV12 with PC-levels I get only 235 as white value and with TV-levels 255 (RGB value).

I am completely confused now, where is my thinking error?

AvsPmod Display setting TV-Levels:
ConvertToRGB32("Rec709") and DecodeYUVtoRGB(matrix=1, gain=74, offset=0) are the same (I thought this is narrow range)

AvsPmod Display setting PC-Levels:
ConvertToRGB32("PC709") and DecodeYUVtoRGB(matrix=1, gain=64, offset=16) are equal (I thought this is full range)

StainlessS
1st June 2023, 17:43
Then I'll probably mess something up. I asezoate 'narrow range' with TV-levels 16-235 and 'full range' with PC-levels 0-255
Google guesses that you mean "associate" there. [better than my guess which did not exist]

DTL
1st June 2023, 21:52
"'narrow range' with TV-levels 16-235 and 'full range' with PC-levels 0-255"

Yes - in EBU terms narrow range is 16..235. And PC is not limited to any range mapping but widely used at PCs sRGB uses 0 black and 255 max (and nominal ?) white.

"AvsPmod Display setting TV-Levels:
DecodeYUVtoRGB(matrix=1, gain=74, offset=0) are the same (I thought this is narrow range)"

In latest version with 0..219 computing it is not correct. The 'narrow' integer range mapping is also 'shifted/offsetted range' - its black is offsetted to code value 16 in 8bit words to have some footroom for underblacks in same 8bit unsigned words. Underblacks (and superwhites) typically not exist in PC-sRGB so sRGB (named also full) not require such shift and compression of nominal white to under-255 area.

Also PC-users like to map nominal 'moving pictures' white of 235 to max sRGB 255 white (so possible valid superwhites of 'motion pictures' become clipped). It is just one of widely used practice - other users may like to monitor up to at least 254 'moving pictures' Y/RGB non-clipped or even route RGB datastream to 'video/motion pictures/professional' display device (not sRGB PC monitor) - so that device will handle all levels in 0..255 code words in 'narrow mapping' as it should (with both scaler and displaying of superwhites).

So to convert computed in 0..219 RGB signed 16bit integer to narrow/shifted unsigned integer it is required to add only offset of 16. After adding offset of 16 it will map to 16..235 (it not mean 0..15 and 236..255 code values are not used - they may be populated with underblacks and superwhites).

" DecodeYUVtoRGB(matrix=1, gain=64, offset=16) are equal (I thought this is full range)"

To convert 0..219 into full-sRGB range only gain/scale with 255/219 ratio required so it is DecodeYUVtoRGB(matrix=1, gain=74, offset=0). Negative underblacks below 0 in signed 16bit integers are auto-cut-off by saturated 16bit signed to 8bit unsigned SIMD conversion at 8bit RGB producing so not require additional handling.

gispos
1st June 2023, 22:40
"'narrow range' with TV-levels 16-235 and 'full range' with PC-levels 0-255"

Yes - in EBU terms narrow range is 16..235. And PC is not limited to any range mapping but widely used at PCs sRGB uses 0 black and 255 max (and nominal ?) white.

Described the other way:

ConvertToRGB32("Rec709") visually looks like DecodeYUV(matrix=1, gain=74, offset=0).
And "Rec709" is called TV-levels, so narrow range

ConvertToRGB32("PC709") visually looks like DecodeYUV(matrix=1, gain=64, offset=16).
And "PC709" is called PC-levels, so full range

But you write:
narrow range = gain=64, offset=16
full range = gain=74, offset=0

But it doesn't matter, I use it in a way that it matches the other settings.

DTL
2nd June 2023, 09:27
First you need to download latest ver 0.4.0 (all previous uses different RGB computing and require different output proc-amp settings for levels mapping).

Test script for both levels and performance is

LoadPlugin("DecodeYUVtoRGB.dll")

ColorBarsHD(640, 480)
ConvertToYV12()

// make caching of YV12 to skip ConvertToYV12 compute at each frame for performance check
Trim(1,1)
Loop(1000000)

DecodeYUVtoRGB(matrix=1, gain=64, offset=16)


I open it in the VirtualDub and Ctrl+1 frame to buffer and paste into MS Paint to check levels in code values with colour pick tool (not simply look into image) -
Its Yellow patch RGB is in the narrow range of 180 and 16. 180 is computed to 180-16=164 164/219=~0.75 and it looks correct for 75% colour bars (in transfer-domain, not linear).

Also in VirtualDub monitor window it is visible all black level setup patches are visible (using PC sRGB monitor mode) - so black is shifted/offsetted to higher levels from normal display. If user have PC or other display with switching to limited/narrow/16-235 levels display - it may be switched to that mode and black will be placed to nominal.

For full range -
DecodeYUVtoRGB(matrix=1, gain=74, offset=0)

Now Yellow patch RGB is in range 190 and 0 - it is full (sRGB) range mapping with zero black for sRGB black display.

ConvertToRGB32(matrix="Rec709") - output Yellow RGB in 191 and 0 range - so it is equal to full/sRGB.

ConvertToRGB32(matrix="PC.709") - output Yellow RGB in 181/180/12 - it is somehow 'broken' narrow/limited range.

Also some info on YUV to RGB computing:
The simple equations of
R,B = Y + (Kb, Kr) * (U, V)
G = Y - Kgu * U - Kgv * V

Looks only work for YUV in 0.0f..1.0f range and produce RGB in 0.0..1.0f range. It was designed for some abstract YUV also may be analog range 0 to 0.7V , bipolar voltage with negative underblacks.

Digital YUV with unsigned integers code values have scaled and biased range, also not equal Y and UV scale:
Digital Y is Y*219 + 16
Digital UV is UV*224 + 128
(looks like equal for all commonly used standards of 601/709/2020)

So before start computing of RGB it is required both subtraction of bias of 16 and 128 from Y and UV and also make scale of UV and Y equal (for example division of UV to 224/219=1.02283). The additional division may be included into Kr,Kb, Kgu, Kgv coefficients of computing to make processing faster.

So version of DecodeYUVtoRGB from 0.4.0 have both Y-16 added and division of UV to 1.02283 included - so total compute errors in RGB expected to be lower. But it also cause range shift to 0..219. Also it adds some performance penalty over versions before 0.4.0 but I hope not very visible.

poisondeathray
2nd June 2023, 16:40
What was the reason for such strange matrix ? Wiki says PC-matrix keep range unchanged.


PC matrix still has usage scenario - for full range video. Y=0 black , Y=255 white . Many videos are full range out of the camera (e.g. gopro, many consumer cameras, some phones), gameplay recordings

If you take a perfect full range ramp Y 0-255 from a 256 width video. The pc matrix returns RGB 0-255. Each x-coordiante produces perfect RGB value. (e.g. x position 96 would equal RGB 96,96,96)


BlankClip(length=1, width=256, height=256, pixel_type="Y8")
mt_lutspa(mode="relative closed", expr="x 255 *")


Neither of the DecodeYUVtoRGB variants produce the 1:1 mapping desired result in this case, there are values repeated and missing


For 'Full' levels mapping: DecodeYUVtoRGB(matrix=0, threads=1, gain=74, offset=0)

For non-clippig superwhites monitoring or other processing with zero black: DecodeYUVtoRGB(matrix=0, threads=1, gain=69, offset=0)

DTL
2nd June 2023, 17:28
So we have different YUV->RGB conversion tools for different use cases. My version designed to better decode colour bars from some (Japan/Asian ?) ARIB standard YUV implemented in AVS ColorBarsHD() source. I not test extreme 'full YUV' values.

"If you take a perfect full range ramp Y 0-255 from a 256 width video. The pc matrix returns RGB 0-255. Each x-coordiante produces perfect RGB value. (e.g. x position 96 would equal RGB 96,96,96)"

But to decode output of ColorBarsHD with better low/high RGB mapping to 16 and 180 it require additional Levels() processing ?

"Neither of the DecodeYUVtoRGB variants produce the 1:1 mapping desired result in this case, there are values repeated and missing"

Hmm - the initial design of DecodeYUVtoRGB is to decode 'always narrow/limited' YUV to either narrow/limited or 'full' or other RGB. I not test it with 'full YUV' input. I even not shure how awful nightmare may be full-YUV in 8bit if our 'normal YUV narrow/limited' already produce out-of-range RGB triplets. Though if this 'full YUV' is encoded from game capture with RGB full-range initially it will simply not have some extreme YUV triplets ?

As I read the PC-matrix is 'not change range'. So if you provide 'full YUV' and want 'full RGB' (unchanged range) it probably will be with
DecodeYUVtoRGB(matrix=0, threads=1, gain=64, offset=16) (no gain, offset 16 to compensate for input Y-16).

So gain=64, offset=16 proc-amp setting should work as 'not change range' - if narrow/limited input - it will also output narrow/limited. Also if full input - it will also output full. And gain=74, offset=0 is 'expand from narrow/limited to full' range setting.

Also if user want full YUV to narrow/limited RGB conversion it may be gain=55 ((219/255)*64) and offset=16 (may be someone need such conversion too).

poisondeathray
2nd June 2023, 18:02
But to decode output of ColorBarsHD with better low/high RGB mapping to 16 and 180 it require additional Levels() processing ?


Yes for PC matrix. That was demonstrated earlier. PC matrix is not the same thing as "Studio RGB"



Though if this 'full YUV' is encoded from game capture with RGB full-range initially it will simply not have some extreme YUV triplets ?

Probably - Game captures begin as RGB (and some people capture as RGB for higher quality, eg. Fraps) ,but many people capture as full range YUV. The conversion is 8bit RGB to 8bit YUV full range using something similar to PC matrix

But full range YUV camera recordings are internally raw, debayered to RGB and processed at higher bitdepths, then converted to usually 8bit 4:2:0 full range for the recording format. Some recording formats are 10bit 4:2:0 now, 10bit is becoming more commonplace in consumer world


As I read the PC-matrix is 'not change range'. So if you provide 'full YUV' and want 'full RGB' (unchanged range) it probably will be with
DecodeYUVtoRGB(matrix=0, threads=1, gain=64, offset=16) (no gain, offset 16 to compensate for input Y-16).


Not change min,max range, or intermediate ranges ? For Y values on the grey ramp , none of the values are changed . Y = R = G = B

Yes that's equivalent to pc matrix for Y values on the ramp . Not sure about colors. But it is a valid usage case, I suggest you add that example to the documentation examples.

DTL
3rd June 2023, 10:02
"PC matrix is not the same thing as "Studio RGB"

As practice show the YUV to RGB decoder may have its own Transfer Function. Even if it is linear it can do range remapping. So for AVS core the rec709 is range expanding Transfer Function embedded in transform. For PC.709 it is range no change ? So if narrow/limited at input - it will also output narrow/limited (but looks not completely and not match other plugins).

"Not change min,max range, or intermediate ranges ?"

As Transfer Function of typical YUV to RGB conversion expected to be linear - so all immediate code values should follow general range remapping. Only compute/rounding quantization errors may make some additional digital-noise.

I not sure if fixed Y-16 internal will make best RGB for full-YUV input. So it looks the YUV to RGB need to have adjustable proc-amps at input and at output. I will add Ybias and UVbias as new params in next builds. So Ybias will be -16 and UVbias -128 default. For full-YUV input it may be better to set Ybias=0 (and output offset to 0) ? The gains (for Y and UV) may be also important - but most easier to use without performance lost is UVgain only (it is additional multiplier to all UV coefficients). So may be UVgain (float) of 1.0 default better to add too.

Some full-YUV may use not 224 gain and not 128 offset for Digital UVs ?

poisondeathray
3rd June 2023, 16:11
As practice show the YUV to RGB decoder may have its own Transfer Function. Even if it is linear it can do range remapping. So for AVS core the rec709 is range expanding Transfer Function embedded in transform. For PC.709 it is range no change ? So if narrow/limited at input - it will also output narrow/limited (but looks not completely and not match other plugins).


That's why I like zimg better. You can specify input/output ranges, matrix, transfer, primaries. fmtc is slower but has additional transfer curve options



I not sure if fixed Y-16 internal will make best RGB for full-YUV input. So it looks the YUV to RGB need to have adjustable proc-amps at input and at output. I will add Ybias and UVbias as new params in next builds. So Ybias will be -16 and UVbias -128 default. For full-YUV input it may be better to set Ybias=0 (and output offset to 0) ? The gains (for Y and UV) may be also important - but most easier to use without performance lost is UVgain only (it is additional multiplier to all UV coefficients). So may be UVgain (float) of 1.0 default better to add too.

Some full-YUV may use not 224 gain and not 128 offset for Digital UVs ?

I think it's better to have options . There are different valid usage scenarios


For reference, this is what vegas is doing with the studio RGB interpretation of the grey ramp. The R channel was extracted and waveform plotted with histogram (on colorbars it gets 180 and 16 for primaries +/-2 for 8bit bars, perfect for 10bit bars) .

So there appears to be a discrepancy in the low and high values and the slope. Vegas' studio RGB interpretation appears linear, with some repeats/gaps. The internal levels(0,1,255,16,125,false) + ConvertToRGB appears close approximation, but with more gaps than vegas'

https://i.postimg.cc/59wrNZ5B/decodeyuvtorgb-compare.png (https://postimages.org/)

DTL
3rd June 2023, 22:07
New version - https://github.com/DTL2020/ConvertYUVtoRGB/releases/tag/0.4.1

Defaut params values for input YUV proc-amp (Ybias=-16, UVbias=-128, UVgain=1.0) selected to make things unchanged for 'standard narrow YUV' input.

For full-YUV you can now test Ybias=0, gain=64, offset=0. It expected to decode colours in case of full-YUV input more precisely. But I not have full-YUV test charts to test it. Also user may try to tweak UVgain for either some saturation tweaking or for better dematrix if full-YUV source uses non-224 scale for Digital UV. UVgain may be as low as 0.0 - no colour (black and white equal RGB - copy of Y to RGB channels). Too high UVgain values may cause 16bit processing overflows and severe distortions. It is expected to be some fine tuning. For the case some source may use 219 scale for Digital UV for example. So UVgain may be in about 0.9..1.1f range.

All these adjustments should be no change in performance (no changes to processing core).

The shape of the computing errors of different engines with linear ramp input may be interesting.

I tried to use HistogramRGBParade script from http://avisynth.nl/images/Histograms_in_RGB_%26_CMY.avsi to display such graphs - but it cause VirtualDub crash with AVS+ 3.7.3 (some build) and 3.6.1 and masktools latest (?) 2.2.30. With both my plugin and ConvertToRGB32 conversion with script:


LoadPlugin("masktools2.dll")


function HistogramRGBLevels( clip input, bool "range", float "factor" )
{
return HistogramRGBLevelsType( input, input.ConvertToRGB(), $800000, $008000, $000080, range, factor )
}

function HistogramCMYLevels( clip input, bool "range", float "factor" )
{
return HistogramRGBLevelsType( input, input.ConvertToRGB().Invert(), $008080, $800080, $808000, range, factor )
}

function HistogramRGBParade( clip input, float "width" )
{
return HistogramRGBParadeType( input, input.ConvertToRGB(), $800000, $008000, $000080, width )
}

#---

# Generic levels form, not very useful as a standalone function
function HistogramRGBLevelsType( clip input, clip rgb, int color1, int color2, int color3, bool "range", float "factor" )
{
range = default(range,true)
ChannelHeight = 64
Gap = 8 # divisible by 4

r = rgb.ShowRed ("YV12").HistogramChannel("Levels", color1, "add", ChannelHeight, range, factor)
g = rgb.ShowGreen("YV12").HistogramChannel("Levels", color2, "add", ChannelHeight, range, factor)
b = rgb.ShowBlue ("YV12").HistogramChannel("Levels", color3, "add", ChannelHeight, range, factor)
gap = BlankClip(r, height=Gap)
hist = StackVertical(r,gap,g,gap,b).ConvertToMatch(input)
return input.Height() > hist.Height() ? \
StackHorizontal(input, hist.AddBorders(0,0,0,input.Height() - hist.Height())) : \
StackHorizontal(input.AddBorders(0,0,0,hist.Height() - input.Height()), hist)
}

# Generic parade form, not very useful as a standalone function
function HistogramRGBParadeType( clip input, clip rgb, int color1, int color2, int color3, float "width" )
{
width = default(width,0.25)
Gap = 8 # divisible by 4

rgb = rgb.PointResize( m4(rgb.Width()*width), m4(rgb.Height()) ).TurnRight()
r = rgb.ShowRed ("YV12").HistogramChannel("Classic", color1, "chroma", 0, true)
g = rgb.ShowGreen("YV12").HistogramChannel("Classic", color2, "chroma", 0, true)
b = rgb.ShowBlue ("YV12").HistogramChannel("Classic", color3, "chroma", 0, true)
gap = BlankClip(r, height=Gap)
hist = StackVertical(r,gap,g,gap,b).TurnLeft().ConvertToMatch(input)
return input.Height() > hist.Height() ? \
StackHorizontal(input, hist.AddBorders(0,0,0,input.Height() - hist.Height())) : \
StackHorizontal(input.AddBorders(0,0,0,hist.Height() - input.Height()), hist)
}

# Used by functions above, not a standalone function
function HistogramChannel( clip input, string type, int color, string colorMode, int height, bool range, float "factor" )
{
input.Histogram(type, factor).Crop(input.Width(),0,0,height).Greyscale()
range ? last : Levels(128,1.0,255,0,255,false)
return Overlay(BlankClip(color=color), mode=colorMode)
}

# Returns "input" converted to same colorspace as "ref"
function ConvertToMatch( clip input, clip ref )
{
return ref.IsYV12() ? input.IsYV12() ? input : input.ConvertToYV12() : \
ref.IsRGB32() ? input.IsRGB32() ? input : input.ConvertToRGB32() : \
ref.IsRGB24() ? input.IsRGB24() ? input : input.ConvertToRGB24() : \
ref.IsYUY2() ? input.IsYUY2() ? input : input.ConvertToYUY2() : \
ref.IsYV16() ? input.IsYV16() ? input : input.ConvertToYV16() : \
ref.IsYV24() ? input.IsYV24() ? input : input.ConvertToYV24() : \
ref.IsY8() ? input.IsY8() ? input : input.ConvertToY8() : \
ref.IsYV411() ? input.IsYV411() ? input : input.ConvertToYV411() : \
input
}

# Convert value to multiple of 4 which is >= 16
function m4( float x ) { return (x < 16 ? 16 : int(round(x / 4.0) * 4)) }


BlankClip(length=1, width=256, height=256, pixel_type="Y8")
mt_lutspa(mode="relative closed", expr="x 255 *")

ConvertToRGB32()
#DecodeYUVtoRGB(matrix=1, threads=1, cl=true, cs=false, gain=64, offset=16, ib=16, Ybias=-16, UVbias=-128, UVgain=0.0)

HistogramRGBParade()


Debugger shows

Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014D070.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014D070.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014D070.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014D070.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014D240.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014D240.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014D240.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014D240.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014D240.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014D240.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014D290.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014D290.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014D9C0.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014D9C0.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014E030.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFA5458CF19 in Veedub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x000000000014E030.
Critical error detected c0000374
Veedub64.exe has triggered a breakpoint.


Not sure where is the bug - AVS or masktools or VirtualDub 1.10.4 ? The HistogramRGBParade is simply script for AVS and should not cause crashes ? AVSmeter looks like also crashes at startup (exit without error at F0 / T0.00), so it is not VirtualDub crash ?

The
mt_lutspa(mode="relative closed", expr="x 255 *")
produced some ramp without crash. Only call to HistogramRGBParade start crash. Is it some AVS+ core new crash ?

StainlessS
3rd June 2023, 22:52
DTL,
Have you tried VirtualDub2 (VDub 1.10.4 Oct 2013, is pretty much abandoned).

VirtualDub2:- https://forum.doom9.org/showthread.php?t=172021
[SourceForge: Latest, March 2020, Version 20, VirtualDub_Pack: VirtualDub2_44282.zip]:- https://sourceforge.net/projects/vdfiltermod/files/

VirtualDub 1.10.4 is out (Oct 2013) :- https://forum.doom9.org/showthread.php?t=169640

DTL
3rd June 2023, 23:02
Got VirtualDub2_44282 - also crashes. It draw wide frame (so got frame width/height from AVS OK) but next disappear-crash.

Debugger shows same errors -
Exception thrown at 0x00007FFA5458CF19 in VirtualDub64.exe: Microsoft C++ exception: ReturnExprException at memory location 0x0000000000CFCD20.
Exception thrown at 0x00007FFA5458CF19 in VirtualDub64.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
and so on.

So it is some AVS+masktools or AVS+ only crash ?

Without masktools it also crashes:


function HistogramRGBLevels( clip input, bool "range", float "factor" )
{
return HistogramRGBLevelsType( input, input.ConvertToRGB(), $800000, $008000, $000080, range, factor )
}

function HistogramCMYLevels( clip input, bool "range", float "factor" )
{
return HistogramRGBLevelsType( input, input.ConvertToRGB().Invert(), $008080, $800080, $808000, range, factor )
}

function HistogramRGBParade( clip input, float "width" )
{
return HistogramRGBParadeType( input, input.ConvertToRGB(), $800000, $008000, $000080, width )
}

#---

# Generic levels form, not very useful as a standalone function
function HistogramRGBLevelsType( clip input, clip rgb, int color1, int color2, int color3, bool "range", float "factor" )
{
range = default(range,true)
ChannelHeight = 64
Gap = 8 # divisible by 4

r = rgb.ShowRed ("YV12").HistogramChannel("Levels", color1, "add", ChannelHeight, range, factor)
g = rgb.ShowGreen("YV12").HistogramChannel("Levels", color2, "add", ChannelHeight, range, factor)
b = rgb.ShowBlue ("YV12").HistogramChannel("Levels", color3, "add", ChannelHeight, range, factor)
gap = BlankClip(r, height=Gap)
hist = StackVertical(r,gap,g,gap,b).ConvertToMatch(input)
return input.Height() > hist.Height() ? \
StackHorizontal(input, hist.AddBorders(0,0,0,input.Height() - hist.Height())) : \
StackHorizontal(input.AddBorders(0,0,0,hist.Height() - input.Height()), hist)
}

# Generic parade form, not very useful as a standalone function
function HistogramRGBParadeType( clip input, clip rgb, int color1, int color2, int color3, float "width" )
{
width = default(width,0.25)
Gap = 8 # divisible by 4

rgb = rgb.PointResize( m4(rgb.Width()*width), m4(rgb.Height()) ).TurnRight()
r = rgb.ShowRed ("YV12").HistogramChannel("Classic", color1, "chroma", 0, true)
g = rgb.ShowGreen("YV12").HistogramChannel("Classic", color2, "chroma", 0, true)
b = rgb.ShowBlue ("YV12").HistogramChannel("Classic", color3, "chroma", 0, true)
gap = BlankClip(r, height=Gap)
hist = StackVertical(r,gap,g,gap,b).TurnLeft().ConvertToMatch(input)
return input.Height() > hist.Height() ? \
StackHorizontal(input, hist.AddBorders(0,0,0,input.Height() - hist.Height())) : \
StackHorizontal(input.AddBorders(0,0,0,hist.Height() - input.Height()), hist)
}

# Used by functions above, not a standalone function
function HistogramChannel( clip input, string type, int color, string colorMode, int height, bool range, float "factor" )
{
input.Histogram(type, factor).Crop(input.Width(),0,0,height).Greyscale()
range ? last : Levels(128,1.0,255,0,255,false)
return Overlay(BlankClip(color=color), mode=colorMode)
}

# Returns "input" converted to same colorspace as "ref"
function ConvertToMatch( clip input, clip ref )
{
return ref.IsYV12() ? input.IsYV12() ? input : input.ConvertToYV12() : \
ref.IsRGB32() ? input.IsRGB32() ? input : input.ConvertToRGB32() : \
ref.IsRGB24() ? input.IsRGB24() ? input : input.ConvertToRGB24() : \
ref.IsYUY2() ? input.IsYUY2() ? input : input.ConvertToYUY2() : \
ref.IsYV16() ? input.IsYV16() ? input : input.ConvertToYV16() : \
ref.IsYV24() ? input.IsYV24() ? input : input.ConvertToYV24() : \
ref.IsY8() ? input.IsY8() ? input : input.ConvertToY8() : \
ref.IsYV411() ? input.IsYV411() ? input : input.ConvertToYV411() : \
input
}

# Convert value to multiple of 4 which is >= 16
function m4( float x ) { return (x < 16 ? 16 : int(round(x / 4.0) * 4)) }


BlankClip(length=1, width=256, height=256, pixel_type="Y8")

ConvertToRGB32()

HistogramRGBParade()

As a pure AVS script.
So need to be reported as bug at github ?

poisondeathray
4th June 2023, 01:22
I believe the crash is dimension related (width, height)
No crash if you resize to 640x480, preview , then change to 512x512. But it only works after you run a script first that works (this is in avspmod) . If you start with 512x512, it crashes

It's odd behaviour


BlankClip(length=1, width=256, height=256, pixel_type="Y8")
mt_lutspa(mode="relative closed", expr="x 255 *")
ConvertToRGB(matrix="PC.601")
#pointresize(640,480) #1st run
pointresize(512,512)
histogramrgbparade


EDIT: actually I can't reproduce it consistently, it sometimes crashes. But resizing to 640x480 always works. It seems height related - you need a certain min height

StainlessS
4th June 2023, 02:11
With PDR script,

Windows Logs/Application: 0xc0000374, Heap Corruption.


Faulting application name: VirtualDub64.exe, version: 2.0.0.0, time stamp: 0x5e73f48a
Faulting module name: ntdll.dll, version: 10.0.19041.2788, time stamp: 0x2f715b17
Exception code: 0xc0000374
Fault offset: 0x00000000000ff449
Faulting process ID: 0x24f4
Faulting application start time: 0x01d99680ff1cb793
Faulting application path: C:\NON-INSTALL\VDUB\VDUB2\VirtualDub64.exe
Faulting module path: C:\WINDOWS\SYSTEM32\ntdll.dll
Report ID: 3170e74f-582d-40e8-891b-0847f484c03c
Faulting package full name:
Faulting package-relative application ID:

DTL
4th June 2023, 07:32
It is good to narrow where the initial C++ exception happen - may be in AVS core and passed via SEH stack into VirtualDub module and finally thrown to operating system so debugger point to the .exe module and not to AVS.dll ? Or in calling application ? But debugger point to ntdll.dll and it is Windows part and it may detect heap corruption with initial source in either AVS of VirtualDub ?

flossy_cake
4th June 2023, 13:01
Is there any possibility to upgrade DirectShowSource() to support pixel formats greater than 8-bits?

https://i3.lensdump.com/i/63lgbq.png

https://i.lensdump.com/i/63lZlD.png

DTL
4th June 2023, 16:28
RGB48 is 3x 16bit RGB ? So you can try to force output in RGB48. It will cover 10bit precision too.

flossy_cake
4th June 2023, 18:07
RGB48 is 3x 16bit RGB ? So you can try to force output in RGB48. It will cover 10bit precision too.

Yeah the wiki for DirectShowSource doesn't mention RGB48 as a supported pixel_type but I did try it anyway and it doesn't seem to work - no video frame displayed as if there isn't any video stream present, but audio still plays. RGB24 works though. Converting RGB24 to RGB48 with ConvertToRGB48() works and media player renderer reports pixel format RGB48LE. I don't really want to be converting to RGB in Avisynth as that involves chroma upscaling & matrix that I want to handle elsewhere.