View Full Version : CALL command


DDogg
19th February 2003, 23:41
This might be way over the top, but I am wondering if there exists a method or the possibility of implementation of a CALL command (to call an external commandline program) in AviSynth?

The background for the question is this. My wife does some video editing in Movie Maker 2 and then hands it off to me to finish up in Video Vegas. WMM2 creates a Type 1 DV file that nothing seems to like so I have to convert it, or save out the wav and use wavsource or load it in VDub as separate wav audio. If you have 25 files to do this gets to be a real pain, plus I run into many other situations where I wish I could call an external program. Sort of a batch file mentality I guess.

As I was playing around with writing some automatic templates for AVISynthesizer (the real one - the first one), I was struck with how nice it would be to have the ability to call an external program to strip the audio from an AVI as a wav file and then use wavsource. Something like this:

#DV-T1 Template
Call ("avi2wav.exe mytest.avi mytest.wav") #imaginary
V=avisource("mytest.avi")
A=wavsource("mytest.wav")
AudioDub(V,A)

This might also be useful with MPGs and mpasource. I may well be way off target but I sure do wish there was a way to automate this chore from within AviSynth. Am I missing some obvious solution?

Add: Another thing that got me thinking about this was Nic's mpegdecoder and mpasource both do/can call a routine before allowing the script to complete. Nic builds a d2v file if needed and mpasource creates an index. So, it does not seem too big a stretch to think an external executable might be able to run from within Avisynth.
DD

DDogg
20th February 2003, 15:33
Well this went over like a lead ballon. So, let me ask a more straight forward question of the coders:

Is it possible to code a plugin/filter with the single purpose of calling and passing params to a external commandline program? If so, would somebody consider doing it?

sh0dan
20th February 2003, 16:06
Should be easy enough - you could even make it trigger on a certain frame. If someone could device a plugin, I'd be happy to implement it into the core.

DDogg
20th February 2003, 16:38
sh0dan, thanks for the lifeline :D I was starting think this suggestion might be a big hairball. Seriously, IMO, the additional flexibility made possible could be well worth an effort on somebody's part.

Some:
1> One could do both pre-process and post-process operations from within a script.
2> It would open (somewhat) AviSynth to anybody that could write a simple program or even a batchfile to accomplish one-off "individual enthusiasms". If some of those one-offs were of greater interest a more experienced coder could refine them.

Q: Can a plug-in coder send a string to video output? Like "Executing external command, please wait"?

DD

sh0dan
20th February 2003, 17:18
Can a plug-in coder send a string to video output? Like "Executing external command, please wait"?


Yes - but unless you open a new window it will be in the final frame of your video.
MPEGSource opens a new window for a progress bar for instance.

Belgabor
20th February 2003, 18:22
@DDogg, you seem to have a small misconception of avisynth scripts or fell into a small trap of thought. The script is not processed once form start to end like e.g. a bash script on linux, there is no temproal one-command-after-the-other, only a stream of frames so to speak which can be accessed randomly.
The result is that a CALL command could only be (someone correct me if I'm wrong)

executed on open
executed on close
executed each time / the first time a specific frame is requested

so, like sh0dan said, reporting of execution status is not possible via video output.

Cheers
Belgabor

DDogg
20th February 2003, 19:24
... or fell into a small trap of thought.
Yep, I am always doing that. A very little knowledge can be dangerous (ME - I cheerfully admit), but, hopefully can occasionally stimulate thought :p
The result is that a CALL command could only be (someone correct me if I'm wrong)

executed on open
executed on close
executed each time / the first time a specific frame is requested

so, like sh0dan said, reporting of execution status is not possible via video output.
Those three options would be more than enough! Status would just have been frosting on the cake. Who am I to quibble? A guy can dream, yes? :)

Seriously, Belgabor, thanks for helping me understand better and thanks for all the work on VDubMod. So ..., now that I am a toady, would you be interested in writing this plugin? :cool:

Nic
21st February 2003, 10:18
The chances are, for instance with BeSweet, the "call" command would just be doing a ShellExecute or CreateProcess, so the application will popup and have its own progress showing...It may not be the neatest way, but should be enough :)

