View Full Version : How to keep 1 frame by second in 29.97 fps ?
Music Fan
18th December 2013, 18:30
Hi,
I have a video in 29.97 fps (progressive) and I'd like to keep 1 frame by second ; I tried SelectEvery(29.97) but it does not work ; SelectEvery(30) works but it's maybe not very good for a 29.97 fps video.
Or I can maybe do this trick (which works) ;
my 29.97 fps video
assumefps(30)
SelectEvery(30)
assumefps(30000, 1001)
Is there simpler ?
Gavino
18th December 2013, 18:50
That script doesn't actually work the way you think.
AssumeFPS() doesn't change the frame count, so you are still selecting every 30th frame of the original.
You need to use ChangeFPS() instead.
ChangeFPS(30)
SelectEvery(30)
AssumeFPS(30000, 1001)
Music Fan
18th December 2013, 19:33
I'm not sure ChangeFPS is a good idea because new frames will be created and I don't need this, especially because 30 is not a multiple of 29.97, thus it will create judder.
But if assumefps(30) is not useful in this case, I guess I can simply put SelectEvery(30) without assumefps.
raffriff42
18th December 2013, 20:27
This script selects frames very close to even seconds (within about 3/100 sec)## sample data (640x480, RGB32, 29.97p, 1 hour)
A = ColorBars.Info
return A.ChangeFPS(3000000, 1001)
\ .SelectEvery(2997)
## frame 0 = 00:00:00.000
## frame 1 = 00:00:00.967
## frame 2 = 00:00:01.968
## ...
## frame 3599 = 00:59:58.995The "extra" frames are never actually created (I think), so there's no performance penalty.
Gavino
18th December 2013, 22:19
...
return A.ChangeFPS(3000000, 1001)
\ .SelectEvery(2997)
## frame 0 = 00:00:00.000
## frame 1 = 00:00:00.967
## frame 2 = 00:00:01.968
## ...
## frame 3599 = 00:59:58.995
I just checked and that's exactly the same timings I get for my script with ChangeFPS(30).SelectEvery(30).
The "extra" frames are never actually created (I think), so there's no performance penalty.
That's correct. Basically what both your script and mine do is select the closest original frame to each 1-second time point.
EDIT: Thinking further, the SelectEvery() is actually unnecessary and a single ChangeFPS(1) will suffice.
(But note that, because reducing the rate by a factor of more than 10, linear=false must then also be specified in the ChangeFPS() call.)
But if assumefps(30) is not useful in this case, I guess I can simply put SelectEvery(30) without assumefps.
It really depends what you are trying to achieve.
If you want the closest frames to the 1-second points, use ChangeFPS(). If you prefer an approximate, but strictly uniform spacing, just use SelectEvery(30) on its own, which will give you a frame every 1.001 seconds.
Motenai Yoda
19th December 2013, 05:47
I'm not sure ChangeFPS is a good idea because new frames will be created and I don't need this...
nope ChangeFPS select or duplicate frames, while ConvertFPS blends frame together weighted by time position.
Music Fan
19th December 2013, 16:10
nope ChangeFPS select or duplicate frames
That's what I meant (when increasing framerate).
Music Fan
19th December 2013, 16:24
This script selects frames very close to even seconds (within about 3/100 sec)## sample data (640x480, RGB32, 29.97p, 1 hour)
A = ColorBars.Info
return A.ChangeFPS(3000000, 1001)
\ .SelectEvery(2997)
## frame 0 = 00:00:00.000
## frame 1 = 00:00:00.967
## frame 2 = 00:00:01.968
## ...
## frame 3599 = 00:59:58.995The "extra" frames are never actually created (I think)
They are created, I just tested with my video : 51900 frames in 29.97 fps, 51950 when adding ChangeFPS(30), thus I will avoid ChangeFPS() and will simply use SelectEvery(30) (without assumefps(30) before, it seems pointless in this case).
I guess we can't actually keep exactly one frame per second with decimal framerates.
johnmeyer
19th December 2013, 19:35
I have been following this thread and do not understand why the initial post doesn't work. I just took some 29.97 footage and ran it through this script:AVISource("E:\Documents and Settings\Dnload\Unpack\viacom1986.avi")
assumefps(30)
selectevery(30,1)
assumefps(29.97)
I started with only the first line. That passed through everytyhing, untouched. I then added the second line and still had the same number of frames (333 frames in my test clip), but now playing at 30 fps instead of 29.97 fps.
I then added the third line and ended up with 12 frames, but at 30 fps (333/30 = 11.1, which gets rounded up to 12). I then added the final line and still had 12 frames, but playing at the original 29.97 rate.
Like I said, I must be missing the point of what the OP was trying to do because this seems to decimate, exactly, all but one frame from each second of video, and yet keep the original playback speed. The only issue is one of how you want the roundoff to be handled because the total number of frames is not an integer multiple of 30. In this case, it simply rounds up.
zero9999
19th December 2013, 19:42
I have been following this thread and do not understand why the initial post doesn't work. I just took some 29.97 footage and ran it through this script:I started with only the first line. That passed through everytyhing, untouched. I then added the second line and still had the same number of frames (333 frames in my test clip), but now playing at 30 fps instead of 29.97 fps.
I then added the third line and ended up with 12 frames, but at 30 fps (333/30 = 11.1, which gets rounded up to 12). I then added the final line and still had 12 frames, but playing at the original 29.97 rate.
AssumeFPS() does exactly nothing because AviSynth only cares about frames, not time, so you must be mixing up the line order.
johnmeyer
19th December 2013, 19:57
AviSynth only cares about frames, not time, so you must be mixing up the line order.Ahhh ... got it.
Gavino
19th December 2013, 20:51
Like I said, I must be missing the point of what the OP was trying to do because this seems to decimate, exactly, all but one frame from each second of video, and yet keep the original playback speed.
The point is it doesn't keep exactly one frame per second.
It keeps one frame in every 30, which is every 1.001 seconds.
Music Fan
19th December 2013, 21:04
Yes, that's what I guessed in my previous post.
I have been following this thread and do not understand why the initial post doesn't work.
You didn't read well, it works, like I said in the first post.
raffriff42
19th December 2013, 21:05
I guess we can't actually keep exactly one frame per second with decimal framerates.That is exactly what Gavino's script and my script do, in their different ways. Not *exactly* but within a tolerance of course - what did you expect?
What is your actual use case? I assumed you wanted to generate representative thumbnails or something - like the timeline display on a video editor. Did you want something else, such as exact 30x playback speed for a timelapse effect?
Music Fan
19th December 2013, 21:11
That is exactly what Gavino's script and my script do, in their different ways.
Your script is wrong (it duplicates frames and thus creates judder), as I said above.
There is only one command to add to make what I need ;
SelectEvery(30)
Did you want something else, such as exact 30x playback speed for a timelapse effect?
Yes.
raffriff42
19th December 2013, 21:29
SelectEvery(30) does not meet the requirements as stated. After an hour you will be 3.6 seconds off.
johnmeyer
19th December 2013, 21:35
You didn't read well, it works, like I said in the first post.I did read well and it doesn't actually drop one per second. Obviously my approach fails as well (zero9999 explained the flaw in my thinking).
I don't think anyone has presented a solution that actually decimates exactly one frame every second, while also keeping the original frames perfectly intact.
The solution, I think, is to implement "drop frame" code that, in essence, doesn't drop a frame every 1001 frames, or something like that.
Music Fan
19th December 2013, 21:42
SelectEvery(30) does not meet the requirements as stated. After an hour you will be 3.6 seconds off.
Yes but that's not a problem, I understood that choosing a frame all x frames was more important than choosing a frame per period (when the framerate is a decimal number).
Music Fan
19th December 2013, 21:53
I did read well and it doesn't actually drop one per second.
Ok, I believed you meant that I couldn't do what I needed to do (timelapse).
I don't think anyone has presented a solution that actually decimates exactly one frame every second, while also keeping the original frames perfectly intact.
Actually I'm not sure it's possible with decimal framerates.
In my opinion, the lesson of this topic (at least for my purpose) is that focusing on original frames is more important than focusing on precise periods (and I was focused on seconds when I created this topic).
Gavino
20th December 2013, 00:06
I don't think anyone has presented a solution that actually decimates exactly one frame every second, while also keeping the original frames perfectly intact.
Both my solution and that of raffriff42 keep original frames 'intact', in the sense that each output frame is a completely unchanged frame from the input.
Obviously, it's impossible to select frames exactly one second apart with a non-integer source framerate, so the next best thing is to choose the frame closest to each 1-second point. These frames occur at intervals averaging exactly one frame per second over the long term(*). That's what we believed Music Fan wanted, but it turned out that exactly one frame per second was not really a requirement after all.
[(*)Specifically, for each sequence of 1001 frames, you get 971 intervals of 1.001 seconds (each corresponding to 30 source frames) and 30 intervals of (approx) 0.968 seconds (each corresponding to 29 source frames).]
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.