View Full Version : SlowMo: Simple slow motion, using interpolation


spoRv
6th December 2016, 11:41
###########################################################################################
### SlowMo 1.01: Simple slow motion, using interpolation ###
### ###
### Usage: SlowMo(clip,multiplier) ###
### ###
### Example: want to make clip to play at half rate ###
### ###
### SlowMo(clip,2) - or just SlowMo(clip) as 2 is the default value ###
### ###
### AviSynth script made by spoRv (http://blog.sporv.com) - Created: 2016-12-05 ###
### ###
### Creative Commons 4,0 - Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) ###
### Link to the licence page: https://creativecommons.org/licenses/by-sa/4.0/ ###
###########################################################################################

function slowmo(clip clip, int "mul") {
num=clip.FrameRateNumerator
den=clip.FrameRateDenominator
mul=default(mul,2)
clip.assumefps(num,den)
backward_vec = clip.MVAnalyse(blksize=16, isb = true, chroma=false, pel=1, searchparam=1, idx=1)
forward_vec = clip.MVAnalyse(blksize=16, isb = false, chroma=false, pel=1, searchparam=1, idx=1)
last.MVFlowFps(backward_vec, forward_vec, num=num*mul, den=den, mask=0, idx=1)
assumefps(num,den)
}


Needed to slow a shot in a clip, I searched for a proper script, but haven't found it; I thought to use InterFrame, and assumefps at half the final rate, but was too "heavy" for my old PC... I just needed something better than ConvertFPS...

Found a code here: http://www.avsforum.com/forum/26-home-theater-computers/1025800-avisynth-script-doubling-video-frame-rates.html - take it, slightly modified - with my limited knowledge - and corrected the most important thing, that nobody seems to take in account: when a film (23.976fps = 24000/1001) must be converted to double frame (for interframe purpose or, like in this case, for a slow motion) it should be 48000/1002 and NOT 48000/1001... with this error, an entire movie will have many frames less, and audio will be audibly out of sync after few minutes. I was wrong, 48000/1001 is the right number; corrected the code to reflect this.

My little contribution; hope this code is right (if not, feel free to correct/improve it) and could be useful for someone.

FranceBB
6th December 2016, 13:35
It's always good to have a filter to do this kind of things in avisynth.
I'm gonna try it tomorrow, as I'm at work right now ;)

jmartinr
6th December 2016, 13:50
it should be 48000/1002 and NOT 48000/1001.
That can't be right. Please explain.

ChaosKing
6th December 2016, 14:12
(48000/1002) / 2 ~= 23,952
(48000/1001) / 2 ~= 23,976 ;)

Groucho2004
6th December 2016, 16:20
You guys realize that this "script" is an example from the MVTools2 manual with a simple AssumeFPS() at the end, right? There are also a shitload of variations of this all over this forum.

The "made by" and "creative license" are ridiculous.

johnmeyer
6th December 2016, 17:14
I agree that this doesn't really advance the state of the art much and, since it is a function, it really should have a little more packed into it that the average user might not think of doing if he or she was just going to use the cookbook code in the documentation.

But there is a MUCH bigger issue that even Groucho2004 didn't pick up on: this function uses the obsolete MVTools plugin!!! That plugin is ancient history, almost a decade old, and it has completely and totally been superseded by MVTools2.

I have over a dozen slow-mo scripts that I've written (or stolen), and I just scanned through them. Here are some things the OP might want to consider adding:

1. Use MVTools2 NOT the old MVTools!!!!
2. Normally the block size is large for doing slow motion, so having a fixed block size of 16 is probably OK. However, you can get different results by using the overlap parameter. That needs to be used.
3. There are variations on the slo-mo script which use MRecalculate (something introduced in MVTools2 as it was updated). The OP needs to try this out and see if it produces better and/or faster results.
4. Use prefiltering for the vector clip. Removegrain is often used, although I've seen fft3D and other filters used as well.
5. Once you update to use the much better (and multi-threaded) MVTools2, there are all sorts of other parameters you should play with, such as pel=2, search=3, etc.

I too am confused by the denominator of 1002. I don't think that is right, and would love to understand the thinking behind it. The 1000/1001 multiplier is required to accommodate the NTSC color convention. That same ratio is used for both 24 and 30 fps material, yielding 23.976 and 29.97 respectively (rounded). I sort of understand the thinking that may have lead to using 1000/1002 for 48 fps, but I don't think it is correct.

Finally, I would suggest making a generalized version of the function which can also handle interlaced video.

So, while I applaud the effort, I think it needs some serious rework before it can be useful for slow motion in the year 2016.

johnmeyer
6th December 2016, 17:22
P.S. Here is some code to get the OP started re-writing the function to use MVTools2. This is nothing special, and is only slightly more advanced than what is in the documentation:


prefiltered = RemoveGrain(source,2)
super = MSuper(source,hpad=16, vpad=16, levels=1) # one level is enough for MRecalculate
superfilt = MSuper(prefiltered, hpad=16, vpad=16) # all levels for MAnalyse
backward = MAnalyse(superfilt, isb = true, blksize=16,overlap=8,search=3,dct=0)
forward = MAnalyse(superfilt, isb = false, blksize=16,overlap=8,search=3,dct=0)
forward_re = MRecalculate(super, forward, blksize=8, thSAD=100)
backward_re = MRecalculate(super, backward, blksize=8, thSAD=100)
MFlowFps(source,super, backward_re, forward_re, num=30000, den=1001,ml=200,mask=2)

If I were to write a function, I'd look at every single parameter for each individual function in the MVTools2 slow motion chain, and play around with it in order to see its impact on slow motion. The key to writing this function is to produce something which produces the minimum number of artifacts. The place where these artifacts are most prominent are:

1. Strong vertical lines. A horizontal pan of a picket fence is a real torture test.

2. Object reveal. When a background object emerges from behind a foreground object, you often get all sorts of strange morphing.

I'd also look at adding some sort of masking to the function.

Groucho2004
6th December 2016, 17:24
5. Once you update to use the much better (and multi-threaded) MVTools2
Even though there is a version of MVTools2 (out of way too many floating around) that can make use of avstp.dll, all newer versions by Fizick and pinterf are not multi-threaded.

And yes John, I missed that the script is for MVTools(1). :p

spoRv
6th December 2016, 17:33
@Groucho2004:
Thanks for the input; "made by" because I simply copy&paste some code, and added some variation... not that difficult, I must admit, but I've done it, so, that's it. Creative Commons is a nice addition, albeit unuseful, I suspect! :D

@johnmeyer:
Constructive feedbacks are always welcome! As I'm not an avisynth programmer, this is a simple function I added to my library, concious that a very better version could be done; but, in comparison to the basic ConvertFPS, it's better, and it is sufficent for my purposes. So, I would be more than happy if you would like to make a complete rework using better/more efficient filters,

48000/1002 is the right calculation for the slow motion, half speed, of film rate, and NOT for the 48fps, that should be 48000/1001 - even if I don't know if there is any standard that supports it. For NTSC half speed, is 60000/1002, while for PAL a simple 50/1 - or 50000/1000 :D
THIS IS NOT TRUE, my fault, going to correct the script right now; please, do NOT use avisynth during renal colis, it could happen your mind is not that lucid...

Groucho2004
6th December 2016, 17:34
There was a lot of discussion about this going on in the MVTools threads:
http://forum.doom9.org/showthread.php?p=1783504#post1783504
http://forum.doom9.org/showthread.php?p=1785795#post1785795

captaiŋadamo
6th December 2016, 17:40
48000/1002 is the right calculation for the slow motion, half speed, of film rate, and NOT for the 48fps, that should be 48000/1001 - even if I don't know if there is any standard that supports it. For NTSC half speed, is 60000/1002, while for PAL a simple 50/1 - or 50000/1000 :D

Where do you get the 1002 from? If you want to half the speed you need only double the numerator. The NTSC offset doesn't change.

spoRv
6th December 2016, 17:53
My fault! You are all right, and I'm a completely stupid... :(
Going to correct the script right now!

It was something like 48000/2002 which is equal to 24000/1001 - what I was thinking...

captaiŋadamo
6th December 2016, 17:57
48000/1001/2 != 24000/1001

You're joking, right? Basic algebra proves you wrong.

