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
18th July 2023, 04:51
IIRC it will load them in alphabetical order, so the "bwdif (v1.2.5).dll" in your example will be used because it load after the 1st one, I think it's a same thing for avsi

Thanks.

@StainlessSBy any chance did you happen to make a plugin that can get the version string from a plugin, something like this?

https://i3.lensdump.com/i/JP19LC.png

kedautinh12
18th July 2023, 05:10
TIVTC had 1.0.27 now
https://github.com/pinterf/TIVTC/releases

flossy_cake
18th July 2023, 05:54
TIVTC had 1.0.27 now
https://github.com/pinterf/TIVTC/releases

Yes I know - that's actually the problem, something in 1.0.27 interprets the field order differently that makes it incompatible with my script. It has to do with the fact that I use DoubleWeave() which alternates the field order per frame and the new version of TFM doesn't appear to interpret field order in the same way that 1.0.26 does, resulting in some failure to field match.

I have lodged an issue on the Git but it probably won't be fixed for a long time, and even if it was fixed, a newer version of TIVTC or other plugin could break something, so I'd rather have my script validate all plugin versions on startup so I can be confident the user will get the output frames that I've tested it with across a variety of content over the last few months.

StainlessS
18th July 2023, 13:33
By any chance did you happen to make a plugin that can get the version string from a plugin, something like this?
Nope, and neither did Groucho2004 with his SysInfo plugin:- https://forum.doom9.org/showthread.php?t=176131
He does though provide a few for Avisynth.dll itself,

Avisynth related functions:

string AI_AvsFileVersion
Returns the value of the FileVersion resource property

string AI_AvsProductVersion
Returns the value of the ProductVersion resource property

int AI_AvsPlusBuildNumber
Returns the AVS+ build number

# ...

not that that is of any use to you.

