Log in

View Full Version : Duplicate each 1000th frame


LigH
4th April 2024, 14:19
Having trouble with some WMV clips which get async over a longer time in Avisynth, but stay in sync when played in a media player, I wanted to try different attempts to fix a possible processing mistake. One of my ideas was to prolong the video stream in relation to the audio stream by using
SelectRangeEvery(1000, 1001, 0, false)
I assumed that it would output a range of 1001 frames for each position at a multiple of 1000 frames of video input, hence duplicate each 1000th frame effectively.

But the number of frames did not change. :scared: Where is my mistake?

johnmeyer
4th April 2024, 15:04
Those numbers suggest a playback error related to NTSC video. Because of how color was added to the existing B&W standard back in the early 1950s, we ended up with a strange 29.97 frames per second. That number is arrived at because of the extra frame every 1,000 frames.

I don't know anything about your video or your script, but the usual way to deal with this is to convert one way or the other using AssumeFPS(). It changes the playback speed without duplicating or deleting frames.

So, depending on which way you need to go, you would either use:

AssumeFPS(30)

or

AssumeFPS(29.97)

If you need the ultimate precision you can specify 29.97 as:

(1000 / 1001) * 30

However, I always forget whether you need to use the decimal point to force the proper calculation, i.e.,

(1000.0 / 1001.0) * 30.0

LigH
4th April 2024, 15:16
I do have a video of 30000/1001 fps, but in 720p HD resolution. I could surely also try a combination of AssumeFPS and ChangeFPS in the required order to slow it down further.

Kisa_AG
4th April 2024, 15:23
I do have a video of 30000/1001 fps, but in 720p HD resolution. I could surely also try a combination of AssumeFPS and ChangeFPS in the required order to slow it down further.

Yes, if you already have 30000/1001 fps, then you can do the following thing:

AssumeFPS("ntsc_video")
ChangeFPS(30)
AssumeFPS("ntsc_video")

This will duplicate every 1000th frame and you will have 30000/1001 fps video at the end.

LigH
4th April 2024, 15:51
In the end it was a lot more complicated, but I discovered a ratio which made it pretty synchronous.

But my original question was not only how to do it instead of SelectRangeEvery, but also why SelectRangeEvery is not suitable. I guess it does not go back to frame 1000 after returning 1001 frames? So it is only useful to skip frames but never to repeat any?

johnmeyer
4th April 2024, 16:11
I provided generic advice above. It's impossible to answer your question about your specific problem without a sample clip.

LigH
4th April 2024, 16:20
I wouldn't say "impossible". The developers of Avisynth+ could.

Test clip? Sure.

ColorBarsHD()
Trim(0, -100)
Info()
SelectRangeEvery(10, 11, 0, false)
100 frames if there is no change; about 10 more what I would have expected instead.

johnmeyer
4th April 2024, 16:26
I have no idea what you are trying to do. Someone else will have to help.

LigH
4th April 2024, 16:32
I assumed that SelectRangeEvery(1000, 1001) would:

return frame 0-1000 (1001 frames), then
return frame 1000-2000 (1001 frames), then
return frame 2000-3000 (1001 frames), then
return frame 3000-4000 (1001 frames) ...

But it does not.

poisondeathray
4th April 2024, 17:09
Alternative way is SelectEvery, InterleaveEvery

For WMV which are VFR you can use DirectShowSource("blah.wmv", fps=blah, convertfps=true)

LigH
4th April 2024, 18:11
If SelectRangeEvery is designed to only reduce frame numbers by skipping frames beyond ranges, it may be suitable to include that in the Wiki description.

In case of SelectEvery, I would have to explicitly type a list of 1000 frame numbers.

There is no InterleaveEvery in the Avisynth+ Wiki.

I wanted to avoid DSS but it is always a last chance...

poisondeathray
4th April 2024, 19:22
In case of SelectEvery, I would have to explicitly type a list of 1000 frame numbers.

There is no InterleaveEvery in the Avisynth+ Wiki.

I wanted to avoid DSS but it is always a last chance...

InterleaveEvery is part of ApplyEvery an external plugin
http://avisynth.nl/index.php/ApplyEvery


orig=blankclip(length=10000).showframenumber().assumefps(30000,1001)

sel=orig.selectevery(1000,999).text("selection").loop(2,0,0)
#999,1999,2999...

interleaveevery(orig, sel, 1001,0).trim(1,0)

wonkey_monkey
4th April 2024, 21:33
Unfortunately SelectRangeEvery includes this piece of code:

length = clamp(_length,1,every);

which seems to serve no other purpose than to prevent it doing exactly what you want it to do!

There's a bit of conditional code further down which tests

every<length

suggesting that every being less than length was considered a valid possibility at some point.

LigH
4th April 2024, 21:58
Okay, thank you for pointing this out. At least we are sure now.