ETA: Seems you've spotted your mistake. :)

BetA13
6th December 2016, 18:54
can i use this for realtime rendering with my videos?
lets say id use mpchc with ffdshow - avisynth.

where or how should i get started to use this with my videp player?

thanks for any help :)

johnmeyer
6th December 2016, 19:49
For real time rendering you might want to look into SVPFlow (http://forum.doom9.org/showthread.php?t=164554). That is what is was built for (i.e., real-time interpolation).

Groucho2004, thanks for those links. The second one, linking to StainlessS' code, is especially interesting.

BetA13
6th December 2016, 21:18
For real time rendering you might want to look into SVPFlow (http://forum.doom9.org/showthread.php?t=164554). That is what is was built for (i.e., real-time interpolation).

Groucho2004, thanks for those links. The second one, linking to StainlessS' code, is especially interesting.


yes, i do use svp, BUT, i do want slow motion..so, how do i do it..

Groucho2004
6th December 2016, 22:06
Here (https://www.dropbox.com/s/s63qy9spnfohnrw/str.mkv?dl=0) is a clip I have been using to test the slo-mo functions. Watch the motion estimation go nuts on the striped patterns. :D

johnmeyer
6th December 2016, 22:46
Here (https://www.dropbox.com/s/s63qy9spnfohnrw/str.mkv?dl=0) is a clip I have been using to test the slo-mo functions. Watch the motion estimation go nuts on the striped patterns. :DInteresting test case. I played around with it and, while certainly not perfect, I could live with the results of this script:


prefiltered = RemoveGrain(source,22)
super = MSuper(source,hpad=16, vpad=16, levels=1) # one level is enough for MRecalculate
superfilt = MSuper(prefiltered, hpad=16, vpad=16) # all levels for MAnalyse
backward = MAnalyse(superfilt, isb = true, blksize=16,overlap=4,search=3,dct=0)
forward = MAnalyse(superfilt, isb = false, blksize=16,overlap=4,search=3,dct=0)
forward_re = MRecalculate(super, forward, blksize=8, overlap=2, thSAD=100)
backward_re = MRecalculate(super, backward, blksize=8, overlap=2, thSAD=100)
output=MFlowFps(source,super, backward_re, forward_re, num=48000, den=1001,ml=200,mask=2)
output=output.selectodd()
interleave(source,output)


As you can see, I made sure that every other frame is an original, so you can easily see the merging and breaking of the stripes.

At the end of the clip, where she lowers her leg, the script does produce ghosting, although when played, this artifact will not look too bad, at least compared to the "morphological" artifacts that you get when the stripes break.

Groucho2004
6th December 2016, 23:12
Interesting test case. I played around with it and, while certainly not perfect, I could live with the results of this script
That's better than all my attempts. Very nice.

johnmeyer
7th December 2016, 00:02
That's better than all my attempts. Very nice.Thanks! Unfortunately, as you well know, this code will fail on some other clip. It's just the nature of the current state of the art, I guess.

StainlessS
7th December 2016, 00:36
Perhaps of use in testing.


Function ChangeFrameRate(clip c,Bool "Blend",Bool "Flow",Int "Num",Int "Den",
\ Bool "Prefilter",Bool "Chroma",Bool "Chroma1",Bool "Chroma2",
\ Int "BlkSize",Int "Recalc",
\ Int "OverLap",Int "OverLap1",Int "OverLap2",
\ Int "thSAD1",Int "thSAD2"
\ ) {
# Req MvTools2 v2.7.1.22+ for FINAL Overlap>0
Blend = Default(Blend,False) # Avoid blends at scene change (copy previous frame)
Flow = Default(Flow,False) # If True, Use MFlowFps instead of MBlockFps
n=Default(num,0) d=default(den,0) valid=(n>0 && d>0) n=(!valid)?c.FramerateNumerator*2:n d=(!valid)?c.FramerateDenominator:d # Default=doublerate
Prefilter=Default(Prefilter,True)
Chroma = Default(Chroma ,True)
Chroma1 = Default(Chroma1,True)
Chroma2 = Default(Chroma2,True)
BlkSize = Default(BlkSize,16)
Recalc = Default(Recalc,2) # 0 -> 2.
Overlap = Default(Overlap ,4)
Overlap1= Default(Overlap1,2)
Overlap2= Default(Overlap2,0)
thSAD1 = Default(thSAD1,100) # MRecalculate default is 200
thSAD2 = Default(thSAD2,100)
Assert(0 <= Recalc <=2,"ChangeFrameRate: 0 <= ReCalc <= 2")
super = c.MSuper(pel=2, hpad=BlkSize, vpad=BlkSize,rfilter=4,Levels=(0<Recalc)?1:0) # MRecalculate needs only 1 Level, MAnalyse needs all Levels
MAnal = (Prefilter) ? c.RemoveGrain(22).MSuper(hpad=BlkSize, vpad=BlkSize) : Super
bv = MAnal.MAnalyse(isb=true, chroma=Chroma, blksize=BlkSize, OverLap=OverLap , searchparam=3, search=3, badrange=(-24), plevel=0)
fv = MAnal.MAnalyse(isb=false, chroma=Chroma, blksize=BlkSize, OverLap=OverLap , searchparam=3, search=3, badrange=(-24), plevel=0)
bv = (0<ReCalc)?MRecalculate(super, chroma=Chroma1, bv, blksize=BlkSize/2, Overlap=OverLap1, searchparam=1, search=3, thSAD=thSAD1):bv
fv = (0<ReCalc)?MRecalculate(super, chroma=Chroma1, fv, blksize=BlkSize/2, Overlap=OverLap1, searchparam=1, search=3, thSAD=thSAD1):fv
bv = (1<ReCalc)?MRecalculate(super, chroma=Chroma2, bv, blksize=BlkSize/4, Overlap=OverLap2, searchparam=0, search=3, thSAD=thSAD2):bv
fv = (1<ReCalc)?MRecalculate(super, chroma=Chroma2, fv, blksize=BlkSize/4, Overlap=OverLap2, searchparam=0, search=3, thSAD=thSAD2):fv
Return (!Flow)
\ ? c.MBlockFps(super, bv, fv, num=n, den=d, Blend=Blend, mode=0)
\ : c.MFlowFps(super, bv, fv, num=n, den=d, Blend=Blend)
}


Function DoubleRate(clip c,Bool "Blend",Bool "Flow") {Return c.ChangeFrameRate(Blend,Flow,c.FramerateNumerator*2,c.FramerateDenominator)}

spoRv
7th December 2016, 01:47
Thanks a lot StainlessS; the blend variable is the perfect touch!

So, using your function, mine would be:

function slowmo(clip clip, int "mul") {
num=clip.FrameRateNumerator
den=clip.FrameRateDenominator
mul=default(mul,2)
clip.assumefps(num,den)
ChangeFrameRate(num=num*mul,den=den)
assumefps(num,den)
}

Right?

StainlessS
7th December 2016, 02:23
Something like this would do

Function slowmo(clip clip, int "mul") {
clip
mul=default(mul,2)
ChangeFrameRate(num=FrameRateNumerator*mul,den=FrameRateDenominator)
assumefps(clip.FrameRateNumerator,clip.FrameRateDenominator)
}

EDIT:
You can add other args to ChangeFrameRate() as deemed fit.

EDIT: I've changed post #21 numbering of Chroma, OverLap and thSAD args to be more sensible.

manolito
7th December 2016, 04:54
Just out of curiosity I converted Groucho's test clip to half speed using the old MotionProtectedFPS routine which uses the Motion.dll plugin by clouded.
Download the result here:
http://www87.zippyshare.com/v/bHByFhAB/file.html

Background:
Some time ago I worked with MrC (author of AVStoDV) on the implementation of a motion protected fps conversion routine. After many tests I always came back to the above method because it always produced less and mainly less annoying artifacts than the MVFlowFPS based routines.

Of course there are more elaborate FPS converting routines like the one by Stainless, but at this time the point was to keep it as simple and fast as possible.

I find the result of MotionProtectedFPS very pleasing to watch, but then again I can only watch it on a mediocre laptop display and on a CRT TV. How does my conversion compare to the other scripts posted so far?


Cheers
manolito

pinterf
7th December 2016, 08:44
Even though there is a version of MVTools2 (out of way too many floating around) that can make use of avstp.dll, all newer versions by Fizick and pinterf are not multi-threaded
I'm not using avstp but since my mod is partly originated from 2.6.0.5, avstp would work with it, at least I haven't removed this feature.

Groucho2004
7th December 2016, 10:12
I'm not using avstp but since my mod is partly originated from 2.6.0.5, avstp would work with it, at least I haven't removed this feature.
Hm, I did not even try that. Anyway, multi-threading by using avstp is unfortunately not very efficient so it's better to use AVS+ or SEt's AVSMT for that.

StainlessS
7th December 2016, 18:56
but at this time the point was to keep it as simple and fast as possible.

You could set defaults Prefilter=False, Recalc=0, and perhaps Overlap=0 Chroma=false, for speed (Flow =true/false depending upon preference).
I dont know best settings for Chroma, Overlap and thSAD args, someone needs to do tests and make suggestions for better defaults for specific purpose,
ie speed or quality.
Purpose of function was to make testing easier without having to have a dozen or more different functions.
There is little unnecessary overhead in the function, perhaps a little in the pre frame serving stage only (during filter graph construction,
maybe a few milliseconds).

manolito
8th December 2016, 14:31
Many hours later I have some interesting test results...

The test results can be downloaded here:
https://we.tl/0JWNRaj3nj

I used two source files. The first one comes from Groucho, the other one is a very demanding anime clip. I converted both sources to SD resolution so my slow computer could play them.

For the conversion I used three scripts:
1. The original MotionProtectedFPS script
2. The script by StainlessS from the top of this page
3. The script by JohnMeyer from post #18 in this thread

For the StainlessS script I had to install the older MVTools2 v2.5.11.22 because the current pinterf mods do not like my non-SSE2 CPU. I did not get any errors using the default values so I think everything was OK.

For the JohnMeyer script I removed the little dirty trick to interleave the result with the source.


For all three scripts I also tried to convert the source to twice the source fps, but this was not helpful. The resulting clips were not smoother, and the motion artifacts were even more prominent.

Speed was very similar for the scripts. MotionProtectedFPS clocked in at 1.7fps, StainlessS was 1.5fps, and JohnMeyer came in at 1.4fps. Not too significant.


Now for the quality:
Motion artifacts cannot be avoided for these methods, the question is how unpleasant these artifacts are.

MotionProtectedFPS:
Lot of ghosting on the girl's leg for Groucho's clip. The anime clip is very critical at 1min 55sec. The vertical edges of the grill do have considerable warping artifacts.

StainlessS:
No difference for Groucho's clip. The anime clip does look slightly better.

JohnMeyer:
By far the least motion artifacts. BUT...
For both clips during the first 10 seconds there is some horrible motion judder. I have no idea if this can be fixed by different params for the backward motion vectors. The judder disappears completely after the first 10 seconds, so there should be a way to treat the beginning of a clip differently from the rest. Don't know...


Cheers
manolito

johnmeyer
8th December 2016, 18:49
JohnMeyer:
By far the least motion artifacts. BUT...
For both clips during the first 10 seconds there is some horrible motion judder. I have no idea if this can be fixed by different params for the backward motion vectors. The judder disappears completely after the first 10 seconds, so there should be a way to treat the beginning of a clip differently from the rest. Don't know...
oConverting the video to SD pretty much invalidates everything else you did because it changes how the tools work (see my post a few years ago about bugs in some versions of MVTools2 when used with certain resolutions). It also may have introduced other issues.

Before I submitted my script code earlier in this thread, I tuned it using the original HD clip. I can assure you that there was absolutely zero judder. Groucho2004 also tried the code and had some nice things to say, and didn't report any judder.

So, I suspect that whatever you used to change the resolution ended up screwing up the video.

johnmeyer
8th December 2016, 19:13
I created some video from the "torture test" clip. I used exactly the script I already posted, but addedassumefps(24.0 * 1000.0 / 1001.0)to the end so that the result was slow motion. I used Cineform for the codec.

Here's the link to resulting the 67 MB clip:

50% Slo-Mo test using "torture clip" (https://www.mediafire.com/?aj871mrbrf8m1qe)

Groucho2004
8th December 2016, 19:51
JohnMeyer:
By far the least motion artifacts. BUT...
For both clips during the first 10 seconds there is some horrible motion judder.
I suspect that you have a mistake in the script, I can't reproduce the "judder" from your sample clips. Wrapping John's code into a slo-mo function would look like this:
AVISource("str.avi")
SloMo(multi = 2)

function SloMo(clip source, int "multi")
{
org_num = FramerateNumerator(source)
org_den = FramerateDenominator(source)
multi = default(multi, 2)

prefiltered = RemoveGrain(source, 22)
super = MSuper(source, hpad = 16, vpad = 16, levels = 1) # one level is enough for MRecalculate
superfilt = MSuper(prefiltered, hpad = 16, vpad = 16) # all levels for MAnalyse
backward = MAnalyse(superfilt, isb = true, blksize = 16, overlap = 4, search = 3, dct = 0)
forward = MAnalyse(superfilt, isb = false, blksize = 16, overlap = 4, search = 3, dct=0)
forward_re = MRecalculate(super, forward, blksize = 8, overlap = 2, thSAD = 100)
backward_re = MRecalculate(super, backward, blksize = 8, overlap = 2, thSAD = 100)
multiclip = MFlowFps(source, super, backward_re, forward_re, num = org_num * multi, den = org_den, ml = 200, mask = 2)
out = AssumeFPS(multiclip, org_num, org_den)

return out
}

Groucho2004
8th December 2016, 19:58
I used Cineform for the codec.[/URL]I can't find a standalone codec/decoder for this.

johnmeyer
8th December 2016, 20:01
I can't find a standalone codec/decoder for this.It used to be easy to get, but since GoPro bought Cineform, they bundled the codec into their "Cineform Studio" free editor.

I can encode and then upload using a different codec. Which one would you suggest?

Groucho2004
8th December 2016, 22:20
I can encode and then upload using a different codec. Which one would you suggest?
UTVideo or, if that results in a too large file, x264 (MKV) with a low CRF like 12-14.

StainlessS
8th December 2016, 22:23
Thank you Mani,
No surprise that JohnMeyer is the king, pin, I suspected it all the long :)
I tried my best to amalgamate what was considered 'bestish', I think pretty much all tests talked about could be included in the test function that I provided,
We are waiting for Mani's test :) *You still got a lovely smile Mani, I suspect that it is not really yours).

Mani, test alternative switches in the StainleSSS, thing, what you like best ?

(The StainlessS thing is just all of the others, mixed together)

johnmeyer
9th December 2016, 01:34
I must be having a senior moment because I'm not sure where to get the MKV codec so I can encode from within VirtualDub. Is this the right place?

http://www.mkvcodec.com/

Groucho2004
9th December 2016, 03:18
I must be having a senior moment because I'm not sure where to get the MKV codec so I can encode from within VirtualDub. Is this the right place?

http://www.mkvcodec.com/
MKV is just a container. With x264 you can directly encode the script and wrap the elementary stream in a MKV. Just specify the extension .mkv for the output file.
As for VDub - The only encoding I do with VDub is to UTVideo, I prefer using the command line. However, there is an option to use external command line encoders like x264 but I have never used it. I hope someone more knowledgable than me can provide better guidance.

manolito
9th December 2016, 09:36
I suspect that you have a mistake in the script, I can't reproduce the "judder" from your sample clips. Wrapping John's code into a slo-mo function would look like this:

You may call me "AviSynth challenged", but I have been around long enough to be able to wrap a script into a function, thank you very much... :D:D

After a lot of more tests I finally found the stupid culprit. It was DirectShowSource (which I used just for laziness - I am integrating the routine into a universal speed conversion tool which I made for some musician friends, and everyone has DirectShowSource).

Anyway, johnmeyer's script seems to do a lot more seeking than the other scripts. Now I use DSS2Mod with a preroll value of 15, and the judder is completely gone...


@ StainlessS
Sorry so far I did not find any time to play with the params in your script. I don't even know if I will do it at all, because johnmeyer's script just works beautifully with all the clips I tried so far.


@ johnmeyer
Converting the video to SD pretty much invalidates everything else you did because it changes how the tools work (see my post a few years ago about bugs in some versions of MVTools2 when used with certain resolutions). It also may have introduced other issues.

Before I submitted my script code earlier in this thread, I tuned it using the original HD clip. I can assure you that there was absolutely zero judder. Groucho2004 also tried the code and had some nice things to say, and didn't report any judder.

So, I suspect that whatever you used to change the resolution ended up screwing up the video.

No, it didn't. I used Spline36Resize which is very neutral and encoded with HCenc at a bitrate of 8500 and the highest quality settings. I use Fizick's latest MVTools version.

Well, the issue is solved... :o
I do have a different philosophy on these things. I do not care this much about HD and UHD resolutions, for my aging eyes DVD resolution is all I need. And the inherent problems for motion protected FPS conversions are the same for HD and SD.

And then I certainly have no use for an FPS converter which needs to be fine tuned for every source. An FPS converter is not a creative or artistic tool like a lot of other filters. It just has to get the job done without introducing any (or at least as few as possible) artifacts. And its settings should work well for all sources.

For me your script does just that, it works way better than the other scripts I tested. Thanks a lot for sharing it.

BTW I just saw that you are from California. I hope that the rainy season hasn't started yet. I get a little homesick for Santa Cruz, I haven't been there in a couple of years... ;)


Cheers
manolito

amayra
9th December 2016, 12:07
so this script is like FrameTools (https://github.com/gdiaz384/frameTools) ?

manolito
9th December 2016, 15:34
No, I cannot see any similarities...

Cheers

manolito
9th December 2016, 15:39
Here is the little Speed Changing tool I was talking about. Download here:
https://files.videohelp.com/u/172211/ChangeSpeed.zip

I made it a while ago for a musician friend who needed this to slow down music clips while preserving the pitch so he could learn the songs more easily.

It is rough and ugly, but it does what it was intended for. Right now I integrated johnmeyer's FPS conversion script plus I updated all the tools.

Have fun...

Cheers
manolito

johnmeyer
9th December 2016, 17:59
Anyway, johnmeyer's script seems to do a lot more seeking than the other scripts. Now I use DSS2Mod with a preroll value of 15, and the judder is completely gone...

... And the inherent problems for motion protected FPS conversions are the same for HD and SD.
I'd be interested to know what you meant by "seeking." I'd love to make it run faster.

As for your second statement, it it generally correct, but it also is misleading for two reasons. The first I already mention: there is a bug in some version of MVTools2 which only shows up at certain resolutions. The second reason is that the block sizes you choose are going to depend on the resolution. To illustrate, if you had a video that was only 16x16 pixels, a block size of 16 would not do much for you. Put another way, the block size needs to be chosen with some thought to the size of the "structures" you are attempting to track. As you increase the number of pixels used to represent the same scene, the block size (and overlap) probably have to be increased.

Groucho2004
9th December 2016, 18:05
I'd be interested to know what you meant by "seeking." I'd love to make it run faster.
It means that MVTools requests frames in a non-linear fashion in this script. The source filter has to provide past and future frames relative to the current frame. DirectShowSource is notorious for choking on non-linear frame requests and should be avoided if possible.

johnmeyer
9th December 2016, 18:28
Thanks for the clarification, Groucho2004. Is there any way to control this? I guess I've heard of this before because there is a "Requestlinear" statement that is available with some AVISynth filters.

manolito
9th December 2016, 20:25
The second reason is that the block sizes you choose are going to depend on the resolution. To illustrate, if you had a video that was only 16x16 pixels, a block size of 16 would not do much for you. Put another way, the block size needs to be chosen with some thought to the size of the "structures" you are attempting to track. As you increase the number of pixels used to represent the same scene, the block size (and overlap) probably have to be increased.

Yes, I see your point. But the values for block size and overlap you used in your script do work very well for all the SD clips I tested so far. Looks like you hit the sweet spot...

But even if there is a linear relation between the source resolution and the optimum block size and overlap, shouldn't it be possible to automatically pick the optimal values? AviSynth knows the source frame size.

My main use for motion protected fps conversion is not slo-mo, it is standard conversion between NTSC and PAL. The usual methods all have their flaws. PAL folks often have not much tolerance for repeated or dropped fields. Right now I am running a torture NTSC -> PAL conversion where the source is truly interlaced (Prince - The Hits). The usual method introduces some judder (bob deinterlace, changeFPS, resize and reinterlace). What I am trying now is same rate deinterlace, resize and convert framerate to progressive 25 fps using your script.

I already tried this a while ago using MotionProtectedFPS, the result was not bad at all, but still too many artifacts. I am very curious how this conversion using your script will come out.


Cheers
manolito

Groucho2004
9th December 2016, 21:42
Thanks for the clarification, Groucho2004. Is there any way to control this? I guess I've heard of this before because there is a "Requestlinear" statement that is available with some AVISynth filters.
If you're using a decent source filter with frame accurate seeking you should usually not need helper functions like RequestLinear. I never needed it, even with multi-threaded QTGMC().

manolito
10th December 2016, 14:43
Right now I am running a torture NTSC -> PAL conversion where the source is truly interlaced (Prince - The Hits Collection - US release). The usual method introduces some judder (bob deinterlace, changeFPS, resize and reinterlace). What I am trying now is same rate deinterlace, resize and convert framerate to progressive 25 fps using your script.

I already tried this a while ago using MotionProtectedFPS, the result was not bad at all, but still too many artifacts. I am very curious how this conversion using your script will come out.

This conversion took a long time on my ancient desktop machine at 1.5 fps, but it was worth it. The source is very demanding, and my older MotionProtectedFPS conversion displayed a lot of artifacts. Not too annoying, but still. Especially the end credits with vertically moving letters looked bad.

And now this conversion using johnmeyer's script does not have any of these artifacts. Near perfect, even the end credits. I think that for motion protected fps conversions this script is all you can ask for. It will certainly replace the MotionProtectedFPS routine for me.


Thanks and cheers
manolito

StainlessS
10th December 2016, 17:56
Ok, here mod of previous test function + a bit more.
Modded to be (I think) by default, same as JohnMeyer's offering, with exception of SearchParam in MRecalculate which is dropped down from 3 in MAnalyse (default 2),
down to 1. Flow default changed to True. Recalc to 1.
Also added Flow_ml and Block_Mode args.
Maybe someone like to test for modified SearchParam.

Also, Added John's Interleave original frames jiggery pokery [implemented in MulRate()] and works also with frames multiplier greater than 2.


Function ChangeFrameRate(clip c,Bool "Blend",Bool "Flow",Int "Num",Int "Den",
\ Bool "Prefilter",Bool "Chroma",Bool "Chroma1",Bool "Chroma2",
\ Int "BlkSize",Int "Recalc",
\ Int "OverLap",Int "OverLap1",Int "OverLap2",
\ Int "thSAD1",Int "thSAD2",
\ Float "Flow_ml",
\ Int "Block_Mode"
\ ) {
# Req MvTools2 v2.7.1.22+ for FINAL Overlap>0
Blend = Default(Blend,False) # Avoid blends at scene change (copy previous frame)
Flow = Default(Flow,True) # If True, Use MFlowFps instead of MBlockFps
n=Default(num,0) d=default(den,0) valid=(n>0 && d>0) n=(!valid)?c.FramerateNumerator*2:n d=(!valid)?c.FramerateDenominator:d # Default=doublerate
Prefilter=Default(Prefilter,True)
Chroma = Default(Chroma ,True)
Chroma1 = Default(Chroma1,True)
Chroma2 = Default(Chroma2,True)
BlkSize = Default(BlkSize,16)
Recalc = Default(Recalc,1) # 0 -> 2.
Overlap = Default(Overlap ,4)
Overlap1= Default(Overlap1,2)
Overlap2= Default(Overlap2,0)
thSAD1 = Default(thSAD1,100) # MRecalculate default is 200
thSAD2 = Default(thSAD2,100)
Flow_ml = Float(Default(Flow_ml,200.0))
Block_Mode=Default(Block_Mode,0) # 0 (Fastest, default) -> 5(debug)
Assert(0 <= Recalc <=2,"ChangeFrameRate: 0 <= ReCalc <= 2")
super = c.MSuper(pel=2, hpad=BlkSize, vpad=BlkSize,rfilter=4,Levels=(0<Recalc)?1:0) # MRecalculate needs only 1 Level, MAnalyse needs all Levels
MAnal = (Prefilter) ? c.RemoveGrain(22).MSuper(hpad=BlkSize, vpad=BlkSize) : Super
bv = MAnal.MAnalyse(isb=true, chroma=Chroma, blksize=BlkSize, OverLap=OverLap , search=3, searchparam=3, badrange=(-24), plevel=0)
fv = MAnal.MAnalyse(isb=false, chroma=Chroma, blksize=BlkSize, OverLap=OverLap , search=3, searchparam=3, badrange=(-24), plevel=0)
bv = (0<ReCalc)?MRecalculate(super, chroma=Chroma1, bv, blksize=BlkSize/2, Overlap=OverLap1, search=3, searchparam=1, thSAD=thSAD1):bv
fv = (0<ReCalc)?MRecalculate(super, chroma=Chroma1, fv, blksize=BlkSize/2, Overlap=OverLap1, search=3, searchparam=1, thSAD=thSAD1):fv
bv = (1<ReCalc)?MRecalculate(super, chroma=Chroma2, bv, blksize=BlkSize/4, Overlap=OverLap2, search=3, searchparam=0, thSAD=thSAD2):bv
fv = (1<ReCalc)?MRecalculate(super, chroma=Chroma2, fv, blksize=BlkSize/4, Overlap=OverLap2, search=3, searchparam=0, thSAD=thSAD2):fv
Return (!Flow)
\ ? c.MBlockFps(super, bv, fv, num=n, den=d, Blend=Blend, mode=Block_Mode)
\ : c.MFlowFps(super, bv, fv, num=n, den=d, Blend=Blend, ml =Flow_ml)
}

Function MulRate(clip c,Bool "Blend",Bool "Flow",int "mul",Bool "ILeave") {
Function MulRate_EvS(String s,int n,int mul) {
s=(s!="")?","+s:s
s="SelectEvery("+String(mul)+","+String(n)+")"+s
# RT_DebugF("s='%s'",s,name="MulRate: ")
return (n>1)?MulRate_EvS(s,n-1,mul):s
}
c
mul=default(mul,2)
Ileave=Default(Ileave,True)
ChangeFrameRate(Blend,Flow,c.FramerateNumerator*mul,c.FramerateDenominator)
(ILeave&&mul>=2) ? Eval("Interleave(c,"+MulRate_EvS("",mul-1,mul)+")") : NOP
Return Last
}

Function DoubleRate(clip c,Bool "Blend",Bool "Flow",Bool "ILeave") { return c.MulRate(Blend,Flow,2,ILeave) }

Function SlowMo(clip c,Bool "Blend",Bool "Flow", int "mul",Bool "ILeave") {
c
MulRate(Blend,Flow,mul,ILeave)
Return Last.assumefps(c.FrameRateNumerator,c.FrameRateDenominator)
}



client

AVISource("D:\SlowMoTester.mkv.AVI")

SlowMo(mul=2,iLeave=True) # Double framecount, Interleave (EDIT: replace with) original frames every even frame.


EDIT: Blend=False, unlike John's default true, I refuse to use blend mode (change yourself if you prefer not being able to detect scene changes).

EDIT: On-site edit broke script, fixed.

Creates some weird warping if you set mul to 10.

manolito
11th December 2016, 10:06
Thanks StainlessS for the new script. Very nifty scripting. especially the MulRate function for the ILeave thing, you are a real AviSynth wiz... :cool:

I did a few tests already, the source was the most critical section of my Anime clip.

Results:
johnmeyer's script still gets my top rating.

Yours is very close, probably no visual difference with natural film. But still the artifacts on this vertical grill are a little more prominent. The Blend and ILeave variables made no difference at all to my eyes.

And MotionProtectedFPS is just not competetive any longer... :devil:

Download the resulting clips here:
http://www47.zippyshare.com/v/lJmnElOu/file.html


Cheers
manolito

johnmeyer
11th December 2016, 17:00
Just a note to anyone who does their own comparisons: you have to tune the script to get good results. I am flattered that "my script" produces good results, but that is mostly due to the fact that I spent ten minutes trying dozens of different settings (block size, overlap, threshholds, etc.) until I got a good result. I then posted the script with those settings. I suspect that you might get equal -- or perhaps better -- results with some of the other scripts if you did similar tuning yourself.

More to the point: don't think that my script is some sort of slow-motion panacea. It too will produce worse results than will some other scripts when fed a different test case.

StainlessS
11th December 2016, 19:09
Very nifty scripting
I'de swap it all to have a smile like your Mani :D

StainlessS
12th December 2016, 18:17
OK, nuther tester.
Added all args to higher level funcs, Added SearchParam args and changed defaults slightly, seems to me that old SearchParam = 0 (recalc=2) might be a NOP (not sure how implemented).
Should SearchParam be based on current MAnaylse/Recalc OverLap ??? (search==3=Exhastive search, where SearchParam=Radius and square side=2*Radius+1).

here mod:

Function ChangeFrameRate(clip c,Bool "Blend",Bool "Flow",Int "Num",Int "Den",
\ Bool "Prefilter",Bool "Chroma",Bool "Chroma1",Bool "Chroma2",
\ Int "BlkSize",Int "Recalc",
\ Int "OverLap",Int "OverLap1",Int "OverLap2",
\ Int "SearchParam",Int "SearchParam1",Int "SearchParam2",
\ Int "thSAD1",Int "thSAD2",
\ Float "Flow_ml",
\ Int "Block_Mode"
\ ) {
# Req MvTools2 v2.7.1.22+ for FINAL Overlap>0
Blend = Default(Blend,False) # Avoid blends at scene change (copy previous frame)
Flow = Default(Flow,True) # If True, Use MFlowFps instead of MBlockFps
n=Default(num,0) d=default(den,0) valid=(n>0 && d>0) n=(!valid)?c.FramerateNumerator*2:n d=(!valid)?c.FramerateDenominator:d # Default=doublerate
Prefilter=Default(Prefilter,True)
Chroma = Default(Chroma ,True)
Chroma1 = Default(Chroma1,True)
Chroma2 = Default(Chroma2,True)
BlkSize = Default(BlkSize,16)
Recalc = Default(Recalc,1) # 0 -> 2.
Assert(0 <= Recalc <=2,"ChangeFrameRate: 0 <= ReCalc <= 2")
Overlap = Default(Overlap ,4)
Overlap1 = Default(Overlap1,2)
Overlap2 = Default(Overlap2,0)
SearchParam = Default(SearchParam ,Recalc==2?3:2) # MAnalyse default (as John's default) = 2 (presume MRecalculate same, not doc'ed)
SearchParam1 = Default(SearchParam1,Recalc==2?2:1) # Search==3=Exhaustive search, where SearchParam=Radius, square side = 2*Radius+1
SearchParam2 = Default(SearchParam2, 1 ) # From above, SearchParam of 0, seems like might be useless NOP (not sure).
thSAD1 = Default(thSAD1,100) # MRecalculate default is 200
thSAD2 = Default(thSAD2,100) # ditto
Flow_ml = Float(Default(Flow_ml,200.0)) # MFlowFPS default is 100.0
Block_Mode = Default(Block_Mode,0) # 0 (Fastest, default) -> 5(debug)
super = c.MSuper(pel=2, hpad=BlkSize, vpad=BlkSize,rfilter=4,Levels=(0<Recalc)?1:0) # MRecalculate needs only 1 Level, MAnalyse needs all Levels
MAnal = (Prefilter) ? c.RemoveGrain(22).MSuper(hpad=BlkSize, vpad=BlkSize) : Super
bv = MAnal.MAnalyse(isb=true, chroma=Chroma, blksize=BlkSize, OverLap=OverLap , search=3, searchparam=SearchParam, badrange=(-24), plevel=0)
fv = MAnal.MAnalyse(isb=false, chroma=Chroma, blksize=BlkSize, OverLap=OverLap , search=3, searchparam=SearchParam, badrange=(-24), plevel=0)
bv = (0<ReCalc)?MRecalculate(super, chroma=Chroma1, bv, blksize=BlkSize/2, Overlap=OverLap1, search=3, searchparam=SearchParam1, thSAD=thSAD1):bv
fv = (0<ReCalc)?MRecalculate(super, chroma=Chroma1, fv, blksize=BlkSize/2, Overlap=OverLap1, search=3, searchparam=SearchParam1, thSAD=thSAD1):fv
bv = (1<ReCalc)?MRecalculate(super, chroma=Chroma2, bv, blksize=BlkSize/4, Overlap=OverLap2, search=3, searchparam=SearchParam2, thSAD=thSAD2):bv
fv = (1<ReCalc)?MRecalculate(super, chroma=Chroma2, fv, blksize=BlkSize/4, Overlap=OverLap2, search=3, searchparam=SearchParam2, thSAD=thSAD2):fv
Return (!Flow)
\ ? c.MBlockFps(super, bv, fv, num=n, den=d, Blend=Blend, mode=Block_Mode)
\ : c.MFlowFps(super, bv, fv, num=n, den=d, Blend=Blend, ml =Flow_ml)
}

Function MulRate(clip c,Bool "Blend",Bool "Flow",int "mul",Bool "ILeave",
\ Bool "Prefilter",Bool "Chroma",Bool "Chroma1",Bool "Chroma2",Int "BlkSize",Int "Recalc", Int "OverLap",Int "OverLap1",Int "OverLap2",
\ Int "SearchParam",Int "SearchParam1",Int "SearchParam2",Int "thSAD1",Int "thSAD2",Float "Flow_ml",Int "Block_Mode") {
Function MulRate_EvS(String s,int n,int mul) {
s="SelectEvery("+String(mul)+","+String(n)+")"+((s!="")?","+s:s)
# RT_DebugF("s='%s'",s,name="MulRate: ")
return (n>1)?MulRate_EvS(s,n-1,mul):s
}
c
mul=default(mul,2)
Ileave=Default(Ileave,True)
ChangeFrameRate(Blend,Flow,c.FramerateNumerator*mul,c.FramerateDenominator,Prefilter,Chroma,Chroma1,Chroma2,BlkSize,Recalc,
\ OverLap,OverLap1,OverLap2,SearchParam,SearchParam1,SearchParam2,thSAD1,thSAD2,Flow_ml,Block_Mode)
(ILeave&&mul>=2) ? Eval("Interleave(c,"+MulRate_EvS("",mul-1,mul)+")") : NOP
Return Last
}

Function DoubleRate(clip c,Bool "Blend",Bool "Flow",Bool "ILeave",
\ Bool "Prefilter",Bool "Chroma",Bool "Chroma1",Bool "Chroma2",Int "BlkSize",Int "Recalc", Int "OverLap",Int "OverLap1",Int "OverLap2",
\ Int "SearchParam",Int "SearchParam1",Int "SearchParam2",Int "thSAD1",Int "thSAD2",Float "Flow_ml",Int "Block_Mode") {
return c.MulRate(Blend,Flow,2,ILeave,Prefilter,Chroma,Chroma1,Chroma2,BlkSize,Recalc,
\ OverLap,OverLap1,OverLap2,SearchParam,SearchParam1,SearchParam2,thSAD1,thSAD2,Flow_ml,Block_Mode)
}

Function SlowMo(clip c,Bool "Blend",Bool "Flow", int "mul",Bool "ILeave",
\ Bool "Prefilter",Bool "Chroma",Bool "Chroma1",Bool "Chroma2",Int "BlkSize",Int "Recalc", Int "OverLap",Int "OverLap1",Int "OverLap2",
\ Int "SearchParam",Int "SearchParam1",Int "SearchParam2",Int "thSAD1",Int "thSAD2",Float "Flow_ml",Int "Block_Mode") {
c
MulRate(Blend,Flow,mul,ILeave,Prefilter,Chroma,Chroma1,Chroma2,BlkSize,Recalc,
\ OverLap,OverLap1,OverLap2,SearchParam,SearchParam1,SearchParam2,thSAD1,thSAD2,Flow_ml,Block_Mode)
Return Last.assumefps(c.FrameRateNumerator,c.FrameRateDenominator)
}


Client

AVISource("D:\SlowMoTester.mkv.AVI")

#DoubleRate(ILeave=True,Recalc=1)

SlowMo(mul=2,iLeave=True,ReCalc=1) # Double framecount, Interleave (replace with) original frames every even frame, 1 instance of MRecalculate.


EDIT: Mani, Blend only matters at scene change (1st frame of scene NOT blended, copied from End Of Scene frame, when Blend=False).

manolito
13th December 2016, 08:43
Thanks for the update, but IMO it's still not completely there yet...

Test result:
http://www16.zippyshare.com/v/b0eFhc3u/file.html

I only judge the result by the warping artifacts on those vertical edges of the grill to the right of the clip. John Meyer's result has fewer artifacts.

I kept all the defaults for JM and for your script. Encoding by X264 at CRF 20.

I also simplified your script to be just an FPS converter because this is all I need:

Function StainlessS_fps(clip c, float "fps") {
# Req MvTools2 v2.7.1.22+ for FINAL Overlap>0
fps = default(fps, 25.000)
fps_num = int(fps * 1000)
fps_den = 1000
Blend = False # Avoid blends at scene change (copy previous frame)
Flow = True # If True, Use MFlowFps instead of MBlockFps
Prefilter = True
Chroma = True
Chroma1 = True
Chroma2 = True
BlkSize = 16
Recalc = 1 # 0 -> 2.
Assert(0 <= Recalc <=2,"ChangeFrameRate: 0 <= ReCalc <= 2")
Overlap = 4
Overlap1 = 2
Overlap2 = 0
SearchParam = Recalc==2?3:2 # MAnalyse default (as John's default) = 2 (presume MRecalculate same, not doc'ed)
SearchParam1 = Recalc==2?2:1 # Search==3=Exhaustive search, where SearchParam=Radius, square side = 2*Radius+1
SearchParam2 = 1 # From above, SearchParam of 0, seems like might be useless NOP (not sure).
thSAD1 = 100 # MRecalculate default is 200
thSAD2 = 100 # ditto
Flow_ml = Float(200.0) # MFlowFPS default is 100.0
Block_Mode = 0 # 0 (Fastest, default) -> 5(debug)
super = c.MSuper(pel=2, hpad=BlkSize, vpad=BlkSize,rfilter=4,Levels=(0<Recalc)?1:0) # MRecalculate needs only 1 Level, MAnalyse needs all Levels
MAnal = (Prefilter) ? c.RemoveGrain(22).MSuper(hpad=BlkSize, vpad=BlkSize) : Super
bv = MAnal.MAnalyse(isb=true, chroma=Chroma, blksize=BlkSize, OverLap=OverLap, search=3, searchparam=SearchParam, badrange=(-24), plevel=0)
fv = MAnal.MAnalyse(isb=false, chroma=Chroma, blksize=BlkSize, OverLap=OverLap, search=3, searchparam=SearchParam, badrange=(-24), plevel=0)
bv = (0<ReCalc)?MRecalculate(super, chroma=Chroma1, bv, blksize=BlkSize/2, Overlap=OverLap1, search=3, searchparam=SearchParam1, thSAD=thSAD1):bv
fv = (0<ReCalc)?MRecalculate(super, chroma=Chroma1, fv, blksize=BlkSize/2, Overlap=OverLap1, search=3, searchparam=SearchParam1, thSAD=thSAD1):fv
bv = (1<ReCalc)?MRecalculate(super, chroma=Chroma2, bv, blksize=BlkSize/4, Overlap=OverLap2, search=3, searchparam=SearchParam2, thSAD=thSAD2):bv
fv = (1<ReCalc)?MRecalculate(super, chroma=Chroma2, fv, blksize=BlkSize/4, Overlap=OverLap2, search=3, searchparam=SearchParam2, thSAD=thSAD2):fv
Return (!Flow)
\ ? c.MBlockFps(super, bv, fv, num=fps_num, den=fps_den, Blend=Blend, mode=Block_Mode)
\ : c.MFlowFps(super, bv, fv, num=fps_num, den=fps_den, Blend=Blend, ml=Flow_ml)
}

The slowdown to half speed was done by "AssumeFPS(framerate / 2)" before calling the script.


Even if johnmeyer is adamant in requesting to find optimal parameters for every source, these params so far have given me the best results for every source I have tried. I experimented a lot using different values for block size and overlap, but the result was either the same or it was worse.

The remaining artifacts in my test clip using JM's script are probably not avoidable. At least I tried, but I could not get a better result.

And the StainlessS script is just a little bit worse. The new test script did not make any difference to the previous one BTW.
What does this comment mean?
Req MvTools2 v2.7.1.22+ for FINAL Overlap>0
Is the FINAL Overlap == Overlap2 ? The reason I ask is that I have to use the latest Fizick version of MVTools2, PinterF versions do not run on my machine.


Cheers
manolito

StainlessS
13th December 2016, 18:37
What does this comment mean?

Is the FINAL Overlap == Overlap2 ? The reason I ask is that I have to use the latest Fizick version of MVTools2, PinterF versions do not run on my machine.


In non pinterf version, Overlap cannot be non zero in vectors used in MBlockFPS, ie from final MRecalculate, or from MAnalyse if MRecalculate not used at all.
So, script will probably fail with your version MVTools if Flow=False.
[EDIT: Except if set Recalc=2, where Overlap2 defaults 0, OR if you set relevant OverlapN=0].

http://forum.doom9.org/showthread.php?p=1785781#post1785781

Also if you wanted easy interface but with all defaults could have created stub eg (untested)

Function Manolito_fps(clip c, float "fps") { fps=default(fps,25.0) num=int(fps*1000) Return ChangeFrameRate(c,num=num,den=1000) }


EDIT: For stub using eg Recalc=0 and Overlap=0, then just create new stub using non defaults, calling
ChangeFrameRate(..., Recalc=0,OverLap=0)

StainlessS
25th July 2018, 00:18
Mod of the fabled jm_fps, modded by Manolito and again a little by this humble soul.

JohnFPS.avs

Function JohnFPS(clip c,Val "num", int "den",int "Sharp",int "rFilter",Int "BlkSize",int "Search",int "dct",Float "ml",Int "Mask",Bool "Blend") {
/*
https://forum.doom9.org/showthread.php?p=1847109#post1847109
Motion Protected FPS converter script by JohnMeyer from Doom9
Slightly modified interface by Manolito, and a smidgen more by ssS.
Requires MVTools V2 and RemoveGrain
Also needs fftw3.dll in the System32 or SysWOW64 folder for Dct values other than 0
Specify FrameRate using num (Numerator) and den (Denominator)
num only, eg num=25.0, FrameRate = 25.0 FPS
num & den, eg num=24000 den=1001, FrameRate = 23.976 FPS (Both should be type Int).
neither specified FrameRate = Double input framerate.
*/
def = num.Defined ? (den.Defined ?1:0) : (!den.Defined) ? 2 : -1 # 0=NumOnlyDef, 1=BothDef, 2=NoneDef, -1=DenOnlyError
Assert(0<=def,"JohnFPS: Cannot specify framerate using den only")
# Rate=num : Rate=num/den : Rate=DoubleRate
n=(def==0) ? Round(num * 1000): (def==1) ? Int(num) : 2*c.FrameRateNumerator
d=(def==0) ? 1000 : (def==1) ? den : c.FrameRateDenominator
Sharp = Default(Sharp,1) # MSuper default = 2
rFilter= Default(rFilter,4) # MSuper default = 2
BlkSize= Default(BlkSize,16) # Manalyse default 8, Maybe 32 for HD
Search = Default(Search,3) # Manalyse default 4
dct = Default(dct,0) # Manalyse default 0, 1=Slow
ml = Default(ml,200.0) # MFlowFps default 100.0
Mask = Default(Mask,2) # MFlowFps default 2
Blend = Default(Blend,False) # MFlowFps default True
prefilt = c.RemoveGrain(22)
super = c.MSuper(hpad=16,vpad=16,levels=1,sharp=Sharp,rfilter=rFilter) # One level is enough for MRecalculate
superfilt= prefilt.MSuper(hpad=16,vpad=16,sharp=Sharp,rfilter=rFilter) # All levels for MAnalyse
bv = superfilt.MAnalyse(isb=true ,blksize=BlkSize,overlap=4,search=Search,dct=dct)
fv = superfilt.MAnalyse(isb=false,blksize=BlkSize,overlap=4,search=Search,dct=dct)
bv = super.MRecalculate(bv,blksize=8,overlap=2,thSAD=100)
fv = super.MRecalculate(fv,blksize=8,overlap=2,thSAD=100)
return c.MFlowFps( super,bv,fv,num=n,den=d,blend=Blend,ml=ml,mask=Mask)
}

EDIT: Update, add Blend arg.

One day they will sing the ballad of JohnFPS (unfortunately, the hero always dies in a horrible & painful way, well you cant have everything I suppose).

Sparktank
25th July 2018, 00:44
Can't wait to check out these mods.

Always looking for something new and fun :)

manolito
26th July 2018, 01:00
@ StainlessS

Nice mod you posted, I played a little bit with it, these are my 2 cents:

1. You exposed a lot more MVTools parameters in the function. Nice for users who like to play, I certainly don't need this.

2. The way you enabled either a float FPS value as a param or using int params for num and den is very nifty. This will make both camps happy. I really tried to break it, but I couldn't. Hats off...

3. Unsure about the "BadRange" param. I did a few conversions with the default "Search=3", either using "BadRange=-24" or omitting the BadRange parameter. The conversion results were bit identical in all cases, so I assume that MVTools is smart enough to use "-24" by default if "Search=3" is specified.


I also found that there are differences in the output depending on the method which gets used for specifying the target frame rate. Probably just rounding errrors, but still...

Using either
JohnFPS(60000/1001)
or
JohnFPS(60000, 1001)

results in very different outputs. I cannot say if one looked better than the other, but the method using num and den is definitely considerably faster.


Cheers
manolito


OT:
Your advice to not forget to bring my brolly for my recent motorcycle trip to Scotland was unjustified. Only great weather, no rain or drizzle at all. This was my third Scotland trip, and I never got wet up there... :D

StainlessS
26th July 2018, 08:53
BadRange,
Was little addition just before posting,based purely on docs suggestion, no harm to either remove or leave as is.

JohnFPS(60000/1001)
I hope you did something in test like

JohnFPS(60000/Float(1001))
JohnFPS(Float(60000)/1001)
JohnFPS(60000.0/1001)
JohnFPS(60000/1001.0)


but the method using num and den is definitely considerably faster.

Did not really expect that, but good to know (I tend to use num, den myself).

OT, you lucky lucky lad :)

StainlessS
26th July 2018, 09:24
Post #55 Update. Remove BadRange, added MFlowFPS Blend arg (defaulted false, EDIT:MFlowFPS default is true).

manolito
26th July 2018, 19:11
I hope you did something in test like

JohnFPS(60000/Float(1001))
JohnFPS(Float(60000)/1001)
JohnFPS(60000.0/1001)
JohnFPS(60000/1001.0)


No, I didn't. And this is exactly what I want to avoid no matter what. I do not want to have to specify a variable type when calling the function. This is just too prone to errors.

What if I change "Val" to "Float" in the function declaration for "num"? I think this should not break anything, but then you are the AviSynth wiz, not me... :D


Cheers
manolito

StainlessS
26th July 2018, 20:51
Val makes it explicit that the accepted type is variable, using Float would (as of v2.60) force type to float(even when client provided int), I did not want that.

An integer divided by an integer, produces an [EDIT: truncated] integer (BAD in this case)


Colorbars.killaudio.BilinearResize(320,240)
x=60000/1001
y=60000/1001.0
subtitle("x="+String(x)+" : y="+string(y))


https://s20.postimg.cc/6ccrfp8el/div.jpg (https://postimages.org/)

EDIT: So internally in function,
if provided with num arg as num=60000/1001.0, n=59940, d=1000,
whereas num=60000/1001, n=59000, d=1000 (wrong by nearly a whole frame per second).

EDIT:
I do not want to have to specify a variable type when calling the function. This is just too prone to errors.
But you do want to provide the correct arguments. Specifying float is not the requirement, but if its a floating point framerate that is required then you need to specifiy a floating point argument, not doing so is not just 'prone to errors', it is an error.

If you have previously generally not understood the 'Interger divide' thing, then you had best check all of your scripts for similar integer divide errors.

EDIT: Also this is WRONG, Float(60000/1001), is already wrong answer before converting to float.
Float / integer, and Integer / Float, both produce a float result (the integer is converted to float before divide), same with addition, subtraction, and multiplication.

Sparktank
26th July 2018, 20:56
This is awesome work!
I love it when mad scientists come together.

I am definitely going to start using this cript for converting videos.

SVP is fine for watching movies.
But this collaberated work is really what I'm looking for when converting clips of my favorite movies.

manolito
26th July 2018, 23:37
Alright Master StainlessS, I checked it, and of course you are right. :stupid:

I falsely assumed that AviSynth would parse an expression like "float(60000/1001)" from left to right and automatically treat the int arguments as float. But obviously it works the other way around. The integer division is executed first, and only then the truncated result is converted to float. I don't like it...


Cheers
manolito

wonkey_monkey
27th July 2018, 10:20
I falsely assumed that AviSynth would parse an expression like "float(60000/1001)" from left to right and automatically treat the int arguments as float. But obviously it works the other way around. The integer division is executed first, and only then the truncated result is converted to float. I don't like it...

It's perfectly cromulent. There is only one argument to float(), which is the value 60000/1001. And that is an integer, because you are dividing an integer by an integer, and so it is expected that you want to do integer division.

StainlessS
27th July 2018, 11:17
It's perfectly cromulent.
Nice to see that you are keeping abreast of the 'hip' new words entering dictionary, good man.
(I took it to mean something connected to eg 'Cromwellian' ).

assumed that AviSynth would parse an expression like "float(60000/1001)" from left to right and automatically ...
Most languages work in the same sort of way. If [B]Float is a function then whatever is in the parenthesis is the argument and without
any manipulation/substitution, if Float were to be implemented via parser, then as arg is in parenthesis, it would be evaluated prior to float conversion, both ways would produce same result. It would not be a very good idea for parsers to make assumptions about what is required.
EDIT: When doing mixed type arithmetic, one of the types has to be converted to the other (least precise to most precise) so
that you are not eg dividing apples by oranges [eg 60000/1000.0 ===>>> 60000.0/1001.0], and the result is that of the most precise type.I don't like it...
Get used to it :)

EDIT: To below: Now you are just showing off :)

