Log in

View Full Version : 30fps improperly decimated to 24


kuchikirukia
2nd June 2017, 12:59
I have a 24fps Bluray that has a skip every 4th frame, so it looks to have been filmed in 30 and they dropped frames down to 24. Is there a way to interpolate this back?

johnmeyer
2nd June 2017, 16:59
That sounds like an odd production decision. I'm not saying it isn't so, but I am saying that it sure doesn't make sense. Please post a sample.

I did develop a script for finding gaps (missing frames) in video, and it works to some degree. However, even with strong motion in the video, it is rather difficult to reliably detect a missing frame. I posted it here in this forum many years ago. You won't want to use the part of the script that finds the duplicates, but the gap detection may be of some use:

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

You will also find a link in my first post in that thread which goes to a thread where the OP was trying to solve the problem of a video that had been decimated from 30 to 24 fps. Sound familiar?

In case you don't want to find that link, here it is:

Inverse of Decimate (https://forum.doom9.org/showthread.php?p=1407101)

kuchikirukia
2nd June 2017, 23:13
https://ufile.io/qmfz4

poisondeathray
3rd June 2017, 00:22
If the cadence is constant , you can interpolate by inserting frames at the set interval, and replacing that with mvtools interpolated frame . The potential problem is if there was an edit post production (after the decimation), which can screw up the cadence and the results will be off - then you would need some procedural script with detection

eg just adjust the period and offset
https://forum.videohelp.com/threads/352741-Frame-interpolation#post2222196

For your clip, if you trim(2,0) to delete the first few frames (duplicates), it would be 5,3



orig=FFVideoSource("00003-002.mkv").trim(2,0)

# Make a black clip, the same characteristics as your source
BlankClip(Orig)
Black=last

# Insert black frame in those missing frames (just temporary placeholder, will replace later)
Orig
InterleaveEvery(Black, 5,3)
BlackInserted=last


# Generates Missing Frames by interpolation
BlackInserted
sup = MSuper()
bv = MAnalyse(sup, isb=true, delta=2)
fv = MAnalyse(sup, isb=false, delta=2)
interpolated = MFlowInter(sup, bv, fv, time=50.0, ml=100).DuplicateFrame(0)
replace = interpolated.SelectEvery(5,3)

# Delete Black Frames
DeleteEvery(5,3)

# Replace Deleted Frames With Interpolated Frames
InterleaveEvery(replace, 5,3)



It's "smoother", but you're left with the ugly interpolation artifacts; very bad in some frames. You can try tweaking some of the mvtools2 settings to get slighty better results

johnmeyer
3rd June 2017, 00:28
BlockSize and Overlap in the MAnalyze call are the main things you want to play with to minimize the artifacts.

wonkey_monkey
3rd June 2017, 11:37
Rather than mflowinter, I'd use mflowfps and then do a single selectevery or deleteevery - it'd make for a simpler script and would avoid all those interleaves.

johnmeyer
3rd June 2017, 13:48
I finally had a chance to look at the clip. It presents an impossible situation with all of those one-frame laser flashes and strobe lights. Motion estimation doesn't stand a chance. I think you'd get better results, at least on this clip, using simple frame blending, in place of the motion estimation.

Sharc
3rd June 2017, 13:58
You may also want to try out MysteryX's FrameRateConverter:
https://forum.doom9.org/showpost.php?p=1808302&postcount=405

Edit:
Out of curiosity I will run an encode with "slower" setting and upload the result when it's done ..... encoding at 0.07fps ......

Edit2:
Here is what I got. The top left picture is made with ConvertFPS("ntsc_video") for comparison.
http://www.mediafire.com/file/ph6dr2tos2dy6kg/FRC_kuchi_b.mkv

StainlessS
4th June 2017, 15:22
For constant cadence,
(every 5th frame of original source missing, eg 29.97 decimated to 23.976)


Avisource("D:\00003-002.mkv.AVI") # EDIT: I converted to AVI first
ORG=Last # ADDED

CONVFPS=true # True= ConvertFPS [ie blend],
# False DoubleRate [from:- http://forum.doom9.org/showthread.php?p=1789461#post1789461 ]
# Any DoubleRate Interpolator could be substituted
SEL = 2 # 0 -> 3 # EDIT: Position to blend/interpolate (0 interpolates 0<->1, 1 interp 1<->2 etc)

# CONVFPS==FALSE, DoubleRate() Settings
FLOW=True
BLKSZ=32
OLAP=16

(CONVFPS)
\ ? ConvertFPS(FrameRate*2.0)
\ : DoubleRate(Flow=FLOW,Blksize=BLKSZ,Overlap=OLAP)

# EDIT: Changed
# E0=SelectEvery(8,0) O0=SelectEvery(8,1)
# E1=SelectEvery(8,2) O1=SelectEvery(8,3)
# E2=SelectEvery(8,4) O2=SelectEvery(8,5)
# E3=SelectEvery(8,6) O3=SelectEvery(8,7)
# EDIT: Just incase substitute DoubleRate() does not keep exact same EVEN input frames. (ConvertFPS and Linked DoubleRate do).
E0=ORG.SelectEvery(4,0) O0=SelectEvery(8,1)
E1=ORG.SelectEvery(4,1) O1=SelectEvery(8,3)
E2=ORG.SelectEvery(4,2) O2=SelectEvery(8,5)
E3=ORG.SelectEvery(4,3) O3=SelectEvery(8,7)

Return Select(SEL,Interleave(E0,O0,E1,E2,E3),Interleave(E0,E1,O1,E2,E3),Interleave(E0,E1,E2,O2,E3),Interleave(E0,E1,E2,E3,O3))

EDIT: MUST Try with SEL in range 0 -> 3, I did not bother to find which was required (and no idea if constant cadence).
EDIT: I think for your sample clip @ that start position, SEL should be 2 (greatest YDifference to next frame, most of the time).

EDIT: I/P 23.976, O/P 29.97 FPS

StainlessS
4th June 2017, 17:09
Script to select best SEL setting for constant cadence clip,
(every 5th frame of original source missing, eg 29.97 decimated to 23.976)


# Show Best SEL
Avisource("D:\00003-002.mkv.AVI")
# Below dont need to be GLOBAL when at main script level (only if in function)
G_Cnt0 =0
G_Cnt1 =0
G_Cnt2 =0
G_Cnt3 =0
SSS="""
n=current_frame m=n%4 ms=n/4*4
m0=RT_YDifference(Last,n=ms+0,delta=1) m1=RT_YDifference(Last,n=ms+1,delta=1)
m2=RT_YDifference(Last,n=ms+2,delta=1) m3=RT_YDifference(Last,n=ms+3,delta=1)
mB=Max(m0,m1,m2,m3)
B=(m0==mB)?0:(m1==mB)?1:(m2==mB)?2:3
G_Cnt0=(n==ms && B==0) ? G_Cnt0 + 1 : G_Cnt0 # If in function, Assignment to G_Cntx need to be eg Global G_Cnt0= etc
G_Cnt1=(n==ms && B==1) ? G_Cnt1 + 1 : G_Cnt1
G_Cnt2=(n==ms && B==2) ? G_Cnt2 + 1 : G_Cnt2
G_Cnt3=(n==ms && B==3) ? G_Cnt3 + 1 : G_Cnt3
x=RT_YDifference(Last,n=n,delta=1)
CntMx=Max(G_Cnt0,G_Cnt1,G_Cnt2,G_Cnt3)
BstCnt=(CntMx==G_Cnt0)?0:(CntMx==G_Cnt1)?1:(CntMx==G_Cnt2)?2:3
c0=(BstCnt==0) ?"!":"-"
c1=(BstCnt==1) ?"!":"-"
c2=(BstCnt==2) ?"!":"-"
c3=(BstCnt==3) ?"!":"-"
return RT_Subtitle("%d:%d] Dif=%f BestSEL=%d BestDif[%d]=%f\n\a%sSelCnt0=%d\a- \a%sSelCnt1=%d\a- \a%sSelCnt2=%d\a- \a%sSelCnt3=%d",
\ n,m,x,B,B,mB,c0,G_Cnt0,c1,G_Cnt1,c2,G_Cnt2,c3,G_Cnt3)
"""
ScriptClip(SSS)


For your sample clip on last frame shows this (cropped for below image):-
https://s20.postimg.org/dixlqjrzx/Sel_Cnt_zpsihb4rie7.jpg (https://postimg.org/image/ujghz8515/)

StainlessS
4th June 2017, 17:55
NOT for OP clip.

Where 30FPS decimated to 25.0, ie every 6th frame of original source missing (have seen many of these).

Check SEL setting


# Show Best SEL, (every 6th frame of original source missing, eg 30.0 decimated to 25.0, or 29.97 to 24.975)

Avisource("D:\00003-002.mkv.AVI") # Some file name, not for OP clip
# Below dont need to be GLOBAL when at main script level (only if in function)
G_Cnt0 =0
G_Cnt1 =0
G_Cnt2 =0
G_Cnt3 =0
G_Cnt4 =0
SSS="""
n=current_frame m=n%5 ms=n/5*5
m0=RT_YDifference(Last,n=ms+0,delta=1) m1=RT_YDifference(Last,n=ms+1,delta=1)
m2=RT_YDifference(Last,n=ms+2,delta=1) m3=RT_YDifference(Last,n=ms+3,delta=1) m4=RT_YDifference(Last,n=ms+4,delta=1)
mB=Max(m0,m1,m2,m3,m4)
B=(m0==mB)?0:(m1==mB)?1:(m2==mB)?2:(m3==mB)?3:4
G_Cnt0=(n==ms && B==0) ? G_Cnt0 + 1 : G_Cnt0 # If in function, Assignment to G_Cntx need to be eg Global G_Cnt0= etc
G_Cnt1=(n==ms && B==1) ? G_Cnt1 + 1 : G_Cnt1
G_Cnt2=(n==ms && B==2) ? G_Cnt2 + 1 : G_Cnt2
G_Cnt3=(n==ms && B==3) ? G_Cnt3 + 1 : G_Cnt3
G_Cnt4=(n==ms && B==4) ? G_Cnt4 + 1 : G_Cnt4
x=RT_YDifference(Last,n=n,delta=1)
CntMx=Max(G_Cnt0,G_Cnt1,G_Cnt2,G_Cnt3,G_Cnt4)
BstCnt=(CntMx==G_Cnt0)?0:(CntMx==G_Cnt1)?1:(CntMx==G_Cnt2)?2:(CntMx==G_Cnt3)?3:4
c0=(BstCnt==0) ?"!":"-"
c1=(BstCnt==1) ?"!":"-"
c2=(BstCnt==2) ?"!":"-"
c3=(BstCnt==3) ?"!":"-"
c4=(BstCnt==4) ?"!":"-"
return RT_Subtitle("%d:%d] Dif=%f BestSEL=%d BestDif[%d]=%f\n\a%sSelCnt0=%d\a- " +
\ "\a%sSelCnt1=%d\a- \a%sSelCnt2=%d\a- \a%sSelCnt3=%d\a- \a%sSelCnt3=%d",
\ n,m,x,B,B,mB,c0,G_Cnt0,c1,G_Cnt1,c2,G_Cnt2,c3,G_Cnt3,c4,G_Cnt4)
"""
ScriptClip(SSS)


Fix

# Every 6th frame of original source missing, eg 30.0 decimated to 25.0, or 29.97 to 24.975

Avisource("D:\00003-002.mkv.AVI") # Some file name, not for OP clip

ORG=Last

CONVFPS=true # True= ConvertFPS [ie blend],
# False DoubleRate [from:- http://forum.doom9.org/showthread.php?p=1789461#post1789461 ]
# Any DoubleRate Interpolator could be substituted
SEL = 0 # 0 -> 4 # Position to blend/interpolate (0 interpolates 0<->1, 1 interp 1<->2 etc)

# CONVFPS==FALSE, DoubleRate() Settings
FLOW=True
BLKSZ=32
OLAP=16

(CONVFPS)
\ ? ConvertFPS(FrameRate*2.0)
\ : DoubleRate(Flow=FLOW,Blksize=BLKSZ,Overlap=OLAP)

# EDIT: Just incase substitute DoubleRate() does not keep exact same EVEN input frames.
E0=ORG.SelectEvery(5,0) O0=SelectEvery(10,1)
E1=ORG.SelectEvery(5,1) O1=SelectEvery(10,3)
E2=ORG.SelectEvery(5,2) O2=SelectEvery(10,5)
E3=ORG.SelectEvery(5,3) O3=SelectEvery(10,7)
E4=ORG.SelectEvery(5,4) O4=SelectEvery(10,9)

Return Select(SEL,Interleave(E0,O0,E1,E2,E3,E4),Interleave(E0,E1,O1,E2,E3,E4),Interleave(E0,E1,E2,O2,E3,E4),
\ Interleave(E0,E1,E2,E3,O3,E4),Interleave(E0,E1,E2,E3,E4,O4))

StainlessS
5th June 2017, 05:09
PART_1, Post 1 of 2

# FindRepairCycleOffset.avs

Function FindRepairCycleOffset(clip c,Int "OutCycle",Float "PassPerc",String "ARR",Bool "Verbose",Int "MaxAcross") {
/*
FindRepairCycleOffset(), By StainlessS @ Doom9, http://forum.doom9.org/showthread.php?p=1808723#post1808723

Colorspace, v2.6 Planar, YUY2, RGB.
Requires:- RT_Stats, CallCmd, GScript, Grunt.

Shows RepairCycle() required Offset arg for constant cadence clip where 1 frame in every OutCycle frames of original source was
omitted from botched clip c.
If start of clip is trimmed afterwards, then needs to be redone (or recalculated), before calling RepairCycle(),
unless FramesTrimmed % (OutCycle-1) == 0 (ie trimmed by complete InCycles).

If you jump forward, then display will cease whilst ALL frames up to jump frame are sampled and results added to an array,
can jump backwards OK as all frames up to current frame are already in array. If you wish, you can call eg
FindRepairCycleOffset().Trim(FrameCount-1,-1), ie trim off last frame only, and this will produce the final result
frame with all frames sampled, and also is the fastest possible way as no frames are displayed before final result.

A count array (CNT[InCycle]) is established of size InCycle.
Each frame is differenced with the frame following using Luma RT_YDifference() and the element within the CNT[] array representing
the frame with greatest difference within a Cycle, is incremented.
When sufficient cycles have been sampled, the CNT[] element with greatest value is more likely to indicate the position
within the cycle where the original source frames were omitted. (Anyway, thats the theory, but needs lots of samples/cycles
to be of any use, the best and only real result is on the very last frame, any metrics prior to the last frame are based only
on the data available up to that point in the clip).

Args:-
c, Botched input clip.
OutCycle, Default 5, (3 <= OutCycle <= 1001), original source clip cycle, one frame of which was ommited from Botched input clip c.
The only real reason for limiting OutCycle to 1001, is that there are only 1024 User Attributes in an RT_Stats array,
so the number of items in returned user array attributes is also limited (hopefully this is enough for anyone,
shout if not).

eg Outcycle = 5, InCycle=4 (Outcycle-1)
every 5th frame of original source missing, eg 30.0 was decimated to 24.0, or 29.97 to 23.976.
eg Outcycle = 6, InCycle=5 (Outcycle-1)
every 6th frame of original source missing, eg 30.0 was decimated to 25.0, or 29.97 to 24.975.

Original Rate = c.FrameRate * OutCycle / InCycle

PassPerc, Default (200.0/InCycle)%, (0.0 <= PassPerc < 100.0.).
Greatest Cnt[OffSet] has to be greater or equal to this percentage of CyclesProcessedSoFar,
to be considered 'conclusive' (0.0 = accept any result as conclusive).

ARR, Default "" (not user supplied). Filename of User RT_Stats Array.
If Not supplied, then temp Array will be created and will be auto deleted upon clip closure.
If User Supplied, then will use supplied filename and return with resultant Array existing.
Suggest name something like 'ARR=RT_GetFullPathName("~TMP"+RT_LocalTimeString(File=True)+".ARR")'.
On Last frame and valid result >= PassPerc, then will set Array attributes as return result to
client script, where array attributes are set:-
Attrib[0] = Int, 1, if completed OK, 0 = Invalid Attribute results (Not >= PassPerc).
Attrib[1] = Int, RESULT:- Offset (The Cycle offset RESULT of function)
Attrib[2] = Int, InCycle (OutCycle = InCycle + 1)
Attrib[3] = Int, TotalCycles in clip
Attrib[4] = Int, CNT[Offset], Count of cycles where result Offset frame greatest dif to next.
Attrib[5] = Float, Percentage of cycles where CNT[Offset] was greatest.
Attrib[6+i] = Int, CNT[i] where i = 0 -> InCycle - 1.
Can retrieve Array attributes via eg, 'OK = RT_ArrayGetAttrib(ARR,0) == 1' # Are Attributes Valid ?

Verbose, Default True. Show Count Array on frame.

MaxAcross, Default 10. Max width of Cnt[] array displayed on frame (when Verbose=True), if would screen wrap.

Shows Metrics as below when OutCycle==5 (InCycle=OutCycle-1, and MaxIndex of Cnt[MaxIndex]=InCycle-1):

"230:2 Flgs: SC? Cnt[2]=40" <- Current_frame, local cycle offset, Flags, and Maximum Cnt[Offset]=Value.
"Dif=0.000 : BigDif[1]=16.787" <- YDifference Current_Frame<->Current_Frame+1, Greatest diff within current cycle.
"Cnt[0]=05 Cnt[1]=06 Cnt[2]=40 Cnt[3]=07" <- The HiLited Cnt[2] is the global result Offset, on last frame. (Verbose=True, MaxWidth)
"Cycle=58/58 : CompletedTo=230/230" <- Clip Progress, by Cycle, by FrameNo.
"PassPerc=50.0% : 40=68.97%" <- Goodness so far.
"Offset=2" <- The result, ie as above; highest Cnt[2]=40 and '?' NOT hilited.

Where:-
'230' is current frame number. "2"=Zero relative InCycle index of current frame(0->InCycle-1).
Flgs:
"S" If HiLited, then current frame within InCycle has greatest difference to following frame (current InCycle metric).
"C" If HiLited, then current frame within InCycle Index has greatest count so far.
Ideally, S and C flags should be HiLited BOTH TOGETHER, once every InCycle (OutCycle-1) frames.
"?" If HiLited, then result is inconclusive, ie hilited Cnt[CycleIndex] as a percentage (of CyclesSoFar) is not >= PassPerc.
CurDif='0.000', Difference between current_frame (as above '230') and next (frame 230 is last frame so dif to next = 0.0).
BigDif[1]="16.787", Greatest Difference in current Cycle is at Cycle offset 1.
Cnt[CycleIndex]=nnn, where CycleIndex in range 0->InCycle-1,
and 'nnn' is count of cycles where CycleIndex had max dif to next frame (within scanned cycles so far).
The Cnt[CycleIndex] with highest count (ie above Cnt[2]=40), will be hilted, ie is the FINAL result on Last frame of input clip.
Offset="2", the final result on last frame when '?' flag NOT HiLited.
*/
myName="FindRepairCycleOffset: "
OutCycle=Default(OutCycle,5)
PassPerc = Default(PassPerc,200.0/(OutCycle-1))
Verbose=Default(Verbose,True)
MaxAcross=Default(MaxAcross,10)
ARR=Default(ARR,"") # Default, auto delete temp array file on clip closure.
UserARR = ARR!=""
Assert(RT_FunctionExist("GScriptClip"),RT_String("%sEssential GRunT plugin installed, http://forum.doom9.org/showthread.php?t=139337",myName))
Assert(RT_FunctionExist("GScript"),RT_String("%sEssential GScript plugin installed, http://forum.doom9.org/showthread.php?t=147846",myName))
Assert(RT_FunctionExist("CallCmd"),RT_String("%sEssential CallCmd plugin installed, http://forum.doom9.org/showthread.php?t=166063",myName))
Assert(0.0 <= PassPerc < 100.0,RT_String("%s0.0 <= PassPerc < 100.0(%f)",myName,PassPerc))
Assert(3 <= OutCycle <= 1001,RT_String("%s3 <= OutCycle(%d) <= 1001",myName,OutCycle))
InCycle=OutCycle-1
FuncS="""
Function Fn@@@(clip c,Int InCycle,String DARR,String CARR,String Fmt,String Fmt2,Bool Verbose) {
c n=current_frame FC=c.FrameCount CompletedTo=CompletedTo@@@
if(n > CompletedTo) {
CycleBase = CompletedTo + 1
CycleY = CycleBase/InCycle
CycleEndBase = n/InCycle*InCycle
cntMxIx = (CycleY ==0) ? 0 : RT_ArrayGet(CARR,CycleY-1,1) # If not first cycle, prev Hi ix
for(CycleStartFrm = CycleBase, CycleEndBase, InCycle) {
mxDf= -1.0 mxDfIx=0
for(i=0, InCycle-1) {
FrameNo=CycleStartFrm+i
df=Last.RT_YDifference(n=FrameNo,delta=1)
(FrameNo<FC) ? RT_ArraySet(DARR,df,FrameNo) : NOP
if(df>mxDf) { mxDF=df mxDfIx=i } # find max dif to next frame
if(CycleY>0) {
xix = 2+i
RT_ArraySet(CARR,RT_ArrayGet(CARR,CycleY-1,xix),CycleY,xix) # Copy from Prev Cycle
}
}
mxDfCnt = RT_ArrayGet(CARR,CycleY,2+mxDfIx) + 1 # Incr Count with greatest diff
RT_ArraySet(CARR,mxDfCnt,CycleY,2+mxDfIx) #
RT_ArraySet(CARR,mxDfIx ,CycleY,0) # And store mxDfIx
if(mxDfIx != cntMxIx) { # was not current greatest cnt, is it better ?
cntMx = RT_ArrayGet(CARR,CycleY,2+cntMxIx)
if(mxDfCnt >= cntMx) { # If equal, then mxDf was greater
cntMxIx=mxDfIx # and the newly overtaking mxDfcnt
}
}
RT_ArraySet(CARR,cntMxIx,CycleY,1)
CycleY=CycleY+1
}
CompletedTo = CycleStartFrm-1 Global CompletedTo@@@ = CompletedTo
}

CycleY = n / InCycle
CyclesAtN = CycleY + 1
CycleStartFrm = CycleY * InCycle

if(n==FC-1) {
cntMxIx = RT_ArrayGet(CARR,CycleY,1)
cntMx = RT_ArrayGet(CARR,CycleY,2+cntMxIx)
if(cntMx>=CyclesAtN*PassPerc@@@) {
if(RT_ArrayGetAttrib(CARR,0)==0) { # Not yet set completed flag
myname="Fn@@@_DBUG: "
Tim = RT_TimerHP-TImerStart@@@
RT_DebugF("Scan Time = %f secs %fFPS",Tim,FC/Tim,name=myName)
RT_DebugF("CntMax(%d) = %6.3f%% of TotalCycles(%d)",cntMx,cntMx*100.0/CyclesAtN,CyclesAtN,name=myName)
RT_DebugF("Setting Attributes",name=myName)
RT_ArraySetAttrib(CARR,0,1) # Attrib[0]=COMPLETED OK, Attribute Results ARE VALID (DO NOT SET A SECOND TIME).
RT_DebugF(" Attrib[0]=1 # VALID", name=myName)
RT_ArraySetAttrib(CARR,1,cntMxIx) # Attrib[1]=RESULT:- Offset (The Cycle offset RESULT of function)
RT_DebugF(" Attrib[1]=%-3d # Offset (Result)",cntMxIx,name=myName)
RT_ArraySetAttrib(CARR,2,InCycle) # Attrib[2]=InCycle (OutCycle = InCycle + 1)
RT_DebugF(" Attrib[2]=%-3d # InCycle (OutCycle=%d)",InCycle,InCycle+1,name=myName)
RT_ArraySetAttrib(CARR,3,CyclesAtN) # Attrib[4]=Cnt[Offset], Cnt of cycles where result Offset frame greatest dif to next.
RT_DebugF(" Attrib[3]=%-6d # TotalCycles in clip",CyclesAtN,name=myName)
cnt=RT_ArrayGet(CARR,CycleY,2+cntMxIx)
RT_ArraySetAttrib(CARR,4,cnt) # Attrib[4]=Cnt[Offset], Cnt of cycles where result Offset frame greatest dif to next.
RT_DebugF(" Attrib[4]=%-5d # Cnt[Offset]",cnt,name=myName)
GotPerc=cntMx*100.0/CyclesAtN
RT_ArraySetAttrib(CARR,5,GotPerc) # Attrib[5]=GotPerc
RT_DebugF(" Attrib[5]=%.3f # Percent gotten",GotPerc,name=myName)
for(i=0,InCycle-1) {
cnt=RT_ArrayGet(CARR,CycleY,2+i)
RT_ArraySetAttrib(CARR,6+i,cnt) # Attrib[6+i] = Cnt[i]
RT_DebugF(" Attrib[6+%d]=%-4d # Cnt[%d]",i,cnt,i,name=myName)
}
}
}
}

StainlessS
10th June 2017, 02:17
PART_2, post 2 of 2

mxDfIx = RT_ArrayGet(CARR,CycleY,0)
cntMxIx = RT_ArrayGet(CARR,CycleY,1)
cntMx = RT_ArrayGet(CARR,CycleY,2+cntMxIx)
curDf = RT_ArrayGet(DARR,n)
BigDf = RT_ArrayGet(DARR,CycleStartFrm+mxDfIx)
HILITE = 33 # RT_Ord("!")
LOLITE = 76 # RT_Ord("L")
WHITE = 45 # RT_Ord("-")
xc=XCnts@@@ ixL=XCntIxLen@@@ cL=XCntLen@@@
S=""
if(Verbose) {
for(i=0,InCycle-1) {
cnt=RT_ArrayGet(CARR,CycleY,2+i)
Startcol=i==cntMxIx?HILITE:WHITE
Midcol =(Startcol==WHITE&&i==mxDfix)?HILITE:Startcol
S=S+RT_string(Fmt2,Startcol,MidCol,ixL,i,Startcol,cL,cnt,(i%xc==xc-1||i==InCycle-1)?10:32)
}
}
SF=(n-CycleStartFrm==mxDfIx) ? HILITE:LOLITE
CF=(n-CycleStartFrm==cntMxIx) ? HILITE:LOLITE
BF=(cntMx>=CyclesAtN*PassPerc@@@) ? LOLITE:HILITE
RT_Subtitle(Fmt,n,n-CycleStartFrm,SF,CF,BF,ixL,cntMxIx,cL,RT_ArrayGet(CARR,CycleY,2+cntMxIx),curDf,mxDfIx,BigDf,
\ S,
\ CyclesAtN,TotalCycles@@@,CompletedTo>=FC-1?HILITE:WHITE,Min(CompletedTo,FC-1),FC-1,
\ PassPerc@@@*100.0,cntMx,cntMx*100.0/CyclesAtN,
\ BF==HILITE?"???":RT_String("%-3d",cntMxIx))
Return Last
}
Fmt = "%d:%-2d] Flgs: \a%cS\a%cC\a%c?\a- \a!Cnt[%0.*d]=%0.*d\a-\nCurDif=%-7.3f : BigDif[\a!%d\a-]=%-7.3f\n" +
\ "%s" +
\ "Cycles=%d/%d : \a%cCompletedTo=%d\a-/%d\n" +
\ "PassPerc=%.2f%% : \a!%d\a-=%.2f%% \n" +
\ "Offset=%s"
Fmt2="\a%cCnt[\a%c%.*d\a%c]=%.*d\a-%c"
Global XCntLen@@@ = Int(Log10(Float(c.FrameCount) / InCycle)+1)
Global XCntIxLen@@@=Int(Log10(InCycle-1)+1)
Global XCnts@@@=Min((c.Width-20)/((7+XCntIxLen@@@+XCntLen@@@)*10),MaxAcross) # 7 = len of "Cnt[]= ", 10=width of chars in pixels.
Global TImerStart@@@ = RT_TimerHP
Global CompletedTo@@@ = -1
Global PassPerc@@@ = PassPerc/100.0
Global TotalCycles@@@ = (c.FrameCount+InCycle-1)/InCycle
TmpNam = "~TMP@@@"+RT_LocalTimeString(File=True)
ARR = RT_GetFullPathName( UserARR ? ARR : TmpNam+".CARR")
DARR = RT_GetFullPathName( TmpNam+".DARR")
RT_ArrayAlloc(ARR ,Type=1,Dim1=TotalCycles@@@,Dim2=2+InCycle) # 2 dimensional Array of Int
RT_ArrayAlloc(DARR,Type=2,Dim1=c.FrameCount) # 1 dimensional Array of Float
ARGS = "InCycle,DARR,ARR,Fmt,Fmt2,Verbose"
c.GScriptClip("Fn@@@(last, "+ARGS+")",local=true, args=ARGS,after_frame=true)
CallCmd(Close="CMD /C del "+DARR, Hide=true) # Auto Delete TEMP Array on clip closure.
!UserARR ? CallCmd(Close="CMD /C del "+ARR, Hide=true) : NOP # Auto Del non-user TEMP ARR on clip closure.
Return Last
"""
GIFunc ="FindRepairCycleOffset" # Function Name, Supply unique name for your multi-instance function.
GIName =GIFunc+"_InstanceNumber" # Name of the Instance number Global
RT_IncrGlobal(GIName) # Increment Instance Global (init to 1 if not already exists)
GID = GIFunc + "_" + String(Eval(GIName))
InstS = RT_StrReplace(FuncS,"@@@","_"+GID)
# RT_WriteFile("DEBUG_"+GID+".TXT","%s",InstS) # UnComment to write each unique script function instance to log file
Return GScript(InstS)
}



Client script

Avisource("D:\00003-002.mkv.AVI")
FindRepairCycleOffset(OutCycle=5).Trim(Framecount-1,-1) # Return only with Last frame and showing final result.
Return Crop(0,0,640,128)


Debug Output

00000096 565.37261963 [3140] Fn_FindRepairCycleOffset_1_DBUG: Scan Time = 5.205181 secs 44.378864FPS
00000097 565.37280273 [3140] Fn_FindRepairCycleOffset_1_DBUG: CntMax(40) = 68.966% of TotalCycles(58)
00000098 565.37292480 [3140] Fn_FindRepairCycleOffset_1_DBUG: Setting Attributes
00000099 565.37335205 [3140] Fn_FindRepairCycleOffset_1_DBUG: Attrib[0]=1 # VALID
00000100 565.37371826 [3140] Fn_FindRepairCycleOffset_1_DBUG: Attrib[1]=2 # Offset (Result)
00000101 565.37414551 [3140] Fn_FindRepairCycleOffset_1_DBUG: Attrib[2]=4 # InCycle (OutCycle=5)
00000102 565.37457275 [3140] Fn_FindRepairCycleOffset_1_DBUG: Attrib[3]=58 # TotalCycles in clip
00000103 565.37512207 [3140] Fn_FindRepairCycleOffset_1_DBUG: Attrib[4]=40 # Cnt[Offset]
00000104 565.37548828 [3140] Fn_FindRepairCycleOffset_1_DBUG: Attrib[5]=68.966 # Percent gotten
00000105 565.37603760 [3140] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+0]=5 # Cnt[0]
00000106 565.37664795 [3140] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+1]=6 # Cnt[1]
00000107 565.37719727 [3140] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+2]=40 # Cnt[2]
00000108 565.37774658 [3140] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+3]=7 # Cnt[3]


