Log in

View Full Version : New Documentation


jmac698
12th January 2011, 06:01
I just wanted to point out that the wiki has been updated with some new pages. Hope these are helpful to someone. Any ideas for programming tricks or things that are not clear from the manual?

http://avisynth.org/mediawiki/Advanced_Scripting_Tips
http://avisynth.org/mediawiki/Known_Issues

Gavino
12th January 2011, 10:24
There are a number of inaccuracies on the 'Known Bugs' page you have just created.

'PointResize bug' - this (RGB/YUV difference) is a long known feature of PointResize.
Whether it should be regarded as a 'bug' depends on whether you think PointResize should be defined in terms of its visual effect or in terms of its effect on pixel memory layout. (Personally I do think it 'should' have been the former, but not everyone will agree, and anyway backwards compatibility means it's unlikely to change.)

'Overlay bugs'. Again not really a 'bug', and only shows up after many repeated partial overlays on an RGB base clip (because of repeated RGB->YUV->RGB conversions). Workaround is to use YUY2 for base clip.

'Layer bug' - not a bug at all, it's meant to work that way. When layering with RGB32, it's up to you to ensure your input has the desired alpha channel.

jmac698
12th January 2011, 10:36
I'd be happy to use a more neutral term to not offend anyone.
Thanks for your suggestions.
I have my own opinions, but they don't matter - I'm doing this for the community, and I just want to let people be aware of the potential impact of the issues. They affected me, and I would have appreciated being aware of them, and I can't find it in the manual that comes with the program.

About the layer bug, it wasn't a point of not having the right alpha channel, obviously that's a problem with your script. My issue was that there was some memory leak and unstability without the alpha channel. It's still unexplained why overlay uses so much memory as well. We can debate these issues elsewhere though.

It took you some experimentation to understand the cause of the yellow tinge issue, and you're the best scripter I've seen - so obviously it's an issue that needs to be made more aware of.

Any input on programming tips?

Update: Documentation updated

Gavino
12th January 2011, 12:16
About the layer bug [...] My issue was that there was some memory leak and unstability without the alpha channel.
I don't think this has been demonstrated (and in my view it's unlikely).
It took you some experimentation to understand the cause of the yellow tinge issue, and you're the best scripter I've seen - so obviously it's an issue that needs to be made more aware of.
I've added a bit about this to the Overlay (http://avisynth.org/mediawiki/Overlay#Repeated_overlays_on_RGB_base_clip) page.
Any input on programming tips?
It's a very wide topic and difficult to give general advice.
It helps very much to understand how Avisynth works (at least in general terms, ie have the correct mental model) and to have read the manual from cover to cover several times, including the 'advanced' bits.
Your page currently has a very narrow focus and I'm not sure if many people will find it useful.
And I'm disappointed you didn't at least mention GScript. :(:)

jmac698
12th January 2011, 12:25
Well, it's a work in progress. I can't say who is going to find it useful, however I've never seen a detailed explanation of recursion, that's certainly something I found hard to pick up.
I have nothing against GScript, I just feel it should have it's own page - it's important enough for that :) Add your own text anyhow, it's a community project!
And I wrote a bug -err, issue in the 2.6 topic.
It's great that you added a note in overlay! I just don't see why overlay couldn't be "improved" to detect when all inputs are rgb and just do processing in that mode. I can't see any backwards compatibility issues or disadvantage to it. Of course modes like "chroma" make sense only in a YUV colorspace, but that doesn't mean that certain modes couldn't be rgb - it's actually simpler, just don't call the convert function.

anyhow if anyone else replies, tell me what did you have difficulty learning in scripting, or had a major "aha!" moment when you discovered it?

jmac698
12th January 2011, 12:52
Oh - you must think GScript obsoletes recursion - yeah, good point :) It might be a good place to mention it - bet you like the page better now :)

Gavino
12th January 2011, 13:07
I just don't see why overlay couldn't be "improved" to detect when all inputs are rgb and just do processing in that mode. I can't see any backwards compatibility issues or disadvantage to it.
Well, the 'disadvantage' is that someone would have to do the work to implement that. :)
And we already have Layer as a better alternative for RGB.

BTW Here's a very simple demo of the Overlay issue:
function OverlayN(clip c, clip c2, int n) {
GScript("for (i=1, n) { c = c.Overlay(c2, y=32) }")
return c
}