wonkey_monkey
27th July 2018, 11:55
Nice to see that you are keeping abreast of the 'hip' new words entering dictionary, good man.


I'm always trying to embiggen my vocabulary.

StainlessS
27th July 2018, 12:02
OT
David, As noted elsewhere, TWriteAVI v2.0 (to x64) requires a CPP/ASM/Intrinsic programmer, I was just thinking maybe that
project might be right up your Straße [any thoughts ?].

EDIT: I saw somewhere that you were writing an assembler for x86.

EDIT: TWriteAVI v2.0, is an incredibly useful plug, and if implemented in x64 could be used as starting point for
many projects, eg Video Capture and the like. Even a plain C implementation of the ASM would be a huge plus.

wonkey_monkey
27th July 2018, 14:39
I'll take a look, but I probably won't be able to do anything. Where is the ASM in the source code? Off the top of my head, I can't think of a good reason for such a thing to need it...

manolito
27th July 2018, 20:16
Most languages work in the same sort of way. If Float is a function then whatever is in the parenthesis is the argument and without
any manipulation/substitution, if Float were to be implemented via parser, then as arg is in parenthesis, it would be evaluated prior to float conversion, both ways would produce same result. It would not be a very good idea for parsers to make assumptions about what is required.

Get used to it :)


Probably I am too much used to "simpler" languages which DO make assumptions about what the user wants.. :devil:
Like AutoIT which only offers the Variant type.

