Log in

View Full Version : CALL command


Pages : 1 [2]

Chikuzen
25th December 2011, 22:04
Reviving this ancient thread...

Is this any way to send an apostrophe (') inside an argument without CALL_25.dll converting it to a double quote (")?

I've tried \' and everything I could think of but no luck.

on DOS-prompt, escape sequence is not \ but ^

vampiredom
26th December 2011, 03:03
on DOS-prompt, escape sequence is not \ but ^
Nope. Doesn't work either. I believe CALL_25.dll was made to internally translate single-quotes to double-quotes; to make it easier for people to send long strings as arguments without having to triple-quote things in AviSynth. This works great – except, of course, when you want to include single-quotes in the string!

Gavino
26th December 2011, 13:55
I believe CALL_25.dll was made to internally translate single-quotes to double-quotes; to make it easier for people to send long strings as arguments without having to triple-quote things in AviSynth.
Looking through the thread (original was before my time), it seems people were unaware you could use triple-quotes, or perhaps that facility didn't exist back then. Anyway, I've had a look at the CALL source code and it always translates single-quotes to double-quotes - unfortunately, there is no escape mechanism, so the implementation is badly conceived.

vampiredom
26th December 2011, 19:53
it always translates single-quotes to double-quotes - unfortunately, there is no escape mechanism, so the implementation is badly conceived

Yeah, unfortunate. I think I will write a "partner" .exe for CALL_25.dll that allows some kind of escape mechanism. Perhaps I could use ^x, followed by a hex character code. (so that ' would be ^x27). Does that sound like a reasonable workaround for this issue?

vampiredom
30th December 2011, 21:45
Download (http://3dvp.com/Call_25_Helper.zip)

OK, I made this little "helper" app to allow single-quotes (and just about any other funky chars, theoretically) to be passed via CALL_25.dll

The following chars need to be escaped, like such:

^ -> ^x5E
' -> ^x27
\ -> ^x5C
" -> ^x22

These are then unescaped by my .exe

There is also its buddy-function for AviSynth, CALL_25_Helper(), which does the escaping automatically.

# Modify the CALL_25_Helper_Dir variable to contain the path to CALL_25_Helper.exe
# This path should end with a trailing slash (or backslash)
# example:
# global CALL_25_Helper_Dir = "C:/Program Files (x86)/AviSynth 2.5/plugins/"

global CALL_25_Helper_Dir = ""

# CALL_25_Helper()
# Usage examples:
# CALL_25_Helper("c:\path\to\foo.exe", "argument1 argument2 argument3")
# CALL_25_Helper("c:\path\to\bar.exe", """-a "quoted string #1" -b "quoted string #2"""")

Note that you need to define the global CALL_25_Helper_Dir so that CALL_25 can find the helper .exe ... so either modify the line in the .avsi or include the "global" statement in the top of your script:

global CALL_25_Helper_Dir = "C:\Program Files (x86)\AviSynth 2.5\plugins\"

**EDIT**
Note: In reality, only the ' and " chars truly need to be escaped. The reason ^ gets escaped is to avoid any confusion with the escape sequence (though this is improbable). The \ gets escaped only because my .exe will sometimes interpret it as an escape char when passed inside of an argument (such as the case of \", which would be an escaped quote). Safety first.

vampiredom
31st December 2011, 04:14
Another interesting thing about the CALL_25_Helper ...

Since the command is ultimately being executed by the CALL_25_Helper.exe (instead of directly by CALL_25.dll) it now possible to execute system commands ... and you can omit the full path when the the executable is in the system path. A simple example:

# Open up a Windows Explorer window @ drive d: from AviSynth
CALL_25_Helper("explorer", "d:")

Nifty.

martin53
15th July 2012, 19:38
Hi nic, vampiredom or anyone interested and capable of doing this,

is there anyone who likes to help me with this idea:
- Add a clip parameter to call, and make the call plugin first copy the current frame to the clipboard before executing the command
- allow call to execute the command with every frame
- wait for the command to finish, then copy the clipboard content to the return clip (you got it: the command changed the frame in the clipboard)
- maybe add another clip parameter which gives the assumed return clip properties for the graph creation phase of the AviSynth script

The use case I have in mind is to call ImageMagick operations inside an AviSynth script.
Even if it might me slow, all available ImageMagick operations would be accessible at one stroke. I am specifically interested in the fourier and other transform features, which are slow anyway.

The command would be the ImageMagick script, of course, that would start and end reading/writing the clipboard.

Just to allow the command to change the dimensions or other clip properties, it would be useful to give the extended call plugin the 2nd clip as prototype for ImageMagick's return data.

um3k
15th July 2012, 19:55
I wonder if it would be better to use stdin and stdout instead of the clipboard?

StainlessS
15th July 2012, 21:20
mg262's run_25_dll_20050616 dll WarpEnterprises (Runs a system command. Simple source in text file, very succinct)

martin53
16th July 2012, 20:14
mg262's run_25_dll_20050616 dll WarpEnterprises (Runs a system command. Simple source in text file, very succinct)

hmm, indeed, http://avisynth.org/warpenterprises/files/run_25_dll_20050616.zip could be a close to perfect starting point. Today, it just returns the unchanged clip. This would need some work.

vampiredom
16th July 2012, 21:07
For ImageMagick usage, you could use ImageWriter() to write an image sequence, then perform ImageMagick filters on it via CALL25. Then, import the modified sequence for additional AviSynth processing. It may not be ideal, but it would work.

martin53
17th July 2012, 20:09
mg262's run_25_dll_20050616 dll WarpEnterprises (Runs a system command. Simple source in text file, very succinct)
run does not work - it just seems to execute once during graph build.
For ImageMagick usage, you could use ImageWriter() to write an image sequence, then perform ImageMagick filters on it via CALL25. Then, import the modified sequence for additional AviSynth processing. It may not be ideal, but it would work.

Call works indeed. I made this function - you need Gavino's GRunT plugin to use it.

function xCall(clip c, string "command") {
c
ConvertToRGB24() #for ImageWriter, ImageSource
ScriptClip("""
Trim(current_frame, -1) #to fix filename to 000000 and make Call execute on all frames
ImageWriter("C:\Temp\", 0, 0,type="tif") #no success with ebmp
Call(command, "0")
""", args="command", local=true, after_frame=true)
ScriptClip("""
ImageSource("C:\Temp\000000.tif")
""", after_frame=true)
}

EDIT 9/23/12: optimized version in one ScriptClip(), also runtime environment enabled
function xCall(clip c, string "command") {
c
ConvertToRGB24() #for ImageWriter, ImageSource
ScriptClip("""
Trim(current_frame, -1) #to fix filename to 000000 and make Call execute on all frames
ImageWriter("C:\Temp\", 0, 0,type="tif") #no success with ebmp
Call(command, "0")
StackHorizontal(last,ImageSource("C:\Temp\000000.tif")).Crop(c.width,0,0,0)
""", args="command")
}

Get e.g. MOGRIFY from the ImageMagick package and call
xCall(last,"...somePath...\Mogrify -flip C:\Temp\000000.tif")

There is a flicker of a shell window with every frame, but

:) it makes ImageMagick filters available to AviSynth scripts! :) http://www.imagemagick.org/script/command-line-options.php (called 'options' there)

______

StainlessS
3rd September 2012, 23:21
run does not work - it just seems to execute once during graph build.


So it would run on every frame in your scriptclip example.
So you could use
if(current_frame==Whatever){ # Assuming GScript
run(...)
}

Anyway, here's an alternative to Run,
RT_Call() implemented in RT_Stats plugin,
Calls an executable at either compile time or in runtime script.

http://forum.doom9.org/showthread.php?t=165479

EDIT:
There is a flicker of a shell window with every frame, but

RT_Call(String Cmd,bool "Hide"=false) # Hide the console widow, no flicker (If True)

martin53
23rd September 2012, 20:17
So you could use
if(current_frame==Whatever){ # Assuming GScript
run(...)
}

Anyway, here's an alternative to Run,
RT_Call() implemented in RT_Stats plugin,


See in this post (http://forum.doom9.org/showthread.php?p=1592468#post1592468) why run() and RT_Call() do not work as expected, only Call() does.

StainlessS
27th September 2012, 07:56
@Martin53,

OK, Find CallCmd() v0.0 beta, source included here:-
Link deleted, see post #69

Give it a whirl.


CallCmd() by StainlessS, Based on Call by Nic.

Outline by Nic from Call v1.3
--------------------------------------------------------------------------------

Call.dll v1.3:- http://forum.doom9.org/showthread.php?t=46506

Conceived by DDogg, thrown together badly by Nic

To Use:
LoadPlugin("D:\plugin\call.dll")
Call("d:\besweet\besweet.exe -core( -input d:\matrix\matrix.ac3 -output d:\matrix\matrix.mp3 )", "0")

This will do the command on frame 0
if you want to do things on multiple frames seperate with a comma or semicolon
i.e.
Call("d:\besweet\besweet.exe", "0,20,50")
will do the call on frames 0, 20 and 50. Using the number -1 will make it do it on the very last frame!

New Features !! :
----------------

1)
To get Call to operate before any encoding starts is to specify a clip and the
frame number as -2
i.e.
LoadPlugin("call.dll")
Call(BlankClip, "lame --decode fatboy.mp3 fatboy.wav", "-2")
WavSource("fatboy.wav")

The above script will convert fatboy.mp3 into fatboy.wav and then load it :)
(BlankClip is very useful here :) )

