Log in

View Full Version : 3.0 news


Pages : [1] 2

Bidoche
16th May 2003, 16:42
After some time without doing anything, I finally got back to the code. (not committed yet)

In the last changes, I redefined AVSValue as boost::any (templated multi type class like the name says) and used type_info to describe type info.
Thanks to that types are no longer hardcoded, which makes it easier to add new ones.

I already added CPVideoFrame (3.0 pointer to constant videoframe) and PAVSFunction (pointer to avsfunction).
The point in these adds is mainly to allow cleaner and easier creation of "shodan-like" :p conditional filter. The condition function is passed already processed by the parser as a filter argument.
And all the Videoframe functions he created will be just regular avsfunctions since videoframe are a legal type.

If you think of others types that may worth considering, I am listening. I already thought of some vector/matrix, but will it be really useful... You tell me.


Another point : I am thinking about removing the environment vartable, essentially because its very existence may arise some refcount circularities (env ref a clip who ref the env... and so refcount never reach 0 and nothing is deleted ever).
In 2.X this vartable is used for script vars, I intend to have a separate one for that in 3.0, so unless filters have a real need for it for I don't know what... it can go.

trbarry
16th May 2003, 21:56
I'm probably not the only one that does not really speak Oop.

Could you explain the implications of all this?

- Tom

vhelp
17th May 2003, 00:55
@ Bidoche.. and other AVIsynth gurus ( or whatever you call or
consider yourselves hehe.. ) ..

It's a shame (and a crime) that AVIsynth is only useful w/ MCV !!

Yeah.. instead of hording MCV compilable AVIsynth only to those select
and few MCV owners..

..How about, a once and for all, making AVIsynth compilable w/ other
C++ platforms ie, C++ Builder, etc. so that other C++ platform
speaking peoples can make AVIsynth filters too ??

I mean, if you're gonna take it appart anyways, why not ??

Thank for some reasonable answers :D
-vhelp

Bidoche
17th May 2003, 00:59
Well I didn't have the impression I was talking about Oop :/, at least the input I request do not require such understanding


Thanks to that types are no longer hardcoded, which makes it easier to add new ones.
The implications are if I want to use other types than the 5 originals, I just do it and it will works (without changing the existing code)
X x; //where X is a defined type
AVSValue value = x; //will always work whatever X may be

So if tomorrow we decide that avisynth should be able to handle matrix (for example), I just have to come up with a class to represent them and the rest is already OK to work with.


With function as an avs type, shodan ConditionalFilter becomes like this :
clip ConditionalFilter(clip a, clip b, function condition)
Where condition must be a fonction who takes an int (the frame number) and return a bool.
This form allows more flexibility in the tuning of the condition you pass to the filter, since you have the whole parser power to come up with an appropriate funtion construct (Provided the expected functions operations are made available)



And finally refcount (short for reference count) are used to handle the sharing of clips and videoframes. It simply counts how many times they are in use by others. When this number reach 0, they are no longer used and can be safely destroyed (that is done automatically).
The problem is :
if A use B and B use A. Neither A nor B refcount can reach 0 even if noone else use them. That's a cause for memory leak and thus not desirable.

Now I wan't asking you to understand refcount issues, but to answer this question :
Do you need the environment vartable ?
If not, I'd rather get rid of it than solving the ugly refcount problems it arises.

Bidoche
17th May 2003, 01:07
@vhelp

I think it's the inline asm that ties the code to MCV (but I won't bet anything on it :p)

3.0 should finally solve plugin compatibility issues by offering a normalized COM interface for its objects (to know what is COM ask google or msdn, not me). So one may write its plugin in everything that is COM-able, C Builder certainly is.

vhelp
17th May 2003, 01:16
@ Bidoche..

Thank you for your fast reply.. much appreciated :) :)

I know I've read elswhere's "some" of the reasons why AVIsynth is
not multi-platform supported ie, C++ Builder, but I can't place my
finger on those websites, but thank you for reminding me of those
that were listed in your post. I'll try and do further reading on
my own. Sorry if I sounded abrubt, as it was furthest from my mind :)

-vhelp

Belgabor
18th May 2003, 15:27
Originally posted by Bidoche
@vhelp

I think it's the inline asm that ties the code to MCV (but I won't bet anything on it :p)