With this code:
#include <MsgBoxConstants.au3>
MsgBox($MB_SYSTEMMODAL, "Division", "60000/1001 = " & 60000/1001)

you get the following result:
http://i64.tinypic.com/sv5q1j.jpg


Cheers
manolito


//EDIT//
I also remember my old Turbo Pascal days where I learned right from the beginning to use "/" instead of "div" to get the "correct" result from an integer division. BTW who said that the result of a divsion between 2 integers has to be an integer again? Every second-grader knows that 3/2 is NOT 1, it is 1.5. This is just common sense, and I don't care what some old language designers once thought.

StainlessS
27th July 2018, 22:49
You have been told, ... learn :)

Bit messed up at the mo, will come back.

manolito
28th July 2018, 01:34
You have been told, ... learn :)


That's what I'm always trying to do...

Still not convinced, though. After an extended research session my conclusion is that a lot of this has historical reasons. At the time the C language was designed computers normally did not have a separate FPU, so a design goal was to keep integer math and floating point math strictly separate.

In our special case this means that the expression 60000 / 1001 is evaluated first with no regard to its outside encapsulation. The only way to get a float result is to type cast at least one of the operands to float.

I tried to analyze the "num" parameter in order to find a "/" character in it and then act accordingly. No chance, the input for my "FindStr" command always was the already evaluated integer value.