2)
If you need to put in " for long file names put in single quotes as apostrophes ' and that should now
work. i.e. Call(BlankClip, "lame --decode 'e:\my rip dir\fatboy.mp3' fatboy.wav", "-2")

3)
NicEcho can be used for outputting stuff.
use as:
Call(BlankClip, "d:\nicecho.exe d:\report.txt 'Hello world how are you?\nCarriage Return'", "-2")
Remember the single quotes around the test!
If you want to append to an already existing file prefix the file name with a @
i.e.
Call(BlankClip, "d:\nicecho.exe @d:\report.txt 'Appending'", "-2")

Notes:
1) REMEMBER THE QUOTES FOR THE SECOND PARAMETER (i.e. its not an integer input but a string!)
2) REMEMBER THAT THE PROGRAM YOUR CALLING MUST CLOSE ITSELF AFTER PROCESSING. OTHERWISE THE ENCODE
WILL GET STUCK UNTIL YOU CLOSE IT MANUALLY!
3) REMEMBER TO PUT IN FULL PATHS TO YOUR PROGRAM. TO TEST YOUR PATH, GO START->RUN THEN TRY IT FROM
THERE TO MAKE SURE IT WILL WORK.

(sorry for the shouting, but I say it just to make you read it ;) )

-Nic

PS
CALL_25.dll is the AviSynth 2.5 version! :)

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