flossy_cake
24th July 2023, 06:00
Not to worry, it seems Avisynth has this DLLName_function() (https://avisynthplus.readthedocs.io/en/latest/avisynthdoc/syntax/syntax_plugins.html#plugin-autoload-and-conflicting-function-names-v2-55) so I can force a particular version with eg.


TIVTCv1026_TFM() # uses TFM() from TIVTCv1026.dll

StainlessS
24th July 2023, 08:40
Yes, that works, but beware of possible problems if the dll name has "_" underscore in it. [eg dll = "TIVTC_v1026.dll"]

tebasuna51
29th July 2023, 10:31
Removed a duplicated post and moved the answers to QTGMC Deinterlacing Script (v3.384) (https://forum.doom9.org/showthread.php?t=174544)

flossy_cake
30th July 2023, 06:00
IIRC it will load them in alphabetical order, so the "bwdif (v1.2.5).dll" in your example will be used because it load after the 1st one, I think it's a same thing for avsi

For completeness I just tested this now and indeed Avisynth uses whichever one comes alphabetically last. Makes sense if Avisynth is just iterating through all dll's in alphabetical order and loading each one.

Yes, that works, but beware of possible problems if the dll name has "_" underscore in it. [eg dll = "TIVTC_v1026.dll"]

Checked this as well and it seems Avisynth is only looking for the last underscore so there can be others before it and it works fine, at least in my testing (don't hold me to it!).

I tried hyphens and that produced some weirditude...

MyScript.avs:
MyFunc-AnyRandomStringHere() #triggers stuff in MyFunc()

MyScript.avsi in plugins64:

function MyFunc(val "arg1"){
Assert(Defined(arg1), "Inside MyFunc() - arg1 is not defined")
}

LigH
30th July 2023, 09:47
Hyphens are not allowed as part of identifiers; they should cause a syntax error due to an invalid function name...

flossy_cake
30th July 2023, 13:03
Regarding Gavino's memory leak workaround:


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(...)")




The workaround was working nicely until I started setting some debug strings and got large memory leak again. It seems the string concatenation (+) is the culprit:


ColorBars().ConvertToYV12().KillAudio()

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

function Leak(clip c, int current_frame){

# doesn't leak
# string =
# \ "stringstringstringstringstringstringstringstringstringstringstringstringstringstring
# \ stringstringstringstringstringstringstringstringstringstringstringstringstringstring
# \ stringstringstringstringstringstringstringstringstringstringstringstringstringstring
# \ stringstringstringstringstringstringstringstringstringstringstringstringstringstring
# \ stringstringstringstringstringstringstringstringstringstringstringstringstringstring
# \ stringstringstringstringstringstringstringstringstringstringstringstringstringstring
# \ stringstringstringstringstringstringstringstringstringstringstringstringstringstring
# \ stringstringstringstringstringstringstringstringstringstringstringstringstringstring
# \ stringstringstringstringstringstringstringstringstringstringstringstringstringstring
# \ stringstringstringstringstringstringstringstringstringstringstringstringstringstring
# \ stringstringstringstringstringstringstringstringstringstringstringstringstringstring
# \ stringstringstringstringstringstringstringstringstringstringstringstringstringstring
# \ stringstringstringstringstringstringstringstringstringstringstringstringstringstring
# \ stringstringstringstringstringstringstringstringstringstringstringstringstringstring"

# leaks 1MB/sec
string =
\ "string" + "string" + "string" + "string" + "string" + "string" + "string" + "string" +
\ "string" + "string" + "string" + "string" + "string" + "string" + "string" + "string" +
\ "string" + "string" + "string" + "string" + "string" + "string" + "string" + "string" +
\ "string" + "string" + "string" + "string" + "string" + "string" + "string" + "string" +
\ "string" + "string" + "string" + "string" + "string" + "string" + "string" + "string" +
\ "string" + "string" + "string" + "string" + "string" + "string" + "string" + "string" +
\ "string" + "string" + "string" + "string" + "string" + "string" + "string" + "string" +
\ "string" + "string" + "string" + "string" + "string" + "string" + "string" + "string" +
\ "string" + "string" + "string" + "string" + "string" + "string" + "string" + "string" +
\ "string" + "string" + "string" + "string" + "string" + "string" + "string" + "string" +
\ "string" + "string" + "string" + "string" + "string" + "string" + "string" + "string" +
\ "string" + "string" + "string" + "string" + "string" + "string" + "string" + "string" +
\ "string" + "string" + "string" + "string" + "string" + "string" + "string" + "string"

c
}

real.finder
30th July 2023, 13:20
thanks, that work but will all other 2.5 plugins will not work? there are some of them even close source

I was test some old script that use yadifmod (I have tritical one not Chikuzen) and I note the same problem, so I think any avs 2.5 plugin can have this problem

Gavino
30th July 2023, 16:19
Hyphens are not allowed as part of identifiers; they should cause a syntax error due to an invalid function name...
Not a syntax error as such, but a hyphen is interpreted as a 'minus' sign, so in the example
MyFunc-AnyRandomStringHere() #triggers stuff in MyFunc()
it will attempt to call MyFunc and subtract the result of AnyRandomStringHere().

flossy_cake
8th August 2023, 13:57
:scared: what has happened to the wiki @ avisynth.nl?
Heaps of pages missing / incomplete / old

StainlessS
8th August 2023, 14:10
:scared: what has happened to the wiki @ avisynth.nl?
Heaps of pages missing / incomplete / old
Dont know.

(replying to flossy_cake) Hyphens are not allowed as part of identifiers; they should cause a syntax error due to an invalid function name...

Valid Variable/FunctionName/ identifier [really also applies to dll name excluding the ".dll" appended to end].

1st character, "_" or Alpha character.
Thereafter = "_" or Alpha character, or digit.
(other languages tend to have exact same requirement for identifiers)

VoodooFX
8th August 2023, 14:15
:scared: what has happened to the wiki @ avisynth.nl?
Heaps of pages missing / incomplete / old

Looks like a back-up from 2013, 10 years of stuff missing.

flossy_cake
8th August 2023, 14:50
Looks like a back-up from 2013, 10 years of stuff missing.

I'll be pulling my hair out if that's the only backup they've got.

DJATOM
8th August 2023, 19:04
Fortunately wayback snapshot available - https://web.archive.org/web/20230729032301/http://avisynth.nl/index.php/Main_Page. Someone very dedicated can site-rip that content and put back onto the site :D

FranceBB
8th August 2023, 20:28
:scared: what has happened to the wiki @ avisynth.nl?

Wilbert changed his hosting company: https://forum.doom9.org/showthread.php?p=1990518

Looks like a back-up from 2013, 10 years of stuff missing.

Yeah... July 2013... :scared:

I'll be pulling my hair out if that's the only backup they've got.

As a regular contributor, I feel your pain...
I think only Wilbert can answer our questions...

Fortunately wayback snapshot available - https://web.archive.org/web/20230729032301/http://avisynth.nl/index.php/Main_Page. Someone very dedicated can site-rip that content and put back onto the site :D

Yeah, copy-pasting is better than rewriting everything, sure, but still... if we actually have to do this I'm gonna cry...

https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExNG9mdXRnMzFhdWZkOXEwcXllbnN6YzBkN2p5ZXA3cjR1ZHZpYnY2dCZlcD12MV9naWZzX3NlYXJjaCZjdD1n/l378giAZgxPw3eO52/giphy.gif

flossy_cake
9th August 2023, 17:33
The wiki has been restored. All's right with the world.

FranceBB
9th August 2023, 20:41
Yep, it's back to a modern backup. Nice.

kedautinh12
10th August 2023, 02:34
I'm still got 404 error with this page
https://avisynth.nl/index.php/External_filters

VoodooFX
10th August 2023, 03:09
I think https never worked, use this: http://avisynth.nl/index.php/External_filters

flossy_cake
10th August 2023, 13:44
Yeah that's always been an issue for me as well - the wiki site has no support for https. Often I'll open a link and my browser automatically changes it to https and then I have to manually delete the s, it's quite annoying and frankly I don't know how that could even be a thing.

flossy_cake
12th August 2023, 21:39
Does Avisynth not have a clip property for colour range (16-235 vs 0-255)?

There appears to be a FRAME property, but that relies on the source filter setting it.

Surely Avisynth must know the colour range of the clip otherwise its internal processing would be all wrong. Should I just infer that if the pixel type is YV12 that it's limited range, or is there such a thing as YV12 full range?

Thanks

real.finder
13th August 2023, 16:53
Does Avisynth not have a clip property for colour range (16-235 vs 0-255)?

There appears to be a FRAME property, but that relies on the source filter setting it.

Surely Avisynth must know the colour range of the clip otherwise its internal processing would be all wrong. Should I just infer that if the pixel type is YV12 that it's limited range, or is there such a thing as YV12 full range?

Thanks

I don't think there are clip property for this but there are http://avisynth.nl/index.php/Internal_functions#ColorRange and IIRC vs use frame property of frame 0 as clip property

and there are YV12 full range even in mpeg2 japanese tv but it's rare or very rare

flossy_cake
13th August 2023, 23:23
use frame property of frame 0 as clip property

I was going to do that but then I saw FFMS2 and DirectShowSource don't set the property at all, only LWLibAv does. I guess it's better than nothing so I'll use it if available.

I'm worried AverageLuma() will be different for full range vs limited. I'm trying to normalise my scenechange detection threshold to AverageLuma as I noticed brighter content has higher scenechange framediffs, especially brighter animation which was causing me some false positives.

StainlessS
14th August 2023, 08:24
I'm worried AverageLuma() will be different for full range vs limited.
Limited range luma mid point is 125.5 ie (16+235)/2.0 (rounded to 126),
whereas full range is 127.5 ie (0 + 255)/2.0 (rounded to 128).

EDIT: Also, Subtract always assumes limited range mid point 126, so
Subtract(ClipA,ClipA) always produces a clip where all luma result samples are 126.

DTL
14th August 2023, 08:55
I'm worried AverageLuma() will be different for full range vs limited. I'm trying to normalise my scenechange detection threshold to AverageLuma as I noticed brighter content has higher scenechange framediffs, especially brighter animation which was causing me some false positives.

You can try MSCDetection from mvtools. To make it faster the fastest settings may be provided to MAnalyse like pel=1, levels=1, searchparam=1 - so it will work mostly as SAD computing engine only. Though using some real MVs search and better SADs from single cutscene makes scenedetection even better.

As I see some plugins uses scenedetection based on SAD computing between frames (vsTTempSmooth and mvtools and maybe other too) and it work good enough.

StainlessS
15th August 2023, 15:09
Some SC detect stuff:- https://forum.doom9.org/showthread.php?p=1954985#post1954985

EDIT: Dont know if of any use


Function MMaskFromPrevClip(clip c,Int "MaskType",Float "Gamma",Int "thSCD1",Int "thSCD2") {
# MaskType:- 0=Motion, 1=SAD, 2=Occlusion, 3=Horizontal, 4=Vertical, 5=ColorMap.
MaskType=Default(MaskType,0) Gamma=Default(Gamma,1.0) thSCD1=Default(thSCD1,400) thSCD2=Default(thSCD2,130)
sup=c.MSuper(pel=1,sharp=0,rfilter=2,hpad=16, vpad=16)
fv=sup.MAnalyse(isb=false,delta=1,blksize=16)
Return c.MMask(fv,Gamma=1.0,kind=MaskType,thSCD1=thSCD1,thSCD2=thSCD2)
}

Function MMaskFromNextClip(clip c,Int "MaskType",Float "Gamma",Int "thSCD1",Int "thSCD2") {
# MaskType:- 0=Motion, 1=SAD, 2=Occlusion, 3=Horizontal, 4=Vertical, 5=ColorMap.
MaskType=Default(MaskType,0) Gamma=Default(Gamma,1.0) thSCD1=Default(thSCD1,400) thSCD2=Default(thSCD2,130)
sup=c.MSuper(pel=1,sharp=0,rfilter=2,hpad=16, vpad=16)
bv=sup.MAnalyse(isb=True,delta=1,blksize=16)
Return c.MMask(bv,Gamma=1.0,kind=MaskType,thSCD1=thSCD1,thSCD2=thSCD2)
}

Function EndOfSceneClip(clip c,Int "thSCD1",Int "thSCD2") { # All Luma Samples set 255 at EOS, else 0
thSCD1=Default(thSCD1,400) thSCD2=Default(thSCD2,130)
sup=c.MSuper(pel=1,sharp=0,rfilter=2,hpad=16, vpad=16)
bv=sup.MAnalyse(isb=true, delta=1,blksize=16)
Return c.MSCDetection(bv,thSCD1=thSCD1,thSCD2=thSCD2)
}

Function StartOfSceneClip(clip c,Int "thSCD1",Int "thSCD2") { # All Luma Samples set 255 at SOS, else 0
thSCD1=Default(thSCD1,400) thSCD2=Default(thSCD2,130)
sup=c.MSuper(pel=1,sharp=0,rfilter=2,hpad=16, vpad=16)
fv=sup.MAnalyse(isb=false,delta=1,blksize=16)
Return c.MSCDetection(fv,thSCD1=thSCD1,thSCD2=thSCD2)
}

Function SceneCutClip(clip c,Int "thSCD1",Int "thSCD2") { # All Luma pixel = 0 =Norm, 1=EOS, 2=SOS, 3=EOS & SOS
thSCD1=Default(thSCD1,400) thSCD2=Default(thSCD2,130)
Sup = c.MSuper(pel=1,sharp=0,rfilter=2,hpad=16, vpad=16)
BvEos= Sup.MAnalyse(isb=True, delta=1,blksize=16)
FvSos= Sup.MAnalyse(isb=False, delta=1,blksize=16)
Eos = c.MSCDetection(BvEos,thSCD1=thSCD1,thSCD2=thSCD2)
Sos = c.MSCDetection(FvSos,thSCD1=thSCD1,thSCD2=thSCD2)
Return MT_Lutxy(Eos,Sos,yexpr="y 0 == x 0 == 0 1 ? x 0 == 2 3 ? ?",u=-128,v=-128)
}


EDIT: Added below
It works sorta like ScSelect/ScSelect_HBD, but you must also Provide a "BOTH" [ie both EOS and SOS detect] clip (you can choose whatever solution you like for that possible outcome).
You will likely fire a BOTH if there is a single frame scene cut, ie and 'odd' frame that belongs neither with previous nor following scenes.

Function SceneCutSelectClip(clip dClip,clip Start,clip End,clip Both,clip Motion,Int "thSCD1",Int "thSCD2") { # (c) ssS: https://forum.doom9.org/showthread.php?p=1955111#post1955111
thSCD1=Default(thSCD1,400) thSCD2=Default(thSCD2,130)
Sup = dClip.MSuper(pel=1,sharp=0,rfilter=2,hpad=16, vpad=16)
BvEos= Sup.MAnalyse(isb=True, delta=1,blksize=16)
FvSos= Sup.MAnalyse(isb=False, delta=1,blksize=16)
Eos = dClip.MSCDetection(BvEos,thSCD1=thSCD1,thSCD2=thSCD2).crop(0,0,4,4)
Sos = dClip.MSCDetection(FvSos,thSCD1=thSCD1,thSCD2=thSCD2).crop(0,0,4,4)
CondS="""
ix = (Sos.AverageLuma>0?1:0) + (Eos.AverageLuma>0?2:0)
Return ix==0?Motion:ix==1?Start:ix==2?End:Both
"""
ARGS="Motion,CondS,Motion,Start,End,Both,Eos,Sos"
Motion.GSCriptClip(CondS,Args=ARGS,After_Frame=True,Local=True) # Requires Grunt
}

# Client
AviSource("D:\hard sub - 01 WEBdlRip 720p, 23.976.mkv.AVI")
dclip = BilinearResize(320,240).Blur(1.0) # Whatever (just testing frame size can be different to other clips)
ConvertToRGB32 # Just testing works where Dclip colorspace is differenct from the other clips.
Motion = Last
Start = Subtitle("START",size=64,align=5)
End = Subtitle("END",size=64,align=5)
Both = Subtitle("BOTH",size=64,align=5)
SceneCutSelectClip(dClip,Start,End,Both,Motion,400,130)


Also perhaps SCSelect_HBD() of interest too [Works a little like SCSelect but less likely to produce erroneous detect where near dupe either precedes or follows a dupe].
https://forum.doom9.org/showthread.php?t=182392

EDIT: By DTL,
To make it faster the fastest settings may be provided to MAnalyse like pel=1, levels=1, searchparam=1
Maybe add in the above DTL suggest options for eg "EndOfSceneClip()" to speed up a bit [we already used pel=1].
MAnalyse(int pelsearch) is defaulted to MSuper(pel), so defaults 1 below in MAnalyse.
EDIT: Eg (Presumed intent of DTL mods)

Function EndOfSceneClip(clip c,Int "thSCD1",Int "thSCD2") { # All Luma Samples set 255 at EOS, else 0
thSCD1=Default(thSCD1,400) thSCD2=Default(thSCD2,130)
sup=c.MSuper(pel=1,sharp=0,rfilter=2,hpad=16, vpad=16)
bv=sup.MAnalyse(isb=true, delta=1,blksize=16,Levels=1,searchparam=1) # Levels Default 0(ALL). searchparam Default=2 (radius)
Return c.MSCDetection(bv,thSCD1=thSCD1,thSCD2=thSCD2)
}

From MvTools2 docs
Search, searchparam, pelsearch

search decides the type of search at every level, searchparam is an additional parameter (step, radius) for this search, and pelsearch is the radius parameter at finest (pel) level. Below are the possible values for the search type:
0 'OneTimeSearch'. searchparam is the step between each vectors tried (if searchparam is superior to 1, step will be progressively refined).
1 'NStepSearch'. N is set by searchparam. It's the most well known of the MV search algorithm.
2 Logarithmic search, also named Diamond Search. searchparam is the initial step search, there again, it is refined progressively.
3 Exhaustive search, searchparam is the radius (square side is 2*radius+1). It is slow, but it gives the best results, SAD-wise.
4 Hexagon search, searchparam is the range. (similar to x264).DEFAULT Search type
5 Uneven Multi Hexagon (UMH) search, searchparam is the range. (similar to x264).
6 pure Horizontal exhaustive search, searchparam is the radius (width is 2*radius+1).
7 pure Vertical exhaustive search, searchparam is the radius (height is 2*radius+1).



EDIT: above modded EndOfSceneClip(), pre mod = 33 secs on a sample clip, post mod = 27 secs on same clip.

DTL
16th August 2023, 17:00
"MAnalyse(isb=true, delta=1,blksize=16,Levels=1,searchparam=1)"

If quality is enough with levels=1 in MAnalyse - you can also set levels=1 for MSuper to skip calculating lower sized levels. Also idea to set large blocksize also may add good performance - try blocksize 32 or even 64 if quality still good. Also if function used with bitdepth > 8 clips - input to scenedetect function may be converted to fixed 8 bit to make performance better.

StainlessS
17th August 2023, 02:45
Thanks DTL, do these look OK-ish :) {in particular, MSuper(levels=Levels) and MAnalyse(levels=0<default ie All>)
Made defaults for better detection, but user moddable via args.


/*
BlkSz, Default 16. Allows for faster 32x32 and 64x64 block size (8 maybe better accuracy).
Pel, Default 2. (1 or 2 or 4) 1 is fastest.
Levels, Default 0 (ALL)
Search, Default 4 (4 Hexagon search)
Search decides the type of search at every level, searchparam is an additional parameter (step, radius) for this search, and pelsearch is the radius parameter at finest (pel) level. Below are the possible values for the search type:
0 'OneTimeSearch'. searchparam is the step between each vectors tried (if searchparam is superior to 1, step will be progressively refined).
1 'NStepSearch'. N is set by searchparam. It's the most well known of the MV search algorithm.
2 Logarithmic search, also named Diamond Search. searchparam is the initial step search, there again, it is refined progressively.
3 Exhaustive search, searchparam is the radius (square side is 2*radius+1). It is slow, but it gives the best results, SAD-wise.
4 Hexagon search, searchparam is the range. (similar to x264). # MVTOOLS DEFAULT.
5 Uneven Multi Hexagon (UMH) search, searchparam is the range. (similar to x264).
6 pure Horizontal exhaustive search, searchparam is the radius (width is 2*radius+1).
7 pure Vertical exhaustive search, searchparam is the radius (height is 2*radius+1).
SearchParam, Default 2
TM, Default true. (MAnalyse(TrueMotion=TM), but MAnalyse(Global=True) even when TM=False) <TrueMotion is a group setting>
Bits8, Default False, True forces source conversion to 8 bit (8 bit result clip).
Chroma, Default true, False, dont use chroma in analysis {BEST change to false if greyscale}
*/

Function EndOfSceneClip(clip c,Int "thSCD1",Int "thSCD2",
\ int "BlkSz", int "Pel",int "Levels",int "Search",int "SearchParam",Bool "TM",Bool "Bits8",bool "Chroma") { # All Luma (and Chroma) Samples set 255 at EOS, else 0
thSCD1=Default(thSCD1,400) thSCD2=Default(thSCD2,130)
BlkSz=Default(BlkSz,16) Pel=Default(Pel,2) Levels=Default(Levels,0)
Search=Default(Search,4) SearchParam=Default(SearchParam,2) TM=Default(TM,True)
Bits8=Default(Bits8,False) Chroma=Default(Chroma,true)
Pad=Max(BlkSz,8)
Try{bpc=c.BitsPerComponent} Catch(msg) {bpc=8}
c = (bpc==8 || !Bits8) ? c : c.ConvertBits(8)
sup=c.MSuper(hpad=Pad, vpad=Pad, pel=Pel, levels=Levels, chroma=Chroma, sharp=0, rfilter=2)
bv=sup.MAnalyse(isb=true, blksize=BlkSz, levels=Levels,search=Search, searchparam=SearchParam, chroma=Chroma, delta=1,truemotion=TM, global=True)
Return c.MSCDetection(bv,thSCD1=thSCD1,thSCD2=thSCD2)
}

Function StartOfSceneClip(clip c,Int "thSCD1",Int "thSCD2",
\ int "BlkSz",int "Pel",int "Levels",int "Search",int "SearchParam",Bool "TM",Bool "Bits8",bool "Chroma") { # All Luma (and Chroma) Samples set 255 at SOS, else 0
thSCD1=Default(thSCD1,400) thSCD2=Default(thSCD2,130)
BlkSz=Default(BlkSz,16) Pel=Default(Pel,2) Levels=Default(Levels,0)
Search=Default(Search,4) SearchParam=Default(SearchParam,2) TM=Default(TM,True)
Bits8=Default(Bits8,False) Chroma=Default(Chroma,true)
Pad=Max(BlkSz,8)
Try{bpc=c.BitsPerComponent} Catch(msg) {bpc=8}
c = (bpc==8 || !Bits8) ? c : c.ConvertBits(8)
sup=c.MSuper(hpad=Pad, vpad=Pad, pel=Pel, levels=Levels, chroma=Chroma, sharp=0, rfilter=2)
fv=sup.MAnalyse(isb=false, blksize=BlkSz, levels=Levels, search=Search, searchparam=SearchParam, chroma=Chroma, delta=1,truemotion=TM, global=True)
Return c.MSCDetection(fv,thSCD1=thSCD1,thSCD2=thSCD2)
}

Function SceneCutClip(clip c,Int "thSCD1",Int "thSCD2",
\ int "BlkSz", int "Pel",int "Levels",int "Search",int "SearchParam",Bool "TM",Bool "Bits8",bool "Chroma") { # All Luma samples = 0 =Norm, 1=EOS, 2=SOS, 3=EOS & SOS
thSCD1=Default(thSCD1,400) thSCD2=Default(thSCD2,130)
BlkSz=Default(BlkSz,16) Pel=Default(Pel,2) Levels=Default(Levels,0)
Search=Default(Search,4) SearchParam=Default(SearchParam,2) TM=Default(TM,True)
Bits8=Default(Bits8,False) Chroma=Default(Chroma,true)
Pad=Max(BlkSz,8)
Try{bpc=c.BitsPerComponent} Catch(msg) {bpc=8}
c = (bpc==8 || !Bits8) ? c : c.ConvertBits(8)
sup=c.MSuper(hpad=Pad, vpad=Pad, pel=Pel, levels=Levels, chroma=Chroma, sharp=0, rfilter=2)
BvEos= Sup.MAnalyse(isb=True, blksize=BlkSz, levels=Levels, search=Search, searchparam=SearchParam, chroma=Chroma, delta=1,truemotion=TM, global=True)
FvSos= Sup.MAnalyse(isb=False, blksize=BlkSz, levels=Levels, search=Search, searchparam=SearchParam, chroma=Chroma, delta=1,truemotion=TM, global=True)
Eos = c.MSCDetection(BvEos,thSCD1=thSCD1,thSCD2=thSCD2)
Sos = c.MSCDetection(FvSos,thSCD1=thSCD1,thSCD2=thSCD2)
Return MT_Lutxy(Eos,Sos,yexpr="y 0 == x 0 == 0 1 ? x 0 == 2 3 ? ?",u=-128,v=-128)
}

Function SceneCutSelectClip(clip dClip,clip Start,clip End,clip Both,clip Motion,Int "thSCD1",Int "thSCD2",
\ int "BlkSz",int "Pel",int "Levels",int "Search",int "SearchParam",Bool "TM",Bool "Bits8",bool "Chroma") {
thSCD1=Default(thSCD1,400) thSCD2=Default(thSCD2,130)
BlkSz=Default(BlkSz,16)
Pel=Default(Pel,2) Levels=Default(Levels,0)
Search=Default(Search,4) SearchParam=Default(SearchParam,2) TM=Default(TM,True)
Bits8=Default(Bits8,False) Chroma=Default(Chroma,true)
Pad=Max(BlkSz,8)
Try{bpc=dClip.BitsPerComponent} Catch(msg) {bpc=8}
dClip = (bpc==8 || !Bits8) ? dClip : dClip.ConvertBits(8)
sup = dClip.MSuper(hpad=Pad, vpad=Pad, pel=Pel, levels=Levels, chroma=Chroma, sharp=0, rfilter=2)
BvEos= Sup.MAnalyse(isb=True, blksize=BlkSz, levels=Levels, search=Search, searchparam=SearchParam, chroma=Chroma, delta=1,truemotion=TM, global=True)
FvSos= Sup.MAnalyse(isb=False, blksize=BlkSz, levels=Levels, search=Search, searchparam=SearchParam, chroma=Chroma, delta=1,truemotion=TM, global=True)
Eos = dClip.MSCDetection(BvEos,thSCD1=thSCD1,thSCD2=thSCD2).crop(0,0,4,4)
Sos = dClip.MSCDetection(FvSos,thSCD1=thSCD1,thSCD2=thSCD2).crop(0,0,4,4)
CondS="""
ix = (Sos.AverageLuma>0?1:0) + (Eos.AverageLuma>0?2:0)
Return ix==0?Motion:ix==1?Start:ix==2?End:Both
"""
ARGS="Motion,CondS,Motion,Start,End,Both,Eos,Sos"
Motion.GSCriptClip(CondS,Args=ARGS,After_Frame=True,Local=True) # Requires Grunt
}

EDIT: BugFix In BLUE changed from 'c' to dClip.

Testing 1, 2, 3

AviSource(".\DE.avi")
Trim(2543,0)
ConvertBits(10) # TESTING
ORG=Last
Try{bpc=ORG.BitsPerComponent} Catch(msg) {bpc=8} # Remember original bit depth
#########

BLKSZ = 16 # 16
PEL = 2 # 2
LEVELS = 0 # 0
SEARCH = 4 # 4 <Hexagon search>
SEARCHPARAM = 2 # 2 <radius>
TM = True # True <MAnalyse(TrueMotion=TM), but MAnalyse(global) ALWAYS true> <TrueMotion is a group setting>
BITS8 = False # False
CHROMA = True # True, Best change to false if greyscale

#
SZ=Height/16
STARTC=ORG.Subtitle("START OF SCENE",Size=SZ,Align=5)
ENDC=ORG.Subtitle("END OF SCENE",Size=SZ,Align=5)
BOTHC=ORG.Subtitle("BOTH START AND END OF SCENE",Size=SZ,Align=5)

##########
# UNCOMMENT ONLY ONE of BELOW LINES

#EndOfSceneClip(Last,blksz=BLKSZ,pel=PEL,search=SEARCH,Searchparam=SEARCHPARAM,bits8=BITS8,Chroma=CHROMA)
#StartOfSceneClip(Last,blksz=BLKSZ,pel=PEL,search=SEARCH,Searchparam=SEARCHPARAM,bits8=BITS8,Chroma=CHROMA)
#SceneCutClip(Last,blksz=BLKSZ,pel=PEL,search=SEARCH,Searchparam=SEARCHPARAM,bits8=BITS8,Chroma=CHROMA).ScriptClip("""Subtitle(String(AverageLuma,"%.0f"),Size=48)""")
SceneCutSelectClip(Last,StartC,EndC,BothC,Last,blksz=BLKSZ,pel=PEL,search=SEARCH,Searchparam=SEARCHPARAM,bits8=BITS8,Chroma=CHROMA)

##########

Try{StackVertical(ORG,Last)} Catch(msg){StackVertical(ORG,Last.ConvertBits(bpc)) }

Return last

BugFix EDITED:

DTL
17th August 2023, 06:32
"sup=c.MSuper(hpad=Pad, vpad=Pad, pel=Pel, levels=Levels, chroma=Chroma, sharp=0, rfilter=2)
bv=sup.MAnalyse(isb=true, blksize=BlkSz, search=Search, searchparam=SearchParam, chroma=Chroma, delta=1,truemotion=TM, global=True)"

Default levels in MAnalyse is 0 (all), so user can not set levels in MSuper < levels in MAnalyse. MAnalyse will throw error "not enough levels in super clip". So for performance user may set equal 'levels' number in MSuper and MAnalyse.

Also chroma typically not very critical and may be skipped for scenechange detection with good performance boost at many types of content.

StainlessS
17th August 2023, 14:03
Post 2631, Fixed bug in SceneCutSelectClip, used clip c, instead of dClip, marked in BLUE.

Also, changed MAnalyse(levels=Levels) # I thought Default levels=0, meant All levels as set for MSuper.

Thanx DTL for the help, 2 operations on Dislocated and Broken ankle make for bad moods and shitty thinking. :(

flossy_cake
18th August 2023, 06:01
Also chroma typically not very critical and may be skipped for scenechange detection with good performance boost at many types of content.
@Stainless

Coincidentally I was wondering about chroma weighting in Stainless's RT_FrameDifference(): 0.333 for chroma and 0.666 for luma. I am curious to know the reasoning behind this if Stainless wouldn't mind explaining. I have been using this weighting for my scene change detection and it seems to work quite well, even better if I scale it to AverageLuma() and use change of value instead of absolute value (avoid false positive on fast pans). Still some rare false positive on contrasty animation when character fills the screen and does some large 1-frame gestures like waving arms or something. But it is fast and can be implemented with Avisynth built in Y/U/VDifferenceToNext(). Realtime performance (60+fps on quad core) is a requirement so I can't really use MVTools as I'm already leaving some headroom for that with a QTGMC pass later on. I'm biasing my errors towards false positive instead of false negative. Is there such a thing as perfect scene change detection?

StainlessS
18th August 2023, 14:31
RT_FrameDifference(): 0.333 for chroma and 0.666 for luma.
Actually, I've come to prefer ChromaWeight in the region of about 0.10 -> 0.20, or of course, just use 0.0 for luma only.
Obviously use ChromaWeight=0.0 for greyscale.
I had a clip where was a sort of nightclub situation under red light, ChromaWeight=0.0 was real bad detections, non zero much better.

EDIT: Also, I remember in one of the X-Men movies, in the room where all mutant 'souls' were projected onto a wall, ChromaWeight=0.0
could not tell apart different scene frames that should be totally different and were much better detected with non 0.0 chromaweight.

I'm biasing my errors towards false positive instead of false negative.
Same preferred here. [EDIT: Also, it is a lot easier to manual edit false positive to no detect, than the other way around]
Is there such a thing as perfect scene change detection?
Dont be silly :) [EDIT: Take a look at some of JohnMeyer American Football clips]
SC detection quickly loses its fun factor, kinda like banging your head against a wall.
(Some A.I. thingy might be better one day)

EDIT: Also, simple difference dont take into account ambient light level, low light situation differences should be weighted higher, somehow.
EDIT: Where there is some visible color in low light, I think non 0.0 Chromaweight should detect better (as for the nightclub situation in 1st paragraph).

flossy_cake
19th August 2023, 10:00
EDIT: Also, simple difference dont take into account ambient light level, low light situation differences should be weighted higher, somehow.

What you're describing sounds like what I meant by scaling the framediff to AverageLuma - or did you mean something else?

StainlessS
19th August 2023, 16:00
Sounds similar.

pokota
30th August 2023, 17:41
Quick question - are the plugins folders searched recursively (that is, can I organize my plugins into folders within the plugins folder)? I'm setting up AnimeIVTC and would prefer to keep "the stuff AnimeIVTC depends on" separate from the small collection of plugins I already have.

poisondeathray
30th August 2023, 22:41
Quick question - are the plugins folders searched recursively (that is, can I organize my plugins into folders within the plugins folder)? I'm setting up AnimeIVTC and would prefer to keep "the stuff AnimeIVTC depends on" separate from the small collection of plugins I already have.

Subfolders are not parsed

StainlessS
31st August 2023, 08:47
pokota, You can have a loader avsi to load plugins in sub folder.

flossy_cake
6th September 2023, 11:07
ScriptClip appears to return audio from the clip being iterated on instead of the clip returned by the expression


global withAudio = ColorBars().ConvertToYV12().Text("withAudio")

global withoutAudio = ColorBars().ConvertToYV12().KillAudio().Text("withoutAudio")

ScriptClip(withoutAudio, "return withAudio", after_frame=true, local=false)

# the returned clip appears to be equivalent to AudioDub(withAudio, withoutAudio)

Gavino
6th September 2023, 13:42
ScriptClip appears to return audio from the clip being iterated on instead of the clip returned by the expression
That's by design.
ScriptClip doesn't do any audio processing, it only operates on the video track.

flossy_cake
6th September 2023, 19:24
If it's by design, then I would say it's not very good design as I noticed just now that it also sets the field parity of the returned clip to that of the one being iterated on.


last = ColorBars().ConvertToYV12().KillAudio()
global tff = last.AssumeTFF().Text("TFF", align=9)
global bff = last.AssumeBFF().Text("BFF", align=9)
ScriptClip(tff, "return bff", after_frame=true, local=false)
info()


This will cause problems for filters downstream from the ScriptClip which need to see its field order, such as if the ScriptClip returns DoubleWeave which has alternating field order. Hopefully this can be worked around by manually setting the parity of each frame back to what it should be via a custom frame property.

wonkey_monkey
7th September 2023, 00:40
If it's by design, then I would say it's not very good design

It has to get its output clip properties from somewhere, and while it's easy for a human to look at "return bff" and know that it's just returning all the frames of bff, it would (correct me if I'm wrong, Gavino) be far too complicated for ScriptClip to be able to do this kind of introspection on arbitrary inputs. For a lot of scripts it would just be impossible - for example, if you wrote a ScriptClip that selected a frame from one of three clips depending on the frame number, how would it know which clip's properties (frame rate, field parity, etc) to use?

flossy_cake
7th September 2023, 16:21
for example, if you wrote a ScriptClip that selected a frame from one of three clips depending on the frame number, how would it know which clip's properties (frame rate, field parity, etc) to use?

I believe the fps of the input clip and return clip have to be the same for it to work correctly, otherwise eg. if input clip is 30 and return clip is 60, the output plays back at half speed.

I don't see the need to modify the audio or field order of the output clip.

flossy_cake
7th September 2023, 17:05
Also sorry if my comments about ScriptClip sound overly critical - I've been fighting with it the past few weeks and it's causing me a lot of headaches getting it to play nice with multithreading, avoiding memory leaks and my QTGMC output was broken due to this field order issue. Gavino's Grunt thread page 1 has some quotes from other members noting how quirky and strange the runtime environment is, so I know I'm not alone in this frustration.

flossy_cake
18th September 2023, 08:21
I'm just playing around with Avisynth's internal TimeStretch audio filter and was wondering about this:

Since tempo, rate and pitch are floating-point values, but sample rates are integers, rounding effects in calculations are unavoidable; the resulting audio track duration may be off by up to several 10's of milliseconds (less than one video frame) per hour.

Several 10's of milliseconds per hour doesn't seem trivial to me - a 3 hour movie could be off by 100ms then? That seems significant, and longer recordings of several hours, say, live events like sports or whathaveyou could become ruined by it.

I was thinking... is it possible to somehow force a manual audio resync every n minutes, to nudge it back in sync? Could this be done in Aviysynth scripting or only within the TimeStretch plugin itself?

tebasuna51
18th September 2023, 22:44
...
Several 10's of milliseconds per hour doesn't seem trivial to me - a 3 hour movie could be off by 100ms then? That seems significant, and longer recordings of several hours, say, live events like sports or whathaveyou could become ruined by it.

The time can't be stretched.

The audio don't be never stretched, if it is not in sync with the video is a video fps problem. Play the video at fps it was filmed and the audio is always in sync.

If you film the Usain Bolt 100 m WR (9.58 s) at 24 fps and play it at 25 fps you have a new WR of 9.2 s

BTW if you want modify the real audio duration to fit the wrong video duration you can add some correction at your taste, there are audio editors.

flossy_cake
19th September 2023, 04:28
If you film the Usain Bolt 100 m WR (9.58 s) at 24 fps and play it at 25 fps you have a new WR of 9.2 s

I think that depends if you used ChangeFPS() or AssumeFPS().

Anyway, I'm not modifying the video fps at all. The TimeStretch function only processes audio, and I'm going to be modifying audio pitch while retaining audio length, and the wiki says audio length will be slightly off due to unavoidable rounding errors, and if the audio length is different then it's not going to be in sync with video.

I tried to reproduce it by taking a 1hr clip and Loop(20).TimeStretch(pitch_n=24000, pitch_d=25025) to simulate pitch down of 4% and skipped to the end and audio was still in sync. But I don't think this simulates the issue - I'll probably have to leave the video running overnight and come back the next day and see if it's still in sync.

If it isn't, then I had an idea: split the clip into say 3 hour chunks with Trim, and do the TimeStretch() on each individual clip before joining them back together with ++. But then maybe there will be a little audio glitch every 3 hours at the splice point. I think the optimal solution would be for TimeStretch to handle it internally and when it detects drift is > some value it should smooth over the resync point using its own timestretching algorithms.

r0lZ
19th September 2023, 07:37
It is usually assumed that an A/V difference of 100 ms or even more is not perceptible. So, unless you want absolutely to watch a 24 hours movie, you should not worry too much.