Result:
https://s20.postimg.org/c17k18xvh/Demo1_zpslgoyok8v.jpg (https://postimg.org/image/puvwqaqgp/)

client 2 script (just to demo Verbose MaxAcross, not neally enough frames for OutCycle=30, nor is clip suitable)

Avisource("F:\V\JurassicPark.AVI").trim(0,-10000)
FindRepairCycleOffset(OutCycle=30,MaxAcross=5).Trim(Framecount-1,-1) # Return only with Last frame and showing final result.
Return Crop(0,0,640,256)


Result:
https://s20.postimg.org/aat4di5q5/Demo2_zpsye57biu7.jpg (https://postimg.org/image/uuxybzlh5/)

Works real good.

EDIT: And just for good measure, heres the debug output

00000006 51.55144119 [2692] Fn_FindRepairCycleOffset_1_DBUG: Scan Time = 47.423885 secs 210.864212FPS
00000007 51.55158234 [2692] Fn_FindRepairCycleOffset_1_DBUG: CntMax(35) = 10.145% of TotalCycles(345)
00000008 51.55171204 [2692] Fn_FindRepairCycleOffset_1_DBUG: Setting Attributes
00000009 51.55212021 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[0]=1 # VALID
00000010 51.55253220 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[1]=0 # Offset (Result)
00000011 51.55296326 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[2]=29 # InCycle (OutCycle=30)
00000012 51.55335999 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[3]=345 # TotalCycles in clip
00000013 51.55390167 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[4]=35 # Cnt[Offset]
00000014 51.55430222 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[5]=10.145 # Percent gotten
00000015 51.55485916 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+0]=35 # Cnt[0]
00000016 51.55540085 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+1]=16 # Cnt[1]
00000017 51.55594635 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+2]=16 # Cnt[2]
00000018 51.55650711 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+3]=17 # Cnt[3]
00000019 51.55705261 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+4]=12 # Cnt[4]
00000020 51.55759811 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+5]=19 # Cnt[5]
00000021 51.55813980 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+6]=8 # Cnt[6]
00000022 51.55868912 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+7]=10 # Cnt[7]
00000023 51.55925369 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+8]=13 # Cnt[8]
00000024 51.55979919 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+9]=10 # Cnt[9]
00000025 51.56033707 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+10]=3 # Cnt[10]
00000026 51.56089020 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+11]=10 # Cnt[11]
00000027 51.56143570 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+12]=8 # Cnt[12]
00000028 51.56198120 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+13]=12 # Cnt[13]
00000029 51.56252289 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+14]=7 # Cnt[14]
00000030 51.56306839 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+15]=8 # Cnt[15]
00000031 51.56361008 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+16]=7 # Cnt[16]
00000032 51.56415939 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+17]=9 # Cnt[17]
00000033 51.56470871 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+18]=11 # Cnt[18]
00000034 51.56525040 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+19]=11 # Cnt[19]
00000035 51.56581497 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+20]=9 # Cnt[20]
00000036 51.56636047 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+21]=9 # Cnt[21]
00000037 51.56690598 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+22]=6 # Cnt[22]
00000038 51.56745148 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+23]=9 # Cnt[23]
00000039 51.56799316 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+24]=9 # Cnt[24]
00000040 51.56854248 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+25]=12 # Cnt[25]
00000041 51.56908798 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+26]=5 # Cnt[26]
00000042 51.56963348 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+27]=15 # Cnt[27]
00000043 51.57017899 [2692] Fn_FindRepairCycleOffset_1_DBUG: Attrib[6+28]=29 # Cnt[28]


