Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Capturing and Editing Video > Avisynth Usage
Register FAQ Calendar Today's Posts Search

Reply
 
Thread Tools Search this Thread Display Modes
Old 13th December 2020, 22:41   #1  |  Link
Nuihc88
Registered User
 
Nuihc88's Avatar
 
Join Date: Oct 2016
Location: Tellus, Milky Way Galaxy
Posts: 21
Methods for Duplicate Frame Detection & Deletion in Scripts?

I have been trying to come up with a script for detecting and removing duplicate frames from a video stream to turn constant frame rate video into variable frame rate to be used with animated content to make motion interpolation smoother and less resource intensive. For now i intent to rely on existing frame timestamps, but might add some sort of timestamp generation later on...

Thus far i have been able to get the detection part working, although there is still room for improvement, but i haven't been able to figure out how to actually discard the duplicate frames from a video stream...

This is what i have now:
Code:
global DupThreshold = 0.618034
last = ScriptClip(last, """
Duplicate = YDifferenceFromPrevious < DupThreshold
Subtitle("Duplicate = " + String(Duplicate) + "    Threshold Value = " + string(DupThreshold) + "    Difference = " + string(YDifferenceFromPrevious) + "    Frame# = " + string(current_frame), align=2)
#Duplicate ? DeleteFrame(current_frame) : last
""")
The commented out line is just one variation of countless attempts i've made. I'm getting the impression that i'm going about this in a fundamentally wrong way, but have no idea what i could be missing...
Nuihc88 is offline   Reply With Quote
Old 13th December 2020, 23:35   #2  |  Link
johnmeyer
Registered User
 
Join Date: Feb 2002
Location: California
Posts: 2,695
I am just about to scan an hour of video for duplicates, so I'm revisiting my old dup detection script. It is the same as yours, but has the ability to write the frame numbers to a file.

Code:
#This script finds exact duplicate frames and outputs the frame numbers

global blankthreshold=3

filename = "e:\output_duplicate_frames.txt"
AVISource("e:\fs.avi").killaudio()
i=AssumeBFF.ConvertToYV12

#This line below will output EVERY frame that is below threshold, which results in LOTS of frames
#Normally you don't do this, but it is included for those who want this capability.
#WriteFileIf(last, filename,  "(YDifferenceFromPrevious(i)<=blankthreshold)", "current_frame+1", append = false)

#The line below writes the FIRST frame that falls below the threshold
#WriteFileIf(last, filename,  "(YDifferenceFromPrevious(i)>blankthreshold)&&YDifferenceToNext(i)<=blankthreshold", "current_frame", append = false)

#Use this instead of WriteFile in order to determine blankthreshold
ScriptClip("Subtitle(String(YDifferenceFromPrevious(i)))")
This particular video I'm about to work on has dozens of duplicates in a row, where the streaming service froze. I simply want to create a marker in my NLE that will appear at the beginning of the dups, and then go in and edit out the bad spot. Thus, I only want the frame number of the first frame in a string of duplicates.
johnmeyer is offline   Reply With Quote
Old 14th December 2020, 12:09   #3  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Not quite working John,
this does.

Code:
blankthreshold=0.1      # ssS: does not need be Global (only needed inside function, not at main script level)

filename = ".\output_duplicate_frames.txt"  # In current directory

Colorbars.KillAudio.Trim(0,-100).ShowFrameNumber
A=Trim(0,9)
B=Trim(10,0)
D=A.Trim(9,-1)            # dupe of frame 9
A++D++D++D++B             # Frames 10, 11, and 12 exact dupes

AssumeBFF.ConvertToYV12   # you dont need clip i

#This line below will output EVERY frame that is below threshold, which results in LOTS of frames
#Normally you don't do this, but it is included for those who want this capability.
#WriteFileIf(last, filename,  "YDifferenceFromPrevious<=blankthreshold", "current_frame", append = false)  # Dump "+1", current_frame is the dupe

#The line below writes the FIRST frame that falls below the threshold
#WriteFileIf(last, filename,  "YDifferenceFromPrevious>blankthreshold && YDifferenceToNext<=blankthreshold", "current_frame+1", append = false)

