# KenBurnsEffect() - June 12st, 2008
# Given a clip, Zooms, Pans & Rotates Clip with the Ken Burns Effect.
#
# Requirements:
# zoom.dll
# http://forum.doom9.org/showthread.php?t=49429 -Original zoom thread
# http://avisynth.org/warpenterprises/files/zoom_25_dll_20050122.zip -Direct Download
# CalcBox(), ZoomBoxIt()
# http://forum.doom9.org/showthread.php?p=1111789#post1111789
#
# Inputs:
# clip c: input clip, needs to be RGB32() if useZoomBox = 0 or 1
# Optional Parameters:
## ##
# Mode 2 - Starting Alignment:
# int startAlign: -9 to +9 (0=Do not use Align). Positive values - fit with no black borders, may crop clip. Negative values - fit with black borders, may letterbox clip.
# 1:top left. 2:top center. 3:top right.
# 4:middle left. 5:middle center. 6:middle bottom.
# 7:bottom left. 8:bottom center. 9:bottom right.
#
# Mode 1 - Starting Box:
# float startX1: upper left x cord
# float startY1: upper left y cord
# float startX2: lower right x cord
# float startY2: lower right y cord
# 3 or 4 out of 4 points must be defined when using Mode 1
# when omitting a single point, it will calculate the missing value, with the Aspect Ratio in mind.
#
# float startZoomFactor: 100 = 100%, ect...
# Negative values is the zoom of the pixels, positive values is the zoom of the frame.
# When converting AR, this isn't perfect.
# float startPanX: shift the clip x pixels. Value in source pixels. - left, + right
# float startPanY: shift the clip x pixels. Value in source pixels. - up, + down
# float startAngle: Rotate clip so many degrees. Positive is Clockwise.
## ##
#
## ##
# Mode 2 - Ending Alignment:
# int endAlign: -9 to +9 (0=Do not use Align). Positive values - fit with no black borders, may crop clip. Negative values - fit with black borders, may letterbox clip.
# 1:top left. 2:top center. 3:top right.
# 4:middle left. 5:middle center. 6:middle bottom.
# 7:bottom left. 8:bottom center. 9:bottom right.
#
# Mode 1 - Ending Box:
# float endX1: upper left x cord
# float endY1: upper left y cord
# float endX2: lower right x cord
# float endY2: lower right y cord
# 3 or 4 out of 4 points must be defined when using Mode 1
# when omitting a single point, it will calculate the missing value, with the Aspect Ratio in mind.
#
# float endZoomFactor: 100 = 100%, ect...
# Negative values is the zoom of the pixels, positive values is the zoom of the frame.
# When converting AR, this isn't perfect.
# float endPanX: shift the clip x pixels. Value in source pixels. - left, + right
# float endPanY: shift the clip x pixels. Value in source pixels. - up, + down
# float endAngle: Rotate clip so many degrees. Positive is Clockwise.
## ##
#
# int width: Output Width
# int height: Output Height
# int startFrame: starting frame of pan and zoom
# int endFrame: ending frame of pan and zoom
# string ResizeMethod: name of resize function. Default = BilinearResize
# float SourceDAR: Display Aspect Ratio of the Source. If 0 then it uses the source aspect ratio.
# float TargetDAR: Display Aspect Ratio of the Target. Usefull for DVD's. If 0 then it uses the source aspect ratio.
#
# int useZoomBox: 0 - Never, 1 - for static parts, 2 - for everything. default 2
# float Speed: 1 is "normal". For high quality set to something like 0.25. For speed set to 5+. Relevant if useZoomBox=0 or 1.
# int cubic: Type of zoom, pan & rotate.
# int cubicX: Type of pan in the x direction.
# int cubicY: Type of pan in the y direction.
# int cubicA: Type of rotation.
# int cubicZ: Type of zoom.
# int color: Color of letterbox border. Default: $000000 (Black). Irrelevant if useZoomBox=0 or 1.
#
#
# Notes:
# Clip should be deinterlaced for best visual quality.
# Aspect ratio for output and box(x1,y1,x2,y2) should be the same, unless you want to distort the clip.
# The aspect ratio for the 2 boxes as well as the output should to be the same.
# Default behavor is to center clip by adding borders (Align=-5).
# If you specify Align (Mode 2) and x1,y1,x2,y2 (Mode 1), Mode 1 will be used and the align will controll the position of the zoomFactor.
# Mode 1 (x1,y1,x2,y2) can take values from a crop opperation. x2 and y2 must be negative though; so if x2 or y2 equals 0, replace 0 with -0.00001.
function KenBurnsEffect(clip c,
\ int "startAlign", float "startX1", float "startY1", float "startX2", float "startY2", float "startZoomFactor", float "startPanX", float "startPanY", float "startAngle",
\ int "endAlign", float "endX1", float "endY1", float "endX2", float "endY2", float "endZoomFactor", float "endPanX", float "endPanY", float "endAngle",
\ int "width", int "height", int "StartFrame", int "EndFrame", string "ResizeMethod", float "SourcePAR", float "SourceDAR", float "TargetPAR", float "TargetDAR",
\ int "useZoomBox", float "speed", int "cubic", int "cubicX", int "cubicY", int "cubicA", int "cubicZ", int "color")
{
#Set Defaults
startAlign = Default(startAlign, -5)
endAlign = Default(endAlign, -5)
startZoomFactor = Default(startZoomFactor, 100.0)
endZoomFactor = Default(endZoomFactor, 100.0)
startPanX = Default(startPanX, 0.0)
startPanY = Default(startPanY, 0.0)
endPanX = Default(endPanX, 0.0)
endPanY = Default(endPanY, 0.0)
startAngle = Default(startAngle, 0.0)
endAngle = Default(endAngle, 0.0)
width = Default(width, c.width())
height = Default(height, c.height())
length = c.Framecount()-1
StartFrame = Default(StartFrame, 0)
EndFrame = Default(EndFrame, length)
ResizeMethod = Default(ResizeMethod, "BilinearResize")
SourceAR = float(c.width())/float(c.height())
TargetAR = float(width)/float(height)
useZoomBox = Default(useZoomBox, 2)
speed = Default(speed, 1)
cubic = Default(cubic, 0)
cubicX = Default(cubicX, cubic)
cubicY = Default(cubicY, cubic)
cubicZ = Default(cubicZ, cubic)
cubicA = Default(cubicA, cubic)
color = Default(color, $000000)
#Calculate Defaults
modzoom = Max(Float(c.width())/Float(width),Float(c.height())/Float(height))
startZoomFactor = startZoomFactor<0 ? (abs(startZoomFactor)/100.0)*modzoom : (abs(startZoomFactor)/100.0)
endZoomFactor = endZoomFactor<0 ? (abs(endZoomFactor)/100.0)*modzoom : (abs(endZoomFactor)/100.0)
#Check For Any Unreasonable Inputs
Assert(startZoomFactor<>0, "KenBurnsEffect: startZoomFactor can not be zero.")
Assert(endZoomFactor<>0, "KenBurnsEffect: endZoomFactor can not be zero.")
Assert((Defined(startX1) && Defined(startY1) && (Defined(startX2) || Defined(startY2))) || !(Defined(startX1) && Defined(startY1) && Defined(startX2) && Defined(startY2)), "KenBurnsEffect: when using Mode 1, you must define startX1,startY1, startX2 and/or startY2")
Assert((Defined(endX1) && Defined(endY1) && (Defined(endX2) || Defined(endY2))) || !(Defined(endX1) && Defined(endY1) && Defined(endX2) && Defined(endY2)), "KenBurnsEffect: when using Mode 1, you must define endX1,endY1, endX2 and/or endY2")
Assert(startAlign<9 || startAlign>-9, "KenBurnsEffect: startAlign [" + String(startAlign) + "] should be between -9 and 9.")
Assert(endAlign<9 || endAlign>-9, "KenBurnsEffect: endAlign [" + String(endAlign) + "] should be between -9 and 9.")
Assert(IsRGB32(c) || useZoomBox==2, "KenBurnsEffect: Clip Needs To Be RGB32. Use ConvertToRGB32() or set useZoomBox=2")
Assert(!((cubic>0 || cubicX>0 || cubicY>0 || cubicZ>0 || cubicA>0) && useZoomBox==2), "KenBurnsEffect: Can not use the Cubic option when useZoomBox=2. Set useZoomBox to 0 or 1 or don't use cubic.")
Assert(endFrame-startFrame<=length, "KenBurnsEffect: Transition length[" + String(endFrame-startFrame) + "] greater then clip lenght[" + String(length) + "]")
Assert(startFrame0 && startFrame>0 ? c.Trim(0, -startFrame).ZoomBoxIt(width, height, ResizeMethod, startX1, startY1, startX2, startY2, color) :nop()
end = useZoomBox>0 && endFrame0 ? start + cAlt : cAlt
cAlt = useZoomBox==2 && endFrame0 ? start + c : c
c = useZoomBox<2 && endFrame