Log in

View Full Version : convert avs script to c++


mathmax
16th September 2010, 15:26
Hello

I would like to convert an avs script to c++ for two reasons:
- make it faster to execute
- be able to debug it

Here is my script

ImageSource("G:\MJ\TBC\WBSS\images\top\%05d.bmp", start=21, end = 23)

PointResize(width, height * 2)
ConvertToYV12()
Levels(16, 1, 235, 0, 255, coring=false)
ProcessLine(0)
PointResize(width, height / 2)

function ProcessLine(clip c, int n)
{
c.Crop(0,n*2,36,2)
newcrop = ScriptClip("
black = int(AverageLuma(Crop(0,0,8,2))) #get the average luma of the left pixels
white = int(AverageLuma(Crop(30,0,8,2))) #get the average luma of the right pixels
l = 70
white = white > l ? l : white
black = black > l ? l : black
margin = (white - black)/15
Levels(black + margin, .18, white, 0, 255, coring=false) #adjust the level to make the left real black and right real white.
")

return (n < 239) ? StackVertical(newcrop, ProcessLine(c, n + 1)) : newcrop
}

Is it possible to write such a script in c++?

Thank you in advance for any help. :)

max

Kuukunen
16th September 2010, 17:45
I would like to convert an avs script to c++
No, you don't.
- make it faster to execute
I very much doubt it would be faster. At least not noticeably so, unless you do something else than just convert the script. All the filters are compiled already you know.
- be able to debug it
This one I don't understand... If the filters you're using have bugs, then those should be debugged, not your script. If your script has logic errors, I don't think it would be easier to debug. (Well one thing is for sure, you'd have to do lots of debugging to even get it to a usable state.)
Is it possible to write such a script in c++?
Sure. Just get Avisynth sources, see what it does and make your own home baked version of avisynth for just that purpose.

What would be much more sensible is to write your own filter for the ProcessLine function, which I guess is the point here. Then it might be a bit faster. Maybe. Logically thinking it shouldn't be too much faster, but I don't know how Avisynth is implemented deep down, so can't say for sure. I guess you could check: http://avisynth.org/mediawiki/Filter_SDK

But in any case your script looks like a very specific one-off thing, so it doesn't sound like it would be worth the trouble. How slow is it anyway? (And how slow is it without the ProcessLine)

Ghitulescu
16th September 2010, 17:49
Why not writting it in assembler? :p:p :p :p That's the fastest way of executing a program....

stax76
16th September 2010, 18:41
I have no idea what you are doing with this script but maybe your problem isn't the script performance but rather opening/closing the script environment (maybe even processes) in sequence, that takes times, also reading many files from the hard drive takes time too.

cretindesalpes
16th September 2010, 20:29
I think you can process the whole picture without any scriptclip and recursive call. The ProcessLine function could be rewrited in a much faster way :

Crop the white and black columns and use a mt_convolution (horizontal="1 1 1 1 1 1 0", vertical="1") on them to replace the AverageLuma. Crop again to isolate the column containing the result (could be x=2 or 3, I don't know, it depends on the way the MaskTools compute the convolution). Oh, you may also have to PointResize x2 your mt_convolution result because of the mod 2 constraint on Crop.

Use a mt_lut to get the min for black and white, PointResize again these clips to match your input clip size and finally use a mt_lutxyz to replace Levels (do the margin calculation on the fly).

mathmax
16th September 2010, 20:34
Thank you for your answers :)

Well, I thought C++ is faster to execute because it's compiled.
Also I would like to observe the values of the variables which is not possible (as far as I know) with an avisynth script...
If you have idea to improve the speed of the current script, I'm also interested :)

mathmax
17th September 2010, 15:47
I really need to watch the content of the variable "white" and "black" for each line of a frame...
I tried to use the WriteFile() function... but it seems that it doesn't work inside ScriptClip().
Any idea to check the content of these variables?

mathmax
17th September 2010, 15:48
edit : duplicated post

Gavino
17th September 2010, 16:55
I really need to watch the content of the variable "white" and "black" for each line of a frame...
I tried to use the WriteFile() function... but it seems that it doesn't work inside ScriptClip().
Use WriteFileStart inside ScriptClip, as each frame is like a newly loaded script.

mathmax
17th September 2010, 17:30
Use WriteFileStart inside ScriptClip, as each frame is like a newly loaded script.

I wrote:
WriteFileStart("c:\output.txt", "white")
inside ScriptClip

And I get the same error message:
script error: expecting a , or )


Another question: this script write 3 times the same line in output.txt. It should only write the value once.
What's the problem?

ImageSource("G:\MJ\TBC\WBSS\images\top\%05d.bmp", start=1, end = 1)

PointResize(width, height * 2)
ConvertToYV12()
WriteFile("c:\output.txt", "AverageLuma(Crop(0,0,6,2))")
ProcessLine(0)


function ProcessLine(clip c, int n)
{
newcrop = ProcessSide(c, n, 684, 40)

return (n < 239) ? StackVertical(newcrop, ProcessLine(c, n + 1)) : newcrop
}

function ProcessSide(clip c, int n, int x, int l)
{
return ScriptClip(c.Crop(x,n*2,36,2), "c")
}