#Use this instead of WriteFile in order to determine blankthreshold
ScriptClip("Subtitle(String(YDifferenceFromPrevious))")
Also can select All frames in txt file, or all frame NOT in text file using SelectRanges() and RejectRanges()
https://forum.doom9.org/showthread.p...60#post1715260

EDIT: You may get frame numbers generated at start and end of clip, ie 0 and FrameCount-1
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 14th December 2020 at 12:17.
StainlessS is offline   Reply With Quote
Old 14th December 2020, 12:38   #4  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Nuihc88,
You cant delete frames in runtime script, result clip must be same length as input to runtime script,
best create text file of frame numbers to drop and use plugin to establish deleted frames and set result clip length
before frame serving begins.
[FrameCount, FrameRate, ColorSpace, FrameSize, (and maybe a few more) are all fixed before frameserving begins, and cannot change]
Gavino wrote a script [cant remember name] that deletes frames, however you end of with a load of duplicates at end of clip,
which need be removed by hand. Basically, the difference between original length and cut length is a repeat of the last frame of cut length.

Get txt file something like
Code:
DupThreshold=0.0       # Detect Exact Dupes only [Changed to <= in comparison]

filename = ".\output_duplicate_frames.txt"  # In current dorectory

Colorbars.KillAudio.Trim(0,-100).ShowFrameNumber
A=Trim(0,9)
B=Trim(10,0)
D=A.Trim(9,-1)            # dupe of frame 9
A++D++D++D++B             # Frames 10, 11, and 12 exact dupes

AssumeBFF.ConvertToYV12

RT_FileDelete(Filename)

SSS = """
    n   = current_frame
    pdf = YDifferenceFromPrevious
    if(pdf <= DupThreshold && n > 0) {
        Subtitle(String(n,"%'0f] ")+String(pdf),align=2)
        RT_WriteFile(filename,"%d",n,Append=True)
    }
    Return Last
"""

ScriptClip(SSS)
Above uses RT_Stats.

and use the RejectRanges() script function [from FrameSel plugin] already linked. [Requires FrameSel and Prune Plugins]

EDIT: Produces
Code:
10
11
12
EDIT: RejectRanges() copes with both single frames and ranges in txt command file.
EDIT: Or use one of the Dedup style plugins. [Probably your best bet].
Even if you could do it in script, making a timecode file would not work very well,
Avs type Float is just not accurate enough for longer clips, need double precision of C/CPP.


EDIT:
And optional detect only first frame of run of dupes, with dif to prev ALWAYS printed on top of frame,
and on bottom if detection.
Code:
DupThreshold=0.0        # Detect Exact Dupes only [Changed to <= in comparison]

filename = ".\output_duplicate_frames.txt"  # In current dorectory
###
FIRSTONLY = False   # If True, only show/write first Dupe of dupe run frame number
SUBS      = True   # False Omit Subtitles, may be faster for only txt file.
TWOPASS   = False  # If True, do in TwoPass mode, ie generate txt file, then remove dupes from result clip. [Switches OFF SUBS]
TRIMAUDIO = False  # When TWOPASS ONLY, False=original audio, True=audio trimmed as for dupe frames.
###
Colorbars.KillAudio.Trim(0,-100).ShowFrameNumber
A=Trim(0,9)
B=Trim(10,0)
D=A.Trim(9,-1)            # dupe of frame 9
A++D++D++D++B             # Frames 10, 11, and 12 exact dupes

AssumeBFF.ConvertToYV12

###########
SUBS = (TWOPASS) ? False : SUBS    # Switch off SUBS if TWOPASS
RT_FileDelete(Filename)

SSS = """
    n    = current_frame
    pdf  = YDifferenceFromPrevious
    IsDup = (pdf <= DupThreshold  && n > 0)
    (SUBS) ? Subtitle(String(n,"%.0f] ")+String(pdf),Text_Color=IsDup?$FFFF00:$FFFFFF,align=8) : NOP
    if(IsDup) {
        if(!FIRSTONLY || YDifferenceFromPrevious(-1) > DupThreshold) {
            (SUBS) ? Subtitle(String(n,"%.0f] ")+String(pdf),align=2) : NOP
            RT_WriteFile(filename,"%d",n,Append=True)
        }
    }
    Return last
"""

ScriptClip(SSS)

