# jdl-interlace.avsi -- Functions for use with interlaced 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_SelectField
#
# Retrieves the top or bottom field of a clip, regardless of field
# order.
#
# PARAMETERS:
# parity : Pass true to retrieve the top field of the clip.
# Pass false to retrieve the bottom field.
# These values correspond to those returned by the internal
# GetParity function.
# (I use the mnemonic "T" = "T"op = "T"rue to remember.)
#
function JDL_SelectField(clip c, bool parity)
{
c = c.IsFrameBased() ? c.SeparateFields() : c
return (c.GetParity() == parity) ? c.SelectEven()
\ : c.SelectOdd()
}
function JDL_SelectTopField(clip c) { return c.JDL_SelectField(true) }
function JDL_SelectBottomField(clip c) { return c.JDL_SelectField(false) }
# JDL_ReverseFieldDominance
#
# Reverses the field-dominance in an interlaced clip.
#
# Unlike Simon Walters' Reverse Field Dominance plug-in,
# JDL_ReverseFieldDominance recombines fields instead of shifting
# scanlines. See:
#
#
#
# for descriptions of the two methods. Although this function uses the
# field recombination method, it does not lose the first field of video
# nor should it introduce audio/video desynchronization.
#
# PARAMETERS:
# "bobFirstLast" : Pass true to bob-deinterlace the first and last frames
# of the output clip.
# (Default: false)
#
# REQUIRES:
# jdl-util.avsi (SetParity, Trim2)
#
function JDL_ReverseFieldDominance(clip c, bool "bobFirstLast")
{
bobFirstLast = Default(bobFirstLast, false)
originallyFrameBased = c.IsFrameBased()
oldParity = c.GetParity()
newClip = originallyFrameBased ? c : c.Weave()
bookend = bobFirstLast
\ ? newClip.JDL_SimpleBob().Amplify(0.0).AssumeFPS(newClip)
\ : newClip.Blackness()
bookend = bookend.SetParity(oldParity)
newClip = bookend.Trim2(0, 1) ++ newClip ++ bookend.Trim2(bookend.FrameCount() - 1)
newClip = newClip.SeparateFields().Trim2(1, -1) # Remove the first and last fields.
newClip = originallyFrameBased ? newClip.Weave() : newClip
return (c.FrameCount() == 0)
\ ? c.ComplementParity()
\ : newClip
}
# JDL_UnfoldFieldsVertical
#
# Separates the fields in a clip and stacks them vertically.
# Regardless of field order, even fields are on top.
#
# Useful for applying spatial-temporal filters to interlaced
# video.
#
# PARAMETERS:
# "flip" : Pass true to flip the bottom field vertically.
# Useful when dealing with spatial filters.
# (Default: false)
#
# USAGE:
# Should be used in conjunction with JDL_FoldFieldsVertical.
#
# JDL_UnfoldFieldsVertical(true)
# PixieDust()
# JDL_FoldFieldsVertical(true)
#
# REQUIRES:
# jdl-util.avsi (SetParity)
#
function JDL_UnfoldFieldsVertical(clip c, bool "flip")
{
Assert(c.IsFrameBased(), "JDL_UnfoldFieldsVertical: clip must not have separated fields")
flip = Default(flip, false)
oldParity = c.GetParity()
# c = c.IsFrameBased() ? c : c.Weave()
c.AssumeTFF().SeparateFields().AssumeFrameBased()
top = SelectEven()
bottom = SelectOdd()
StackVertical(top, flip ? bottom.FlipVertical()
\ : bottom)
return (c.FrameCount() == 0)
\ ? c
\ : SetParity(oldParity)
}
# JDL_FoldFieldsVertical
#
# Recombines the fields from a clip that resulted from calling
# JDL_UnfoldFieldsVertical. Undoes the work of JDL_UnfoldFieldsVertical.
#
# PARAMETERS:
# "flip" : Pass true if the bottom field was flipped vertically with
# JDL_UnfoldFieldsVertical.
# (Default: false)
#
# USAGE:
# See JDL_UnfoldFieldsVertical.
#
# REQUIRES:
# jdl-util.avsi (SetParity)
#
function JDL_FoldFieldsVertical(clip c, bool "flip")
{
Assert(c.IsFrameBased(), "JDL_FoldFieldsVertical: clip must not have separated fields")
Assert(c.Height() % 2 == 0, "JDL_FoldFieldsVertical: unexpected frame height")
flip = Default(flip, false)
oldParity = c.GetParity()
originalHeight = c.Height() / 2
top = c.Crop(0, 0, c.Width(), originalHeight)
bottom = c.Crop(0, originalHeight, c.Width(), originalHeight)
bottom = flip ? bottom.FlipVertical() : bottom
Interleave(top, bottom).AssumeFieldBased().AssumeTFF().Weave()
return (c.FrameCount() == 0)
\ ? c
\ : SetParity(oldParity)
}
# JDL_InterlacedResize
#
# Resizes interlaced material
#
# PARAMETERS:
# w, h : The desired width and height of the output clip.
# "resizeFunc" : The resize function to use for interpolation.
# The function must have the signature:
# resizeFunc(clip c, int w, int h)
# (Default: "LanczosResize")
#
# USAGE:
# If you wish to use a resize function that does not have the required
# syntax, make a wrapper function. For example:
#
# function BicubicResizeWrapper(clip c, int w, int h)
# {
# return c.BicubicResize(w, h, b=0, c=0.75)
# }
#
# JDL_InterlacedResize(320, 240, "BicubicResizeWrapper")
#
# REQUIRES:
# jdl-util.avsi (SetParity)
#
function JDL_InterlacedResize(clip c, int w, int h, string "resizeFunc")
{
resizeFunc = Default(resizeFunc, "LanczosResize")
c.JDL_SimpleBob()
Apply(resizeFunc, last, w, h)
JDL_Interlace()
return last
}
# JDL_SimpleBob
#
# A simplistic Bob function. Losslessly preserves the original
# scanlines.
#
# REQUIRES:
# jdl-util.avsi (SetParity)
#
function JDL_SimpleBob(clip c)
{
# Based on Mug Funky's explanation of Bob/BicubicResize's arguments.
#
c.Bob(0, 0.5)
# Preserve the parity of original clip (in case we want to reinterlace
# later).
return SetParity(c.GetParity())
}
# JDL_DupeField
#
# Duplicates the specified field.
#
# PARAMETERS:
# field : Pass true to duplicate the top field.
# Pass false to duplicate the bottom field.
#
# REQUIRES:
# jdl-util.avsi (SetParity)
#
function JDL_DupeField(clip c, bool field)
{
parity = c.GetParity()
c = c.JDL_SimpleBob()
return (field == parity) ? c.SelectEven() : c.SelectOdd()
}
# JDL_Interlace
#
# Combines frames from a progressive, frame-based clip to produce an
# interlaced version at half the frame-rate.
#
# (This discards half of the fields!)
#
function JDL_Interlace(clip c)
{
Assert(c.IsFrameBased(), "JDL_Interlace: clip must not have separated fields")
# Based on scharfis_brain's method.
#
return (c.FrameCount() == 0)
\ ? c.AssumeScaledFPS(1, 2)
\ : c.SeparateFields().SelectEvery(4, 0, 3).Weave()
}