PDA

View Full Version : Split Screen: Given 4 clips, resizes and arranges them. Similar to the TV show 24.


mikeytown2
7th May 2008, 10:26
http://en.wikipedia.org/wiki/Split_screen_(film)
http://en.wikipedia.org/wiki/24_(TV_series)#Real_time

# SplitScreen() - May 8th, 2008
# Given 4 clips, resizes and arranges them. Similar to the TV show 24.
#
# Inputs
# Required
# int Width: output width.
# int Height: output height.
# int Border: size of black border padding the 4 clips.
# clip A,B,C,D: 4 input clips need the same frame rate and color space; Full Chroma - 4:4:4.
# A: Upper Left
# B: Upper Right
# C: Lower Left
# C: Lower Right
# Optional
# string ResizeMethod: name of resize function. Default = BilinearResize.
# bool AudioMix: mix audio from clips into a stereo signal. Default = true.
#
# Notes
# "Gravity" of the clips is towards the center of the screen.
# Clips can be different sizes.
# If AudioMix is false, sound is 8 channels. Assumes audio in clips is stereo.

function SplitScreen(int Width, int Height, int Border, clip A, clip B, clip C, clip D, string "ResizeMethod", bool "AudioMix")
{
#Check Clips For Full Chroma - 4:4:4
Assert((IsYV12(A) || IsYUY2(A)), "Clip A is not at full chroma (4:4:4). Convert to RGB")
Assert((IsYV12(B) || IsYUY2(B)), "Clip B is not at full chroma (4:4:4). Convert to RGB")
Assert((IsYV12(C) || IsYUY2(C)), "Clip C is not at full chroma (4:4:4). Convert to RGB")
Assert((IsYV12(D) || IsYUY2(D)), "Clip D is not at full chroma (4:4:4). Convert to RGB")

#Set Defaults
ResizeMethod = Default(ResizeMethod, "BilinearResize")
AudioMix = Default(AudioMix, true)

#Set Borders
BorderH = Border
BorderW = Border

#Set Width and Height of individual clips
NewW = Round(float(Width)/2.0 - float(BorderW)*1.5)
NewH = Round(float(Height)/2.0 - float(BorderH)*1.5)

#Process Video
A = A.ResizeKAR(NewW, NewH, ResizeMethod, NoBorders=True)
A = A.AddBorders(NewW-Width(A)+BorderW, NewH-Height(A) + BorderH, 0, 0)
B = B.ResizeKAR(NewW, NewH, ResizeMethod, NoBorders=True)
B = B.AddBorders(BorderW, NewH-Height(B) + BorderH, NewW-Width(B), 0)
C = C.ResizeKAR(NewW, NewH, ResizeMethod, NoBorders=True)
C = C.AddBorders(NewW-Width(C)+BorderW, BorderH, 0, NewH-Height(C))
D = D.ResizeKAR(NewW, NewH, ResizeMethod, NoBorders=True)
D = D.AddBorders(BorderW, BorderH, NewW-Width(D), NewH-Height(D))

#Merge Clips
X = StackHorizontal(A, B).AddBorders(0,0,BorderW,0)
Y = StackHorizontal(C, D).AddBorders(0,0,BorderW,0)
StackVertical(X, Y).AddBorders(0,0,0,BorderH).KillAudio()

#Fix Audio
LongestClip = Int(Max(Framecount(A), Framecount(B), Framecount(C), Framecount(D)))
A = (Framecount(A) <> LongestClip) ? A ++ BlankClip(A, LongestClip-Framecount(A)) : A
B = (Framecount(B) <> LongestClip) ? B ++ BlankClip(B, LongestClip-Framecount(B)) : B
C = (Framecount(C) <> LongestClip) ? C ++ BlankClip(C, LongestClip-Framecount(C)) : C
D = (Framecount(D) <> LongestClip) ? D ++ BlankClip(D, LongestClip-Framecount(D)) : D

#Mix Audio
Sound = (AudioMix) ? MergeChannels(MixAudio(ConvertToMono(A).Amplify(0.49), ConvertToMono(C).Amplify(0.49)), MixAudio(ConvertToMono(B).Amplify(0.49), ConvertToMono(D).Amplify(0.49))):
\ MergeChannels(GetLeftChannel(A), GetRightChannel(A), GetLeftChannel(B), GetRightChannel(B), GetLeftChannel(C), GetRightChannel(C), GetLeftChannel(D), GetRightChannel(D))
AudioDub(last, Sound)
}