Ill whip it up tonight if I get time, but any of the coders here could code it if any of us have 5mins to spair (which I fear we rarely do :( )

-Nic

Nic
21st February 2003, 11:24
Actually, here you go :) :
http://nic.dnsalias.com/Call.zip

Has the source and a Avisynth 2.5 version as well as the normal Call.DLL

I havent really tested it, but someone will be able to fix it if its broken easily. Hopefully the readme.txt will help people use it.

Cheers,
-Nic

ps
Thinking about it you probably need it after some sort of source, so use like:
LoadPlugin("MPEG2Dec.dll")
LoadPlugin("Call.dll")
MPEG2Source("e:\rip\movie.d2v")
Call("d:\besweet", "0,-1")

Call probably has to come after a *Source plugin of some sort :)

DDogg
21st February 2003, 20:38
Nic, this was really decent of you to take the time to do this. God knows your plate always seems full. I'll give it a few tests and report back. Thanks, very much, again.

DD

DDogg
22nd February 2003, 04:21
@Nic
The -1 works like a top, but if 0 is used the call command is implemented twice. If 0 is used it activates @ frame 0 and also at the EOF as if it were passed 0,-1 as its args. If you close the player before the end it also activates.

LoadPlugin("call.dll")
LoadPlugin("mpeg2dec.dll")
testcmd="besweet.exe -core( -input matrix.ac3 -output matrix.wav )"
mpeg2source("Matrix.D2V")
Call(testcmd,"-1")

It was great to see one could use a variable as the argument.

I now more fully understand Belgabor's meaning in the post above. I foolishly ( :o ) thought this might work as if the MP3 could have been produced before the clip:

LoadPlugin("call.dll")
LoadPlugin("mpeg2dec.dll")
LoadPlugin("mpasource.dll")
testcmd="besweet.exe -core( -input matrix.ac3 -output matrix.mp3)"
Call(testcmd,"-1")
V=mpeg2source("Matrix.D2V")
A=mpasource("matrix.mp3")
audiodub(V,A)

I freely and cheerfully admit to a case of ******* :confused:. Be that as it may, I still think people may well find some very interesting uses for CALL.

There seems to be a sortof IfThenElse<(kinda) structure that could be used (I think) to change the string of a variable used by CALL? That might open a few more uses.

Q: Anybody know enough about the import command to tell/show me how to read in a file and reset some variables? I think that is possible but the manual is pretty light on the subject.

Nic
22nd February 2003, 09:41
Hmmmm. Ill look into that DDogg. Ill make that if your setting it for frame 0 then frame 0 is only called once (I dont believe that its getting called at the end, just that the film is being rewound to the first frame by the encoder)

To make a version of Call that works before encoding begins could be tricky. But then again, If I did everything in the constructor of the filter then that should do it before encoding begins....Hmmmm, ill give it a go later.

:)

-Nic

Nic
22nd February 2003, 11:43
http://nic.dnsalias.com/Call.zip

This version now lets you do:

LoadPlugin("call.dll")
Call(BlankClip, "lame --decode fatboy.mp3 fatboy.wav", "-2")
WavSource("fatboy.wav")

which creates fatboy.wav just before WavSource trys to load it :)
Also the "calling frame 0 twice bug" should also be fixed.

Cheers & good luck with it,
-Nic

DDogg
22nd February 2003, 17:09
===> Superman cape to Nic

Wow! This works perfectly:

LoadPlugin("call.dll")
LoadPlugin("mpeg2dec.dll")
LoadPlugin("mpasource.dll")
testcmd="besweet.exe -core( -input matrix.ac3 -output matrix.mp3"
Call(BlankClip, testcmd,"-2")
V=mpeg2source("Matrix.D2V")
A=mpasource("matrix.mp3")
audiodub(V,A)


I had come to think it impossible to do something BEFORE the video event. This adds a new dimension. I'm off to do some expermentation with my head spinning....

Nic, tremendous!

DD

Guest
22nd February 2003, 17:16
Great work, Nic.

I want to commend you also for including the source. This is something we all should do with every binary release.