Thats not all of it. That ties avisynth compilation to MVC, but the trouble is the way the plugin interface works. Diffrent C++ compilers use diffrent ways to implement classes, so with the current interface it will never be possible to write plugins in a diffrent compiler than avisynth was compiled in. So if you make it compile in C++ Builder and Gnu C++ you still haven't won anything, then all MVC plugins will stop working. => COM is the way to go here or make a C interface completely independent of objects.

Guest
18th May 2003, 15:40
I once made it work with C++ Builder by manually editing the mangled names. It's not something I recommend. :)

Bidoche
18th May 2003, 22:54
@Belgabor, neuron2

Thanks for pointing it out, didn't thought about that.


@all

Almost completed the linking code (code used to get the right function given its name and prototype), and I am wondering if I got the priorities right :

- functions who don't use an implicit last clip goes before those who do.
- functions who use the less cast go first (just int -> float for now)
- script defined functions override plugins functions who override the internals


Since nobody seems to care about the global vars of the env, they are now gone.

sh0dan
20th May 2003, 18:04
>>- functions who don't use an implicit last clip goes before those who do.

Implicit last is used, if using the given parameters fail.

>>functions who use the less cast go first (just int -> float for now)

ACtually I think it just uses the first match...?

>>script defined functions override plugins functions who override the internals

Plugins override internals - not sure about script functions - just try replacing abs() or something simple.


Regarding a generic interface - it COULD be done by doing a "class-free" plugin structure, using only structs.
This would probably be slower, since PVideoFrame cannot be directly passed. The env-functions would also have to be available another way. It'll be a bit slower, but not a _very_ hard thing to do.

Bidoche
20th May 2003, 19:19
Implicit last is used, if using the given parameters fail. I am gathering the both case in one pass, that's why I have to sort them out.

>>functions who use the less cast go first (just int -> float for now)
ACtually I think it just uses the first match...?
How is it connected with casting ?
AFAIK avisynth does not take casts into account : int are just allowed to be used as float.
For better consistance and extensibility, I didn't make it so in the current 3.0 codebase : it's the linking code who take care of detecting and arranging casting possiblities.
So my point about counting casts (or should I just take the position into account)

Plugins override internals - not sure about script functions - just try replacing abs() or something simple
I cannot replace abs, it's not a filter (or can I ?)

Regarding a generic interface - it COULD be done by doing a "class-free" plugin structure, using only structs.
This would probably be slower, since PVideoFrame cannot be directly passed. The env-functions would also have to be available another way. It'll be a bit slower, but not a _very_ hard thing to do.
I don't get your point. And besides structs are classes too.


Edit: tried overriding abs (with version) it worked fine despite the original result was int. I forgot avisynth was not really concerned with types (another thing I intend to change)