#
if(TWOPASS) {
    RT_ForceProcess()                               # Force above scriptclip from frame 0 to last frame, writing any text file
    ReJectRanges(Cmd=filename,trimAudio=TRIMAUDIO)  # Reject frames in txt file
}

Return Last
EDIT: TWOPASS only makes sense when FIRSTONLY=False.

EDIT: RejectRanges function from FrameSel plugin SelectRanges.avsi
Code:
Function RejectRanges(clip c,String "SCmd",String "Cmd",Bool "TrimAudio",Float "FadeMS") {
    # RejectRanges() by StainlessS. Required:- FrameSel, Prune, RT_Stats
    # Wrapper to delete frames/ranges along with audio, can supply frames/ranges in SCmd string And/Or Cmd file.
    #   The wrapper makes for easier usage of Prune() which supports up to 256 input clips, but requires a clip index,
    #   eg '3, 100,200' would specify clip 3, range 100 to 200. The wrapper does away with the necessity for the clip index as we
    #   are only using a single clip here. Prune also does not have a 'reject' arg to delete specified frames rather than select them,
    #   this wrapper also converts a list of frames to delete into a list of frames to select so that we can use Prune and its audio
    #   capability.
    #
    # SCmd: Frames/Ranges specified in String (Frames/Ranges either Chr(10) or ';' separated, infix ',' specifies range, eg 'start,end').
    # Cmd:  Frames/Ranges specified in file (one frame/range per line, comments also allowed, see FrameSel for Further info).
    # TrimAudio:
    #   True(default), deletes audio belonging to deleted frames
    #   False, returns original audio, probably out of sync.
    # FadeMS: (default 1.0 millisec). Linear Audio Fade duration at splices when TrimAudio==true, 0 = dont fade (might result in audio 'clicks/cracks').
    c
    TrimAudio=Default(TrimAudio,True)   # default true trims audio, false returns original audio (audiodubbed, as Framesel returns no audio)
    FadeMS=Float(Default(FadeMS,1.0))   # 1 millisecond linear fadeout/fadein at splices
    PruneCmd = (TrimAudio) ? "~Prune_"+RT_LocalTimeString+".txt" : ""
    (!TrimAudio)
        \ ? FrameSel(scmd=SCmd,cmd=Cmd,reject=true)
        \ : FrameSel_CmdReWrite(PruneCmd,scmd=SCmd,cmd=Cmd,reject=true,Prune=True,range=true)
    (TrimAudio) ? Prune(Cmd=PruneCmd,FadeIn=True,FadeSplice=True,FadeOut=True,Fade=FadeMS) : NOP
    # If TrimAudio==true then delete Prune temp file, Else restore original Audio to the now audio-less clip
    (TrimAudio)
        \ ? RT_FileDelete(PruneCmd)
        \ : (c.HasAudio) ? AudioDub(c) : NOP
    Return Last
}
EDIT: Ooops, posted wrong version for each of above code blocks, fixed.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 15th December 2020 at 15:10.
StainlessS is offline   Reply With Quote
Old 14th December 2020, 17:40   #5  |  Link
johnmeyer
Registered User
 
Join Date: Feb 2002
Location: California
Posts: 2,695
My script works just fine. As I said in my earlier post, I was about to run it on an hour video captured from a live streaming event that hiccuped and had pauses at about a dozen random places. I needed to find those and edit out the pause.

I ran it, found all the bad spots, cut them out or replaced the gap with ramped slow motion from the adjacent 5-10 seconds, and produced a nice video from the result.

I could have also done it by looking at the audio track, but I realized that I didn't know how to use AVISynth to search for silent spots on the audio track. I briefly searched, but couldn't find an answer.

Is there an audio level filter?
johnmeyer is offline   Reply With Quote
Old 14th December 2020, 17:52   #6  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Arh, you wanted the frame before the first dupe [the frame that the dupes are a copy of ?].

Well anyways, here is your script with test clip mod [frame 10,11,12 are dupes], and because of diff being only ShowFrameNumber, used threshold =0.1

Code:
#This script finds exact duplicate frames and outputs the frame numbers

#AVISource("e:\fs.avi").killaudio()