A nice summary can be found here:
https://en.wikipedia.org/wiki/Division_(mathematics)#Of_integers


So I prefer languages which will output the "correct" results for integer divisions, and in most cases this will be a float value. This is what an unsuspecting programmer like me would expect, just like the second-grader who is asked what the result of "3 / 2" is. If he answers "1" he will have failed the test.


Cheers
manolito

StainlessS
29th July 2018, 17:04
@DavidHorman,

OK, have converted TWriteAVI to VS2008 (fixed some vs2008 warnings):- https://forum.doom9.org/showthread.php?t=172837

Files with ASM embedded in CPP files

FastWriteStream.cpp // EDIT: was wrongly FastWriteStream.h
cpuaccel.cpp
misc.cpp
tls.cpp (disabled)


I'll take a look, but I probably won't be able to do anything. Where is the ASM in the source code? Off the top of my head, I can't think of a good reason for such a thing to need it...

Well, maybe you just want to create some test AVI files, TWriteAVI Included demo makes in one of the demos, 1000 test AVI's, you try doing that by hand.
Or, maybe create pre-processed QTGMC file, auto write to Lossless encoded AVI, and then continue script using the lossless as input.

Or Maybe you use SoundOut to produce audio file on disk, only problem is it is not available till some time later, with
ForceProcessWAV, is available on disk on return from function.

