Log in

View Full Version : How to interpolate missing frames


P.J
23rd July 2016, 18:33
I have a prores video which has a missing frame after any 3 frames:

1 2 3 (4) 5 6 7 (8) 9 10 11 (12)...

Anyway to fix it? :confused:

poisondeathray
23rd July 2016, 19:07
One way would be to insert a "placeholder" frame every 4th frame, then replace with an interpolated frame

see this post
http://forum.videohelp.com/threads/352741-Frame-interpolation?p=2222196&viewfull=1#post2222196

wonkey_monkey
23rd July 2016, 22:10
Double the framerate using whatever method you prefer - SVPflow, Interframe, MVTools - then do:

selectevery(6, 0,2,4,5)

manono
24th July 2016, 08:03
I'd create duplicate frames to replace the missing ones and then use filldrops to replace them with interpolated frames (similar to pdr's method):

SelectEvery(3,0,1,2,2)# or whatever the exact cadence is
Filldrops()

http://forum.doom9.org/showthread.php?p=753779#post753779

http://forum.doom9.org/showthread.php?p=1493082#post1493082

johnmeyer
24th July 2016, 17:29
Using Selectevery() by itself will work, but only if you have absolutely no interruption in the drop cadence.

I totally agree with Manano, and do this sort of thing all the time. For instance, in this video I manually replaced all the "jump" frames with a duplicate of the previous frame. I then fed that to "FillDrops" and it created near-perfect video:

Restoration of Jumpy Film (https://www.youtube.com/watch?v=uzMFodrGHDs&list=PL230DED9513ECA2CB&index=2)

I too was going to suggest FillDrops:
function filldrops (clip c)
{
super=MSuper(c,pel=2)
vfe=manalyse(super,truemotion=true,isb=false,delta=1)
vbe=manalyse(super,truemotion=true,isb=true,delta=1)
filldrops = mflowinter(c,super,vbe,vfe,time=50)
fixed = ConditionalFilter(c, filldrops, c, "YDifferenceFromPrevious()", "lessthan", "0.1")
return fixed
}

I have a version (FillDropsI) for interlaced video. MugFunky wrote it, but I then updated it to use MVTools2 instead of the original MVTools. However, it was designed to replace a duplicate (or near duplicate), not insert a new frame. Thus, it will have to be modified.

You might find some very interesting code in the following thread I started a few years ago:

Automatically fix dups followed (eventually) by drops (http://forum.doom9.org/showthread.php?t=161758)

My video was the more typical scenario where the video had the correct number of frames, but had lots of dropped frames. To keep the audio in sync, the capture card or streaming service added duplicate frames, usually within 1-2 frames of the drop. Finding the duplicate frames was easy, but sensing where there was a drop was more difficult. Then, I had to come up with a way of creating the fixed video, within the constraints of how AVISynth works. Fortunately, Didée came up with a super-clever solution which I incorporated into the script that I presented in post #6 in that thread. You should look at that script and see if it can be adapted to your needs.

BTW, if you have all these drops, how is your audio staying in sync?? Usually, if frames get dropped, and there are not an equal number of duplicates, the audio and video end up being different lengths.

StainlessS
25th July 2016, 14:17
Might also want to take a look here [MorphDupes_MI(), for runs of dupes but can be limited to single dupe run]:- http://forum.doom9.org/showthread.php?p=1764865#post1764865

EDIT: Oops, fixed link (was to single post, linked script is in two parts).

EDIT: Set MaxInterp=1, th=0.0.

EDIT: Can jump about if required when viewing metrics.

P.J
31st July 2016, 20:32
Thanks all, will try them later :)

StainlessS
29th October 2021, 01:19
Mod to Mugfunky/JohnMeyer/Selur Filldrops()


#########################################################################################
#
# FillDrops.avsi
#
# An AviSynth filter to detect and replace duplicate frames
# with a motion-interpolation of the adjacent frames.
#
# mod 2021-07-10 by Selur
# mod 29 Oct 2021, Added ThreshIs8Bit arg. ssS. https://forum.doom9.org/showthread.php?p=1956020#post1956020
#
# - based on Mug Funky's FillDrops
# - FillDrops by johnmeyer on Doom9's forum
# https://forum.doom9.org/showthread.php?p=1775184#post1775184
# - mod by Selur to parametrize Luma Difference Threshold
# https://forum.videohelp.com/threads/402416-repair-Videos-with-duplicates-and-dropped-frames#post2624936
#
### Requirements ###
#-------------------
# Avs v2.60/+
# MvTools2 (https://github.com/pinterf/mvtools)
#
### Arguments ###
#-----------------
# thresh (default=0.1) - Luma Difference Threshold
# Lets you specify how different a frame has to be (from the previous frame)
# before it's considered not to be a duplicate, and therefore not replaced with a motion interpolated frame.
# If the threshold is too small, some duplicate will not be replaced.
# If it's too large, many frames which aren't duplicates (just having very small motions) will be replaced.
# (explanation by jagabo on VideoHelp)
#
# ---------------
# ThreshIs8Bit, Default False, If True and bit depth > 8 bit, then thresh is converted to current bit depth threshold.
### Changelog ###
#---------------
# Changed requirements: from MvTools to MvTools2 (johnmeyer)
# Parametrized Luma Difference Threshold (Selur)
# ssS: Added Bool arg "ThreshIs8Bit", default = False.
#########################################################################################

Function FillDrops(clip c, float "thresh",Bool "ThreshIs8Bit") {
thresh = Default(thresh, 0.1)
ThreshIs8Bit = Default(ThreshIs8Bit,False) # False = thresh is in current bit depth range
try { bpc=c.BitsPerComponent } catch(msg) { bpc=8 }
thresh = (ThreshIs8Bit) ? thresh * BitLShift(1,bpc-8) : thresh
#
super = MSuper(c, pel=2)
vfe = MAnalyse(super, truemotion=true, isb=false, delta=1)
vbe = MAnalyse(super, truemotion=true, isb=true, delta=1)
filldrops = MFlowInter(c, super, vbe, vfe, time=50)
fixed = ConditionalFilter(c, filldrops, c, "YDifferenceFromPrevious()", "lessthan", String(thresh))
return fixed
}

Function FilldropsI (clip c, float "thresh",Bool "ThreshIs8Bit") {
thresh = Default(thresh, 0.1)
ThreshIs8Bit = Default(ThreshIs8Bit,False) # False = thresh is in current bit depth range
try { bpc=c.BitsPerComponent } catch(msg) { bpc=8 }
thresh = (ThreshIs8Bit) ? thresh * BitLShift(1,bpc-8) : thresh
#
even = c.SeparateFields().SelectEven()
super_even=MSuper(even,pel=2)
vfe=manalyse(super_even,truemotion=true,isb=false,delta=1)
vbe=manalyse(super_even,truemotion=true,isb=true,delta=1)
filldrops_e = mflowinter(even,super_even,vbe,vfe,time=50)
odd = c.SeparateFields().SelectOdd()
super_odd=MSuper(odd,pel=2)
vfo=manalyse(super_odd,truemotion=true,isb=false,delta=1)
vbo=manalyse(super_odd,truemotion=true,isb=true,delta=1)
filldrops_o = mflowinter(odd,super_odd,vbo,vfo,time=50)
evenfixed = ConditionalFilter(even, filldrops_e, even, "YDifferenceFromPrevious()", "lessthan", String(thresh))
oddfixed = ConditionalFilter(odd, filldrops_o, odd, "YDifferenceFromPrevious()", "lessthan", String(thresh))
Interleave(evenfixed,oddfixed)
Weave()
}


You wanna update it on your github JKyle ?

EDIT:
Added arg, Bool "ThreshIs8Bit", default=False.

ThreshIs8Bit, Default False, If True and bit depth > 8 bit, then thresh is converted to current bit depth threshold.
If true, Eg, if bit depth = 10, then multiply thresh by 4 : if bit depth 16 then mult thresh by 256.

Blankmedia
29th October 2021, 15:44
Thank you all this is useful

StainlessS
29th October 2021, 20:22
@ JohnMeyer,
Do you remember Gavino post:- https://forum.doom9.org/showthread.php?p=1409378#post1409378

So in general, if you want to replace a 'bad' frame n by interpolating between its immediate neighbours n-1 and n+1, you need to use delta=2 (and take the result from frame n-1 of MFlowInter).
See the example in the MVTools doc, "recreate bad frames by interpolation with MFlowInter".

You're right, the function certainly does work, and now I see why.
What happens is that if a duplicate is found at frame n, it interpolates between n and n+1, since delta=1.
At first sight, this is wrong, but since frame n is a duplicate of frame n-1, it is equivalent to the desired interpolation between n-1 and n+1, so the final result comes out OK. (Whether by accident or by design, I'm not sure. :))


Would you mind if I fixed that MugFunky 'fortunate mistake' (assuming that it was a mistake).
If we do in fact tween using a 2nd EXACT dupe, then there is no problem at all in how it now works, however, in case of
FillDrops, we do the tween governed by a threshold, and so the 2nd of two assumed identical frames is not necessarily identical at all,
maybe only an eye movement or something.
It is unlikely to make any major difference to results, but there will be times when it produces a definitely better result (I think).

All it needs is to use Delta=2 instead of 1, and use the filldrops frame from n-1 to fix the assumed duplicate at n.
(so we are tweening between n-1 and n+1).

Thoughts ...


EDIT: Whilst I'm at it, I might as well add HPad=16, VPad=16, and maybe a few more usual args to MSuper.
EDIT: I can also fix the interlaced version too.


EDIT: Something like this (untested)

Function FillDrops(clip c, float "thresh",Bool "ThreshIs8Bit") {
thresh = Default(thresh, 0.1)
ThreshIs8Bit = Default(ThreshIs8Bit,False) # False = thresh is in current bit depth range
try { bpc=c.BitsPerComponent } catch(msg) { bpc=8 }
thresh = (ThreshIs8Bit) ? thresh * BitLShift(1,bpc-8) : thresh
#
super = MSuper(c, pel=2,hpad=16,vpad=16)
vfe = MAnalyse(super, truemotion=true, isb=false, delta=2)
vbe = MAnalyse(super, truemotion=true, isb=true, delta=2)
filldrops = MFlowInter(c, super, vbe, vfe, time=50).SelectEvery(1,-1)
fixed = ConditionalFilter(c, filldrops, c, "YDifferenceFromPrevious()", "lessthan", String(thresh))
return fixed
}

StainlessS
29th October 2021, 23:23
John does this meet with your approval [dated 30 Oct 2021, about 40 mins from now].


#########################################################################################
#
# FillDrops.avsi
#
# An AviSynth filter to detect and replace duplicate frames
# with a motion-interpolation of the adjacent frames.
#
# mod 2021-07-10 by Selur
# mod 29 Oct 2021, Added ThreshIs8Bit arg. ssS. https://forum.doom9.org/showthread.php?p=1956020#post1956020
# mod 30 Oct 2021, ssS:- https://forum.doom9.org/showthread.php?p=1956096#post1956096
# Corrected original odd Delta=1 to Delta=2 (see:- https://forum.doom9.org/showthread.php?p=1409378#post1409378 )
# Added ShowDot, arg.
#
# - based on Mug Funky's FillDrops
# - FillDrops by johnmeyer on Doom9's forum
# https://forum.doom9.org/showthread.php?p=1775184#post1775184
# - mod by Selur to parametrize Luma Difference Threshold
# https://forum.videohelp.com/threads/402416-repair-Videos-with-duplicates-and-dropped-frames#post2624936
#
### Requirements ###
#-------------------
# Avs v2.60/+
# MvTools2 (https://github.com/pinterf/mvtools)
#
### Arguments ###
#-----------------
# thresh (default=0.1) - Luma Difference Threshold
# Lets you specify how different a frame has to be (from the previous frame)
# before it's considered not to be a duplicate, and therefore not replaced with a motion interpolated frame.
# If the threshold is too small, some duplicate will not be replaced.
# If it's too large, many frames which aren't duplicates (just having very small motions) will be replaced.
# (explanation by jagabo on VideoHelp)
#
# ---------------
# ThreshIs8Bit, Default False, If True and bit depth > 8 bit, then thresh is converted to current bit depth threshold.
### Changelog ###
#---------------
# ShowDot, If True, Subtitle "*" on frame Bottom Left of interpolated frames. [Interlaced Even field "*-" and Odd field "-*"]
#---------------
# Changed requirements: from MvTools to MvTools2 (johnmeyer)
# Parametrized Luma Difference Threshold (Selur)
# ssS: Added Bool arg "ThreshIs8Bit", default = False. Added ShowDot default False.
#########################################################################################

Function FillDrops (clip c, float "thresh",Bool "ThreshIs8Bit",Bool "ShowDot") {
thresh = Default(thresh, 0.1)
ThreshIs8Bit = Default(ThreshIs8Bit,False) # False = thresh is in current bit depth range
ShowDot = Default(ShowDot,false)
try { bpc=c.BitsPerComponent } catch(msg) { bpc=8 }
thresh = (ThreshIs8Bit) ? thresh * BitLShift(1,bpc-8) : thresh
super = MSuper(c, pel=2,hpad=16,vpad=16,sharp=1,rfilter=4)
vfe = MAnalyse(super, truemotion=true, isb=false, delta=2,blksize=16,blksizeV=16,Overlap=8,OverlapV=8,search=4, dct=0)
vbe = MAnalyse(super, truemotion=true, isb=true, delta=2,blksize=16,blksizeV=16,Overlap=8,OverlapV=8,search=4, dct=0)
filldrops = MFlowInter(c, super, vbe, vfe, time=50,blend=false) # Dont blend at scene change : Generate interpolated frame n at filldrops frame n-1.
# SHIFT n-1 to frame n, and Maintain original length, ConditionalFilter returns length of 2nd (filldrops) clip.
filldrops = filldrops.DuplicateFrame(0).DeleteFrame(c.FrameCount)
filldrops = (ShowDot) ? filldrops.Subtitle("*",align=1,font="Courier New") : filldrops # If ShowDot, then subtitle Single asterisk at bottom left.
fixed = ConditionalFilter(c, filldrops, c, "YDifferenceFromPrevious()", "lessthan", String(thresh))
return fixed.AudioDubEx(c) # ConditionalFilter returns audio from filldrops clip which is shifted. [Should not be necessary, Safety Measure only]
}

Function FilldropsI (clip c, float "thresh",Bool "ThreshIs8Bit",Bool "ShowDot") {
thresh = Default(thresh, 0.1)
ThreshIs8Bit = Default(ThreshIs8Bit,False) # False = thresh is in current bit depth range
ShowDot = Default(ShowDot,false)
try { bpc=c.BitsPerComponent } catch(msg) { bpc=8 }
thresh = (ThreshIs8Bit) ? thresh * BitLShift(1,bpc-8) : thresh
#
even = c.SeparateFields().SelectEven()
super_even=MSuper(even,pel=2,hpad=16,vpad=8,sharp=1,rfilter=4)
vfe=manalyse(super_even,truemotion=true,isb=false,delta=2,blksize=16,blksizeV=8,Overlap=8,OverlapV=4,search=4, dct=0)
vbe=manalyse(super_even,truemotion=true,isb=true, delta=2,blksize=16,blksizeV=8,Overlap=8,OverlapV=4,search=4, dct=0)
filldrops_e = mflowinter(even,super_even,vbe,vfe,time=50,blend=false) # dont blend at scene change
filldrops_e = filldrops_e.DuplicateFrame(0).DeleteFrame(c.FrameCount)
filldrops_e = (ShowDot) ? filldrops_e.Subtitle("*-",align=1,font="Courier New") : filldrops_e # EVEN, If ShowDot, then subtitle asterisk + hyphen (*-) at bottom left.
#
odd = c.SeparateFields().SelectOdd()
super_odd=MSuper(odd,pel=2,hpad=16,vpad=8,sharp=1,rfilter=4)
vfo=manalyse(super_odd,truemotion=true,isb=false,delta=2,blksize=16,blksizeV=8,Overlap=8,OverlapV=4,search=4, dct=0)
vbo=manalyse(super_odd,truemotion=true,isb=true, delta=2,blksize=16,blksizeV=8,Overlap=8,OverlapV=4,search=4, dct=0)
filldrops_o = mflowinter(odd,super_odd,vbo,vfo,time=50,blend=false) # dont blend at scene change
filldrops_o = filldrops_o.DuplicateFrame(0).DeleteFrame(c.FrameCount)
filldrops_o = (ShowDot) ? filldrops_o.Subtitle("-*",align=1,font="Courier New") : filldrops_o # ODD, If ShowDot, then subtitle hyphen + asterisk (-*) at bottom left.
#
evenfixed = ConditionalFilter(even, filldrops_e, even, "YDifferenceFromPrevious()", "lessthan", String(thresh))
oddfixed = ConditionalFilter(odd, filldrops_o, odd, "YDifferenceFromPrevious()", "lessthan", String(thresh))
Interleave(evenfixed,oddfixed)
Weave()
return Last.AudioDubEx(c) # ConditionalFilter returns audio from filldrops clip which is shifted. [Should not be necessary, Safety Measure only]
}

EDIT:
I've used eg BlkSize=16, BlkSizeV=8, Overlap=8,OverlapV=4, for Interlaced, is that OK. [I get rid of interlaced stuff at earliest opportunity]
Also Added a ShowDot whatsit [EDIT: At Bottom left, to distinguish from other ShowDots, Interlaced showdot different for Even/Odd].

johnmeyer
30th October 2021, 00:46
I would have to play around with it to know for sure whether it is an improvement.

I did not go back and re-read that thread, but I've revisited this Delta=2 issue many times. In general, I always try to avoid using Delta=2 because by using information from two frames away, you introduce additional temporal (and spatial) displacement compared to Delta=1. For most MVTools2 applications you use Delta=1 for exactly that reason.

What I have always wanted with MVtools2 -- and maybe there is a way to do this -- is to estimate the next frame using vectors from the two previous frames. You obviously need to have to samples for each pixel from two different frames in order to create a vector. When the goal is to interpolate a new frame at some position following the current frame it just seems like you'd get better results using the previous two frames because that way you only have one point on the vector that is from a moment in time that is two frames away.

However, the proof will be in the use, and when I get a chance I'll try to see if your approach produces cleaner video.

StainlessS
30th October 2021, 02:23
You use Delta=1 only for eg framerate doubling where you want to interpolate/synthesize a frame between each existing adjacent frame pair,
if you want to replace a frame (corrupt frame or tween a dupe) then you have to use Delta=2 (which uses as source those frames either side of the frame to be replaced),
it was pure accident that original Filldrops worked, and seemingly without NOTICABLE problems, but it is most certainly wrong (both spacially and temporally).
Original FillDrops where replacing EXACT dupe, then is no problem at all, but when not exact dupe (ie little motion) then is spatial/temporally wrongly synthesized.
If the mod does not seem better, then will be down to me changing blkSize (from 8 to 16) and the other similar settings that I changed. [ msuper(sharp, rfilter) ]
EDIT: MSuper(hpad=16,vpad=16) can only improve things, pad of 8 can cause distortion around frame edge, mostly left and right. [especially if blksize greater than 8]

EDIT: Here the only example in mvtools docs that uses delta=1. (where moving adjacent frames to align with current for degraining - ie not interpolating at all)

To denoise by MDegrain2 with overlapped blocks (blksize=8) and subpixel precision:

AVISource("c:\test.avi") # or MPEG2Source, DirectShowSource, some previous filter, etc
super = MSuper(pel=2, sharp=1)
backward_vec2 = MAnalyse(super, isb = true, delta = 2, overlap=4)
backward_vec1 = MAnalyse(super, isb = true, delta = 1, overlap=4)
forward_vec1 = MAnalyse(super, isb = false, delta = 1, overlap=4)
forward_vec2 = MAnalyse(super, isb = false, delta = 2, overlap=4)
MDegrain2(super, backward_vec1,forward_vec1,backward_vec2,forward_vec2,thSAD=400)


EDIT: By exact dupe, I suppose non-exact (but intended dupe, eg noise or compression artefacts make it non exact) is OK too in old FillDrops,
but NOT a frame that looks like a dupe simply because the YDifferencetoPrevious is below some threshold.
Where a seeming dupe (low motion non dupe) is synthesized, it would ideally produce a frame that is also quite similar to the
replaced mistaken dupe. [but not where delta=1, where would be spatially/temporally skew whiff - probably not by that much, but wrong nevertheless]

EDIT: when Gavino said this:

So [i]in general, if you want to replace a 'bad' frame n by interpolating between its immediate neighbours n-1 and n+1, you need to use delta=2 (and take the result from frame n-1 of MFlowInter).
See the example in the MVTools doc, "recreate bad frames by interpolation with MFlowInter".

You're right, the function certainly does work, and now I see why.
What happens is that if a duplicate is found at frame n, it interpolates between n and n+1, since delta=1.
At first sight, this is wrong, but since frame n is a duplicate of frame n-1, it is equivalent to the desired interpolation between n-1 and n+1, so the final result comes out OK. (Whether by accident or by design, I'm not sure. :))

He had only considered real dupes being replaced by Filldrops(with delta=1), low motion mistaken for dupes is a totally different kettle of fish.
[If the Big G sees this, then maybe he could respond]

johnmeyer
30th October 2021, 18:53
StainlessS,

I tried out your version of Filldrops and the results looked very good. Thank you for taking the time to do that.

The only additional tweaking might be to slightly modify the MAnalyze parameters. You may remember this thread:

SlowMo: Simple slow motion, using interpolation (https://forum.doom9.org/showthread.php?p=1788725#post1788725)

The script I posted had some "magic" parameters that soon became the touchstone against which other MFlowFPS() attempts were measured. I didn't have any great insight when I made that post, I simply did 100+ tests and kept tuning until I came up with those settings.

Even without the forum rules, there really is no "best," especially when it comes to motion estimation, but any time I need to get the cleanest results from MFlowFPS, I always use start with the two-step estimation shown in that link.

Now I need to spend a few minutes with your last version of "Duplicity" to see if it handles the drop/dup problem that I've been obsessed with perfecting. I don't see how it could work for that, but you've posted a few times that it will, so I'm going to try it on my test cases.

Gavino
30th October 2021, 19:00
If the Big G sees this, then maybe he could respond
Hi StainlessS, I remember that discussion, although the details are a bit hazy now - well, it was 11 years ago!
Your summary and analysis of what I said there is correct - in general, you need to use delta=2 when replacing a frame by interpolating between the frames on either side of it, but delta=1 will work if the frame to be replaced is a dup (exact or perhaps very close) of the previous one.
However, John continued to maintain that in practice delta=1 worked better.
Later in that same thread, I suggested a possible explanation:

By looking at the source code, I have discovered that for occlusion areas, MVFlowInter also uses information from the two further surrounding frames (current-delta and current+2*delta).
So the diagram becomes, when interpolating between C and C+d,
----> <----
C-d C C+d C+2d
----> <----
It is this additional information that will be more accurate when delta=1, explaining your findings
but again that would still only apply to the case where you have a duplicate and not just an unrelated 'bad' frame in the middle.

johnmeyer
30th October 2021, 20:11
However, John continued to maintain that in practice delta=1 worked better.
Later in that same thread, I suggested a possible explanation but again that would still only apply to the case where you have a duplicate and not just an unrelated 'bad' frame in the middle.Yes, that is what I remember finding. I think the reason is that the farther away the reference frames are from the current frame, the less accurate the estimation becomes. This is why I continue to try to find a way to estimate a future frame, using MFLowFPS(), using only previous frames. Perhpas there is no way to do this, but given what MVTools2 is doing, what can't it use vectors from frames n-1 and n-2 to estimate frame n+1? That way you'd only be using information from one Delta frame that is 2 frames away.

I've tried to figure out a way to get MVtools2 to do this, but have never succeeded.

Since most of my use for Filldrops is to remove exact dups, I see no reason not to use my old Delta=1 version since, as pointed out again in this thread, it works when Delta+1 and Delta+2 are the identical frames.

Don't get me wrong, I very much appreciate the mods StainlessS made, and I will use his version when appropriate.

StainlessS
7th November 2021, 23:04
Sorry guys, I've been a bit AWOL.

Gavino,
Good God, 11 years ago !!!
Yep, I vaguely remembered that thing about MFlowInter and occlusion areas, I tried to find it actually but must have skipped over it.
Maybe that 2*delta thingy could be done on purpose, rather than rely on dupe/noisydupe delta=1 whotsit.

by john,
estimate a future frame
Something like
You beat me to it (was busy with an edit).

Might be able to use these (manually),


Function PredictFromPrevious(clip Last)
{ # Predict i frame from Previous
yuy2=(isYUY2())?true:false
PreFilt=Last.DeGrainMedian() # prefiltered for better motion analysis
Last= (yuy2)?Interleaved2planar():Last
PreFilt= (yuy2)?PreFilt.Interleaved2planar():PreFilt
super=Last.MSuper(planar=yuy2)
superPreFilt=PreFilt.MSuper(planar=yuy2)
fv = superPreFilt.MAnalyse(isb = false, truemotion=true,delta = 1)
Last.MFlow(super,fv,planar=yuy2)
Last=(yuy2)?Planar2Interleaved():Last
Return Last
}


Function PredictFromNext(clip Last)
{
yuy2=(isYUY2())?true:false
PreFilt=Last.DeGrainMedian() # prefiltered for better motion analysis
Last= (yuy2)?Interleaved2planar():Last
PreFilt= (yuy2)?PreFilt.Interleaved2planar():PreFilt
super=Last.MSuper(planar=yuy2)
superPreFilt=PreFilt.MSuper(planar=yuy2)
bv = superPreFilt.MAnalyse(isb = true, truemotion=true,delta = 1)
Last.MFlow(super,bv,planar=yuy2)
Last=(yuy2)?Planar2Interleaved():Last
return Last
}


And use ClipClop() plug to select replacement frames from generated predicted clips.

Sometimes works ok, sometimes not.