Colorbars.KillAudio.Trim(0,-100).ShowFrameNumber
A=Trim(0,9)
B=Trim(10,0)
D=A.Trim(9,-1)            # dupe of frame 9
A++D++D++D++B             # Frames 10, 11, and 12 exact dupes

global blankthreshold=0.1

filename = ".\output_duplicate_frames.txt"      # ssS: to current directory
i=AssumeBFF.ConvertToYV12

#This line below will output EVERY frame that is below threshold, which results in LOTS of frames
#Normally you don't do this, but it is included for those who want this capability.
#WriteFileIf(last, filename,  "(YDifferenceFromPrevious(i)<=blankthreshold)", "current_frame+1", append = false)

#The line below writes the FIRST frame that falls below the threshold
WriteFileIf(last, filename,  "(YDifferenceFromPrevious(i)>blankthreshold)&&YDifferenceToNext(i)<=blankthreshold", "current_frame", append = false)

#Use this instead of WriteFile in order to determine blankthreshold
#ScriptClip("Subtitle(String(YDifferenceFromPrevious(i)))")
Dupes @ 10,11,12. [all an exact copy of frame 9, 103 frames in clip, last frame = 102]

1st test uncommented result
Code:
1
11
12
13
2nd test uncommented result [so is this as required ?, dupes are a copy of this ? (ie 9)]
Code:
9
102
Still looks wrong to me [1st test defo wrong, 2nd test depends on what you want to detect]
EDIT: Using PotPlayer

EDIT: I Get, FIRSTONLY=false [my script]
1st
Code:
10
11
12
2nd, FIRSTONLY = True
Code:
10
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 14th December 2020 at 19:02.
StainlessS is offline   Reply With Quote
Old 14th December 2020, 18:30   #7  |  Link
VoodooFX
Banana User
 
VoodooFX's Avatar
 
Join Date: Sep 2008
Posts: 989
Quote:
Originally Posted by StainlessS View Post
Not quite working John,
this does...
Could this exact dupe detection be incorporated into ApparentFPS? Like scanning whole clip then "Show" would show total number of the exact dupes and previous/next frame number of exact dupe.
VoodooFX is offline   Reply With Quote
Old 14th December 2020, 18:52   #8  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Clarify please.
[and what does ApparentFPS have to do with it, detects dupes by DupeThresh, not just exact dupes]

EDIT:
Post #4,
changed threshold to 0.0 [Could not use 0.0 as threshold previously, now 0.0 detects exact only]
# Detect Exact Dupes only [Changed to <= in comparison rather than < ]
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 14th December 2020 at 19:17.
StainlessS is offline   Reply With Quote
Old 14th December 2020, 20:22   #9  |  Link
VoodooFX
Banana User
 
VoodooFX's Avatar
 
Join Date: Sep 2008
Posts: 989
Quote:
Originally Posted by StainlessS View Post
Clarify please.
[and what does ApparentFPS have to do with it, detects dupes by DupeThresh, not just exact dupes]
As I already use ApparentFPS for information on the dupes, would be nice to have that additional functionality in one plugin as sometimes I need to detect those ~few exact dupe frames like John.

PS:
Currently ApparentFPS tests max 1024 frames.

Last edited by VoodooFX; 14th December 2020 at 20:31.
VoodooFX is offline   Reply With Quote
Old 15th December 2020, 12:00   #10  |  Link
Nuihc88
Registered User
 
Nuihc88's Avatar
 