grey = $b4b4b4
BlankClip(10,128,128, color=grey)
b = BlankClip(last, height=height/2)
Animate(0, 9, "OverlayN", b, 0, b, 99)
Oh - you must think GScript obsoletes recursion - yeah, good point :)
Recursion is still necessary for certain types of processing (eg tree-based algorithms). But for the majority of cases where recursion was needed in Avisynth, most people will find it easier to use a loop.

jmac698
12th January 2011, 13:30
I like the recursive version better sometimes, because it's simpler and easier to understand.

messageclip(string(factorial(5)))
function factorial(int n) {
n<2?1:factorial(n-1)*n
}

vs

messageclip(string(factorial(5)))
function factorial(n) {
GScript("""
f=1
for (i=1,n) {
f=f*i
}
""")
f
}

I updated the page to talk about using current_frame=0. I don't really understand the effect of setting this variable. Will it have an effect if I set it to 10? What happens when I play different frames with it set to 10? You know that would be a really nice way to affect certain frame a video, for example a recent topic was, How do I blur certain frames? The answer would be current_frame=21 / blur.

Gavino
12th January 2011, 14:18
I updated the page to talk about using current_frame=0. I don't really understand the effect of setting this variable. Will it have an effect if I set it to 10? What happens when I play different frames with it set to 10?
As I said when I first explained it, setting it to 'n' will cause AverageLuma etc to give the value for frame n. Since it's done at compile-time, it's a one-off call - playing different frames (or even any frames at all) doesn't affect it.
Note that this trick is really 'cheating' by taking advantage of an implementation detail which is not guaranteed to work in future versions (but very probably will).
You know that would be a really nice way to affect certain frame a video, for example a recent topic was, How do I blur certain frames? The answer would be current_frame=21 / blur.
No, that won't work - the variable is only used by the runtime functions (http://avisynth.org/mediawiki/Internal_functions/Runtime_functions).
The correct way to do this is to use ApplyRange (http://avisynth.org/mediawiki/ApplyRange).

Wilbert
12th January 2011, 20:01
I moved your first page to the 'AviSynth FAQ, Guides and Advanced topics' section. I think it's a better place for it.

Regarding Known_Issues. We should have a bug page on v2.58 (that's useful, since there probably won't be a v2.59). Bugs on v2.6x should be reported on sourceforge (if you do that on the wiki it gets outdated after a while and someone should update it). Known issues should be described on the page of the filter (or where applicable) like Gavino did.

jmac698
12th January 2011, 20:09
That's all fine, but I didn't feel that my script samples displaying the issue would be appropriate for a manual reference page?

Wilbert
13th January 2011, 19:34
That's all fine, but I didn't feel that my script samples displaying the issue would be appropriate for a manual reference page?
Sorry, I don't understand your question or statement.

Gavino
13th January 2011, 20:06
About the layer bug [...] My issue was that there was some memory leak and unstability without the alpha channel.
Do you still maintain that view?
Is it not more likely that the problem was due to the bug in your script that I explained here?
I see also that this incorrect code still appears on the Known Issues page as an example for the Overlay issue.

jmac698
14th January 2011, 01:21
http://avisynth.org/mediawiki/Known_Issues updated.
Wilbert; if I copy the known issue text directly to the manual, I felt that including the script which exposes the issue would not be appropriate in a reference manual page.

G, layer in rgb24, I still need to write a script showing the issue. I'm busy with other things right now.

StainlessS
1st December 2012, 22:10
Equivalent routine to SumOfN (recursive) on wiki


Function Terminal(int n) {
# Return sum of integers 1 to n. Input n range 1 to 65535, else returns 0. (From Knuth TAOCP Vol 1)
return (n > 65535 || n <= 0) ? 0 : (n % 2 == 0) ? (n+1)*(n/2) : n * ((n + 1) / 2)
}


Mentioned earlier here: http://forum.doom9.org/showthread.php?p=1603404#post1603404

jmac698
2nd December 2012, 02:43
Good that you know that and read Knuth :) I also know it, and also for cubic, but I learned it from a puzzle question. You can figure it out yourself easily. How do you add all numbers? Add them in pairs, 1+10, 2+9...5+6 or 5*11. Anyhow, the point was to demonstrate recursion, so I did it the hard way.

There's a linear time sort that I've seen a few people discover on their own too.

fvisagie
2nd December 2012, 13:55
Here are some things that either tripped me up or helped a lot that you may want to consider adding.