CallCmd() by StainlessS

CallCmd(clip,String Command, String Frames, bool "Hide"=false, bool "debug"=false)

as well as explicit frame numbers in Frames string, can use

-1 = Last frame.
-2 = In constructor (before first frame).
-3 = In Destructor (after last frame).

Hide if true, hide console window.
debug if true, sends debug info to DebugView Window.

Does NO massaging of Command text string, ie does not replace single quotes with double quotes,
was source of problems in Call().
Instead wrap eg filenames (EDIT: containing spaces) in quotes using perhaps:

Function QuoteStr(String s) { return Chr(34) + s + Chr(34) }

or use triple and single double-quotes eg

CallCmd(BlankClip, """d:\nicecho.exe @d:\report.txt "Appending" """, "-2")


ssS

StainlessS
28th September 2012, 08:36
Additional to above:

I dont like the copy to and from clipboard idea, (sounds too ImageMagick specific) but,

I could add an arg to frames eg "*" meaning DO ON EVERY FRAME (all other frame numbers being disallowed in frame string),
and perhaps a positional insert/escape char in command, to insert a fixed number of digits corresponding to the frame number eg


CallCmd(clip,"C:\PortableApps\ImageMagick\Mogrify.exe -flip C:\Temp\#.tif", "*",Hide=true,Debug=true,Insert="#",digits=6)

Executing on every frame, hiding console window, sending debug info to debugview, and converting command string on frame eg 0 to

"C:\PortableApps\ImageMagick\Mogrify.exe -flip C:\Temp\000000.tif"

would that suffice ?

EDIT:
From ImageReader in docs

start = 0, end = 1000: Specifies the starting and ending numbers used for filename generation.
The file corresponding to start is always frame 0 in the clip, the file corresponding to end is frame (end-start).
The resulting clip has (end-start+1) frames. 'end=0' does NOT mean 'no upper bound' as with ImageWriter.
The first file in the sequence, i.e., corresponding to 'start', MUST exist in order for clip parameters to be computed.
Any missing files in the sequence are replaced with a blank frame.


ImageReader/ImageSource would probably still be a problem as it/they check for existence of (at least) the first image file,
in the constructor, would be more of a problem if existence of ALL images ascertained in constructor.

martin53
29th September 2012, 12:47
@StainlessS,
thank you for your help! CallCmd works fine. To my opinion, an extension "*" is not needed, as anyone could either use it inside the RTE (like me), or with Animate(). At least it can wait until someone asks.

I don't like the overhead of clipboard or temporary file either - but it is an easy way to start with, when someone wants to use ImageMagick features from AviSynth. This seems to be an exotic approach right now. If more people should want to do this, better interfaces can be made.