Join Date: Oct 2016
Location: Tellus, Milky Way Galaxy
Posts: 21
Quote:
Nuihc88,
You cant delete frames in runtime script, result clip must be same length as input to runtime script,
best create text file of frame numbers to drop and use plugin to establish deleted frames and set result clip length
before frame serving begins.
[FrameCount, FrameRate, ColorSpace, FrameSize, (and maybe a few more) are all fixed before frameserving begins, and cannot change]
Gavino wrote a script [cant remember name] that deletes frames, however you end of with a load of duplicates at end of clip,
which need be removed by hand. Basically, the difference between original length and cut length is a repeat of the last frame of cut length.
[...]
EDIT: Or use one of the Dedup style plugins. [Probably your best bet].
Even if you could do it in script, making a timecode file would not work very well,
Avs type Float is just not accurate enough for longer clips, need double precision of C/CPP.
[...]
That's a lot to respond to so i'll just try to summarise what i've tried this far:
  1. I've gotten creating of Dupes.txt file for a test script working before, but trying to get DeleteFrame to load it has failed every time due to "Invalid arguments to function 'DeleteFrame'."; Yet copy-pasting file contents works just fine.
  2. When testing with "DeleteFrame(1,2,3,[...])" directly, the output becomes out of sync, but i haven't encountered any problems with clip length while using either LWLibavVideoSource() or AvsFilterSource().
  3. I have previously experimented with every dupe filter listed here and none met my requirements. Most are either 2-pass only, constant frame rate (frame copy) only or have some other problems with seeking, etc. I'm looking for a solution that can work in realtime-playback as well as traditional scripts (and preferably doesn't add too many extra dependencies). Dup & DeDup seemed promising, but i would need to modify them somehow for variable frame rate output in single-pass and that's beyond my current skill-level.
  4. I've also already considered and experimented with doing extra motion interpolation runs to replace the dupes, but with several missing frames in a row, this could lead to inconsistent CPU & RAM requirements for realtime-playback, which is far from ideal. Even so, that is likely what i'll end up doing assuming i get FrameDelete or equivalent working in single-pass, but can't find another workaround for the sync-issues.

I'm still experimenting to see which parts of your scripts i could adapt for my use case(s). ...could take a while.

Last edited by Nuihc88; 15th December 2020 at 16:09.
Nuihc88 is offline   Reply With Quote
Old 15th December 2020, 15:04   #11  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
From post #4
Quote:
Ooops, posted wrong version for each of above code blocks, fixed.
I seem to have mixed up old/new script versions in post #4, fixed. [There are two code blocks in post #4]

EDIT:
FireFox TextArea Cache addon allowed me to recover the original first code block script [which I had deleted on disk],
not the first time that this great lil' addon saved my bacon.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 15th December 2020 at 15:07.
StainlessS is offline   Reply With Quote
Old 15th December 2020, 22:09   #12  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Nuihc88, here some post on deleting frames in script.

Code:
# Delete frames satisfying user-defined condition
https://forum.doom9.org/showthread.php?t=163107

# Delete Dups
https://forum.doom9.org/showthread.p...me#post1538988

# How can I get fdecimate to use only the Luminance?
https://forum.doom9.org/showthread.p...me#post1479519

# Prune: PruneKeepFrames : PruneDeleteFrames
https://forum.doom9.org/showthread.p...98#post1539598

# RenderSegments.avs
https://forum.doom9.org/showthread.p...41#post1749741

# Auto drop dark frames  : 
https://forum.doom9.org/showthread.p...58#post1181958
EDIT:
However,
You need a 2 pass approach to delete frames properley in Avisynth [and without stutter etc],
and can use RejectFrames() script to do it. [Uses Prune and FrameSel plugins and Frames text file, ie 2 pass].
DeleteFrame() only works with direct int args, not frames file, so cannot use DeleteFrame with frames file.

Avisynth plays only constant framerate clips, so will of course be out of sync when you delete frames, you need use
a plugin which uses 2 pass approach and Timecodes file, and encode to VFR.

Even if you could do as you require (and there is often some way to hack Avisynth) then you would encounter stuttering or
just plane pausing during playback, you need a 2 pass plugin solution.

Attempting 1 pass script solutiong to fit your requirements is doomed to failure.

The 2nd script in post #4 is an AUTO 2 pass solution, does first pass, then starts playing clip at the begining for 2nd pass,
best you are gonna get but will still only play resultant frames at constant framerate.

EDIT: I aint no VFR expert, never touched the stuff except to turn into CFR, I have no use for it.

EDIT:
For this, your original script with slight mods [and synthesized test clip]
Code:
Colorbars.KillAudio.Trim(0,-100).ShowFrameNumber
A=Trim(0,9)
B=Trim(10,0)
D=A.Trim(9,-1)            # dupe of frame 9
A++D++D++D++B             # Frames 10, 11, and 12 exact dupes
AssumeBFF.ConvertToYV12

