# jdl-telecine.avsi -- Functions for use with telecined material. # # Last modified: 2008-09-13 # # Written by James D. Lin (stickboy) and assigned to the public domain. # # The latest version of this file can be downloaded from: # # JDL_Telecine # # Telecines a clip. # # Useful for dealing with hybrid material when the final format is # interlaced. # # REQUIRES: # jdl-util.avsi (SetParity) # function JDL_Telecine(clip c) { Assert(c.IsFrameBased(), "JDL_Telecine: clip must not have separated fields") # We need to handle the case of a null-clip manually; # otherwise, SelectEvery(...) will generate unwanted blank frames. # Unintuitively, DoubleWeave() flips the field order when it combines # fields in frame-based clips. Therefore, we first need to call # ComplementParity() so that the parity of the output clip matches # that of the original. # # For more information, see: # return (c.FrameCount() == 0) \ ? c.AssumeScaledFPS(5, 4) \ : c.ComplementParity().DoubleWeave().SelectEvery(8, 0, 2, 3, 5, 6) \ .SetParity(c.GetParity()) } # JDL_IVTCPattern # # Performs manual 3:2 pulldown removal (inverse-telecine) equivalent # to the manual IVTC settings in VirtualDub. # # Useful for removing 3:2 pulldown on material that has a consistent # telecine pattern. # # PARAMETERS: # offset : [0, 4] # Offset of the combed frames. # "isBFF" : Parity of the clip. # Pass true if the clip is BFF, false if TFF. # This parameter corresponds to the "Invert Polarity" checkbox # in VirtualDub's IVTC dialog; if checked, set this parameter # to true. (Unlike AviSynth, VirtualDub always assumes the # input video is TFF.) # (Default: Determined by the field-order of the clip; # i.e.: c.GetParity() == false) # # REQUIRES: # jdl-util.avsi (SetParity) # function JDL_IVTCPattern(clip c, int "offset", bool "isBFF") { Assert(Defined(offset), "JDL_IVTCPattern: no offset specified") Assert(offset >= 0 && offset <= 4, "JDL_IVTCPattern: invalid offset") Assert(c.IsFrameBased(), "JDL_IVTCPattern: clip must not have separated fields") isBFF = Default(isBFF, c.GetParity() == false) isBFF ? c.AssumeBFF() : c.AssumeTFF() DoubleWeave() # We use SelectEvery(10, ...) instead of Pulldown(...) so that we can # have a bit more control over which frames we select. After # DoubleWeave(), there will be a number of duplicate progressive # frames. We'll choose frames that were originally "whole" in the # source when possible. return (c.FrameCount() == 0) \ ? c.AssumeScaledFPS(4, 5) \ : Eval(Select(offset, \ "SelectEvery(10, 1, 4, 6, 8)", \ "SelectEvery(10, 0, 3, 6, 8)", \ "SelectEvery(10, 0, 2, 5, 8)", \ "SelectEvery(10, 0, 2, 4, 7)", \ "SelectEvery(10, 2, 4, 6, 9)")) \ .SetParity(c.GetParity()) } # JDL_IVTCPattern2 # # Same as JDL_IVTCPattern, except blends the duplicated frames generated # by IVTC. # # PARAMETERS: # (see JDL_IVTCPattern) # # COLORSPACES: # [YUY2, RGB32] # function JDL_IVTCPattern2(clip c, int "offset", bool "isBFF") { Assert(Defined(offset), "JDL_IVTCPattern2: no offset specified") Assert(offset >= 0 && offset < 5, "JDL_IVTCPattern2: invalid offset") overlay = c.JDL_IVTCPattern((offset + 1) % 5, invertPolarity) overlay = overlay.IsRGB32() ? overlay.ResetMask() : overlay return Layer(c.JDL_IVTCPattern(offset, isBFF), overlay, "fast") } # JDL_IVTCPatternSegment # # Performs manual 3:2 pulldown removal to a specified section of a clip. # # PARAMETERS: # start, end : Frames in the range [start, end) are inverse-telecined. # telecineFrame : The frame number to a leading combed frame in the # section. # # Telecined clips usually have three progressive frames # following by two (or fewer) combed frames: # # p p p c1 c2 p p p c1 c2 p p p c1 c2 p p p ... # # The value of should be the frame number # of the first frame in one of the combed pairs (any of # the frames indicated by ; it doesn't matter # which). # # USAGE: # AssumeTFF() # ... or AssumeBFF(). You must set the correct field-order # # of the clip first. # # # Frames 3,4, 8,9, 13,14, ..., 4978,4979 are combed. # seg1 = JDL_IVTCPatternSegment(0, 4982, 3) # # # Frames 4985,4986, 4990,4991, ..., 10875,10876 are combed. # seg2 = JDL_IVTCPatternSegment(4983, 10877, 4985) # # # Frames 10879,10880, 10884,10885, ..., 15379,15380 are combed. # seg3 = JDL_IVTCPatternSegment(10878, 15382, 10884) # # seg1 + seg2 + seg3 # # REQUIRES: # jdl-util.avsi (Trim2) # function JDL_IVTCPatternSegment(clip c, int start, int end, int telecineFrame) { Assert(telecineFrame >= 0, "JDL_IVTCPatternSegment: telecineFrame must be >= 0") offset = ((telecineFrame - start) % 5 + 5) % 5 return c.Trim2(start, end).JDL_IVTCPattern(offset) } # JDL_DecimatePattern # # Discards the frame with the given offset from every group of five # frames. # # A complement to SelectEvery(c, 5, offset). # # DEPRECATED: # Please use DeleteEvery from my ApplyEvery plug-in instead. # # # PARAMETERS: # offset : [0, 4] # The offset the frame to discard. # function JDL_DecimatePattern(clip c, int offset) { Assert(Defined(offset), "JDL_DecimatePattern: no offset specified") Assert(offset >= 0 && offset < 5, "JDL_DecimatePattern: invalid offset") return (c.FrameCount() == 0) \ ? c.AssumeScaledFPS(4, 5) \ : Eval(Select(offset, \ "c.SelectEvery(5, 1, 2, 3, 4)", \ "c.SelectEvery(5, 0, 2, 3, 4)", \ "c.SelectEvery(5, 0, 1, 3, 4)", \ "c.SelectEvery(5, 0, 1, 2, 4)", \ "c.SelectEvery(5, 0, 1, 2, 3 )")) } # JDL_DecimatePattern2 # # Same as JDL_DecimatePattern, except blends the duplicated frames. # # PARAMETERS: # (see JDL_DecimatePattern) # # COLORSPACES: # [YUY2, RGB32] # function JDL_DecimatePattern2(clip c, int "offset") { Assert(Defined(offset), "JDL_DecimatePattern2: no offset specified") Assert(offset >= 0 && offset < 5, "JDL_DecimatePattern2: invalid offset") overlay = c.JDL_DecimatePattern((offset + 1) % 5) overlay = overlay.IsRGB32() ? overlay.ResetMask() : overlay return (offset == 4) \ ? JDL_DecimatePattern2(c.DuplicateFrame(0), 0) \ : Layer(c.JDL_DecimatePattern(offset), overlay, "fast") } # JDL_ShowFrameOffset # # Displays the frame number and the offset within the given cycle (frame # number modulo cycle). # # Useful for determining telecine patterns. # # PARAMETERS: # "cycle" : (Default: 5) # "height" : (Default: 40) # # REQUIRES: # jdl-util.avsi (Trim3) # function JDL_ShowFrameOffset(clip c, int "cycle", int "height") { # The clip width must be even, so expand the frame slightly if it's not. c = (c.Width() % 2 == 0) \ ? c \ : c.AddBorders(0, 0, 1, 0) frameNumClip = BlankClip(c, color=$000000, \ width=(c.Width() / 2), \ height=Default(height, 40)) try { # Use hanfrunz's fast FrameNumber filter if available. See: # frameNumClip = frameNumClip.FrameNumber() } catch (err_msg) { frameNumClip = frameNumClip.ShowFrameNumber() } offsetClip = frameNumClip.Trim3(0, length=Default(cycle, 5)).Loop().Trim3(0, length=c.FrameCount()) return StackVertical(c, StackHorizontal(offsetClip, frameNumClip)) }