1. Select() can return unexpected runtime errors, even with correct syntax and execution flow. Discussion and solution at http://forum.doom9.org/showthread.php?t=166584.

2. When filtering must be restricted to only parts of the input clip, it can become a struggle to match brightness, contrast, saturation etc. between filtered and unfiltered segments. To help with this, an easy way to display measurements for the current/any frame is e.g.

# ...
# Put this at the end of your script
ScriptClip("Subtitle(String(AverageLuma()))")

Gavino
2nd December 2012, 15:38
an easy way to display measurements for the current/any frame is e.g.

# ...
# Put this at the end of your script
ScriptClip("Subtitle(String(AverageLuma()))")

One of my early contributions to the forum (as an enthusiatic noob :)) was a utility function (ShowProperty (http://forum.doom9.org/showthread.php?t=138316)()) to do this sort of thing in a user-friendly way, eg ShowProperty("AverageLuma").
The function allows for optional labelling and positioning of the text.

fvisagie
2nd December 2012, 16:54
Thanks, I was hoping the simplistic example would flush out something more substantial from a (still enthusiastic) non-noob ;).

StainlessS
3rd December 2012, 16:55
There's a linear time sort that I've seen a few people discover on their own too.

Come on Jmac, if you have some pearls, then cast them amongst us swine. :)

(Puzzles may be another Wiki page)