DupThreshold = 0.618034
SSS = """
    Duplicate = YDifferenceFromPrevious < DupThreshold
    Subtitle("Duplicate = " + String(Duplicate) + "    Threshold Value = " + string(DupThreshold) + "    Difference = " + 
    \ string(YDifferenceFromPrevious) + "    Frame# = " + string(current_frame), align=2)
#    Duplicate ? DeleteFrame(current_frame) : last
"""
Return ScriptClip(SSS)
Framecount into, and out of Scriptclip are always the same.
On Entry to Scriptclip, current_frame is always the required output frame number [irrespective of whether it was changed in previous iterations].
Use of above YDifferenceFromPrevious is always on current_frame.
If above DeleteFrame(current_frame) is called, then returns current_frame+1 of scriptclip input clip, where input
to scriptclip is unchanged by any prior uses of DeleteFrame, DeleteFrame(current_frame) only affects resulting
scriptclip output frame.
To do it properley and cope with multiple dupes in a single clip, you need to track number of dupes from input have
already been deleted in previous iterations and test on eg YDifferenceFromPrevious(Offset=DeleteCnt) [ie on current_frame+DeleteCnt],

Something like this. [ALSO, CANNOT JUMP ABOUT, FORWARD ONLY]
We will not actually use DeleteFrame(), will only adjust current_frame to select the one we are interested in.
Code:
Colorbars.KillAudio.Trim(0,-100).ShowFrameNumber
A=Trim(0,9)
B=Trim(10,11)
C=Trim(12,0)
D=A.Trim(9,-1)            # dupe of frame 9
E=B.Trim(1,-1)            # dupe of frame 12
A++D++B++E++C             # Frames 10, and 13, exact dupe
AssumeBFF.ConvertToYV12

DupThreshold = 0.0        # Changed logic <= instead of < for checking exact dupes
DupeCnt=0
SSS = """
    current_frame = current_frame + DupeCnt     # take into account already detected dupe frames when testing YDifferenceFromPrevious
    pdf = YDifferenceFromPrevious
    Duplicate = (pdf <= DupThreshold && current_frame>0)   # Avoid duplicate detect at frame 0
    if(Duplicate) {
        current_frame = current_frame + 1       # skip this single dupe
        DupeCnt       = DupeCnt       + 1       # update dupe count
    }
    Return Trim(current_frame,-1)               # Returning single frame at current_frame
"""
Return ScriptClip(SSS)
Above does not cope with multiple consecutive dupes, for that you would need to detect length of duplicate run.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 16th December 2020 at 01:54.
StainlessS is offline   Reply With Quote
Old 16th December 2020, 02:52   #13  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
OK, here Multiple-consecutive Dupe removel, End frames [Same number as dupes removed] are returned at PC Levels Black.
[ScriptClip must return same result length as input clip]
Code:
DEBUG=True
# Construct TEST clip, Before Insertion of Dupes, ShowFrameNumber 0 to 15 on frames 0 to 15. [dupe removal should be same with some black at End ]
Colorbars.KillAudio.Trim(0,-16).ShowFrameNumber

######################
A=Trim(0,9)           # 10 frames
D1=A.Trim(9,-1)       # dupe of frame 9
B=Trim(10,11)         # 2 frames
D2=B.Trim(1,-1)       # dupe of frame 12
C=Trim(12,15)         # 4 frames
D3=C.Trim(3,-1)       # dupe of frame 15
######################

A+D1+D1+B+D2+D2+D2+C  # Frames 10,11, and 14,15,16, exact dupes [21 frames]
#Last=Last+D3         # If Uncommented,  Frames 10,11, and 14,15,16, and 21 exact dupes [22 frames] # TEST WITH DUPE At End of clip
                      # WHEN ALL DUPES REMOVED, SHOULD READ CONSECUTIVE FRAME NUMBERS ON CLIP
#return last