EDIT: First clip was HD (the OP clip), 2nd clip SD (on my nasty Core Duo duel core 2.4 GHz).

I'll have a go at RepairCycle() tomorrow.

StainlessS
10th June 2017, 17:25
RepairCycle.avs

Function RepairCycle(clip c,Int InCycle,Int Offset,String "RepairFunc",Bool "Show",Bool "Debug") {
/*
RepairCycle(), Interpolate frames where original source clip had decimated 1 frame in every InCycle+1 frames.
Requires, RT_Stats, GScript, MvTools v2.0. (ColorSpace depends upon what MvTools supports, not RGB).

c, Clip to fix.
InCycle,Offset, A synthesized frame will be inserted following every c clip InCycle[Offset] frame.
RepairFunc, Default "ConvertFPS(FrameRate*2.0)" # Default is Blended frames.
or eg RepairFunc="DoubleRate(Flow=True,Blksize=32,Overlap=16)"
# DoubleRate [from:- https://forum.doom9.org/showthread.php?p=1789461#post1789461]
# Any DoubleRate Interpolator could be substituted
*/
c
myName="RepairCycle: "
Assert(RT_FunctionExist("GScript"),RT_String("%sEssential GScript plugin installed, http://forum.doom9.org/showthread.php?t=147846",myName))
Assert(RT_FunctionExist("MSuper"),RT_String("%sEssential MvTools v2.0 Installed",myName))
Assert(2 <= InCycle,RT_String("%s2 <= InCycle",myName))
Assert(0 <= Offset < InCycle,RT_String("%s0 <= Offset < InCycle",myName))
RepairFunc = Default(RepairFunc,"")
RepairFunc = (RepairFunc=="") ? "ConvertFPS(FrameRate*2.0)" : RepairFunc
Show=Default(Show,False)
Debug=Default(Show,False)
GSCript("""
COMMA=RT_Ord(",") SPACE=RT_Ord(" ")
S = RT_String("Interleave(\n")
for(i=0,InCycle-1) {
S = S + RT_String("\\ c.SelectEvery(%d,%d)%c\n",InCycle,i,(i==offset||i!=InCycle-1)?COMMA:SPACE)
If(i==Offset) {
S = S + RT_String("\\ dr.SelectEvery(%d,%d)%c\n",InCycle*2,i*2+1,(i!=InCycle-1)?COMMA:SPACE)
}
}
S = S + "\ )"
(DEBUG) ? RT_DebugF("\nS='%s'",S,name=myName) : NOP
""")
dr = Eval("c."+RepairFunc)
dr = (Show) ? dr.RT_Subtitle("Synthesized",Align=5) : dr
Eval(S)
Return Last
}


