View Full Version : Is there a way to get the current frame number?
medp7060
25th November 2007, 09:39
I tried to find out how to get the current frame number in a script, but failed to find one. Any help is much appreciatd.
Leak
25th November 2007, 10:06
I tried to find out how to get the current frame number in a script, but failed to find one. Any help is much appreciatd.
AFAIK there is none, since the script is only evaluated once before the first frame is evaluated so any decision you could make based on the current frame's number will be made before any frame has been requested.
It might be feasible to provide the current frame number to a function used with ScriptClip et al, though...
np: Denzel + Huhn - Targo (Paraport)
stickboy
25th November 2007, 11:07
I tried to find out how to get the current frame number in a script, but failed to find one. Any help is much appreciatd.Exactly why do you want it?
medp7060
25th November 2007, 11:47
It might be feasible to provide the current frame number to a function used with ScriptClip et al, though...
np: Denzel + Huhn - Targo (Paraport)
But I still do not know how to get it.
I need to know the current_frame number for me to add correct "timecode" to MPEG file recorded by Sony videocamera. I can do it one by one, but when I join many short clips, I need to know when the next clip comes. e.g.
Clip 1: recorded on 12-01-2007 at 14:30
Clip 2: recorded on 09-05-2007 at 04:11
...
foxyshadis
25th November 2007, 14:24
Don't revive old threads when you already have one on the same topic. The documentation for conditional filters have an example of this use. You just have to use a few frameevaluates for the math, and remember to make your initial dates global.
stickboy
25th November 2007, 22:33
I need to know the current_frame number for me to add correct "timecode" to MPEG file recorded by Sony videocamera. I can do it one by one, but when I join many short clips, I need to know when the next clip comes. e.g.
Clip 1: recorded on 12-01-2007 at 14:30
Clip 2: recorded on 09-05-2007 at 04:11How do you plan to use the "current frame" is help you with that?
I still don't understand exactly what you want. If you want static text "Clip 1: recorded on 12-01-2007 at 14:30" throughout "clip 1" to indicate where it came from, then that information can be done with Subtitle per clip, not per frame.
If you want to have a running timestamp throughout the clip (i.e., if clip 1 is 5 minutes, then the first frame says "... 14:30" and the last frame says "... 14:35"), then you can use BlankClip and ShowTime.
If you want to know when the next clip is about to start (i.e., a countdown timer), then you can do Reverse().ShowTime().Reverse().
And if you need to do those operations on multiple clips, you can write a function to do the work for you.
Leak
25th November 2007, 22:41
The documentation for conditional filters have an example of this use.
Maybe so, but other than twice in the first (and rather big) example current_frame isn't listed anywhere on that page, especially not in a prominent place with a description or something like that...
No wonder one can miss it so easily. :(
np: Bola - Magnasushi (Fyuti)
Fizick
25th November 2007, 23:25
both offline and wiki documentation updates is in-progress :)
http://avisynth.org/mediawiki/Runtime_environment
but they are not in-sync. (too many works.)
usually wiki is more updated but not polished.
any help and specific suggestion (correction) will be very fine.
medp7060
25th November 2007, 23:36
here is what I tried:
say:
Clip 1 has 4000 frames (12-01-2007 at 14:30)
Clip 2 has 2000 frames (09-05-2007 at 04:11
I can add both date and time stamps to each of the clips when do it separately, but when merge them as one like this
MPEG2Source("Clip1.d2v")+MPEG2Source("Clip1.d2v")
my script needs to know when the Clip 2 starts, that is why I need to know Frame 4001 starts Clip 2.
I checked the documentation of conditional filters. however, I still cannot work it out. Basically, I need a parameter (frame counter) to let me know which frame is processing now, so I can add the right "date/time stamps" on for Clip2.
I tried this ( which is wrong):
ScriptClip( FrameN=current_frame)
But I cannot use "FrameN" later.
stickboy
26th November 2007, 00:07
here is what I tried:
say:
Clip 1 has 4000 frames (12-01-2007 at 14:30)
Clip 2 has 2000 frames (09-05-2007 at 04:11
I can add both date and time stamps to each of the clips when do it separately, but when merge them as one like this
MPEG2Source("Clip1.d2v")+MPEG2Source("Clip1.d2v")
my script needs to know when the Clip 2 starts, that is why I need to know Frame 4001 starts Clip 2.You're still not being clear. Do you want static information or do you need a running timestamp?
That is, if you just want to know where clip 2 starts, then you can do:
MPEG2Source("Clip1.d2v").Subtitle("Clip 1") + MPEG2Source("Clip2.d2v").Subtitle("Clip 2")and you're done.
If you want to see some running timestamp in each clip, then it's more work, but it'd be essentially the same thing.
My other question is: why does your script need to know where clip 2 starts? You already have clip 2 as a separate entity. If you need to perform some operation on only clip 2, apply it clip 2 before you splice it with clip 1.
Going about this with ScriptClip sounds like the wrong approach. An approach of "I want to conditionally print some string if the frame number is in a certain range" is not the right way to approach AviSynth scripts. The sooner you abandon that and listen to what I'm saying (and clearly explain exactly what you want to see), the sooner we can help you come to a correct working solution...
medp7060
26th November 2007, 00:39
That is, if you just want to know where clip 2 starts, then you can do:
MPEG2Source("Clip1.d2v").Subtitle("Clip 1") + MPEG2Source("Clip2.d2v").Subtitle("Clip 2")
thanks a lot. that is one way to put running date/time stamps. But since there is no original info to use for my MPEG clips, I have to use a workarround which is based on "the date/time created" of each clip. that is a relative alrger script (learned from here) rather than a simple "Subtitle".
If I know when the next clip starts, I can just put a condition before the subtitle script in order to know which date/time to be stamped on the final output.
Or I can change my origina question to:
can I crerate a single script to call many many individual one because I can do it separately?
"001.avs" + "002.avs" + "003.avs"
I even tried Import function like this:
import("001.avs") + import"002.avs" + import"003.avs"
but it is always the parameters from the last avs imported were seen, i.e. "001.avs" showed the date/time code of "003.avs"
Fizick: I checked Runtime_environment, however, there is no way to use the "current_frame" and "last" variables.
stickboy
26th November 2007, 01:09
thanks a lot. that is one way to put running date/time stamps. But since there is no original info to use for my MPEG clips, I have to use a workarround which is based on "the date/time created" of each clip. that is a relative alrger script (learned from here) rather than a simple "Subtitle".
If I know when the next clip starts, I can just put a condition before the subtitle script in order to know which date/time to be stamped on the final output.But how do you know what date/time to use? You'd still have to specify it manually, so it's really no different than explicitly supplying the date/time to Subtitle where you use MPEG2Source.
Trying to generate clip information about the clip segments after you've already concatenated them is backwards. Do it before you concatenate! It's much easier, and it's the way AviSynth is meant to be used.
Anyway, if you want to use the creation time from each file, you can use my GetSystemEnv (http://www.avisynth.org/stickboy/) plug-in and do:
MPEG2Source("Clip1.d2v").Subtitle("Clip 1 " + GetFileInfo("Clip1.d2v", "creationTime")) + ...
Clearly that's a little clunky, so you can write a function to help you:
function MPEG2SourceTS(filename, clipName)
{
return MPEG2Source(filename).Subtitle(clipName + " " + GetFileInfo(filename, "creationTime"))
}
MPEG2SourceTS("Clip1.d2v", "Clip 1") + MPEG2SourceTS("Clip2.d2v", "Clip 2")
Or I can change my origina question to:
can I crerate a single script to call many many individual one because I can do it separately?
"001.avs" + "002.avs" + "003.avs"
I even tried Import function like this:
import("001.avs") + import"002.avs" + import"003.avs"If you want a single script to open other .avs scripts, then you should use:
AVISource("001.avs") + AVISource("002.avs") + AVISource("003.avs")Using Import is equivalent to copying and pasting the contents of one script into another.
medp7060
26th November 2007, 02:31
Anyway, if you want to use the creation time from each file, you can use my GetSystemEnv (http://www.avisynth.org/stickboy/) plug-in and do:
MPEG2Source("Clip1.d2v").Subtitle("Clip 1 " + GetFileInfo("Clip1.d2v", "creationTime")) + ...
That's what I used for the automation of processing multiple files. thanks again for that. You added the GetFileInfo function to help me long time ago here http://forum.doom9.org/showthread.php?p=761271#post761271. I get the date/time, then put running time stamp on the final output.
Clearly that's a little clunky, so you can write a function to help you:
function MPEG2SourceTS(filename, clipName)
{
return MPEG2Source(filename).Subtitle(clipName + " " + GetFileInfo(filename, "creationTime"))
}
MPEG2SourceTS("Clip1.d2v", "Clip 1") + MPEG2SourceTS("Clip2.d2v", "Clip 2")
I need time to digest this. I will see if it will work as I expected.
If you want a single script to open other .avs scripts, then you should use:
AVISource("001.avs") + AVISource("002.avs") + AVISource("003.avs")Using Import is equivalent to copying and pasting the contents of one script into another.
I see.
Edited:
I have now found one function called "ShowFrameNumber", which draws text on every frame indicating what number AviSynth thinks it is. however, I cannot use the actual numebr in a script. hope Avisynth will get a function like below similar to FrameCount()
Framenumber()
stickboy
26th November 2007, 06:23
I have now found one function called "ShowFrameNumber", which draws text on every frame indicating what number AviSynth thinks it is. however, I cannot use the actual numebr in a script. hope Avisynth will get a function like below similar to FrameCount()
Framenumber()It can't. It doesn't make any sense, because AviSynth doesn't work that way. From the perspective of an AviSynth script, there is no such thing as a "current frame". As already explained, scripts are evaluated when they are initially opened, not as you retrieve frames from them. It's like asking, "If I have a function f(x) = sin(x), what's the current value?" There is no current value.
Again, if you think you need a "current frame number", you're almost always thinking of things in the wrong way.
Wilbert
26th November 2007, 19:55
If you want to assign current_frame to a variable and use it, you can do it like this:
function g(clip c)
{
c2 = ScriptClip(c, "subtitle(t)")
c3 = FrameEvaluate(c2, "me()")
c4 = FrameEvaluate(c3, "global text = current_frame")
return c4
}
function me()
{
global t = String(text)
}
v = ColorBars().ConvertToYV12()
g(v)
Wilbert
27th November 2007, 18:39
@medp7060,
You know about Framecount(clip), FrameRateNumerator(clip) and FrameRateDenominator(clip)?
http://avisynth.org/mediawiki/Clip_properties
medp7060
27th November 2007, 22:00
Thanks, Wilbert. Yes, but do not know how to make use of them.
Please advise me this.
AviSource("d:\avi\MVI_3534.AVI")
# this is the code by Wilbert, it shows the current frame at the top left corner.
# But only with some stripes instead of the avi clip
function g(clip c)
{
c2 = ScriptClip(c, "subtitle(t)")
c3 = FrameEvaluate(c2, "me()")
c4 = FrameEvaluate(c3, "global text = current_frame")
return c4
}
function me()
{
global t = String(text)
}
v = ColorBars().ConvertToYV12()
g(v)
# Then how to use the "current_frame" variable out of this function? like this?
cf= t # or current_frame, c, or v (all failed)
IanB
27th November 2007, 22:24
@medp7060,
Perhaps a little insight into how Avisynth work might help.
As Avisynth compiles your script it build a "Video Graph" and an "Audio Graph". The value of all the variables and functions are calculated as the script compiles and the Graphs are built.
As statements like "AviSource()" are compiled, the referenced file is opened and various parameters, like Height, Width, FrameCount, FrameRate, Pixel_Format, etc, are read from the files header information.
All the statements in your script result in objects being chained together to form the "Video Graph" and the "Audio Graph".
The "Video Graph" resulting from very last active statement in your script, exposes a GetFrame subroutine, likewise a GetAudio subroutine is exposed from the "Audio Graph" to the application you are using to open your script with, i.e. VirtualDub.
So as you use VirtualDub you may scrub up and down the timeline to examine how various frames of your clip look. When you ask to look at frame 100, VirtualDub asks the last object in the Avisynth "Video Graph" to render frame 100. The code inside this objects GetFrame subroutine does some calculation with the incoming number 100 and calls the GetFrame subroutine of next member in the "Video Graph".
E.g. The code for a Trim(25, 0) statement would add 25 to the value 100 and then ask the next GetFrame subroutine in the chain for frame 125. When the Video data is returned the Trim code simply returns that data to it's caller.
This process continues all the way along the "Video Graph" until the GetFrame subroutine for an AviSource() statement is executed. This reads the Video data from the .AVI file and returns that Video data to it's caller.
Building these static "Video Graphs" and "Audio Graphs" is how AviSynth can be so fast. But as you are experiencing this methodology does have a downside, i.e. you cannot have concepts like FrameNumber() in your script.
Very complicated code in Functions like FrameEvaluate() try to work around this restriction, by actually recompiling parts of the script inside every call to it's GetFrame subroutine.
For each incoming call it sets the values for the specified script variables, then Compiles another "Video Graph", then calls the GetFrame subroutine of that graph, gets the Video Data, deletes the temporary "Video Graph" and finally returns the Video Data.
This is not an ideal performance situation. To make good use of Avisynth scripts you need another approach. Instead of thinkingIf (FrameNumber() >= 100 && FrameNumber() < 200) {
SubTitle("100 to 200")
}you need to adapt to a model that allows the script decisions to be built at compile timeA=Trim(0, 99)
B=Trim(100, 199).SubTitle("100 to 200")
C=Trim(200, 0)
A + B + CSometimes you just cannot adapt, hence statements FrameEvaluate() and friends exist.
Wilbert
27th November 2007, 22:28
If I know when the next clip starts, I can just put a condition before the subtitle script in order to know which date/time to be stamped on the final output.
I'm not exactly sure what you want.
MPEG2Source("Clip1.d2v").ShowSMPTE # clip1
displays the SMPTE timecode (hours:minutes:seconds:frame) on our clip. Ok, that's only a time and not a date. So, perhaps not exactly what you want.
If you want to start counting clip2 from the timecode of clip1, you need to add an offset:
clip1 = MPEG2Source("Clip1.d2v").ShowSMPTE
off = Framecount(clip1)
clip2 = MPEG2Source("Clip2.d2v").ShowSMPTE(offset_t=off)
clip1 + clip2
Is that want you want? So it all boils down to construct that offset? I think setting "offset_t=Framecount(clip1)" should work.
medp7060
28th November 2007, 00:01
.. it all boils down to construct that offset? I think setting "offset_t=Framecount(clip1)" should work.
Your are right. That is the way I used to show both date and time stamps for individual clips. The original goal has met with the use of Stickboy’s suggestion: AVISource("001.avs") + AVISource("002.avs") + AVISource("003.avs") …
The further discussion is like this: if I first merge the clips like this: MPEG2Source("Clip1.d2v"). + MPEG2Source("Clip2.d2v"). + MPEG2Source("Clip3.d2v"). …
Although I can still measure the “offset_t” of each clip, but since the date/time stamps script has to be told that when it should put the date/time for the next clip. In this sense, if I know the current frame number, I can compare with the “offset_t”, e.g. if the current frame number is great than the “offset_t” of the first clip, I know the 2nd clip starts and the script will get the date/time from the 2nd file and to show the correct date/time. Of course, I can put the info required manually, but it would be better if it can be automatic when process multiple files.
So the issue is how do I know when it goes to the next.
Didée
28th November 2007, 01:53
@ medp7060:
20 posts in this thread, first page break, and still your problem is not really clear.
You repeatedly say you have script that evaluates date/time of the source file. We haven't seen it yet, but ... if that script is able to do the intended job for one file, then it can do the job for many files, too. Apply the script to each single source file before you're splicing them together. Done.
In (pseudo-) code: If you have a working solution like
Mpeg2Source( source1.d2v )
YourFunctionThatDoesTheJob()
then you should NOT try to do:
Mpeg2Source(source1) ++ Mpeg2Source(source2) ++ Mpeg2Source(source3)
YourFunctionThatDoesTheJob( ButNowHasAProblemToDiscernTheIndividualSources )
but instead should do this:
v1 = Mpeg2Source( source1.d2v )
v2 = Mpeg2Source( source2.d2v )
v3 = Mpeg2Source( source3.d2v )
v1
YourFunctionThatDoesTheJob()
trim(...) # if needed
part1 = last
v2
YourFunctionThatDoesTheJob()
trim(...) # if needed
part2 = last
v3
YourFunctionThatDoesTheJob()
trim(...) # if needed
part3 = last
...
etc
...
part1 ++ part2 ++ part3 ++ ..etc..
If this does not work, then the problem is that you're not giving enough information in this thread, and/or that you're not clear enough in describing the crucial point of the problem.
medp7060
28th November 2007, 02:32
Thanks, Didée.
I think you missed some of my reply. I said the original goal had achieved by taking the avs’s as video source, which is basically the same as what you suggested here.
The code I am using to show date/time is here http://forum.doom9.org/showthread.php?p=859651#post859651
Originally Posted by stickboy
How accurate does it really need to be? If one wants an approximate timecode, then you
could something like:
function ShowTime(float totalSeconds)
{
i = Int(totalSeconds)
hours = Int(i / 3600)
minutes = Int((i % 3600) / 60)
seconds = i % 60 + Frac(totalSeconds)
return String(hours, "%02.0f")
\ + String(minutes/ 60, ":%02.0f")
\ + String(seconds, ":%06.3f")
}
ScriptClip("Subtitle(ShowTime(current_frame / FrameRate()))")
Just add correct "offset_t=Framecount(clipx)".
Edited:
Code:
v1 = Mpeg2Source( source1.d2v )
v2 = Mpeg2Source( source2.d2v )
v3 = Mpeg2Source( source3.d2v )
v1
YourFunctionThatDoesTheJob()
trim(...) # if needed
part1 = last
v2
YourFunctionThatDoesTheJob()
trim(...) # if needed
part2 = last
v3
YourFunctionThatDoesTheJob()
trim(...) # if needed
part3 = last
...
etc
...
part1 ++ part2 ++ part3 ++ ..etc..
I tested this, it worked. But I need to give the different variables for each clip for this YourFunctionThatDoesTheJob()
which is not good for automation for multiple files.
To conclude this is the best solution for me:
AVISource("001.avs") + AVISource("002.avs") + AVISource("003.avs")
vBulletin® v3.8.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.