function ResizeKAR(clip c, int maxW, int maxH, string "ResizeMethod", int "BackgroundColor", bool "NoBorders")
{
BackgroundColor = Default(BackgroundColor, $000000)
ResizeMethod = Default(ResizeMethod, "BilinearResize")
NoBorders = Default(NoBorders, False)

ratioS = Float(width(c))/Float(height(c))
ratioD = Float(maxW)/Float(maxH)
newW = Round(maxH*ratioS/2)*2
newH = Round(maxW/ratioS/2)*2

BorderH = (NoBorders==True) ? 0 : Round((maxH-newH)/2)
BorderW = (NoBorders==True) ? 0 : Round((maxW-newW)/2)

#Dest Higher Then Source; Dest Wider Then Source; Same Ratio
c =
\ (ratioS>ratioD) ?
\ Eval(ResizeMethod + "(c, " + String(maxW) + ", " + String(newH) + ")").
\ AddBorders(0, BorderH, 0, BorderH, BackgroundColor) :
\ (ratioS<ratioD) ?
\ Eval(ResizeMethod + "(c, " + String(newW) + ", " + String(maxH) + ")").
\ AddBorders(BorderW, 0, BorderW, 0, BackgroundColor) :
\ (ratioS==ratioD) ?
\ Eval(ResizeMethod + "(c, " + String(maxW) + ", " + String(maxH) + ")" ) :
\ nop()

#fix 1px changes, works only with 4:4:4
c =
\ IsInterleaved(c) && (maxW>width(c)) && (NoBorders==false) ? c.AddBorders(0, 0, 1, 0) :
\ IsInterleaved(c) && (maxH>height(c)) && (NoBorders==false) ? c.AddBorders(0, 0, 0, 1) :
\ c
return c
}

Examples:

A = ColorBars()
B = ColorBars().invert().FlipHorizontal()
C = ColorBars().FlipVertical()
D = ColorBars().invert().FlipVertical().FlipHorizontal()

SplitScreen(640, 200, 3, A, B, C, D)

http://img142.imageshack.us/img142/9049/splitscreenayx6.th.png (http://img142.imageshack.us/my.php?image=splitscreenayx6.png)



A = ColorBars()
B = ColorBars().invert().FlipHorizontal()
C = ColorBars().FlipVertical()
D = ColorBars().invert().FlipVertical().FlipHorizontal()

SplitScreen(640, 480, 3, A, B, C, D)

http://img142.imageshack.us/img142/5360/splitscreenbjw5.th.png (http://img142.imageshack.us/my.php?image=splitscreenbjw5.png)



A = ColorBars().Crop(10, 20, -30, -400)
B = ColorBars().invert().FlipHorizontal().Crop(10, 20, -300, -40)
C = ColorBars().FlipVertical().Crop(10, 200, -30, -40)
D = ColorBars().invert().FlipVertical().FlipHorizontal().Crop(100, 20, -30, -40)

SplitScreen(640, 480, 6, A, B, C, D)

http://img100.imageshack.us/img100/7105/splitscreendgt3.th.png (http://img100.imageshack.us/my.php?image=splitscreendgt3.png)




Modified ResizeKAR to not return a border
http://forum.doom9.org/showthread.php?t=135229

Other Posts/Functions on Subject:
http://forum.doom9.org/showthread.php?t=136375
http://forum.doom9.org/showthread.php?t=133883
http://avisynth.org/vcmohan/HollywoodSq/HollywoodSq.html


Edits:
May 7th 2008: Code cleanup and fixed potential rounding errors.
May 7th 2008: Got rid of Overlays and fixed a sound mixing issue. Eliminated border aspect ratio option since, it was already happening.
May 8th 2008: Checks for Full Chroma - 4:4:4.

Gavino
7th May 2008, 14:26
I haven't checked this out fully, but on first glance I see a bug here:


BorderW = (BorderAR) ? Round(Border*(Width/Height)) : Border

Should be:

BorderW = (BorderAR) ? Round(Border*(float(Width)/Height)) : Border

or else aspect ratio will be calculated as an integer.

Gavino
7th May 2008, 18:40
@mikeytown2: Another comment after further studying your function.

Why do you resize twice? Couldn't you eliminate the second resize (and hence improve image quality) by taking the border sizes into account when calculating the sizes of the 4 inner clips?

mikeytown2
8th May 2008, 01:35
Gavino, Thanks for finding the error in the border calc. It's easy to forget that it needs to be a float. I used resize twice because it makes the logic simple; only resizing once would be ideal. In the near future i plan on doing this as well as getting rid of the Overlays and using the Stack Horiz/Vert.