DDogg
22nd February 2003, 19:37
How would you change this command that uses quotes (from BeSweet GUI) to work with the CALL command? Possible?

"BeSweet.exe" -core( -input "Matrix.ac3" -output "matrix.mp2" ) -azid( -c light -L -3db --maximize ) -2lame( -m d -b 192 -e ) -profile( DSPguru_MP2@192kbps )

The manual says:

"string: surrounded either by "quotation marks" or by ``TeX?-style quotes''. A text string can contain any character except the terminating quotation mark or double-apostrophe. If you need to put a quotation mark inside a string, use the TeX?-style notation. Alternately, you can use Windows extended-ASCII curly-quotes instead of straight quotes to get around this limitation.

I tried replacing the standard double quotes with curly ones “” but that did not work. I don't have a clue what a TeX style quote is.

Guest
22nd February 2003, 19:46
Originally posted by DDogg
I tried replacing the standard double quotes with curly ones “” but that did not work. I don't have a clue what a TeX style quote is. Use two single back-quotes to begin a quotation and two single quotes to end it. The usual double quote symbol doesn't produce the correct result.

DDogg
22nd February 2003, 20:04
Use two single back-quotes to begin a quotation and two single quotes to end it. The usual double quote symbol doesn't produce the correct result.


I'll go back and try it again. Like this ``stuff''?
Edit: Nope, this no worky for me (just drops through as if it saw a #):
testcmd="``c:\Program Files\DVD2SVCD\BeSweet\BeSweet.exe'' -core( -input ``d:\Matrix\Matrix.ac3'' -output ``d:\Matrix\matrix.mp2'' ) -azid( -c light -L -3db --maximize ) -2lame( -m d -b 192 -e ) -profile( DSPguru_MP2@192kbps )"

Not using the quotes seems to work ok. This works fine.

testcmd="BeSweet.exe -core( -input Matrix.ac3 -output matrix.mp2 ) -azid( -c light -L -3db --maximize ) -2lame( -m d -b 192 -e ) -profile( DSPguru_MP2@192kbps )"

Belgabor
22nd February 2003, 20:33
I think I read somewhere that avisynth also accepts TeX stryle quotes, so that my be the reason why it doesnt work. I belive the quotes for besweet are only needed (like with windows commands) if the argument contains white space. I don't know if avisynth allows to escape quotes in strings, otherwise the plugin has to be modified to replace some special character with "

Guest
22nd February 2003, 20:34
I was just answering your question about what TeX-style quotes are. Beyond that... :confused:

Glad you have things working, however!

DSPguru
23rd February 2003, 20:50
DDogg :),
you might wanna replace -2lame( ) with -toolame( ) .. ;)
http://forum.doom9.org/showthread.php?s=&threadid=35480

Nic
23rd February 2003, 20:54
How about I update it so you can do:
testcmd="c:\BeSweet.exe -core( -input `d:\The Matrix\Matrix.ac3' -output `d:\The Matrix\matrix.mp2' )"

and then call will convert all 's into "s before creating the process.

Sound good?

-Nic

DDogg
24th February 2003, 00:51
@DSPguru - Hey, long time. Besweet has just got better and better. Congrats! As to your comment:
you might wanna replace -2lame( ) with -toolame( ) ..
Er, I just pasted the command line from DD's GUI..Are you speaking of your new beta version D9 mentioned? I is Cunfoosed :confused:

@Nic, Well (scratching head), I don't think you would want to introduce a new convention. If CALL could honor the same convention tex style quotes as Avisynth like `stuff''<note two single 's as per neuron2's post (below) then wouldn't that be more in keeping with AviSynth? Or, am I completely confused yet again? If so, I am sure your suggestion would work just fine.
Use two single back-quotes to begin a quotation and two single quotes to end it. The usual double quote symbol doesn't produce the correct result.

DSPguru
24th February 2003, 19:57
Originally posted by DDogg
@DSPguru - Hey, long time. Besweet has just got better and better. Congrats! thanks, it's great to see you here :)!

Er, I just pasted the command line from DD's GUI..Are you speaking of your new beta version D9 mentioned? I is Cunfoosed :confused: yes. the latest beta supports, in addition to mp2enc encoding, toolame encoding. check out latest DD's GUI (b70 ;)).