fvisagie
11th December 2012, 20:45
It seems that the Block statements documentation (http://avisynth.org/mediawiki/Block_statements) overlooks one of the main features, being the Avisynth execution model itself. That is if I understand it correctly ;). "Only filters -ie their resulting clips- that are linked by the final clip returned by the script are part of the filter graph." I understand that to mean that when _clips_ are used as operands in conditional statements, any code, filters and clips associated with clips _not_ used in the result will be excluded from the filter graph, without the scripter having to explicitly subject such code, filters or clips to conditions for processing or performance reasons.

If that's understood correctly, it not only makes writing conditional code implicit to Avisynth scripting, it also automatically optimises the script for execution performance - no unnecessary code is executed. Provided clips are used as operands in the conditional statement.

Here's a somewhat long-winded but at least actual example. You can actually skip straight from the function definition to the conditional statement at the bottom.

function ALBR(clip a, string "mode", ... ) {
...
mode = Default(mode, "AdSharp")
Assert((mode == "AdSharp") ? true : \
(mode == "Sharpen") ? true : \
(mode == "Denoise") ? true : \
false, """'mode' choice """" + mode + """" is invalid""")
...


#-------------------------------------------
# Save source clip motion vectors
#
# Identify large moving areas using larger blocks
# For blurry source choose lambda and pnew values that slightly relax coherence to prevent too many MVs being discarded and causing motion distortion
#
a.MSuper(hpad=hpad, vpad=vpad, pel=pel, rfilter=rfilter)
bvec3 = (degrain == 3) ? \
MAnalyse(isb=true, delta=3, blksize=blksizA, overlap=ovrlapA, temporal=temporl, lambda=lambda, pnew=pnew) : BlankClip()
bvec2 = (degrain >= 2) ? \
MAnalyse(isb=true, delta=2, blksize=blksizA, overlap=ovrlapA, temporal=temporl, lambda=lambda, pnew=pnew) : BlankClip()
bvec1 = MAnalyse(isb=true, delta=1, blksize=blksizA, overlap=ovrlapA, temporal=temporl, lambda=lambda, pnew=pnew)
fvec1 = MAnalyse(isb=false, delta=1, blksize=blksizA, overlap=ovrlapA, temporal=temporl, lambda=lambda, pnew=pnew)
fvec2 = (degrain >= 2) ? \
MAnalyse(isb=false, delta=2, blksize=blksizA, overlap=ovrlapA, temporal=temporl, lambda=lambda, pnew=pnew) : BlankClip()
fvec3 = (degrain == 3) ? \
MAnalyse(isb=false, delta=3, blksize=blksizA, overlap=ovrlapA, temporal=temporl, lambda=lambda, pnew=pnew) : BlankClip()
# Refine motion vectors using smaller blocks to capture fine motion detail, edges and more complex motion
# For blurry source relax re-estimation threshold to prevent too many MVs being discarded and causing motion distortion
bvec3 = (degrain == 3) ? \
MRecalculate(bvec3, thSAD=thSADR, blksize=blksizR, overlap=ovrlapR, lambda=lambda, pnew=pnew) : bvec3
bvec2 = (degrain >= 2) ? \
MRecalculate(bvec2, thSAD=thSADR, blksize=blksizR, overlap=ovrlapR, lambda=lambda, pnew=pnew) : bvec2
bvec1 = MRecalculate(bvec1, thSAD=thSADR, blksize=blksizR, overlap=ovrlapR, lambda=lambda, pnew=pnew)
fvec1 = MRecalculate(fvec1, thSAD=thSADR, blksize=blksizR, overlap=ovrlapR, lambda=lambda, pnew=pnew)
fvec2 = (degrain >=2 ) ? \
MRecalculate(fvec2, thSAD=thSADR, blksize=blksizR, overlap=ovrlapR, lambda=lambda, pnew=pnew) : fvec2
fvec3 = (degrain == 3) ? \
MRecalculate(fvec3, thSAD=thSADR, blksize=blksizR, overlap=ovrlapR, lambda=lambda, pnew=pnew) : fvec3
# Save copies of motion vector data for display and tuning purposes
a_super = last
afvec = fvec1


#-------------------------------------------
# Create frame-adaptive repair mask
#
# Identify detailed vs. flat areas (luma only)
#
edgemsk = a.mt_edge(mode="hprewitt", thY1=thshlow, thY2=thshhi, y=3, u=-128, v=-128)
# Consolidate detailed and flat areas
consmsk = edgemsk.medianblur(rc, 0, 0)
# Normalise mask levels to around full range to prevent sharp transitions around mask edges
consmsk.Levels(Max(0, thshlow-1), 1.000, Min(255,(thshhi+1)), 0, 255, coring=false)
# Deband mask
binomialBlur(vmdb, 0.0, 3, 2, 2, true)
albmask = mt_invert(y=3, u=-128, v=-128)


#-------------------------------------------
# Create sharpened clip
#
# Purposely try to "sharpen" chroma too
#
Eval(Select(shrpnum, \
"""a.gaussianblur(varY=vshy, varC=vshc, y=ysh, u=ush, v=vsh).mt_lutxy(a, "y x - " + String(strsh) + " * y +", y=ysh, u=ush, v=vsh)""", \
"""a.unsharp(varY=vshy, varC=vshc, strength=strsh, y=ysh, u=ush, v=vsh)""", \
"""a.mt_lutxy(a.repair(a.repair(a.repair(a.repair(a.repair(a.repair(a.repair(a.repair(a.medianblur(rshy, rshc, rshc), 4), 4), 4), 4), 4), 4), 4), 4), \
"x x y - abs " + string(strsh, "%#.2f") + " 2 ^ / 1 " + string(strsh, "%#.2f") + " / ^ " + string(strsh, "%#.2f") + " 3 ^ * x y - x y - abs " \
+ string(strsh, "%#.2f") + " + / * +", y=ysh, u=ush, v=vsh)""", \
"""a.mt_lutxy(a.medianblur(rshy, rshc, rshc), "x x y - abs " + string(strsh, "%#.2f") + " 2 ^ / 1 " + string(strsh, "%#.2f") + " / ^ " \
+ string(strsh, "%#.2f") + " 3 ^ * x y - x y - abs " + string(strsh, "%#.2f") + " + / * +", y=ysh, u=ush, v=vsh)""", \
"""a.TUnSharp(strength=Int(strsh), thresholdL=thL, thresholdU=thU, type=type, map=map, lim=lim, radius=rshy, gui=false)""" \
) \
)
# Normalise levels somewhat after including chroma above
shrp = ((hue != 0.0) || (sat != 1.0) || (bright != 0.0) || (cont != 1.0)) ? Tweak(hue=hue, sat=sat, bright=bright, cont=cont, coring=false) : last


#-------------------------------------------
# Use motion-compensated averaging to temporally smooth sharpening artifacts and remove some noise
#
shrp_super = shrp.MSuper(hpad=hpad, vpad=vpad, pel=pel, rfilter=rfilter, levels=1)
# Recalculate vectors to account for improved structure
bvec3 = (degrain == 3) ? \
shrp_super.MRecalculate(bvec3, thSAD=thSADR, blksize=blksizR, overlap=ovrlapR, lambda=lambda, pnew=pnew) : bvec3
bvec2 = (degrain >= 2) ? \
shrp_super.MRecalculate(bvec2, thSAD=thSADR, blksize=blksizR, overlap=ovrlapR, lambda=lambda, pnew=pnew) : bvec2
bvec1 = shrp_super.MRecalculate(bvec1, thSAD=thSADR, blksize=blksizR, overlap=ovrlapR, lambda=lambda, pnew=pnew)
fvec1 = shrp_super.MRecalculate(fvec1, thSAD=thSADR, blksize=blksizR, overlap=ovrlapR, lambda=lambda, pnew=pnew)
fvec2 = (degrain >= 2) ? \
shrp_super.MRecalculate(fvec2, thSAD=thSADR, blksize=blksizR, overlap=ovrlapR, lambda=lambda, pnew=pnew) : fvec2
fvec3 = (degrain == 3) ? \
shrp_super.MRecalculate(fvec3, thSAD=thSADR, blksize=blksizR, overlap=ovrlapR, lambda=lambda, pnew=pnew) : fvec3
# Leave thSAD high enough (400) for only really bad vectors potentially to be re-evaluated - balance against introducing noise
sharpnd = (degrain == 3) ? shrp.MDegrain3(shrp_super, bvec1, fvec1, bvec2, fvec2, bvec3, fvec3) : \
(degrain == 2) ? shrp.MDegrain2(shrp_super, bvec1, fvec1, bvec2, fvec2) : \
shrp.MDegrain1(shrp_super, bvec1, fvec1)


#-------------------------------------------
# Mode decision
#
# "AdSharp" : use repair mask to merge original with sharpened clip
# "Sharpen" : continue with sharpened clip directly
# "Denoise" : continue with input clip
#
mrgd = (mode == "AdSharp") ? mt_merge(a, sharpnd, albmask, luma=false, y=ysh, u=ush, v=vsh) : \
(mode == "Sharpen") ? sharpnd : \
a
...
}

So, when mode == "Denoise", effectively everything up to the last conditional statement is excluded from the filter graph.

If I have this right, in my view this is a major benefit of the Avisynth execution model, and perhaps deserves a mention in the Block statements section?

Gavino
11th December 2012, 22:24
So, when mode == "Denoise", effectively everything up to the last conditional statement is excluded from the filter graph.
That's right.
Note however that 'unused' filters, although no frames will be requested from them at run-time, still get instantiated at compile-time, potentially consuming memory, unless they are on the 'false' part of a conditional branch.
So here the MAnalyses of bvec1 and fvec1, for example, are always instantiated.

Also, in code like
bvec3 = (degrain == 3) ? \
MAnalyse(isb=true, delta=3, blksize=blksizA, overlap=ovrlapA, temporal=temporl, lambda=lambda, pnew=pnew) : BlankClip()
MAnalyse is not instantiated unless degrain==3, but BlankClip is instead. In cases like this I prefer to use NOP() instead of BlankClip() - as well as a (notional) efficiency gain, this shows that the result is not intended to be used (and will provoke an error if I have screwed up the later logic and actually did use it).

Finally note that the '||' operator (and similarly for '&&') is optimised to only evaluate as far as it needs to determine its result, so
Assert((mode == "AdSharp") ? true : \
(mode == "Sharpen") ? true : \
(mode == "Denoise") ? true : \
false, """'mode' choice """" + mode + """" is invalid""")
could be written simply as
Assert((mode == "AdSharp") || (mode == "Sharpen") || (mode == "Denoise"), \
"""'mode' choice """" + mode + """" is invalid""")

As for the block statements (http://avisynth.org/mediawiki/Block_statements) page, the constructs described there are really ugly, which is why I developed GScript. ;)

fvisagie
12th December 2012, 07:42
Thanks for the thorough response, as well as the hints.

fvisagie
12th December 2012, 21:37
PS.

MAnalyse is not instantiated unless degrain==3, but BlankClip is instead. In cases like this I prefer to use NOP() instead of BlankClip() - as well as a (notional) efficiency gain, this shows that the result is not intended to be used (and will provoke an error if I have screwed up the later logic and actually did use it).

I wrongly assumed that the parser would object to mixing operand types (and remained under that assumption for lack of experimenting ;)). I can see how intentionally provoking an error on subsequent logic mistakes can be a benefit, though.

Finally note that the '||' operator (and similarly for '&&') is optimised to only evaluate as far as it needs to determine its result

Although I realise that, visually I prefer the way the original code enumerates legal values, thanks :).