ConvertToYV12
DupThreshold = 0.0   # Changed logic <= instead of <, Allows for checking exact dupes
DupeCnt=0
# !!! SCAN FORWARDS ONLY !!!
SSS = """
    FC=Framecount
    current_frame = current_frame + DupeCnt # take into account already detected input dupe frames when testing YDifferenceFromPrevious
    if(current_frame < FC) { # Is input clip frame range ?
        pdf = YDifferenceFromPrevious
        Duplicate = (pdf <= DupThreshold && current_frame>0)   # Avoid duplicate detect at frame 0
        if(Duplicate) {
            n=current_frame                         # Remember original current_frame to calc current dupe run count
            current_frame = current_frame + 1       # We are not using Offset for YDifferenceFromPrevious, modding current_frame instead
            while(current_frame < FC && YDifferenceFromPrevious <= DupThreshold) {
                current_frame = current_frame + 1
            }
            RunLen = current_frame - n              # Length of duplicate run
            (DEBUG) ? RT_DebugF("%d] Dupes %d to %d [Len=%d] removed",n,n,n+RunLen-1,RunLen,name="DupDel: ") : NOP
            DupeCnt = DupeCnt + RunLen   # update dupe count
            # If we have totally exhausted input clip due to dupes at end of clip, ret black frame
            (current_frame >= FC) ? Last.BlankClip(Length=1,color_yuv=$008080) : NOP
        }
    } else { Last.BlankClip(Length=1,color_yuv=$008080) }  # Out of input clip bounds [deleted lots of frames and past end of input clip]
    Return Trim(current_frame,-1)                   # Returning single frame at current_frame [current_frame is valid range limited]
"""
Return ScriptClip(SSS)

# Frames where input clip exhausted due to skipping dupes, are returned at PC Levels Black $008080 at END of result clip
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 16th December 2020 at 14:26.
StainlessS is offline   Reply With Quote
Old 20th December 2020, 16:41   #14  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
@VoodooFX, still pondering your request, have not (yet) forgotten, dont know if it will come to anything and is on back burner.
Dont hold your breath waiting.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 20th December 2020 at 16:55.
StainlessS is offline   Reply With Quote
Old 23rd December 2020, 00:20   #15  |  Link
Nuihc88
Registered User
 
Nuihc88's Avatar
 
Join Date: Oct 2016
Location: Tellus, Milky Way Galaxy
Posts: 21
Since AviSynth doesn't support variable frame rates without sync-problems, i decided to continue experimenting with Frame Interpolation and eventually managed to put together something that sort of works...

...Apart from the diagnostic info floating about, two separate passes of interpolation multiplying every bit of distortion by a factor of itself and the whole thing being slow enough to be welcomed into the government.

Here's a somewhat stripped down, but still messy and completely unoptimized version of what i have pieced together at the moment:
Code:
global rate="{rate:{num:2,den:1}"
global super_params="{pel:1,gpu:1,full:false}"
global analyse_params="{block:{w:32,h:32,overlap:0}}"
global smoothfps_params=",algo:2,cubic:1,linear:false,
scene:{mode:1,blend:false,limits:{scene:2220,zero:4,blocks:42}}}"

DupeInterpolator = """global DupeThreshold=.618034    global DupeCounter=0        global FrameCounter=current_frame+DupeCounter
Subtitle("Duplicates = "+String(DupeCounter) + "    Threshold = "+string(DupeThreshold) + "    Difference = "+string(YDifferenceFromPrevious) + "    Frame# = "+string(current_frame)+" / "+string(FrameCounter), align=2)

if(Framecount>current_frame && DupeThreshold>=YDifferenceFromPrevious) {
    FrameNumber=current_frame               current_frame=current_frame+1
    DupeFactor=current_frame-FrameNumber    DupeCounter=DupeCounter+DupeFactor

while(Framecount>current_frame && DupeThreshold>=YDifferenceFromPrevious) {current_frame=current_frame+1}

    trim(FrameNumber-1,-1)+trim(FrameNumber+DupeFactor,-1)
        super0=SVSuper(last,super_params)
        vectors0=SVAnalyse(super0,analyse_params,src=last)
        DupeFactor="{rate:{num:"+string(DupeFactor+1)+",den:1}"
        SVSmoothFps(super0,vectors0,DupeFactor+smoothfps_params,mt=1).Subtitle("Dupe-Pass: Interpolated")
    trim(1, Framecount-2)}

else{current_frame=current_frame+1          last.Subtitle("Dupe-Pass: Original")}
"""
last = ScriptClip(DupeInterpolator)

super=SVSuper(last, super_params)
vectors=SVAnalyse(super, analyse_params, src=last)
SVSmoothFps(last, super, vectors, rate+smoothfps_params, mt=1).Subtitle("Regular-Pass: Enabled", align=1)
It should be fairly easy to adapt for other Frame Interpolation filters, if someone feels so inclined; They'll just need replace everything in between the trim-lines.