OP clip

Import("FindRepairCycleOffset.avs")
Import("RepairCycle.avs")

# OP clip
OUTCYCLE=5
SHOW=True
OFFSET=2
DEBUG=True
REPAIRFUNC="DoubleRate(Flow=True,Blksize=32,Overlap=16)"
Avisource("D:\00003-002.mkv.AVI")
RepairCycle(OUTCYCLE-1,OFFSET,Repairfunc=REPAIRFUNC,Show=SHOW)
return last


Known InCycle Offset

Import("FindRepairCycleOffset.avs")
Import("RepairCycle.avs")
OUTCYCLE=5
SHOW=True
LEN=10000
OFFSET=2 # OutCycle[OFFSET+1] is missing
DEBUG=True
REPAIRFUNC="DoubleRate(Flow=True,Blksize=32,Overlap=16)"
# Make test clip from JP PAL 25FPS.
Avisource("F:\V\JurassicPark.AVI").trim(0,-LEN) # LEN frames test clip
# Omit every forth frame (OutCycle[3] or following InCycle[OFFSET] ie following InCycle[2])
Interleave(SelectEvery(OUTCYCLE,0),SelectEvery(OUTCYCLE,1),SelectEvery(OUTCYCLE,2),SelectEvery(OUTCYCLE,4))
RepairCycle(OUTCYCLE-1,OFFSET,Repairfunc=REPAIRFUNC,Show=SHOW)
Return Last