Gavino
17th September 2010, 18:07
I wrote:
WriteFileStart("c:\output.txt", "white")
inside ScriptClip
To use quotes inside ScriptClip, you need to change the outer quotes in the ScriptClip call to triple quotes:
ScriptClip("""... "..." ...""")
Another question: this script write 3 times the same line in output.txt. It should only write the value once.
It should write one line for every frame rendered. Is that what you get?

mathmax
17th September 2010, 18:44
To use quotes inside ScriptClip, you need to change the outer quotes in the ScriptClip call to triple quotes:
ScriptClip("""... "..." ...""")

It should write one line for every frame rendered. Is that what you get?
Thank you so much. It works :)

But still I get three lines for a single frame... that's very strange. Could you test the script on this picture ?

http://www.mediafire.com/i/?9x4a6xzt8q1mrx9

Gavino
17th September 2010, 23:04
But still I get three lines for a single frame... that's very strange. Could you test the script on this picture ?
You get more than one line (for just a single frame) because the result of WriteFile here is used as input to ProcessLine, and so gets used 240 times through StackVertical.

I don't know why you get exactly three lines (in principle you might expect to get 240), but I expect it is a result of the Avisynth cache limiting the repeated uses.

mathmax
17th September 2010, 23:10
no.. look. I use writefile() before the call to ProcessLine().
I get 240 lines if I use it inside the ProcessLine() function, but here it should only write one line.
Did you try to execute the script on your side?

Gavino
17th September 2010, 23:24
Yes, I tried it and got three lines, same as you.

Using WriteFile before the ProcessLine call means that its output (a clip) becomes the input to ProcessLine, and that clip gets used (directly or indirectly) 240 times. Each time Avisynth fetches a frame from the clip, WriteFile will be triggered to write a line. It seems the cache limits the accesses to 3 rather than 240, but basically that's what's going on.

mathmax
17th September 2010, 23:32
I see... :) Thank you.

Gavino, you helped me a lot with this script :) I've still one issue: the execution speed...

cretindesalpes (I love this name ;) ) proposed the following:

I think you can process the whole picture without any scriptclip and recursive call. The ProcessLine function could be rewrited in a much faster way :

Crop the white and black columns and use a mt_convolution (horizontal="1 1 1 1 1 1 0", vertical="1") on them to replace the AverageLuma. Crop again to isolate the column containing the result (could be x=2 or 3, I don't know, it depends on the way the MaskTools compute the convolution). Oh, you may also have to PointResize x2 your mt_convolution result because of the mod 2 constraint on Crop.

Use a mt_lut to get the min for black and white, PointResize again these clips to match your input clip size and finally use a mt_lutxyz to replace Levels (do the margin calculation on the fly).
but I don't really understand what it means... Will this really do the same as my script?

mathmax
17th September 2010, 23:43
Yes, I tried it and got three lines, same as you.

Using WriteFile before the ProcessLine call means that its output (a clip) becomes the input to ProcessLine, and that clip gets used (directly or indirectly) 240 times. Each time Avisynth fetches a frame from the clip, WriteFile will be triggered to write a line. It seems the cache limits the accesses to 3 rather than 240, but basically that's what's going on.

seems a bit more complicated... cause this script return only one line.. (I just removed the call to ProcessSide() and replaced it with "c.Crop(0,n*2,36,2)")

ImageSource("G:\MJ\TBC\WBSS\images\top\%05d.bmp", start=1, end = 1)

PointResize(width, height * 2)
ConvertToYV12()
WriteFile("c:\output.txt", "AverageLuma(Crop(0,0,6,2))")
ProcessLine(0)

function ProcessLine(clip c, int n)
{
newcrop = c.Crop(0,n*2,36,2)

return (n < 239) ? StackVertical(newcrop, ProcessLine(c, n + 1)) : newcrop
}

Gavino
18th September 2010, 17:14
seems a bit more complicated... cause this script return only one line.. (I just removed the call to ProcessSide() and replaced it with "c.Crop(0,n*2,36,2)")
Interesting - in that case the caching seems to work 'perfectly' and the WriteFile frame is only fetched once.

I think the 'three lines' result may actually be a side-effect of ScriptClip's error handling. In your code
return ScriptClip(c.Crop(x,n*2,36,2), "c")
the local variable "c" is not in scope at run-time, so you get an error (but the clip is too small for the message to be seen). If I replace it by
return ScriptClip(c.Crop(x,n*2,36,2), "last")
then WriteFile only produces one line of output.

cretindesalpes
18th September 2010, 22:00
I see... :) cretindesalpes (I love this name ;) ) proposed the following:
but I don't really understand what it means... Will this really do the same as my script?

The purpose of the method I described is to do the same thing as your script by transforming the script variables into pixel values. Everything is done in the pixel world and in a single pass. This is a "SIMD" (single instruction, multiple data) philosophy. The script loop is replaced by "vector" operations.

For example, the mt_convolution (horizontal="1 1 1 1 1 1 0", vertical="1") actually computes the average luma of 6 neighbour pixels on the same line. Instead of storing the AverageLuma result into the variable "black" or "white" for each single line, the operation stores the result into a pixel luma in a new clip (let's call it "black" or "white"), for all the lines, and in a single pass. Think the clip as an array of variables.

Then you can do all the required operations by selecting the right pixels on the clips with crops and using the masktool's lut to do the arithmetics.