Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion. Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules. |
|
18th June 2009, 11:18 | #1 | Link |
Avisynth language lover
Join Date: Dec 2007
Location: Spain
Posts: 3,431
|
GScript - language extensions for Avisynth
This is something I started as a 'proof of concept' for my own amusement.
As I think some people will find it useful, I am making it generally available. GScript is a plugin that extends the Avisynth scripting language to provide additional control-flow constructs: multi-line conditionals (if-then-else blocks), 'while' loops and 'for' loops. Rather than trying to simulate these constructs with functions, GScript effectively extends the language syntax, making it easy to use the new constructs in a natural way and in arbitrary combinations. Here are the constructs in detail: 'if' statement Code:
if ( condition ) { statements } else { statements } The statements can be any Avisynth statements, including the GScript extensions themselves, and so the new constructs can be nested. The else part may be omitted (equivalent to else {}). GScript also provides the 'else if' construct (optionally repeated to create a chain of conditionals). Thus Code:
if ( condition ) { statements } else if ( condition ) { statements } else if (...) { ... } ... else { statements } Code:
while ( condition ) { statements } Example: Code:
while (Height() < h) { StackVertical(last, c) } Code:
for ( variable = init , limit , step ) { statements } First the variable is set to the value of init. The statements are repeated until the exit condition is met, ie variable exceeds limit (if step > 0), or is less then limit (if step < 0). After each iteration, variable is incremented by step. If the initial value satisfies the exit condition, the number of iterations will be zero. Example: Code:
for (i=1, nBlurs) { Blur(0.5) } Once the plugin is loaded (either via LoadPlugin or by installing GScript.dll in your plugins folder), there are two ways to use the extended language features. Firstly, a script (or part of a script) containing extensions can be passed as a text string to the GScript function (similar to the way functions like ScriptClip or MT are used). For example, Code:
GScript(""" if (i > 10) { x = 1 y = 2 z = 3 } else { x = 4 y = 5 z = 6 } """) The advantage of this is that you don't have to put quotes around the script, or worry about possible problems if the embedded script itself contains both triple and single quotes. Thus, you can write entire scripts directly in the extended language and just pass to Avisynth a single GImport command to read it. Code:
GImport("MyGScript.avs") Update: Version 1.1 (GScript_11.zip) released 6th Dec 2009 Last edited by Gavino; 15th February 2010 at 13:58. Reason: Remove v1.0 dll from attachments |
18th June 2009, 11:51 | #2 | Link |
Registered User
Join Date: May 2006
Posts: 957
|
Good god man! This is brilliant.
__________________
x264 log explained || x264 deblocking how-to preset -> tune -> user set options -> fast first pass -> profile -> level Doom10 - Of course it's better, it's one more. |
18th June 2009, 14:11 | #4 | Link | |
Registered User
Join Date: Apr 2002
Location: Germany
Posts: 5,389
|
Quote:
For *such* a simple task, Avisynth's standard language (conditional operation through bool ? this : that) is fully sufficient ... Code:
src = last dest_modulo = 2 # or 4, 6, 8, 1337, ... src_modulo = src.width()%dest_modulo padding = dest_modulo - src_modulo src_modulo==0 ? src : src.addborders(0,0,padding,0)
__________________
- We´re at the beginning of the end of mankind´s childhood - My little flickr gallery. (Yes indeed, I do have hobbies other than digital video!) |
|
18th June 2009, 14:20 | #5 | Link | |
Avisynth language lover
Join Date: Dec 2007
Location: Spain
Posts: 3,431
|
Quote:
EDIT: as Didée has just shown! Where the extended 'if' becomes really useful is when you need to write more than one statement in one of the conditional 'branches'. Without GScript, you are limited to the rather messy techniques described here, which can't be easily nested. See also here. Last edited by Gavino; 18th June 2009 at 14:22. Reason: Didée's answer |
|
18th June 2009, 15:58 | #7 | Link |
Registered User
Join Date: Mar 2005
Posts: 366
|
Very nice indeed! This way of coding in a more readable syntax(plus the extra functions) is more that welcome. One could hope that this would eventually be implemented in Avisynth so the quotes around the script would not be needed at all.
__________________
DVD slideshow GUI(Freeware). |
19th June 2009, 17:16 | #8 | Link | |
Avisynth language lover
Join Date: Dec 2007
Location: Spain
Posts: 3,431
|
Quote:
To implement the plugin, I used a modified version of the Avisynth parser code. The changes are relatively self-contained and all clearly marked in my source code. It would take little more than a cut-and-paste job to put those changes into the 'real' parser. |
|
18th June 2009, 18:00 | #9 | Link |
Kid for Today
Join Date: Aug 2004
Posts: 3,477
|
hehe ok thanks fellas, as we say in France "caviar doesn't taste better w/ a big spoon"...ideally I'd love to an automatic script that'd make everything mod2 in ffdshow by simply adding horizontal black bars *only* if required, I'll look into Didée's script
|
18th June 2009, 20:39 | #10 | Link |
Resize Abuser
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
|
Gavino, thanks for doing this! It makes script development a lot simpler now
__________________
Mine: KenBurnsEffect/ZoomBox CutFrames Helped: DissolveAGG ColorBalance LQ Animation Fixer |
19th December 2009, 14:48 | #12 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
This is my new bestest plugin, thanx Gavino,
Thought you might like to know I've posted a little script:- http://forum.doom9.org/showthread.ph...74#post1354574 Using GScript, uses a recursive function, tried it up to about 140 levels of recursion without probs, assume that it is a dynamic heap type stack rather than a real one in Avisynth. Anyways, LOVE THIS, everyone shoud get this for XMAS. PS, where can I get one of these fabled Paper cutting laser machines? |
19th December 2009, 17:48 | #13 | Link |
Avisynth language lover
Join Date: Dec 2007
Location: Spain
Posts: 3,431
|
Thanks, StainlessS. Interesting example.
Although it doesn't actually seem to be a problem, you could eliminate the recursive call to GScript itself by defining the entire function within GScript, ie Code:
GScript(""" Function __FPS_23_to_24__(clip Last) { ... } """) I wondered if that recursion could be easily removed by using a 'while' loop, but I think your algorithm is easier to express recursively, as you have done. |
19th December 2009, 20:31 | #14 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
@ Gavino,
I shall edit the GScipt(""" stuff to outside the function, thought it was purely compile time. After getting it working recursively, I did spend about 10 mins converting using while loop, but thought, 'sod it, why bother'. It can be more difficult than recursive, the iterative Euclid() thing runs quite a lot quicker than rercursive, and in Knuth, (maybe Fundamental Algorithms) he does a fairly longer iterative version that is quite a bit faster than that. If it could be converted to iterative, it would not be too difficult a job to make it run without GScript (Eval), but would not want to even try doing it that way without something that already worked. I have not really done any coding [other than my new filter Exblend() as posted on doom Dec 2nd], for about 14 years. Did quite a bit of graphics type stuff, quick drawing of lines, circles, ellipse, torus etc, using something called DDA. Cannot for the life of me remember what its called [DDA], nor anything about how it works. Was thinking that maybe I could use it [DDA] in doing a direct conversion from 23.976 to 25 FPS (instead of a 24FPS interim conversion). Could you please take a quick look at the below comments from a function I wrote about 16 or 17 years ago, I cant make head nor tail of it and dont even know what to look for on the net, looked DDA up on Wikipedia, got something completely unrelated. See Below:- Code:
void wrcircle0(int xc,int yc,int r,int pen) { /* circle Single pixel render version (ie wrpixel()). Draw a lovely round circle on a 1:1 aspect ratio device using a DDA. Uses equation of circle:- x*x + y*y <= r*r where pixel is exactly on circumference of circle when the equation balances exactly. We wish for rounding to the nearest pixel using the distance from the origin to the circumference ie sqrt(x*x + y*y) <= r + 0.5 The above in effect calculates the distance from the centre of the origin to the centre of the target pixel (ie the coords themselves are NOT rounded, simply the distance from centre to centre) and it is the radius that is rounded rather than the x,y coords. We need the pixel that provides the greatest distance from the origin while maintaining the above relationship. We want to re-write in the form of the first equation so x*x + y*y <= (r + 1/2)*(r + 1/2) Expanding the right hand side we get x*x + y*y <= r*r + r + 1/4 As (x*x + y*y) never produces a fractional result, we can drop the 1/4 from the equation without affect. Rewriting:- x*x + y*y - r*r - r <= 0 where ((r*r) - r) is constant and (x*x) and (y*y) vary and can be calculated easily without multiplication as we step through the x,y coordinates. Where n -1 0 1 2 3 4 (n*n) -1 0 1 4 9 16 (n*n)-((n-1)*(n-1)) -1 1 3 5 7 diffstep 2 2 2 2 The difference (n*n) - ((n-1)*(n-1)) cancels to:- 2n - 1 and varies by diffstep (2) when stepping through x,y coords. The threshhold at x,y of (0,r) is calculated as (0*0) + (r*r) - (r*r) - r which cancels to (-r). We step coords clockwise from top centre (0,r) to (r,0). We check first that x+1,y is ok to print and if so we move RIGHT (From our rotation and the perfect aspect ratio, the pixel to the right of current is ALWAYS further away and always furthest possible if plottable), if this fails then we KNOW we have to check 1 DOWN and RIGHT of current as this is always next possible longest radius, if plottable we move DOWN and RIGHT, otherwise we KNOW that 1 down from current is always closer than current so we do not need to check whether its plottable and so we move DOWN. The above method ensures that plotted points are no more than 1 pixel from the previous one (counting diagonal as one) and so leaves no gaps in the circle. To save complications, when plotting 4 quadrants we plot in 2 parts, the initial top and bottom middle pixels are plotted first and it then loops to find the next coords, plots two of those and waits until the next loop to do the same coords in the other quadrants. This removes the necessity to plot the top, bot, left, and right centre pixels as special cases (Otherwise plots same pixels twice). Have tested from radius 1 to 1500 and NO pixels overlap any other plotted pixels therefore not affecting XOR type operations. DONT CHANGE algorithm without good cause. Further, To calculate the upper coord of the vertical cord where x==r we use:- y*y <= (r*r) + r + 1/4 - (x*x) As (x == r) and 1/4 will not take any significance we rewrite as:- y*y <= r OR y = (int)sqrt(r); (Fract part discarded) This algorythm does produce the occasional extra pixel at 45 degrees which results in a pointy bit instead of a smooth diagonal, however, as there are only about 5 instances with a radius less than 10,000 and only 4 less than 1000 radius (ie 1, 8, 49, 288). We we could eradicate this but do not due to the overhead of detection for such a small improvement. [ if((thresh <= 0)&&((x+1)!=y)) step right ELSE step left]. NOTE, At radius == 1, the aforesaid pointy bit is desired. */ long thresh; /* Needs long (ranges about +- 2r ) */ long xd; /* Needs long (ranges about -1 to 2(r+1) - 1) */ long yd; /* Needs long (ranges about -1 to 2r - 1) */ int x,y,terminate,tem; const long diffstep = 2L; /* long to avoid size extension */ if ( (r<=0) || ((yc-r) > clip[3]) || ((yc+r) < clip[1]) || ((xc-r) > clip[2]) || ((xc+r) < clip[0]) )return; /* Clip thresh, (-ve if fully within clipping area ) */ if((terminate=clip[1]-yc)<(tem=yc-clip[3])) terminate = tem; x=0;y=r; /* Preset plot at (0,r) and init thresh for (1,r) */ yd = (2L*r - 1L); /* yd(r) */ xd = (2L*0 - 1L + 2L); /* xd from 0 to 1 */ thresh = (-r); /* thresh(0,r) */ thresh += xd; /* thresh(1,r) */ while((y > 0)&&(y >= terminate)) { wrpixel(xc + x ,yc - y,pen,NULL); /* quad 1 (And starting plot) */ wrpixel(xc - x ,yc + y,pen,NULL); /* quad 3 (And starting plot) */ if(thresh <= 0) /* Can we do (x+1,y), 1 to RIGHT of current */ { /* Yes, step x Right */ xd += diffstep; /* xd from x+1 to x+2 */ thresh += xd; /* thresh(x+2,y) */ ++x; /* This is longest poss radius, DONE */ } else { /* No, stepping y Down */ thresh -= yd; /* thresh(x+1,y-1) */ yd -= diffstep; /* yd from y to y-1 */ if(thresh <= 0)/* Can we do (x+1,y-1), 1 dwn, 1 RGT of current */ { /* Yes, stepping both DOWN and RIGHT */ xd += diffstep; /* xd from x + 1 to x + 2 */ thresh += xd; /* thresh(x+2,y-1) */ ++x; } --y; /* Dont forget to DOWN step y */ } wrpixel(xc - x ,yc - y,pen,NULL); /* quad 2 (And closing plot) */ wrpixel(xc + x ,yc + y,pen,NULL); /* quad 4 (And closing plot) */ } } PS, Seem to remember that the DDA thing tends to use XD, YD and Diffstep, whether in line drawing or any other use. |
19th December 2009, 21:17 | #15 | Link | |
Avisynth language lover
Join Date: Dec 2007
Location: Spain
Posts: 3,431
|
Quote:
I'm preparing for a trip at the moment, so I don't have time to study your circle algorithm right now. Is it related to Bresenham's circle algorithm? I don't see the connection with frame-rate conversion though. |
|
19th December 2009, 23:11 | #16 | Link |
HeartlessS Usurer
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
|
Bresenham's circle algorithm,
That seems to ring a bell and probably is similar in some respects (probably even based on), however, the circle algo I posted was unlike any other currently used on any platform. At one time there were competing graphical models floating about and most platforms settled on the same model. Things like not plotting the last pixel of a line. The included circle routine plots absolutely lovely round circles even at small sizes but does not fit in the accepted model. A similar sized circle done with this compared to one drawn in windows looks well different. I think part of it is that my circle judges the origin to be in the centre of the pixel, whereas the accepted model (rounding to x,y coordinates) effectively puts the origin in the bottom left corner (depending upon coordinate system used). [At least thats what seems to be coming back to me]. EDIT:- Got the above circle center thing completely back to front. Anyways, I think there was summick called Bresenhams line algorithm, and I think that, that is the thing I was looking for. It uses a DDA, (whatever that means) to draw eg diagonal lines, stepping regularly on one axis and every now and again, taking a step on the alternate axis. As you say, it may be of no use at all in this instance, but i could not remember how it worked. Will look at your link, try and figure out the DDA thing, might just have to use floating point instead, inserting a sysnthesized frame every 23.4140625 input frames. Thankyou for taking the time to point out Bresenham, he is exactly the guy I was looking for, I think. Please enjoy your holiday and dont bother with the circle thing, you given me every thing I need to find what I am looking for. Ta very much Byesey bye EDIT:- Yeah, your right, complete wild goose chase, thanx for your time. Last edited by StainlessS; 21st December 2009 at 05:00. |
25th March 2010, 11:53 | #17 | Link |
Avisynth language lover
Join Date: Dec 2007
Location: Spain
Posts: 3,431
|
Stephen - thanks for your suggestions. I will need to think about them before giving a full answer.
In the meantime: - a crude way to force exit from a loop is to set the loop counter to its final value; - you might want to look at the array features in AVSLib. |
1st April 2010, 16:46 | #18 | Link |
Avisynth language lover
Join Date: Dec 2007
Location: Spain
Posts: 3,431
|
I'm still thinking about it.
Neither feature is completely trivial, but on the other hand they're not totally infeasible either. My current thinking is that arrays would require further support from the core to be worth having, eg ability to use them as function arguments. So the break/continue feature seems a more likely GScript candidate. I think this could be done, but before expending more effort, I'd like to know how much of a demand there is for this. Note that the effects of break/continue can in principle already be achieved using if/else and appropriate boolean flags in your (G)script. What do you think, good users? |
21st October 2014, 04:34 | #20 | Link |
Registered User
Join Date: May 2007
Posts: 146
|
calling a variable using string + incremented value
Hi
Hope this is the right place to post this question Hi let's say I have a number of subtitles c0="Hello World" c1="Hello and GoodBye" c2="Love is all you need" c3="avisynth rocks" c4="Gscript is awesome" and I want to call these subtitles (variables) in a loop, where the value of k represents a different clip or image being processed in the loop and I want to add each subtitle I can use this syntax to use subtitle c0 k=k.subtitle(c0, 8,460) but how do I use this if I want to use the values of c0, c1, etc I have been trying something like this caption= "c" + string(i) k=k.subtitle(caption,8,460) this give me text strings "c0", "c1", "c2", . . . but I want to get the "value" of c0, c1, c2, etc I tried using caption= eval("c" + string(i)) but I get "Script Error - invalid arguments to function "Subtitle"" TIA |
Tags |
for-loop, if-then-else, while-loop |
Thread Tools | Search this Thread |
Display Modes | |
|
|