Auto repair

Import("FindRepairCycleOffset.avs")
Import("RepairCycle.avs")
# Auto mode
OUTCYCLE=5
SHOW=True
LEN=10000
DEBUG=True
REPAIRFUNC="DoubleRate(Flow=True,Blksize=32,Overlap=16)"
# Make test clip from JP PAL 25FPS.
Avisource("F:\V\JurassicPark.AVI").trim(0,-LEN) # LEN frames test clip
# Omit every forth frame (OutCycle[3] or following InCycle[OFFSET] ie following InCycle[2])
Interleave(SelectEvery(OUTCYCLE,0),SelectEvery(OUTCYCLE,1),SelectEvery(OUTCYCLE,2),SelectEvery(OUTCYCLE,4))
# Find InCycle Offset.
ARR=RT_GetFullPathName("~TMP"+RT_LocalTimeString(File=True)+".ARR")
RESULTC=FindRepairCycleOffset(OutCycle=OUTCYCLE,ARR=ARR)
RT_AverageLuma(RESULTC,n=Framecount-1) # Force Last frame to be fetched (otherwise not requested unless returning RESULTC for display)
OK = RT_ArrayGetAttrib(ARR,0) == 1 # Are Attributes Valid ?
Assert(OK,"Offset Not found")
Offset=RT_ArrayGetAttrib(ARR,1)
RepairCycle(OUTCYCLE-1,Offset,Repairfunc=REPAIRFUNC,Show=SHOW,Debug=DEBUG)
RT_FileDelete(ARR)
Return Last # Return auto repaired clip


