# Dupped() attempts to make duplicate frames mathematically identical. # # This filter requires a YUV source. Use converttoyv12 if needed # before calling dupped() # ## Parameters # thresh = Used to determine when to delare a frame as new # Use stats=true to help determine the best value for your source # Lower number = more sensitive. (Default=16) # # panthresh=1.65 This is used to determine when to consider a frame # part of a low motion scene. (Default=1.65) # # stats = Enable/disable display of stats. (Default=false | Not shown) # (Last = last frame, this = this frame, next = next frame) # # showme = Enable/disable display of video that most stats are # derived from. (Default=false | Not shown) # ## Notes # Do not use with SetMTMode(). This function requires the frames to be # accessed sequentially. Instead, use MT() to mulit-thread on a per-filter basis. # # Example: # dupped(thresh=20,panthresh=1.65,stats=true,showme=true) Function Dupped(clip c, int "thresh", float "panThresh", bool "stats", bool "showme") { c Global dupThresh = default(thresh, 16) Global panThresh = Float(default(panThresh, 1.65)) Global dupStats = default(stats, false) Showme = default(showme, false) Global lastNewFrame=0 scriptclip(""" c = Last n=current_frame FC = FrameCount prev_frame = (n > 0) ? n-1 : 0 next_frame = (n < FC-1) ? n+1 : FC-1 #Get Y related stats as needed prevCurrentYMinMax = Subtract(Trim(prev_frame,-1),c).YPlaneMinMaxDifference currentNextYMinMax = prevCurrentYMinMax < dupThresh ? Subtract(Trim(next_frame,-1),c).YPlaneMinMaxDifference : 256 prevNextYMinMax = currentNextYMinMax < dupThresh ? Subtract(Trim(prev_frame,-1),Trim(next_frame,-1)).YPlaneMinMaxDifference : 0 #calculate dynamic pan threshold. Set to 256 if looking for a pan is pointless neighborAvgMinMax = (prevCurrentYMinMax + currentNextYMinMax) / 2.0 dynPanThresh = prevNextYMinMax != 0 ? Abs(neighborAvgMinMax * panthresh) : 256.0 #determine if the current frame is new IsNewFrame = (prevCurrentYMinMax >= dupThresh || prevNextYMinMax >= dynPanThresh) Global lastNewFrame = IsNewFrame ? n : lastNewFrame c = Trim(lastNewFrame,-1) c = dupStats ? c.subtitle("prevframe: "+string(prev_frame)+" currentframe: "+string(n)+" nextframe: "+string(next_frame)) : c c = dupStats ? c.subtitle("Last new frame: "+string(lastNewFrame)+" IsNewframe: "+string(IsNewFrame),y=15) : c c = dupStats ? c.subtitle("prevCurrentYMinMax: "+string(prevCurrentYMinMax)+" (Threshold:"+string(dupThresh)+")",y=45) : c c = dupStats && currentNextYMinMax != 256 ? c.subtitle("currentNextYMinMax: "+string(currentNextYMinMax),y=60) : c c = dupStats && prevNextYMinMax >= dynPanThresh ? c.subtitle("prevNextYMinMax: "+string(prevNextYMinMax),y=90) : c c = dupStats && prevNextYMinMax >= dynPanThresh ? c.subtitle("Pan Threshold: "+string(dynPanThresh)+ \ " ("+string(neighborAvgMinMax)+" * "+string(panThresh)+")",y=105) : c c = dupStats && prevNextYMinMax >= dynPanThresh ? c.subtitle("Slow pan detected",y=120) : c return c """) Return showme ? stackvertical(Last,subtract(c.duplicateframe(0),c)) : Last }