You are right with the 'existence check' problem. I did not have it with earlier tests. Maybe I inadvertently had created that file. Proposed fix: add red code line.
exist("C:\Temp\000000.tif") ? last : ImageWriter("C:\Temp\", 0, 0, type="tif")
ScriptClip("""
c = last
currentframe=current_frame
Trim(current_frame, -1)
ImageWriter("C:\Temp\", 0, 0, type="tif")
CallCmd("C:\PortableApps\ImageMagick\Mogrify.exe -flip C:\Temp\000000.tif", "0",hide=true)
StackHorizontal(last,ImageSource("C:\Temp\000000.tif").Crop(c.width,0,0,0)
""", after_frame=true)

StainlessS
29th September 2012, 15:22
extension "*" is not needed

Well while awaiting reply, I've implemented it anyway as proposed above. (It was previously requested in this thread anyway).
Implemented as below:

CallCmd(clip,String Command, String Frames,String "Insert"="",Int "Digits"=6,Bool "Once"=True,Int "Offset"=0,bool "Hide"=false,bool "Debug"=false)

as well as explicit frame numbers in Frames string, can use

-1 = Last frame.
-2 = In constructor (before first frame).
-3 = In Destructor (after last frame).

Insert, Character which is replaced by frame number + Offset with at least Digits number of digits.
Digits, Minimum number of digits in inserted text.
Once, If true (default) then only executes command once on each frame, if replayed, does not exec 2nd time.
Offset, Offset added to frame number when generating inserted text.
Hide, If true, hide console window.
Debug, If true, sends debug info to DebugView Window.

Almost done, suffering crashes right now but probably just something silly to correct.

StainlessS
1st October 2012, 03:00
Here 0.01beta CallCmd()

LINK REMOVED


CallCmd() by StainlessS, Based on Call by Nic.

Outline by Nic from Call v1.3
--------------------------------------------------------------------------------

Call.dll v1.3:- http://forum.doom9.org/showthread.php?t=46506

Conceived by DDogg, thrown together badly by Nic

To Use:
LoadPlugin("D:\plugin\call.dll")
Call("d:\besweet\besweet.exe -core( -input d:\matrix\matrix.ac3 -output d:\matrix\matrix.mp3 )", "0")

This will do the command on frame 0
if you want to do things on multiple frames seperate with a comma or semicolon
i.e.
Call("d:\besweet\besweet.exe", "0,20,50")
will do the call on frames 0, 20 and 50. Using the number -1 will make it do it on the very last frame!

New Features !! :
----------------

1)
To get Call to operate before any encoding starts is to specify a clip and the
frame number as -2
i.e.
LoadPlugin("call.dll")
Call(BlankClip, "lame --decode fatboy.mp3 fatboy.wav", "-2")
WavSource("fatboy.wav")

The above script will convert fatboy.mp3 into fatboy.wav and then load it :)
(BlankClip is very useful here :) )

2)
If you need to put in " for long file names put in single quotes as apostrophes ' and that should now
work. i.e. Call(BlankClip, "lame --decode 'e:\my rip dir\fatboy.mp3' fatboy.wav", "-2")

3)
NicEcho can be used for outputting stuff.
use as:
Call(BlankClip, "d:\nicecho.exe d:\report.txt 'Hello world how are you?\nCarriage Return'", "-2")
Remember the single quotes around the test!
If you want to append to an already existing file prefix the file name with a @
i.e.
Call(BlankClip, "d:\nicecho.exe @d:\report.txt 'Appending'", "-2")

Notes:
1) REMEMBER THE QUOTES FOR THE SECOND PARAMETER (i.e. its not an integer input but a string!)
2) REMEMBER THAT THE PROGRAM YOUR CALLING MUST CLOSE ITSELF AFTER PROCESSING. OTHERWISE THE ENCODE
WILL GET STUCK UNTIL YOU CLOSE IT MANUALLY!
3) REMEMBER TO PUT IN FULL PATHS TO YOUR PROGRAM. TO TEST YOUR PATH, GO START->RUN THEN TRY IT FROM
THERE TO MAKE SURE IT WILL WORK.

(sorry for the shouting, but I say it just to make you read it ;) )

-Nic

PS
CALL_25.dll is the AviSynth 2.5 version! :)

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

CallCmd() v1.01beta by StainlessS

CallCmd(clip,String Command, String Frames,String "Insert"="",Int "Digits"=6,Bool "Once"=True,Int "Offset"=0,bool "Hide"=false,bool "Debug"=false)


as well as explicit frame numbers in Frames string, can use

-1 = Last frame.
-2 = In constructor (before first frame).
-3 = In Destructor (after last frame).
* = DO ON EVERY FRAME (all other frame numbers being disallowed in frame string).

Insert, Character which is replaced by frame number + Offset with at least Digits number of digits. If Insert character occurs in text then
escape it by inserting two copies, OR, choose a different Insert character.

Digits, Minimum number of digits in inserted text.

Once, If true (default) then only executes command once on each frame, if replayed, does not exec 2nd time.

Offset, Offset added to frame number when generating inserted text.

Hide, If true, hide console window.

Debug, If true, sends debug info to DebugView Window.

---

Does NOT replace single quotes with double quotes in Command string, was source of problems in Call().

Instead wrap eg filenames containing spaces in quotes using perhaps:

Function QuoteStr(String s) { return Chr(34) + s + Chr(34) }

or use triple and single double-quotes eg

CallCmd(BlankClip, """d:\nicecho.exe @d:\report.txt "Appending" """, "-2")

---

CallCmd(clip,"C:\PortableApps\ImageMagick\Mogrify.exe -flop C:\Temp\#.tif", "*",Insert="#",digits=6,Once=False,Offset=0,Hide=true,Debug=true)

Executing on each playing, on every frame, hiding console window, sending debug info to debugview, and converting command string on frame eg 0 to

"C:\PortableApps\ImageMagick\Mogrify.exe -flop C:\Temp\000000.tif"


ssS


@Martin53, This does as you want. I used '-flop' (h-flip) rather than flip as 2.58 and 2.6 imagesource behave differently. (Easier for testing)