EDIT: Oops, got my names mixed up due to having 2 sets of functions, one set called CycleRepair,, and the other RepairCycle,
changed to all using RepairCycle, I hope. :(

kuchikirukia
14th October 2017, 03:46
What seemed to work best was:
REPAIRFUNC="DoubleRate(Flow=True,Blksize=32,Overlap=16,SearchParam1=3,SearchParam=1,blend=false)"

StainlessS
14th October 2017, 15:47
Did it produce acceptable results ?

I did scripts as a bit of a folly.

When testing on Jurassic Park(PAL), I got the impression that the original was shot at much higher frame rate, and could (I think) tell
where frames had been dropped from the higher rate. (I dont actually remember what I concluded, just that something did
'stick out' from results, could also see where cadence changed from scene to scene due to editing, seemed to be able to tell what it was before
studio editing).

kuchikirukia
14th October 2017, 18:17
Yes, but oddly it seems to miss a frame now and again. It will just double the frame before the jump, and this may continue for a while. Is there some scene change detection, and a way to change the level if so?

StainlessS
14th October 2017, 19:02
If cadence changes then is unlikely to be of use (not terribly useful anyway, as could fix by hand in such a case where constant cadence).
Detect on single scene would likely not create sufficiently useful results, needs lots of frames to be statistically significant.
X-Men II has at least 1 scene/shot of a single frame. (not counting the jump about intro)

kuchikirukia
14th October 2017, 19:12
It's not a cadence change, it just switches from interpolation to doubling.