View Full Version : ScriptClip With Multiple Clips
MysteryX
26th April 2017, 22:55
How can I accomplish this:
I want to display AverageLuma of ClipB onto ClipA.
Similar to this, but the output needs to overlay on top of ClipA.
ClipB = ClipB.ScriptClip("Subtitle(string(AverageLuma)))"
Any idea?
raffriff42
26th April 2017, 22:59
global variables.
EDIT I made a monstrous ScriptClip suite once that animated multiple sprites on screen based on reading a CSV data file. It had a half-dozen global video clips and several dozen nonclip globals. It worked, but was too slow (ahead of its time?)
MysteryX
26th April 2017, 23:25
How do you write it?
raffriff42
26th April 2017, 23:59
My 'monstrous' example is a little hard to post, as it stretches across multiple files.
StainlessS has got an example of the concept in his overlay markers thread.
https://forum.doom9.org/showthread.php?t=174527
TCmullet posted one a couple of years ago here:
https://forum.doom9.org/showthread.php?p=1751443#post1751443
I forgot to mention GScript (http://avisynth.nl/index.php/GScript), which is like an advanced ScriptClip (it's got looping!).
Native support in AVS+. Here's an example from me that I think is applicable to your question; it does process multiple clips:
https://forum.doom9.org/showthread.php?t=172930
I'm not explaining myself clearly, because I'm rusty on the topic and also, I'm pooped right now. Hopefully Gavino will come along and... hey!
Gavino
26th April 2017, 23:59
I want to display AverageLuma of ClipB onto ClipA.
Similar to this, but the output needs to overlay on top of ClipA.
ClipB = ClipB.ScriptClip("Subtitle(string(AverageLuma)))"
ClipA = ClipA.ScriptClip("Subtitle(string(ClipB.AverageLuma))")
No need for global variables if at outer script level (not inside a function).
If inside a function, use GRunT:
ClipA = ClipA.GScriptClip("Subtitle(string(ClipB.AverageLuma))", args="ClipB")
MysteryX
27th April 2017, 00:14
I want to add debug code within a function, so I don't want to add a library dependency for a debug option.
That being said, GRunT looks interesting. If we get conditional functions working in AVS+, how about integrating GRunT into AVS+ core?
I'm still confused with too much code. I just want something very basic.
StainlessS
27th April 2017, 00:52
You have only 3 alternatives,
1 ) Clip variable ClipB at main level and scriptclip also at main level.
2 ) Global clip variable ClipB.
3 ) Script Function with Grunt.
All have already been suggested.
MysteryX
27th April 2017, 00:56
What is the basic syntax to create global script variable ClipB?
StainlessS
27th April 2017, 01:12
ClipB = AviSource("F:\v\StarWars.avi")
ClipA = AviSource("F:\v\XMen2.avi")
Function Fn(clip ClipA,clip ClipB) {Return ClipA.GScriptClip("Subtitle(string(ClipB.AverageLuma))", args="ClipB")}
Fn(ClipA,ClipB)
Global ClipB = AviSource("F:\v\StarWars.avi")
ClipA = AviSource("F:\v\XMen2.avi")
ClipA.ScriptClip("Subtitle(string(ClipB.AverageLuma))")
both tested/working
EDIT: Or
Global ClipB = AviSource("F:\v\StarWars.avi")
ClipA = AviSource("F:\v\XMen2.avi")
Function Fn(clip ClipA) {Return ClipA.ScriptClip("Subtitle(string(ClipB.AverageLuma))")}
Fn(ClipA)
Gavino
27th April 2017, 10:52
StainlessS has correctly described the available solutions.
You might think that this would also work:
Clip1 = ... # whatever
Clip2 = ... # whatever
Function Fn(clip ClipA, ClipB) {
global GClipB = ClipB
Return ClipA.ScriptClip("Subtitle(string(GClipB.AverageLuma))")
}
Fn(Clip1, Clip2)
and it does, but ...
as soon as you call the function more than once with different clips for ClipB, it goes badly wrong:
Clip1 = ... # whatever
Clip2 = ... # whatever
Clip3 = ... # whatever
...
Fn(Clip1, Clip2)
...
Fn(Clip1, Clip3)
Here, despite appearances, Clip3 will be used inside both ScriptClip instances.
The reason is that the second global assignment to GClipB happens at compile-time, before either of the two run-time scripts ("Subtitle(...)") are evaluated. Hence in both cases they see GClipB identified with Clip3.
Even without functions, you can get the following problem:
ClipA = ... # whatever
ClipB = ... # whatever
ClipA.ScriptClip("Subtitle(string(ClipB.AverageLuma))")
...
ClipB = ... # something else
...
Here, the value of ClipB inside the ScriptClip call will be the 'something else', not the original value, again because the second assignment happens before the run-time script is evaluated.
These are both examples of what I call the 'variable binding problem' and what led me to produce GRunT (which solves it).
StainlessS
27th April 2017, 14:07
Here a quick Multi-Instance hack-up from code developed by Gavino and Martin53
Req RT_Stats, Gscript, Grunt.
Function MysteryX_MI(clip c1,clip c2,Bool "Show") {
myName="MysteryX_MI: "
Assert(RT_FunctionExist("GScriptClip"),myName+"Essential GRunT plugin installed, http://forum.doom9.org/showthread.php?t=139337")
Assert(RT_FunctionExist("GScript"),myName+"Essential GScript plugin installed, http://forum.doom9.org/showthread.php?t=147846")
Show=Default(Show,False)
Fmt = "%d ] c1AveLum=%6.2f : c2AveLum=%6.2f" # Make format string only once, not at every frame
FuncS="""
Function Fn@@@(clip c1,clip c2,Bool Show,String Fmt) {
c1
n = current_frame
If(Prev@@@ == n) { # Cache failure, requested same frame again.
RT_DebugF("%d ] Cache Failure",n,name="Fn@@@_DBUG: ")
} Else If(Prev@@@ + 1 != n) { # Init OR Rewind OR User jumped about, dont you just hate users!
if(n == 0) {
if(Prev@@@ == -666) {
RT_DebugF("%d ] Initialized to frame 0",n,name="Fn@@@_DBUG: ")
} else {
RT_DebugF("%d ] Rewind to frame 0",n,name="Fn@@@_DBUG: ")
}
} else {
RT_DebugF("%d ] User Jumped About",n,name="Fn@@@_DBUG: ")
}
}
if(Show) {
RT_Subtitle(Fmt,n, c1.RT_AverageLuma(n=n), c2.RT_AverageLuma(n=n))
}
Global Prev@@@=current_Frame # Previous frame (For next interation jump about detect)
Return Last
}
#######################################
# Unique Global Variables Initialization
#######################################
Global Prev@@@= -666 # Init vars, Prev = -666 forces initalize
#######################################
# Unique Runtime Call, GScriptClip must be a one-liner:
#######################################
ARGS = "c2,Show,Fmt"
c1.GScriptClip("Fn@@@(last, "+ARGS+")", local=true, args=ARGS)
"""
#######################################
# Unique Identifier Definition
#######################################
GIFunc ="MX" # Function Name, Supply unique name for your multi-instance function.
GIName =GIFunc+"_InstanceNumber" # Name of the Instance number Global
RT_IncrGlobal(GIName) # Increment Instance Global (init to 1 if not already exists)
GID = GIFunc + "_" + String(Eval(GIName))
InstS = RT_StrReplace(FuncS,"@@@","_"+GID)
# RT_WriteFile("DEBUG_"+GID+".TXT","%s",InstS) # UnComment to write each unique script function instance to log file
Return GScript(InstS)
}
c1=Avisource("F:\V\StarWars.avi")
c2=Avisource("F:\V\XMen2.avi")
SHOW=True
# Multi-instance with diffent args, compare results
a = MysteryX_MI(c1,c2,Show=SHOW)
b = MysteryX_MI(c1.Trim(1,0),c2.Trim(1,0),Show=SHOW)
StackVertical(a,b) # Bottom clip is 1 frame ahead of top clip (metrics) due to trim
EDIT: Small fix to debug output when user jumped about
Only a bit of testing.
EDIT: All Global Variables MUST be Assigned with preceding "Global" or will only be Local,
EDIT:
Global SomeVar =42
SomeVar = SomeVar + 1 # Local variable Somevar is assigned from Global variable SomeVar and Global variable now hidden by local
Specific to the Multi-Instance script above:
Each Global should be named and assigned like eg "Global SomeVar@@@ = 42".
EDIT: Only use above if many Global variables used. I've posted in the other thread a fix using Grunt for single instance Global.
johnmeyer
27th April 2017, 16:53
I get my wrist slapped by Gavino every time I use global variables. I understand the risks, and I am still alive.
Here is one of a dozen scripts where I used one or more global variables in order to get them inside a conditional. I have commented out the second comment block, so it is the second block of code that actually gets executed. When I simply want to view the metrics, I reverse that somewhat tortured process.
#Motion compensated scene detection. Create file with
#frame numbers where each scene change happens.
Loadplugin("C:\Program Files\AviSynth 2.5\plugins\MVTools\mvtools2.dll")
filename = "e:\Scenes.txt"
global dFact = 2.0
global dMin = 2.0
BLOCKSIZE = 8
thSCD1 = (BLOCKSIZE*BLOCKSIZE) * 64
setMTMode(5,6)
source = AVISource("e:\fs.avi").convertTOYV12().killaudio()
setMTMode(2)
prefiltered = source.blur(1.0)
superfilt = MSuper(prefiltered,pel=2)
super = MSuper(source, pel=2)
back_vec = MAnalyse(superfilt,isb=true, blksize=BLOCKSIZE,overlap=2,search=0)
forw_vec = MAnalyse(superfilt,isb=false, blksize=BLOCKSIZE,overlap=2,search=0)
backcmp = source.MCompensate(super, back_vec, thSCD1=thSCD1, thSCD2=255)
forwcmp = source.MCompensate(super, forw_vec, thSCD1=thSCD1, thSCD2=255)
global mcomp_clip = interleave(forwcmp, source, backcmp)
#---------------------------------
#Next six lines let you view the metrics in order to set detection metrics.
/*
global script = """Subtitle("\nScene = " + String( (dFact * YDifferenceToNext (mcomp_clip) + dMin ) ) + \
"\nYDiffP = " + String( YDifferenceFromPrevious(mcomp_clip) ), lsp=0)"""
global metrics = ScriptClip(mcomp_clip,script)
final = ScriptClip(mcomp_clip,"""YDifferenceFromPrevious(mcomp_clip) > (dFact * YDifferenceToNext(mcomp_clip) \
+ dMin ) && (current_frame %3 == 1) ? Subtitle(metrics,"New Scene",size=Height/4,align=5) : metrics""")
return selectevery(final,3,1)
*/
#---------------------------------
#Evaluate every 3rd frame using Mod(3) = 1
#Comment out next three lines when viewing metrics with code above
#/*
WriteFileIf(mcomp_clip, filename, "(YDifferenceFromPrevious(mcomp_clip) > \
(dFact * YDifferenceToNext(mcomp_clip) + dMin )) && (current_frame %3 == 1)", \
"current_frame/3", append = false)
#*/
StainlessS
27th April 2017, 17:21
I get my wrist slapped by Gavino every time I use global variables.
And rightly so :)
The above Multi-instance function, provides unique named Functions and unique named Globals,
and so are safe to use in multi-instance, so long as below name is unique in the entire script, (multi-instance use in same script ok)
in this case I've just used "MX".
You cannot have two different multi-instance functions both using the same GIFunc name (ie 'MX')
GIFunc ="MX" # Function Name, Supply unique name for your multi-instance function.
With two instances produces these results:- (The RT_WriteFile() line uncommented)
DEBUG_MX_1.TXT
Function Fn_MX_1(clip c1,clip c2,Bool Show,String Fmt) {
c1
n = current_frame
If(Prev_MX_1 == n) { # Cache failure, requested same frame again.
RT_DebugF("%d ] Cache Failure",n,name="Fn_MX_1_DBUG: ")
} Else If(Prev_MX_1 + 1 != n) { # Init OR Rewind OR User jumped about, dont you just hate users!
if(n == 0) {
if(Prev_MX_1 == -666) {
RT_DebugF("%d ] Initialized to frame 0",n,name="Fn_MX_1_DBUG: ")
} else {
RT_DebugF("%d ] Rewind to frame 0",n,name="Fn_MX_1_DBUG: ")
}
} else {
RT_DebugF("%d ] User Jumped About",n,name="Fn_MX_1_DBUG: ")
}
}
if(Show) {
RT_Subtitle(Fmt,n, c1.RT_AverageLuma(n=n), c2.RT_AverageLuma(n=n))
}
Global Prev_MX_1=current_Frame # Previous frame (For next interation jump about detect)
Return Last
}
#######################################
# Unique Global Variables Initialization
#######################################
Global Prev_MX_1= -666 # Init vars, Prev = -666 forces initalize
#######################################
# Unique Runtime Call, GScriptClip must be a one-liner:
#######################################
ARGS = "c2,Show,Fmt"
c1.GScriptClip("Fn_MX_1(last, "+ARGS+")", local=true, args=ARGS)
DEBUG_MX_2.TXT
Function Fn_MX_2(clip c1,clip c2,Bool Show,String Fmt) {
c1
n = current_frame
If(Prev_MX_2 == n) { # Cache failure, requested same frame again.
RT_DebugF("%d ] Cache Failure",n,name="Fn_MX_2_DBUG: ")
} Else If(Prev_MX_2 + 1 != n) { # Init OR Rewind OR User jumped about, dont you just hate users!
if(n == 0) {
if(Prev_MX_2 == -666) {
RT_DebugF("%d ] Initialized to frame 0",n,name="Fn_MX_2_DBUG: ")
} else {
RT_DebugF("%d ] Rewind to frame 0",n,name="Fn_MX_2_DBUG: ")
}
} else {
RT_DebugF("%d ] User Jumped About",n,name="Fn_MX_2_DBUG: ")
}
}
if(Show) {
RT_Subtitle(Fmt,n, c1.RT_AverageLuma(n=n), c2.RT_AverageLuma(n=n))
}
Global Prev_MX_2=current_Frame # Previous frame (For next interation jump about detect)
Return Last
}
#######################################
# Unique Global Variables Initialization
#######################################
Global Prev_MX_2= -666 # Init vars, Prev = -666 forces initalize
#######################################
# Unique Runtime Call, GScriptClip must be a one-liner:
#######################################
ARGS = "c2,Show,Fmt"
c1.GScriptClip("Fn_MX_2(last, "+ARGS+")", local=true, args=ARGS)
I feel quite sure that the big G would not give you a hard time for using such an arrangement as above,
seeing as he was party to its conception.
EDIT: The unique calling code is below the actual unique functions.
EDIT: Produces this in DebugView on first frame
[4024] Fn_MX_1_DBUG: 0 ] Initialized to frame 0
[4024] Fn_MX_2_DBUG: 0 ] Initialized to frame 0
Gavino
27th April 2017, 17:39
Here is one of a dozen scripts where I used one or more global variables in order to get them inside a conditional.
I think you've chosen a bad example here, John.
Your script has five global variables and not one of them actually needs to be global, even when uncommenting the code to display metrics. When everything is at outer script level, there is never a need for globals!
Note also that the input clip to ScriptClip and friends becomes 'last' inside the run-time script, so code such as
WriteFileIf(mcomp_clip, filename, "(YDifferenceFromPrevious(mcomp_clip) > \
(dFact * YDifferenceToNext(mcomp_clip) + dMin )) && (current_frame %3 == 1)", \
"current_frame/3", append = false)
can be replaced by
WriteFileIf(mcomp_clip, filename, "(YDifferenceFromPrevious() > \
(dFact * YDifferenceToNext() + dMin )) && (current_frame %3 == 1)", \
"current_frame/3", append = false)
eliminating a possible reason for introducing a global variable when used inside a function (for example if mcomp_clip had been a function parameter).
StainlessS
27th April 2017, 17:42
So there you are John, not so much a bollocking for using Globals, but for your god awful wrong use of them :)
johnmeyer
27th April 2017, 23:50
I am so embarrassed ...
... but, when faced with my own incompetence, I am reminded of the story my dad was told in lecture hall at M.I.T. on the first day of classes in 1938:
"According to all of our engineering calculations, the bumblebee cannot possibly fly. However, the bumblebee, not being able to do these calculations, merrily flies from one flower to the next."So, sometimes my crummy scripts actually work, despite violating all rules, protocols, and social conventions.
I do try to behave and follow the rules, whenever I can.
Thanks to both StainlessS and Gavino for their continued patience and guidance.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.