DDogg
6th March 2003, 22:50
@Nic

Is this already possible with the CALL command and I am missing it or would there be a way to add calling a dos command? Like:

testcmd="Echo HELLO NIC > d:\test.txt"
Call(BlankClip, testcmd,"-2")

Nic
7th March 2003, 15:17
Your best bet is to try it and see if it works :) It might not because CreateProcess may not be able to call echo (as echo is built into command.com or equivalent)

so if it doesnt work try:
testcmd="cmd.exe /c Echo HELLO NIC > d:\test.txt"
Call(BlankClip, testcmd,"-2")

if on a winnt based system or replace cmd.exe with command.com for Win95/98 systems.
That should definitely work.

Sorry Ive been a bit late with the other version, im swamped with work (& clients who won't pay ;) ) at present :)

Cheers,
-Nic

DDogg
7th March 2003, 17:10
Nic, thanks for your reply and the solution. I had tried the straight commands as well as putting command.com in front and they did not work. However, when the /c parameter you suggested was added IT WORKS perfectly. Also, I found (on XP) just using CMD /c works as well.

This seemingly small thing will allow the CALL command to open up basic disk output for reportage and, I think, the storing of variables for later use in other scripts via the avisynth import command.

Small and poor example of reportage:

loadplugin("call_25.dll")
v=avisource("Tape 1 - Clip 001.avi")
r="Report: "+"%time%"+" "+"%date%"+" " "#duh, how LF or CR to put rest of report on new line after report header???
fct= "Framecount: "+ string(v.framecount)+"
frt="Framerate: "+ string(v.framerate)+" "
w="Width "+ string(v.width)+" "
h="Height "+ string(v.height)+" "
a="Audiorate "+ string(v.audiorate)+" "
sendout=r+fct+frt+w+h+a
testcmd="cmd /c Echo " +sendout+ " > d:\test.txt"
Call(BlankClip,testcmd,"-2")
return(v)


Maybe somebody that really knows what they are doing can do up a proper example. All the clip properties as well as any internal strings, which could be filter parameters, filenames, etc., would be reportable or available to output as reusable variables (import???)

DDogg
8th March 2003, 15:43
Nic, to some degree, the call command introduces a framebased "before, during and after concept", i.e, call("externalprog.exe","0,50,-1") implements the external at frame 0,50, and the last frame of the "video event".

I have some thoughts running around in my head and it would be useful to know if, hypothetically from a code standpoint, would it be possible for CALL to use an internal function as well as an external program,i.e., call ("internalfunction","0,50,-1")?

Oh, a second question, from a code standpoint, what are the ramifications of using the CALL command separately multiple times in a script? Do you see this as a problem? I ran into some problems when I tried something like this:

LoadPlugin("call_25.dll")
version
testcmd="info.bat"
Call(testcmd, "0")
Import("info.avs")
starttime=time
Call(testcmd, "-1")
Import("info.avs")
lasttime = time
#Now you would have a start time and a finish time in variables to use to generate a report.txt using Call and CMD /c echo + stuff + > report.txt

bilu
8th March 2003, 16:16
Nic,

Just to add another concept to Ddogg's idea, do you think it is possible to call (internal functions or external commands) at certain events, like in a WHILE function?

Example: call(internalfunction,my_variable>1) would run internalfunction while the flag I defined is bigger than 1.

[EDIT]
Oh great Master, please look
here (http://forum.doom9.org/showthread.php?s=&threadid=48127) for inspiration :D


Best regards,
Bilu

Nic
9th March 2003, 22:16
After reading that thread I get what you mean now :) lol
Well I know theres an Invoke function I could call in AviSynth but I dont know how flexible it is (or anything about it to be honest). Ill look into it.

At present I dont seem to be able to concentrate on one topic, ive fiddled with my mpeg-2 transcoder/my mpeg-2 directshow filter and dvd2avi_nic today and dont feel like doing any more on any of them. So it may be a while before I look into it, but ill try :)

Cheers,
-Nic