ColorBars().ShowFrameNumber().ConvertToRGB24().Trim(0,99)
#
IM="C:\PortableApps\ImageMagick\Mogrify.exe" # ImageMagick Mogrify exe
TMPDIR="C:\Temp\" # Output directory for images
IMCMD = " -flop " # Image Magick Mogrify Command, Horizontal Flip (Or whatever).
BASENAME="Test_" # Base name
TYPE="tif" # Extension type
#
FRAMES="*" # All Frames
INSERT="#" # Insert number where '#' occurs in Command, escape with '##' if '#' required OR change INSERT.
DIGITS=6 # DONT CHANGE
ONCE=False # MUST do every time as both ImageWriter and ImageSource called every time (default True)
OFFSET=0 # DONT CHANGE
HIDE=True # Hide Console
DEBUG=True # Write debugging to DebugView
#
EXT="." + TYPE
FIRSTNAME=MakePicName(TMPDIR+BASENAME,EXT,DIGITS,0)
CMD= QuoteStr(IM) + IMCMD + QuoteStr(TMPDIR + BASENAME + INSERT + EXT)
RD_NSTR = "%0"+String(DIGITS)+"d"
RD_NAME=TMPDIR+BASENAME+RD_NSTR+EXT
WID = Width # Remember orig width
# ---
# If not exist, Force Write of first image during compile time so that ImageSource will not fail. Result discarded
#(Exist(FIRSTNAME)) ? NOP : ImageWriter(TMPDIR+BASENAME,0,-1, type=TYPE).Trim(0,-1).RT_AverageLuma(n=0,w=1,h=1)
# EDIT:
# Force Write of first image during compile time so that ImageSource will not fail. Result discarded
# Already existing may not be correct size etc, so always force may be better than based on existing.
ImageWriter(TMPDIR+BASENAME,0,-1, type=TYPE).Trim(0,-1).RT_AverageLuma(n=0,w=1,h=1)

# --------------------------------
ImageWriter(TMPDIR+BASENAME,0,0, type=TYPE)
CallCmd(CMD,FRAMES,insert=INSERT,digits=DIGITS,once=ONCE,offset=OFFSET,hide=HIDE,debug=DEBUG) # comment out to disable h-flip
StackHorizontal(ImageSource(RD_NAME,0,FrameCount-1))
#Crop(WID,0,-0,-0) # Comment out to show input and h-flipped output side by side
Return Last
# --------------------------------
Function MakePicName(String BaseName,String Ext,int Digs,int n) {GScript(""" S=String(n) While(StrLen(s)<Digs) {S="0"+S} Return BaseName+S+Ext """)}
Function QuoteStr(String s){Chr(34) + s + Chr(34)}


EDIT: MakePicName requires GScript.
Also uses RT_AverageLuma to force initial tif creation (samples single pixel, RGB->YUV-Y).
Colored text edited.

StainlessS
1st October 2012, 15:26
Would anyone mind if I modified from the original Call() spec for Frames specification?
Was thinking maybe only allow '';' SEMICOLON as a frame number separator with ',' COMMA being used to specify
a range of frames, eg "10,20;55" being frames 10 to 20 and frame 55, and "0,0" replacing the '*' meaning ALL frames,
and eg "100,-10" being frames 100 to 109.

Anybody care ?

EDIT: would probably need individual eg "DoConstructor" and "DoDestructor" type args so that -2 and -3 not
misinterpreted, last frame -1, would need a little more thought, probably not needed if destructor call implemented.

martin53
3rd October 2012, 19:00
You are basically right about # Already existing may not be correct size etc, so always force may be better than based on existing.

Only because inside the ScriptClip, ImageWriter is definitely called during the 1st frame, and writes the file with correct size before the 2nd frame is executed, the result is the same. My personal inclination is that I feel more comfortable with the Exist() solution because in my mind, I am less sure that the other solution does not interfere at later frames. Generally, the parameters 0 and -1 for ImageWriter() should guarantee that, that's right, and the Trim(0,-1) is the braces to the belt, as they'd say in Germany.

Now I have to ask a question where I feel very silly. There is always this discussion about how frames are calculated through the filter graph, and I think I remember that somewhere in the manual or so it is said that ImageWriter() is only executed if it is (in my words) in the filter graph. So, all functions that should do something not only during graph construction, must be a 'null transform' so to speak for the clip, to get their chance for doing something on each frame.