I can figure out how to speed-optimize the other AviSynth-script & SVP-stuff, but the ScriptClip-stuff is a completely new territory for me so any help with that would be appreciated.

Last edited by Nuihc88; 23rd December 2020 at 22:25. Reason: Highlighted diagnostic stuff...
Nuihc88 is offline   Reply With Quote
Old 17th July 2021, 05:39   #16  |  Link
Nuihc88
Registered User
 
Nuihc88's Avatar
 
Join Date: Oct 2016
Location: Tellus, Milky Way Galaxy
Posts: 21
DupeInterpolator

Here's a much more refined version of the script above. Solves floating diagnostic info and amplification of visual distortion issues, while producing much smoother output and having some performance optimizations, yet it still seems to be capped at ~20fps with only 40% of CPU ever getting utilized... Since the script isn't thread-safe, adding Prefetch and OnCPU only adds another ~1 fps at most... Not sure where to go from here...

Code:
global super_params="{pel:1,gpu:1,full:false}"
global analyse_params="{block:{w:32,h:32,overlap:0}}"
global smoothfps_params="},algo:2,cubic:1,linear:false,
scene:{mode:1,blend:false,limits:{scene:2220,zero:4,blocks:42}}}"

#### Use ChangeFPS to create duplicate frames to later be replaced by DupeInterpolator ScriptClip. 
       FramerateTargetingMode=1                # 0 = None    - Don't use ChangeFPS to add extra duplicates to interpolate.
       TargetFPS=59.94              Num=2      # 1 = Dynamic - Uses highest integer multiplier below TargetFPS.
global Stats=false                  Den=1      # 2 = Set FPS - Creates duplicate frames to reach all the way up to TargetFPS.
global DupeThreshold=.618034                   # 3 = Static  - Uses Num / Den values from above to set framerate manually.
     if (FramerateTargetingMode==1) {Num=1 while(FrameRate()*(Num+1)<TargetFPS){Num=Num+1} ChangeFPS(FrameRate()*Num)}
else if (FramerateTargetingMode==2) {ChangeFPS(TargetFPS)}   else if (FramerateTargetingMode==3) {ChangeFPS(Num, Den)}

DupeInterpolator = """Difference=YDifferenceFromPrevious() FrameNumber=current_frame global DupeFactor=0 global DupeCounter=0
if(Framecount()>current_frame && DupeThreshold>=Difference) {current_frame=current_frame+1 DupeFactor=DupeFactor+1 DupeCounter=DupeCounter+1
  while(Framecount()>current_frame && DupeThreshold>=YDifferenceFromPrevious() ) {current_frame=current_frame+1}

    trim(FrameNumber-1,-1)+trim(current_frame,-1)
      super=SVSuper(last,super_params)		vectors=SVAnalyse(super,analyse_params,src=last)
      SVSmoothFps(super,vectors,"{rate:{num:"+string(DupeFactor+1)+",den:1"+smoothfps_params,mt=1)
    trim(1,DupeFactor) Stats ? Subtitle("Dupe-Pass: Interpolated") : last}

else{DupeFactor=0 Stats ? Subtitle("Dupe-Pass: Original") : last}
  Stats ? Subtitle("Threshold = "+string(DupeThreshold) +"    Difference = "+string(Difference)+"    DupeFactor = "+String(DupeFactor)+\
"    Duplicates= "+String(DupeCounter)+ "    Originals = "+string(FrameNumber-DupeCounter)+"    Total = "+string(FrameNumber), align=8) : last"""
ScriptClip(DupeInterpolator)
Sadly at the current speed this script is still useless to me, but perhaps it will be useful to someone else or someone can figure out how to get around the 40% CPU utilization cap problem.....

Last edited by Nuihc88; 22nd July 2021 at 15:06. Reason: fixed highlighting, etc.
Nuihc88 is offline   Reply With Quote
Old 24th October 2023, 10:13   #17  |  Link
rgr
Registered User
 
Join Date: Jun 2022
Posts: 53
How to use this script? Can it be modified to use RIFE for frame interpolation?
https://forum.videohelp.com/threads/...X-InsertFrameX
rgr is offline   Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 15:41.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.