DDogg
9th March 2003, 23:19
So it may be a while before I look into it, but ill try
We couldn't ask any more. You have been real decent about considering some of these more "unusual" ideas. I do think the resulting additional power and flexibility would make it worth your time and who knows, maybe a little fun. It would most certainly be appreciated by many (quite a few of who, at the moment, have no idea what this would be useful for :-) lol)

Best regards,

DD

Wilbert
10th March 2003, 10:43
#duh, how LF or CR to put rest of report on new line after report header???
Did you solve this?

bilu
10th March 2003, 11:10
@Wilbert,

Take a look here. (http://forum.doom9.org/showthread.php?s=&threadid=47972&pagenumber=2)

Haven't tried it yet.


Best regards,
Bilu

Nic
10th March 2003, 12:37
Well very quickly thrown together:

http://nic.dnsalias.com/Call.zip

Sorry no "while" feature yet, but now you can use ' as " to allow for long filenames etc

also included is a little app called NicEcho which can be used like:

Call(BlankClip, "d:\NicEcho.exe @d:\report.txt 'Appending\nHello\nAppended'", "-2")

Which would append to a text file called d:\report.txt the text:
Appending
Hello
Appended

etc.
Hope this helps some, sorry its not much but its start, sorry for the hurried post. At work at present.

-Nic

DDogg
10th March 2003, 17:57
Nic, all these superman capes are going to get heavy. This is awesome!

Here is a reference for anybody playing with Nic's new toy. I am not quite sure why the two ' used in addqt works, but it does.

loadplugin("call_25.dll")
loadplugin("chr.dll")
addqt="''"
hdr="'"
systime=(Time("%I:%M:%S"))
MyTextString="Now is the time \nfor all good men\nTime="
stuff=hdr+MyTextString+addqt+systime+addqt+hdr
Call(BlankClip, "nicecho.exe report.txt " + stuff, "-2")
version()

report.txt contains:

Now is the time
for all good men
Time="04:13:00"
@Nic, thinking out loud, if nicecho.exe could grab the present systime and you could provide a variable? (\systime, \sysdate \sysday) in nicecho.exe when it was called ??? Make any sense to you?
I am still after a straightforward way to get elapsed time from "0" to "-1". Maybe this is already in front of me and I have not seen it yet.

bilu
10th March 2003, 19:33
Originally posted by DDogg
I am still after a straightforward way to get elapsed time from "0" to "-1". Maybe this is already in front of me and I have not seen it yet.

It has allways been if the front of us all but we never used it: the time reported in the AVI stream itself, that you can see in media players where you preview an AVS. We just need a filter to grab it! ;)
(I think)

Best regards,
Bilu

DDogg
10th March 2003, 20:02
Delete

DDogg
10th March 2003, 21:22
More reference stuff - added Warpenterprises CHR plugin for date functions. Edit: Well this will definately creates a base report BEFORE the clip starts playing and appends AFTER the last frame. If nicecho could somehow have a \timevariable for use we could do elapsed time.


loadplugin("call_25.dll")
loadplugin("chr.dll")
avifname="Tape 1 - Clip 001.avi"
v=avisource("Tape 1 - Clip 001.avi")
hdr="'"
FmCt= "\nFramecount = " +string(v.framecount)
FmRt="\nFramerate = "+ string(v.framerate)
W="\nWidth = "+ string(v.width)
H="\nHeight = "+ string(v.height)
A="\nAudiorate = "+ string(v.audiorate)
StTime=(Time("%I:%M:%S %p"))
FinTime=(Time("\nFInish Time %I:%M:%S %p"))# until I can figure out how
FilterParams="nada"
Dte=(Time("Date: %A %x Time: %I:%M:%S %p"))
RptHdr="REPORT: "+dte +"\nFilename: "+avifname + "\nStart Time: " + StTime +"\nParameters: " + FilterParams
stuff=RptHdr+Fmct+FmRt+w+h+a
Call(v,"nicecho.exe report.txt " +hdr + stuff + hdr, "-2")
Call(v,"nicecho.exe @report.txt " +hdr+fintime+hdr, "-1")
Outputs:

REPORT: Date: Monday 03/10/03 Time: 07:43:30 PM
Filename: Tape 1 - Clip 001.avi
Start Time: 07:43:30 PM
Parameters: nada
Framecount = 25346
Framerate = 29.970030
Width = 720
Height = 480
Audiorate = 48000
FInish Time 07:43:30 PM

bilu
11th March 2003, 13:11
Nic,

I hope that this post (http://forum.doom9.org/showthread.php?s=&postid=276847#post276847) can be helpful. ;)

Best regards,
Bilu

DDogg
28th March 2003, 03:25
Nic was nice enough to send me another version of NicEcho.exe that now will output the time by using a \t in the output. Just the exe, see the previous package for call.dll and docs. You can get it here:
http://nic.dnsalias.com/NicEcho.exe

I am happy to say you can now do before video and after video events such as start time and end time: This is pretty rough but works well enough for an example.

#loadplugin("call_25.dll") load not needed if in plugin dir
#loadplugin("chr.dll") from WarpEnterprises Website, used for date but does a whole lot more
hdr="'"
avifname="test_MC.avi"
v=avisource(avifname)
FmCt= "\nFramecount = " +string(v.framecount)
FmRt="\nFramerate = "+ string(v.framerate)
W="\nWidth = "+ string(v.width)
H="\nHeight = "+ string(v.height)
A="\nAudiorate = "+ string(v.audiorate)
StTime="\nStart Time \t" # < \t outputs the current time
FinTime="\nFinish Time \t"
Dte=(Time("Date: %A %x Time: %I:%M:%S %p")) #this from chr.dll
RptHdr="REPORT: "+dte +"\nFilename: "+avifname+ StTime
stuff=RptHdr+Fmct+FmRt+w+h+a
Call(v,"nicecho2.exe report.txt " +hdr + stuff + hdr, "-2") #runs before video
Call(v,"nicecho2.exe @report.txt " +hdr+fintime+hdr, "-1") # after video
#The @report.txt above appends to previous report.txt

Outputs Report.txt to disk

REPORT: Date: Thursday 03/27/03 Time: 08:12:16 PM
Filename: test_MC.avi
Start Time 20:12:16
Framecount = 758
Framerate = 29.970030
Width = 720
Height = 480
Audiorate = 48000
Finish Time 20:12:42

DDogg
28th March 2003, 14:43
Sh0dan, Nic, anybody that might know, a theory question:

Main question - In theory would it be possible for the call command to do multiple tasks while it is in an active state?

Not to distract from the main question and just as a poor example: Say we had a separate file called dothis.call with several actions and execute it with:

call(blankclip,"execute d:\dothis.call","-2")

Contents of external file named "dothis.call" (or marked in a script something like a function?)

dothis.call
# whatever multiple avisynth keywords/actions
NicEcho.exe output some variables
Import something using avisynth import command
internal variable=imported variable
end

Bidoche
28th March 2003, 15:47
won't Import("mycalls.avs") do the job ?

DDogg
28th March 2003, 15:54
er, I am not too swift at this, but I did not think the call command would do an internal command? The import command would have to be done within the call command to cause import to activate at the prescribed place in the video event. I will see if I can figure it out and try. If you have an example in mind it would be appreciated.

/edit After quite a few experiments I do not think it is possible to execute a avisynth internal command like Import from within the CALL command. If I find out different I'll update.

Still looking for "Main question - In theory would it be possible for the call command to do multiple tasks while it is in an active state?", Bidoche?

bilu
29th March 2003, 11:44
Hi Ddogg,

I'm still trying to figure out what you want, but please confirm me if it is this:

(from an old example :) )

INFO.BAT
=========
del c:\info.avs
for /F "usebackq" %%i IN (`time /t`) DO @echo Time=%%i > c:\info.avs
for /F "usebackq" %%i IN (`date /t`) DO @echo Date=%%i >> c:\info.avs

In AVS script
==============
CALL(BlankClip,"c:\info.bat","49")
Import("c:\info.avs",50) --> would import at frame 50 ?


I don't know if the script would stop rendering until the CALL command finishes ... :confused: it could be the only way to know if it would be safe to import a generated script at a specific time.