You seem to use RT_AverageLuma to deal with that.
Beginners question 1: Usually, we need to set current_frame beforehand. Is RT_AverageLuma safe to be used without that (so sorry if it's in the doc and I didn't read carefully)?
Beginners question 2: Afterwards, you have a number, not a clip. Why/how does that work in the graph? Even is AviSynth is so smart to find the 'last' clip for the next ImageWriter command upwards in the script (above all the lines that don't return a clip), where is the connection for the mentioned number :confused:

Finally, I understand that you propose a solution without RTE. Of course I support that from the bottom of my heart. But because the new proposal writes a different file number for each frame, it spills the HD. I appreciate your approach to deal with ever changing file names with ImageMagick (btw I think RightStr("00000"+string(n),6) could replace the while loop), but I had two reasons for the RTE, and the more versatile Call(Frames="*") eliminates only one. Maybe ImmaAVS can make a constant file name, I didn't study that. Or, of course, a Call() can be added that deletes all obsolete files. But would that challenge the file system more, if files are added to and removed from the directory permanently?

martin53
5th October 2012, 20:25
Attached, an alternative proposal that does without runtime environment and still uses only one file. I fall back on Animate() to do it ;)
StainlessS, nice solution with RT_AverageLuma() (if I really understand it or not), I copied that.

Hope you don't mind the script is not polished up with all user constants etc., it is meant as proof of concept.

No doubt if someone processes his photo gallery, it may be very useful to execute Call() on every frame.

StainlessS
6th October 2012, 16:43
Firstly, sorry for not getting back sooner, I've had a nightmare couple of days, including but not limited to, personal injury, a trip to the
hospital, and no power for about 2.5 days (not related to the injury), all in all I've had a real **** time. :(
(NO commiserations required, I'de rather just forget)

Generally, the parameters 0 and -1 for ImageWriter() should guarantee that, that's right, and the Trim(0,-1) is the braces to the belt,
as they'd say in Germany.

I always wear belt and braces with an additional couple of safety pins, and a length of bungy cord just to be sure. :)

As well as a global compile stage, each iteration of scriptclip has a compile stage where filter constructors and functions returning ordinary (non-clip)
variables are called in script sequence, the ordinary variables can be used as args to following constructors. During this time the graph is created.
After all constructors and ordinary functions have been called (compile stage), then the graph is processed by calls to GetFrame, with each instance of
GetFrame in the graph requesting a frame from the one before it.
EDIT: During compile time graph creation phase, it is possible for a compile time function eg RT_AverageLuma OR eg
current_frame=0 AverageLuma() to request frames from a partially existing graph where GetFrame's for filters already
in the graph can be traversed.

In this case, the constructor of ImageReader is called after the constructor to ImageWriter BUT, in the ImageReader constructor
it creates the output VideoInfo using the already existing 1st frame, if there is no existing 1st frame, it puts an error message on the clip.
During GetFrame (graph processing), If exists but size etc are wrong, then it will print an error message when the new frame (written by
call to imagewriter GetFrame) is not the same as the wrong sized previously existing frame (mismatch with the VideoInfo), so the existing
frame MUST be same as the expected result. Always forcing achieves this.
EDIT: See edited text at end of post.