TWriteAVI's usefulness is limited only by your imagination :)

Have Supplied todays update version with full VS 2008 project files, even for x64 (which dont compile due to ASM presence).

Also added VERSION resource in todays update. [Right click, view Properties on dll]

StainlessS
29th July 2018, 17:22
So I prefer languages which will output the "correct" results for integer divisions, and in most cases this will be a float value. This is what an unsuspecting programmer like me would expect, just like the second-grader who is asked what the result of "3 / 2" is. If he answers "1" he will have failed the test.


Well you make some good points,
However, I like the way that AVS script works, (maybe because I'm a C and MC68000 ASM programmer), and it is perfectly acceptable to me that int / int produces an int, anything else is 'taking liberties' in my view. AutoIt's way of doing things is a little bit awkward and probably due to everything being a variant, it can sometimes be a problem to restrict AutoIt from making assumptions about what it required.
Anyways, it dont matter what either of us prefers, we have to stick with the language as it is, and not as we might like it to be,
but feel free to bellyache about it :)

EDIT:
the second-grader who is asked what the result of "3 / 2" is. If he answers "1" he will have failed the test.
1 remainder 1, might also be an acceptable answer.

wonkey_monkey
29th July 2018, 18:19
Well, maybe you just want to create some test AVI files, TWriteAVI Included demo makes in one of the demos, 1000 test AVI's, you try doing that by hand.
Or, maybe create pre-processed QTGMC file, auto write to Lossless encoded AVI, and then continue script using the lossless as input.

Or Maybe you use SoundOut to produce audio file on disk, only problem is it is not available till some time later, with
ForceProcessWAV, is available on disk on return from function.


I meant "why would it need inline ASM" - it didn't strike me as the kind of case that would need hand-optimised code.

StainlessS
29th July 2018, 18:42
OT, moved to TWriteAVI thread:- https://forum.doom9.org/showthread.php?p=1847647#post1847647