Also the Import command seems to load the script to generate the filter graph at start, but it should be possible (Bidoche? :) ) to modify Import (or use within a funtion that could be applied to a certain frame range, don't know if that's possible) to load an imported script at a specific frame.


Best regards,

Bilu

Nic
29th March 2003, 12:28
The parameter passed to Call.dll is just a string, and that string is taken as the main parameter to call CreateProcess with. By giving it an avs file, all that would happen is the avs file would be run and probably Windows Media Player would pop up ;)

Ill think about the best way of outputing the full elapsed time, the script idea could get complex ;) Ill also start to play with the Invoke command in avisynth soon.

Cheers,
-Nic

DDogg
29th March 2003, 15:52
This is too long but I'll try to stay focused so the reader will actually stay with me, read it, and answer. A lot of this is assumption on my part so >please< correct me if I am wrong :)

As way of background - Because of the way an avisynth script executes as a video event there is no internal command to set a variable value or execute other commands at a specified point like start of video, Frame XX or EOF. Workarounds are needed to accomplish this.

My post, 6 above this one, creates a report with a StartTime and EndTime in d:\report.txt using Nic's CALL command and new version of NicEcho.exe with the \t addition. A variation could have created a report with StartTime = "20:12:16" and EndTime ="20:12:42". It logically follows to import and calculate elapsed time, or even execute an external processing script, and return variables to the present script for further action.

We start running into problems because the avisynth script does not execute sequentially. In a multiple line statement like:

CALL(BlankClip,"blah","50")
Import("blah.txt")

The import commad cannot be depended on to execute at frame 50, only CALL.

The CALL command can not execute multiple commands sequentially. Nor can it execute internal commands individually or in multiple like (poor example)- CALL (blankclip, "NicEcho.exe d:\report.txt 'Starttime=xx EndTime = xx':Import report.txt:VarA=VarB","-2") (see post 5 bove this one)

This is what my twice, now thrice asked: "Main question - In theory would it be possible for the call command to do multiple tasks while it is in an active state?" was about. Forgetting the internal command for a minute, I was curious about whether CALL could in theory do multiple external commands in a stacked sequence.

Because we only have ONE Start of video event to trigger from, multiple commands in one CALL event would be very handy. If an internal command like Import could be added to the stack it would even better.

I have tried to think of solutions via the CALL command as it may not be realistic to expect any core modifications like the one Bilu mentioned. Sure, I hope to be wrong. If the core team could tie the Import or maybe some other internal commands to SOF, frame XX, or EOF, we would have tremendous added flexibility.

A solution not involving core would be if the call command could execute internal commands like Import and/or "varA = varB". I assume Nic said he was looking at "invoke" to see if this would be possible.

@Bilu, I am trying to stay away from DOS based solutions as they add another layer of kludge and DOS flavors vary from OS to OS.

@Nic - As you and Bilu will no doubt appreciate, this whole dialog is not really about elapsed time. Rather just an example of Disk I/O, external, and hopefully internal commands executed at specified trigger points. My intuition tells me this could allow much additional processing power.

enterprise
9th July 2004, 21:01
Hi, nic.

I checked your Call Plugin and I think it's amazing! It's exactly what I was looking for.
However I have to reload the avi everytime because once Call command is launched it's not launched anymore until I reload the avi. I think it's because Cache but I don't know how can I fix it. I think that if I compile again AviSynth with a different cache value it would work but I don't know how it could be compiled and also I would want that Call plugin would work on a standar Avisynth.

Could you help me?

stickboy
9th July 2004, 21:24
Exactly what do you want to do?

Call is invoked when the script is loaded, not on a per-frame-basis or anything like that.

Edit:
Okay, I don't know what I'm talking about it. I obviously haven't used Call in awhile and had forgotten it does per-frame-stuff.

enterprise
10th July 2004, 08:11
Thank you for your reply!

I want to execute an external command at specific frame even if I play several times the AVI.


Call("c:\Command.exe", "100")


If I open AVI with Mediaplayer, call command is executed only 1 time at frame 100. but if I play again the AVI, the command is not executed.
I am looking for a way to solve it.

vampiredom
22nd December 2011, 08:34
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.

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