sh0dan
21st May 2003, 15:44
I think int -> float transparency is a good thing (it doesn't work the other way around).

Often parameters only have to be int, but float precision is added as a side-feature. The crop parameters in the resize funtions - ColorYUV paramters are other examples.

Having to do AmplifyDB(3.0), because AmplifyDB(3) isn't allowed just seem silly.

I cannot see any downsides of this. There is no idea in having an int function, when a float function is able to do the same. This will probably only annoy users - and that is not what we intend. :D

Bidoche
21st May 2003, 18:29
You misunderstood me.

I never said you will have to explicitly type 3.0 instead of 3.
It's the linker work to decide to cast ints into float when needed.

If you typed 3 and the linker finds only float, it will use that
But if there is an overloaded int too, it will use preferentially this one.

It's just work like any compiler would.


There is no idea in having an int function, when a float function is able to do the same. is easily reversed :
There is no point in having a float function, when it's actually an int function.
It's just discarding the responsability of the rounding, and eventually it may come at your expense

Bidoche
6th June 2003, 12:11
Finally committed my last code.

The major change is that frames and functions are now legal functions arguments.
Thus making conditional metafunctions a part of the framework.

Defiler
6th June 2003, 13:42
Originally posted by Bidoche
The major change is that frames and functions are now legal functions arguments.
Thus making conditional metafunctions a part of the framework. Wow. That sounds like it will greatly simplify some of my scripting tasks. Nice.

Bidoche
6th June 2003, 21:24
@Defiler

That's the idea.


@all

If anybody has some ideas about a parser syntax for defining functions, it would help.

MfA
11th June 2003, 16:25
Will we also be able to add new types of videoframes? Such as planar-RGB, 16/32 bit per component formats, motion vector formats ... etc.

Xesdeeni
11th June 2003, 16:37
Would it be possible to get rid of the need for explicit line continuation ("\"), a la C?

Xesdeeni

Bidoche
11th June 2003, 19:58
Incredible... I am actually getting feedback. :)
I am not used to :p

@MfA
Will we also be able to add new types of videoframes?It is possible.
Such as planar-RGBEasily done, it's the same data structure than Planar YUV (444) which was already considered.
16/32 bit per component formatsTrickier but possible too.
motion vector formats ... etc.Well it depends what is a motion vector formats :p, I don't really know.

Well anyway, many formats are possible now that videoframe is polymorphic, you just have to convince me (and the other developpers) that it is worth including.


@Xesdeeni

And then how does avisynth tells between line continuation and normal newlines ?
We don't have the C ; for explicit line termination so we can't have implicit line continuation.
You have to choose, it's \ or ;.

MfA
11th June 2003, 20:23
IMO it would be nice to be able to have seperate filters for motion estimation, which could pass their results to other filters such as denoisers/deinterlacers/interpolators. So a motion vector format would simply be a frame with motion vectors instead of colour data.

I wasnt really concerned with datastructure, you can stuff all those formats into standard videoframes and hack it if you wanted ... I was looking for something slightly more elegant and type safe, but since videoframes are polymorphic too that doesnt seem a problem.

Bidoche
11th June 2003, 20:45
IMO it would be nice to be able to have seperate filters for motion estimation, which could pass their results to other filters such as denoisers/deinterlacers/interpolators. So a motion vector format would simply be a frame with motion vectors instead of colour data.
I still don't know what a motion vector actually is, I have a general idea, but not enough to actually code anything about it. If you could direct me to some info or make a code proposal yourself (look at videoframe.h for VideoFrame interface)...

MfA
11th June 2003, 21:04
I mean simply 2 component vector [x,y] either per pixel or per block of pixels, in which case the resolution of the frame will be proportionally smaller than the original videoframes, which defines motion ... usually in respect to the previous frame. 16 bits per component should be plenty (probably defined as 13.3 fixed point).

Of course for this to be usefull someone would first need to program a ME filter, and an effect filter to use it ... just wanted to make sure it would be possible to add stuff like this after the fact without breaking the existing plugins.

Bidoche
11th June 2003, 21:24
I mean simply 2 component vector [x,y] either per pixel or per block of pixels
Ok that is possible (planar or interleaved ?)

just wanted to make sure it would be possible to add stuff like this after the fact without breaking the existing plugins. break plugins ? 3.0 already breaks everything there is, and I was talking about this one (topic is 3.0 news anywa)
It's 3.0 videoframes who are polymorphic not 2.X, to get this working in 2.X it would be far more trickier

MfA
11th June 2003, 22:02
Yes yes, I understand ... but I dont expect this stuff to make it in 3.0 right away, as I said the usefullness of things like that depend on someone wanting to make use of it. I just wanted to make sure that if after the release of 3.0 someone got it in his head to add new frameformats the existing plugins wouldnt break.

MVs are best kept interleaved. Likely you wont ever want to independentely filter the components, so a planar format isnt needed.

Belgabor
11th June 2003, 23:33
Just one thought that crossed me, would it be possible to go a step in the direction of platform independence with 3.0?

MfA
11th June 2003, 23:48
Wouldnt make much sense unless you split Avisynth up in two parts, the vfw/dshow interface part and the script-parsing/image-processing part.

Bidoche
12th June 2003, 10:14
@Belgabor

I think MfA said it all


@MfA

After looking in the code, it appears all your videoframes formats are in fact easily done. Essentially videoframes initialize and behave themselves according to infos given by a polymorphic ColorSpace class.
You have to create a new ColorSpace subclass and the most is done.
Even new planar formats are not really a problem, for now it assumes planes are y, u, v but it can be made requested from ColorSpaces too.

Belgabor
12th June 2003, 13:47
Originally posted by MfA
Wouldnt make much sense unless you split Avisynth up in two parts, the vfw/dshow interface part and the script-parsing/image-processing part.

Well, I'm not much literate in the avisynth sources, but why not? Or simply put a conditional compile around the vfw/dshow interface and don't put it in if the platform doesnt support it.
To make myself clear, I don't necessarily want 3.0 to be platform independent, I just thought it would be a good idea to think about it and if things (like interfaces etc.) change, maybe change them in a way so they don't have to be fiddled with some day again to make it platform independant :p, and if asm has to be rewritten, rewrite it in a way thats easily portable (aka switch to nasm instead of masm).

Xesdeeni
12th June 2003, 14:18
And then how does avisynth tells between line continuation and normal newlines ?
We don't have the C ; for explicit line termination so we can't have implicit line continuation.
You have to choose, it's \ or ;.Actually, I don't think that's true. There is enough syntactical information to determine when a newline isn't the end of a command. For example, if there are any open parentheses in effect, or if the last character was an operator (',', '+', '.', etc.).

But even if we went the C way and used ';', I think it would be preferable. Compare (especially on an 80-column displaay or if you want to print this out):function Deticker(clip input, int tickerheight, int f0, int f1, int f2, int f3)
{
tickerclip = input.Trim(f0, f3)

tickerinpre = tickerclip.Trim(0, f1 - f0 + 1).SeparateFields()
tickerinpost = Animate(0, (f1 - f0) * 2, \
"LanczosResize", \
tickerinpre, \
input.width, input.height / 2, \
0, 0, input.width, input.height / 2, \
tickerinpre, \
input.width, input.height / 2, \
0, 0, input.width, (input.height - tickerheight) / 2).Weave()

ticker = tickerclip.Trim(f1 - f0, f2 - f0 + 1).SeparateFields().LanczosResize(input.width, \
input.height / 2, \
0, \
0, \
input.width, \
(input.height - tickerheight) / 2).Weave()

tickeroutpre = tickerclip.Trim(f2 - f0, f3 - f0 + 1).SeparateFields()
tickeroutpost = Animate(0, (f3 - f2) * 2, \
"LanczosResize", \
tickeroutpre, \
input.width, input.height / 2, \
0, 0, input.width, (input.height - tickerheight) / 2, \
tickeroutpre, \
input.width, input.height / 2, \
0, 0, input.width, input.height / 2).Weave()

return(tickerinpost + ticker + tickeroutpost)
}tofunction Deticker(clip input,
int tickerheight,
int f0,
int f1,
int f2,
int f3)
{
tickerclip = input.Trim(f0, f3);

tickerinpre = tickerclip.
Trim(0, f1 - f0 + 1).
SeparateFields();
tickerinpost = Animate(0, (f1 - f0) * 2,
"LanczosResize",
tickerinpre,
input.width, input.height / 2,
0, 0, input.width, input.height / 2,
tickerinpre,
input.width, input.height / 2,
0, 0, input.width, (input.height - tickerheight) / 2).
Weave();

ticker = tickerclip.
Trim(f1 - f0, f2 - f0 + 1).
SeparateFields().
LanczosResize(input.width,
input.height / 2,
0,
0,
input.width,
(input.height - tickerheight) / 2).
Weave();

tickeroutpre = tickerclip.
Trim(f2 - f0, f3 - f0 + 1).
SeparateFields();
tickeroutpost = Animate(0, (f3 - f2) * 2,
"LanczosResize",
tickeroutpre,
input.width, input.height / 2,
0, 0, input.width, (input.height - tickerheight) / 2,
tickeroutpre,
input.width, input.height / 2,
0, 0, input.width, input.height / 2).
Weave();

return(tickerinpost + ticker + tickeroutpost);
}I chose to line up the continuation marks so I could keep up with them. But this presents a serious annoyance when you are debugging and modifying the code. And note how I didn't even bother with the argument list in the first version because of this.

Xesdeeni

MfA
12th June 2003, 16:35
Originally posted by Belgabor
Well, I'm not much literate in the avisynth sources, but why not?

If the source code carries with it a huge amount of irrelevant code and no usefull input/output interfaces people will just severely hack up the code if they use it at all, which makes keeping things in sync much more of a pain than it should be. Only plugins would be easily portable.

Making it portable is only usefull if the project itself is usefull to others as is. Personally I would think it great if Avisynth 3.0 consisted of 2 modules, and the script-parsing/image-processing part could be plonked down in ffdshow or mplayer without any changes.

To make myself clear, I don't necessarily want 3.0 to be platform independent, I just thought it would be a good idea to think about it and if things (like interfaces etc.) change, maybe change them in a way so they don't have to be fiddled with some day again to make it platform independant :p, and if asm has to be rewritten, rewrite it in a way thats easily portable (aka switch to nasm instead of masm).

It would make more sense to do all asm in softwire.

Bidoche
12th June 2003, 16:39
Actually, I don't think that's true. There is enough syntactical information to determine when a newline isn't the end of a command. For example, if there are any open parentheses in effect, or if the last character was an operator (',', '+', '.', etc.).Maybe, but it's already hard enought to write this parser, so I'd rather not complicate things more than they are.

But even if we went the C way and used ';', I think it would be preferableI agree, the C ; is definitely better but we can't switch to this syntax without breaking script compatibility..
Maybe both cases could be supported and choosable through a metacommand.


@Belgabor

Internals are not that tied to VFW, it just copy data from VFW into its own structures, process it and then get the data back to VFW.

Xesdeeni
12th June 2003, 20:03
I agree, the C ; is definitely better but we can't switch to this syntax without breaking script compatibility..
Maybe both cases could be supported and choosable through a metacommand.That's got my vote!

Xesdeeni

DDogg
12th June 2003, 21:21
You asked for feedback from all, but I am uncomfortable entering into this rarefied programmer type thread. Even so I would ask for:

1> basic disk output. Export d:\test.txt string and string variables
2> Concept of a import loop? (I don't know how else to say it)
Import d:\test.txt
variable manipulation
export d:\test2.txt
do other stuff
End Import
3> Inclusion of an expanded nic style CALL command for external executables.

Bidoche
12th June 2003, 21:29
@DDogg

1> basic disk output. Export d:\test.txt string and string variables
you want vartable exportable in a file, not a problem I think.
Even 2.X can easily do that.

2> Concept of a import loop? (I don't know how else to say it)
Import d:\test.txt
variable manipulation
export d:\test2.txt
do other stuff
End ImportNot understood a thing, plz detail your example.

3> Inclusion of an expanded nic style CALL command for external executablesI am not familiar with CALL. Please describe what you want possible.

bilu
13th June 2003, 15:09
@Bidoche

Some background on DDogg's questions, I was making the same questions at the time:

@sh0dan : WHILE function in Avisynth ?
http://forum.doom9.org/showthread.php?s=&threadid=48127

CALL command
http://forum.doom9.org/showthread.php?s=&threadid=46506

Import execution at start and end
http://forum.doom9.org/showthread.php?s=&threadid=50067

There were no conditional filtering at the time, and to be honest, I haven't worked with it.

CALL is a filter that runs external commands. Such a feature should be integrated into Avisynth, I think.


About

2> Concept of a import loop? (I don't know how else to say it)
Import d:\test.txt
variable manipulation
export d:\test2.txt
do other stuff
End Import



There are already lots of possibilities within ScriptClip, ConditionalFilter and FrameEvaluate.

There is one limitation at least by design, I think: conditional filtering must occur along the script rendering and there is no chance to do a continuous loop checking for some condition. But that's normal.

Possibly what Ddogg is referring here is that:

- CALL and Import() could be worked out for use in conditional filtering, i.e. to respond to a trigger instead of being rendered at the beginning like Import() or at a specific frame like CALL;

- There should be other sort of triggers in conditional filtering, namely periods of time to run filters like CALL or Import();

- Should have a way to accept new variable values during the script rendering (this is somewhat related to Import() );


Now for my requests :D :

- Time calculations function;
- System time grabbing (there is already a filter for this, I think);


Best regards,
Bilu

DDogg
13th June 2003, 16:48
Perhaps "import event" would have been a better term although I am reasonably sure I am using that term improperly. This would be a situation where while you were within the import event you would be working independent of the video event and could do a sequence of actions such as manipulation of variables, export a txt file, call an external command, grab system time into a variable such as before and after the video event, etc. In fact, any event that would be independent of the video event and could be triggered before and/or after the video event and allow a in-line sequence of commands to be triggered would accomplish the same thing.

I fully realize this may be impossible and completely alien to what you are working on. I certainly do not wish to pull this thread too far off topic. The threads bilu posted above should give enough background if you wish to read them (somewhat convoluted I am afraid). Perhaps starting from the end and working backwards might be less painful :-).

As for the why. Many. Everything from full reportage, inclusion of the besweet or other external process directly in a script, to a complete batch file/avs script based encoding applications that analyze compressibility and do a full encode. Here are two examples:

TaZ4hvn:
http://forum.doom9.org/showthread.php?s=&threadid=53043
Bilu:
http://forum.doom9.org/showthread.php?s=&threadid=51228

Bidoche
13th June 2003, 19:26
A quick clarification for now :

The parser is in fact a compiler. It has its syntax, its functions (avisynth commands) and like a C compiler it has directives.

Import is a directive, not a function.
Like the C #include (it works the same), it has to be executed immediately and there is nothing you can do about and there will never be.


And for while and cie, I already said that it can be done, but they will work at execute time.
The Filter chain is the result of the program in which a script compiles. There is no way it can be altered after execution

DDogg
13th June 2003, 20:15
ok, but then that makes me curious how Nic's CALL command can execute a command before frame 0, or during a specific frame, or after last frame.

Nic
13th June 2003, 23:00
It's because im not actually effecting the script structure itself...or calling any other filters. Sorry to be brief (in a rush) :)

-Nic

Bidoche
14th June 2003, 00:54
CALL is a filter and then work at render time.

Just have it do its work at construction, destruction or when frame n is requested. (Or I am mistaken ?)


Maybe what you want is an import filter, but you improper use of the keyword is confusing then.

Something like this :ImportFilter(clip dummy, string fileName)is possible

bilu
14th June 2003, 01:04
@Bidoche

So there can't be a way to periodically or by triggering load external values to variables during the render of the script? Another approach from inside a filter, perhaps?

Bilu

Bidoche
14th June 2003, 01:08
At render there is no script anymore, just a filter graph.
Only filters included in the graph can do something.


Besides when I asked about the environment vartable, nobody answered.
So for now it's gone....

bilu
14th June 2003, 01:28
Besides when I asked about the environment vartable, nobody answered. So for now it's gone....

I'm sorry I didn't look at this thread before.

Because I already knew the answer...

http://forum.doom9.org/showthread.php?s=&postid=275996#post275996

Bilu

PS: Can something be done about this? Some special filter with its own vartable or something? I'm not a programmer so I don't know what to suggest...:confused:

Bidoche
14th June 2003, 10:36
You can setup variables in a filter for others to check them, that's no problem.

bilu
16th June 2003, 23:26
@Bidoche

Would it be possible to use Import() inside FrameEvaluate() to conditionally update variables with external values?

As FrameEvaluate's purpose is to conditionally update variables already, I can't see a problem from using external variables instead of internal... but that's me :)

Together with a clip.framenumber (not available I think) we could also conditionally export variables through CALL like this:

Callcmd="Call(yourcmd,"
FrameEvaluate(Eval(Callcmd+string(last.framenumber)+")"))

and that could be the closest thing to the "import event" as DDogg calls it.



Bilu

Bidoche
19th June 2003, 11:45
For 2.x you can invoke Import and create another filter chain within a filter. And I think it will update variables from the environment as you expect.

For 3.0 I'd have to provide another way to do it.


a 'clip.framenumber' thing will be included in 3.0
The syntax is not fixed yet, but it will look something like that :

function frame myFunction(frame f, int n)
{
CALL("CallCmd(" + n + ")")
return frame
}

ClipTransform(clip, myFunction)

bilu
19th June 2003, 12:12
Thanks for the answer, I'll test to see if it works.

About the clip.framenumber thingy: wouldn't it be possible to use a clip.framenumber just like a clip.framecount in AVS 2.x ? We already have a ShowFrameNumber() function that works as a subtitle, so why will it only be available on 3.0 ? :confused:

I'm not a programmer and I acknowledge this may be a naive question (such as many others :D ).


Bilu

sh0dan
19th June 2003, 12:12
Conditional filters have access to the frame number by accessing the variable "current_frame", which is updated each frame.

bilu
19th June 2003, 12:34
But how can I pass that variable to a filter parameter, like the framenumber on CALL?


Bilu

sh0dan
19th June 2003, 13:31
startcmd="Call("+chr(34)+"cmd"+chr(34)+", "+chr(34)
endcmd=chr(34)+")"
FrameEvaluate("eval(startcmd+string(current_frame)+endcmd)")
#scriptclip("subtitle(startcmd+string(current_frame)+endcmd)")

The scriptclip is purely for illustration.