RT_AverageLuma forces the ImageWriter plug to actually write the file even though the result of RT_AverageLuma is thrown away,
it would be the same if you used standard AverageLuma whether or not the result is stored in a variable, you would need to set
current_frame=0 AverageLuma().
For AverageLuma, current_frame is just a number conveniently set by the system (in RTE), RT_AverageLuma will use current_frame if 'n' is not
supplied and current_frame is available (RTE).
Only filters, (functions that return a clip) can be linked into the graph and if eg ImageWrite is not somehow used in final output (graph) then as no
frames are requested from it, so no frames are produced by it, no images are written and the source to imagewrite has no frames requested from it.
(I dont know for sure, but think that the constructor and destructor would still be called even though it's GetFrame would never be called).

RT_AverageLuma requests a frame from the already existing sub graph in line
"ImageWriter("C:\Temp\", 0, 0, type="tif").Trim(0,-1).RT_AverageLuma(n=0,w=1,h=1)"
forcing ImageWriter to produce an image file. It does not matter that the return value is not used by subsequent filters, the function is called
at compile time and does not require any request from a following filter. Any functions returning ordinary variables are always called irrespective
of whether their return value is used. Concerning the forced write, there is no other effect on the incoming clip and does not interfere with
other frames (assuming not using eg DirectShowSource with some sort of DirectShow auto eg IVTC where random requesting of frames
could cause the ivtc etc to keep loosing track of where it was in the ivtc sequence, really NOT a good idea to use auto anything
prior to avisynth. Someone using ExBlend wanted to know how to remove blending originating in DirectShow auto deinterlacing
which was non-existant in the source. Just forcing frame zero to be called is unlikely to cause any problems, only random or out of
sequence forcing frames might cause DirectShow internal filters to go nuts and the result would be quite obvious, video jumping
about out of sequence, constantly for eg DS auto IVTC).


RightStr("00000"+string(n),6)

Yep, thats perhaps better but I might use a few more zeros, guess I just knocked it up quick.

Have not really looked at the latest attachment too hard but suggest this rather than replace:

Function StrReplace(string s,string find,string replace) # Repeated, string replacements
# Original:- http://forum.doom9.org/showthread.php?t=147846&highlight=gscript By Vampiredom, Gavino, IanB
#{i=s.FindStr(find)return(i==0?s: s.LeftStr(i-1)+replace+s.MidStr(Strlen(find)+i).StrReplace(find,replace))}
# Converted to use RT_Stats RT_StrAddStr() to avoid 2.58/2.6a3 string concatenation bug:-
{i=s.FindStr(find) return(i==0?s:RT_StrAddStr(s.LeftStr(i-1),replace,s.MidStr(Strlen(find)+i).StrReplace(find,replace)))}


From scriptclip example

ColorBars().ShowFrameNumber().ConvertToRGB24().Trim(0,2)
#Exist("C:\Temp\000000.tif") ? last : ImageWriter("C:\Temp\", 0, 0, type="tif")
ImageWriter2("C:\Temp\", 0, 0, type="tif").Trim(0,-1).RT_AverageLuma(n=0,w=1,h=1)
#BilinearResize(640,576) # Produces error message "StackHorizontal "Image Heights Dont Match"
ScriptClip("""
Trim(current_frame,-1).ImageWriter2("C:\Temp\", 0, 0, type="tif")
CallCmd("C:\PortableApps\ImageMagick\Mogrify.exe -flop C:\Temp\000000.tif","0",hide=True,debug=true)
I=ImageSource2("C:\Temp\000000.tif")
StackHorizontal(last,I).Crop(width,0,0,0)
""")



# Forced creation
00000005 22:11:12 ImageWriter2: Constructor
00000006 22:11:12 ImageWriter2: GetFrame(0)
00000007 22:11:12 ImageWriter2: Opening File C:\Temp\000000.tif
00000009 22:11:12 ImageWriter2: Destructor

# Constructor frame 0
00000010 22:11:12 ImageWriter2: Constructor
00000011 22:11:12 CallCmd: Constructor Command = 'C:\PortableApps\ImageMagick\Mogrify.exe -flop C:\Temp\000000.tif'
00000016 22:11:12 ImageReader2: Constructor Parse Header Filename =C:\Temp\000000.tif

# Graph Frame 0
00000020 22:11:12 ImageWriter2: GetFrame(0) Opening File C:\Temp\000000.tif
00000024 22:11:13 CallCmd: GetFrame(0) on command 'C:\PortableApps\ImageMagick\Mogrify.exe -flop C:\Temp\000000.tif'
00000026 22:11:13 ImageReader2: GetFrame(0)

00000027 22:11:13 CallCmd: Destructor
00000029 22:11:13 ImageWriter2: Destructor

00000030 22:11:13 ImageWriter2: Constructor
00000031 22:11:13 CallCmd: Constructor Command = 'C:\PortableApps\ImageMagick\Mogrify.exe -flop C:\Temp\000000.tif'

00000036 22:11:13 ImageReader2: Constructor Parse Header Filename =C:\Temp\000000.tif
00000040 22:11:13 ImageReader2: Destructor # Delayed destructor

00000041 22:11:13 ImageWriter2: GetFrame(0) Opening File C:\Temp\000000.tif
00000045 22:11:13 CallCmd: GetFrame(0) on command 'C:\PortableApps\ImageMagick\Mogrify.exe -flop C:\Temp\000000.tif'
00000047 22:11:13 ImageReader2: GetFrame(0)

00000048 22:11:13 CallCmd: Destructor
00000050 22:11:13 ImageWriter2: Destructor

00000051 22:11:13 ImageWriter2: Constructor
00000052 22:11:13 CallCmd: Constructor Command = 'C:\PortableApps\ImageMagick\Mogrify.exe -flop C:\Temp\000000.tif'
00000057 22:11:13 ImageReader2: Constructor Parse Header Filename =C:\Temp\000000.tif

00000061 22:11:13 ImageReader2: Destructor
00000062 22:11:13 ImageWriter2: GetFrame(0) Opening File C:\Temp\000000.tif
00000066 22:11:13 CallCmd: GetFrame(0) on command 'C:\PortableApps\ImageMagick\Mogrify.exe -flop C:\Temp\000000.tif'
00000068 22:11:13 ImageReader2: GetFrame(0)

00000069 22:11:13 CallCmd: Destructor
00000071 22:11:13 ImageWriter2: Destructor
00000072 22:11:16 ImageReader2: Destructor


EDIT: Would not be surprised if there were a few corrections suggested to the above text.
EDIT: Not sure about the weird destructor sequence above where new ImageRead constructor called before old delayed destructor.

EDIT: The noted line above in red:

#BilinearResize(640,576) # Produces error message "StackHorizontal "Image Heights Dont Match

is produced by StackHorizontal in scriptclip, if different sized existing image is used and StackHorizontal missing (of course the example would
not work then) the the error produced by ImageReader would be from source:

sprintf(buf,"ImageReader2: images must have identical heights"); OutputDebugString(buf);

Its just that the StackHorizontal error is raised before ImageReader has a chance to do it (I think).

EDIT:
Call() can be added that deletes all obsolete files. But would that challenge the file system more, if files are added to and removed from the directory permanently?

Providing you have the disk space, I dont see any real problems, you could use a separate Call/CallCmd destructor call
(outside of any scriptclip) at the end of script (I think, maybe, perhaps).

EDIT: What are the advantages to using Animate rather than Scriptclip with a supplied string, would not be surprised if scriptclip
were implemented something like your example.

EDIT: Currently modding CallCmd() to use separate constructor and/or destructor commands and also the previoulsy posted mod to
frames spec.

EDIT:

# Graph Frame 0
00000020 22:11:12 ImageWriter2: GetFrame(0) Opening File C:\Temp\000000.tif
00000024 22:11:13 CallCmd: GetFrame(0) on command 'C:\PortableApps\ImageMagick\Mogrify.exe -flop C:\Temp\000000.tif'
00000026 22:11:13 ImageReader2: GetFrame(0)

Above, although ImageWriter2 GetFrame is listed as occurring first, it is the result of ImageReader2 being called first (nearest to output)
and it requests a frame from CallCmd which requests one from ImageWriter2 which requests one from Last (before Scriptclip),
the debug messages are printed AFTER the noted function's GetFrame has received the frame from all of the filters before it
(nearer source filter) when it has actually gotten the the requested frame.

martin53
7th October 2012, 20:09
StainlessS,
NO commiserations
Accepted - but since I am happy that you share thoughts, problems and solutions with me, and help me to move forward with things I feel urged to get working, I wish the same well-being for you as I wish for me.

ordinary variables can be used as args to following constructors ... the constructor of ImageReader is called after the constructor to ImageWriter ...
Agreed! That is resonable, and thank you for the really profound explanation of the processes before frame processing.
EDIT:What is ImageWriter2???

Function StrReplace...
Yep, I saw that. I read your RT_Stats doc and know about the bug, was just too lazy to replace all my existing calls to Replace() into StrReplace(), and wanted to post something complete. I copied your function now into my standard 'library' .avsi file and made Replace() an alias that calls the new one.

EDIT: After all you explained, I fully support your script solution.

Regarding HD spilling, I thought of
CMD= "cmd/c del " + QuoteStr(TMPDIR + BASENAME + RD_NSTR + EXT) +
\ " && ren "+ QuoteStr(TMPDIR + BASENAME + INSERT + EXT) + " " + QuoteStr(TMPDIR + BASENAME + RD_NSTR + EXT) +
\" && " + QuoteStr(IM) + IMCMD + QuoteStr(TMPDIR + BASENAME + RD_NSTR + EXT)
#RD_NSTR = "%0"+String(DIGITS)+"d"
RD_NSTR = "000000"
(untested!) but that does not work on frame 0 :(
One possible solution: another Call() must be included into the AviSynth script, that contains only the delete & rename, and is not executed on frame 0. Phew!
I would feel better if ImageWriter could be made to write always to the same file name.

Warning, off topic
I agree on questioning whether Animate() could be better than ScriptClip. With these two examples
##### Animate #####
function DoScript(clip c, int frame, string command) { c GEval(StrReplace(command, "current_frame", string(frame))) }
str="subtitle(string(current_frame))"
Colorbars(pixel_type="RGB32")
Animate(0, Framecount-1, "DoScript", 0, str, Framecount-1, str)

##### ScriptClip #####
Colorbars(pixel_type="RGB32")
GEval("""ScriptClip("subtitle(string(current_frame))")""")
VirtualDub rendered ~85fps with Animate() to ffdshow/huffyuv, with Scriptclip() ~105.

Warning 2, even more off topic
Can I read Windows' %TEMP% and other environment variables with an AviSynth script yet, e.g. instead of manually setting TMPDIR?

jmartinr
7th October 2012, 22:19
Can I read Windows' %TEMP% and other environment variables with an AviSynth script yet, e.g. instead of manually setting TMPDIR?

GetSystemEnv, see: http://avisynth.org/stickboy/

StainlessS
7th October 2012, 22:51
EDIT:What is ImageWriter2???

Sorry, forgot to remove the '2', its just a ripped out version of ImageWriter et al from Avisynth source, had a problem
reading/writing an image some time ago, and ripped out the source and added some debugging stuff so I could establish
the problem, cant remember off hand whether originated from 2.58 or 2.6.
I removed most of the debug messages and combined in a few places in the above listing, 'Parse header' is where ImageReader
creates the VideoInfo from existing image.

Can I read Windows' %TEMP%

Think Stickboy may have a plug for that. (Maybe GetSystemEnv or something like that).
EDIT: Beaten to it.

Will comeback again, very nearly ready to up CallCmd with new frames range spec and separate Open (Constructor) and Close (Destructor) commands.

EDIT: Have added an additional EDIT to post #73

StainlessS
8th October 2012, 23:41
CallCmd v1.00, Execute command - 8 Oct 2012
Execute command on selectable frames or at startup or closedown.
New thread started here:
http://forum.doom9.org/showthread.php?t=166063