View Full Version : Improving Encoding Performance for Videos Larger then 1080p


Skid
9th June 2012, 17:34
There might not be a way to do this but I figured I would ask anyway, are there any commands or plugins that I can use to improve AVISynth performance when encoding videos that have a resolution of 4032x840.

I'm fairly sure the encoding bottleneck is coming from AVISynth because firstly, I can encode at least 3 instances of the same AVS file in MeGUI without impacting the speed of the others. Secondly if I do a re-encode of the raw avi file in Handbrake with the same settings, it processed at over 35FPS (MeGUI only managed 12FPS).

I've put the and example script I use below incase there is something silly I'm doing. But otherwise any advice would be appreciated.

clip1 = AVISource ("F:\Recordings\SupremeCommander2.avi").FadeIn(25).FadeOut(50)
clip0 = BlankClip(clip1, length=150, color=$000000)

img1 = ImageSource("D:\Encoding\AviSynth Files\WSGF.png", end=174).BilinearResize(840, 840)
img2 = ImageSource("D:\Encoding\AviSynth Files\WSGF.png", pixel_type="RGB32", end=174).ShowAlpha(pixel_type="RGB32").BilinearResize(800, 800)
ani1 = Animate(img1, 125, 174, "BilinearResize", 2436,840,0,0,2436,840, 2436,840,798-(8*2436),798-(8*840),8*2436,6720).FadeIn(50).FadeOut(0)
ani2 = Animate(img2, 125, 174, "BilinearResize", 2436,840,0,0,2436,840, 2436,840,798-(8*2436),798-(8*840),8*2436,6720).FadeIn(50).FadeOut(0)
a1 = ImageSource("D:\Encoding\AviSynth Files\WSGF.png", end=30*25).BilinearResize(100, 100).FadeOut(50)
a2 = ImageSource("D:\Encoding\AviSynth Files\WSGF.png", pixel_type="RGB32", end=30*25).ShowAlpha(pixel_type="RGB32").BilinearResize(100, 100).FadeOut(50)
b3 = ImageSource("D:\Encoding\AviSynth Files\WSGF.png", end=4500).BilinearResize(100, 100).FadeOut(50)
b4 = ImageSource("D:\Encoding\AviSynth Files\WSGF.png", pixel_type="RGB32", end=4500).ShowAlpha(pixel_type="RGB32").BilinearResize(100, 100).FadeOut(50)
p1 = BlankClip(a1, length=175)
p2 = BlankClip(a2, length=175)
p3 = BlankClip(b3, length=175)
p4 = BlankClip(b4, length=175)

ol1 = AlignedSplice (p1, a1)
ol2 = AlignedSplice (p2, a2)
ol3 = AlignedSplice (p3, b3)
ol4 = AlignedSplice (p4, b4)

Overlay ( \
Overlay ( \
Overlay ( \
AlignedSplice (clip0, clip1), \
ani1, mask=ani2, mode="blend", opacity=1.0, x=1344+252, y=0), \
ol1, mask=ol2, mode="blend", opacity=1.0, x=3932, y=740), \
ol3, mask=ol4, mode="blend", opacity=0.25, x=3932, y=740)

Subtitle ("If your monitors width is greater then 1920 pixels or you are using a multi monitor setup,\n" + \
"set the quality to original for a much higher resolution video.", \
x=-1, y=794, first_frame=0*25, last_frame=20*25-1, size=36, text_color=$00FFFF00, lsp=10)

ConvertToYV12()

Gavino
9th June 2012, 23:51
Since you are working with RGB32 images, with an alpha channel, using Layer (http://avisynth.org/mediawiki/Layer)() instead of Overlay() will be faster and avoid the need to extract the alpha masks as separate clips.

Also, load the image just once in a single call to ImageSource(), and as a single frame.
Do all resizing on this single frame and use Loop() to repeat the required number of frames.

eg:
img = ImageSource("D:\Encoding\AviSynth Files\WSGF.png", end=0, pixel_type="RGB32")
img1 = img.BilinearResize(840, 840).Loop(174)

img100 = img.BilinearResize(100, 100)
a1 = img100.Loop(30*25).FadeOut(50)
b3 = img100.Loop(4500).FadeOut(50)
etc

IanB
10th June 2012, 00:46
Snap Gavino damn to slow! :D

I reordered your script mostly as an exercise in understanding it, the optimisations flowed from there.

When loading big static images, do it once only as a single frame. Produce all the resized and processed variants still as a single frame. Then use the Loop filter to clone those single frames into a clip of the required length.

Overlay processes in YV24 and will convert input to that format and output back to the original format, so to avoid format conversions with multiple overlay calls do them yourself once at the start and finally at the end. Similarly for alpha masks which are Y8 internally.

You could also do similar with making BlankClip templates, which may save some memory.
# Load up 1 frame image and make some processed templates
ImageSource("D:\Encoding\AviSynth Files\WSGF.png", pixel_type="RGB32", end=0) # 1 frame master image
WSGF24 = ConvertToYV24() # Frame 0 as YV24 ready for overlay
WSGF_A = ShowAlpha(pixel_type="Y8") # Frame 0, Alpha channel as Y8 ready for overlay

WSGF24_100 = WSGF24.BilinearResize(100, 100) # 100x100 pixel version
WSGF_A_100 = WSGF_A.BilinearResize(100, 100)

# Source file
clip1 = AVISource ("F:\Recordings\SupremeCommander2.avi").FadeIn(25).FadeOut(50).ConvertToYV24() # YV24 ready for overlay
clip0 = BlankClip(clip1, length=150, color=$000000)
AlignedSplice (clip0, clip1)


img1 = WSGF24.BilinearResize(840, 840).Loop(175) # Resize Frame 0 only then clone 174 times.
img2 = WSGF_A.BilinearResize(800, 800).Loop(175)

# Not sure about your actual numbers here ???
ani1 = Animate(img1, 125, 174, "BilinearResize", 2436,840, 0,0,2436,840, \
2436,840, 798-(8*2436),798-(8*840),8*2436,6720).FadeIn(50).FadeOut(0)
ani2 = Animate(img2, 125, 174, "BilinearResize", 2436,840, 0,0,2436,840, \
2436,840, 798-(8*2436),798-(8*840),8*2436,6720).FadeIn(50).FadeOut(0)

Overlay(ani1, mask=ani2, mode="blend", opacity=1.0, x=1344+252, y=0)


a1 = WSGF24_100.Loop(30*25+1).FadeOut(50) # Clone 100x100 version 30*25 times
a2 = WSGF_A_100.Loop(30*25+1).FadeOut(50)
p1 = BlankClip(a1, length=175)
p2 = BlankClip(a2, length=175)
ol1 = AlignedSplice (p1, a1)
ol2 = AlignedSplice (p2, a2)

Overlay(ol1, mask=ol2, mode="blend", opacity=1.0, x=3932, y=740)


b3 = WSGF24_100.Loop(4501).FadeOut(50) # Clone 100x100 version 4500 times
b4 = WSGF_A_100.Loop(4501).FadeOut(50)
p3 = BlankClip(b3, length=175)
p4 = BlankClip(b4, length=175)
ol3 = AlignedSplice (p3, b3)
ol4 = AlignedSplice (p4, b4)

Overlay(ol3, mask=ol4, mode="blend", opacity=0.25, x=3932, y=740)

ConvertToYV12() # Convert to YV12 for the normal world

Subtitle ("If your monitors width is greater then 1920 pixels or you are using a multi monitor setup,\n" + \
"set the quality to original for a much higher resolution video.", \
x=-1, y=794, first_frame=0*25, last_frame=20*25-1, size=36, text_color=$00FFFF00, lsp=10)

Gavino
10th June 2012, 08:45
Snap Gavino damn to slow! :D
LOL :D

I see my framecounts were out by one, eg Loop(174) should have been 175, as in your version.
I forgot end=174 gives 175 frames. :(

Is Overlay() using YV24 (in v2.60) now preferable to Layer()?

Skid
10th June 2012, 09:53
Thanks for the help sorry about the odd numbers, I had to do some trial and error to get that working, its basically meant to move and rescale the logo from fullsize on the centre screen to 100x100 on the far bottom right. Had to make a few tweaks but got it working, the version I'm using doesn't have YV24 in it so I changed it back to RGB32, it has increased performance slightly but while its encoding the main 4032x840 its still only sitting around 15-18 FPS with less then half the CPU being used. Any other ideas, or do you think it might be an internal buffer issue in AVISynth, IE one of the internal process buffers aren't large enough to hold the whole frame.

Edit: Arr I think I might have something, there is a seperate multi-threaded version of AVISynth, I'm going to give that a try as I think I'm using the normal version.
Edit2: NVM, it helped with processing the animation but I get no FPS boost when processing the video itself, just a higher CPU usage in some modes.

# Load up 1 frame image and make some processed templates
img = ImageSource("D:\Encoding\AviSynth Files\WSGF.png", pixel_type="RGB32", end=0) # Frame 0
WSGF24 = img
WSGF_A = img.ShowAlpha(pixel_type="RGB32") # Frame 0, Alpha channel

WSGF24_100 = WSGF24.BilinearResize(100, 100) # 100x100 pixel version
WSGF_A_100 = WSGF_A.BilinearResize(100, 100)

# Source file
clip1 = AVISource ("F:\Recordings\SupremeCommander2.avi").FadeIn(25).FadeOut(50) # YV24 ready for overlay
clip0 = BlankClip(clip1, length=150, color=$000000)
AlignedSplice (clip0, clip1)


img1 = WSGF24.BilinearResize(840, 840).Loop(175) # Resize Frame 0 only then clone 174 times.
img2 = WSGF_A.BilinearResize(840, 840).Loop(175)

# Don't worry to much about the numbers, its just how I worked out to move and correctly scale the image
ani1 = Animate(img1, 125, 174, "BilinearResize", 2436,840, 0,0,2436,840, \
2436,840, 798-(8*2436),798-(8*840),8*2436,6720).FadeIn(50).FadeOut(0)
ani2 = Animate(img2, 125, 174, "BilinearResize", 2436,840, 0,0,2436,840, \
2436,840, 798-(8*2436),798-(8*840),8*2436,6720).FadeIn(50).FadeOut(0)

Overlay(ani1, mask=ani2, mode="blend", opacity=1.0, x=1344+252, y=0)


a1 = WSGF24_100.Loop(30*25+1).FadeOut(50) # Clone 100x100 version 30*25 times
a2 = WSGF_A_100.Loop(30*25+1).FadeOut(50)
p1 = BlankClip(a1, length=175)
p2 = BlankClip(a2, length=175)
ol1 = AlignedSplice (p1, a1)
ol2 = AlignedSplice (p2, a2)

Overlay(ol1, mask=ol2, mode="blend", opacity=1.0, x=3932, y=740)


b3 = WSGF24_100.Loop(4501).FadeOut(50) # Clone 100x100 version 4500 times
b4 = WSGF_A_100.Loop(4501).FadeOut(50)
p3 = BlankClip(b3, length=175)
p4 = BlankClip(b4, length=175)
ol3 = AlignedSplice (p3, b3)
ol4 = AlignedSplice (p4, b4)

Overlay(ol3, mask=ol4, mode="blend", opacity=0.25, x=3932, y=740)

ConvertToYV12()

Subtitle ("If your monitors width is greater then 1920 pixels or you are using a multi monitor setup,\n" + \
"set the quality to original for a much higher resolution video.", \
x=-1, y=794, first_frame=0*25, last_frame=20*25-1, size=36, text_color=$00FFFF00, lsp=10)

IanB
11th June 2012, 00:00
Is Overlay() using YV24 (in v2.60) now preferable to Layer()?
The killer with using multiple Overlay() calls is the constant format conversions on the way in and out. In 2.6 there has been some minor hacking to dodge the input frame blits when sources are YV24, the blits take similar time to the filter processing, non-planar format conversions take even longer. So a medium term goal is to make Overlay() a native YV24 filter, this will get rid of the messy private memory allocation issues and also make it possible to get rid the output blit for YV24.

Layer() has explicit code paths for RGB32 and YUY2, so within those formats it has a significant advantage over Overlay() which always converts to and from it's internal YV24 representation.


Skid, if you are going to try MT then you will need SEt's latest version which is a 2.6, so you will be able to use YV24 and Y8 for improved Overlay() performance as well as trying your hand at multi-threading.


Another slight enhancement to your script is to add some FreezeFrame() calls to your Animate() path. Frames 0 to 125 and 174 onwards appear to be the same contents.
...
ani1 = ani1.FreezeFrame(0, 125, 0).FreezeFrame(174, FrameCount(Ani1)-1), 174)
ani2 = ani2.FreezeFrame(0, 125, 0).FreezeFrame(174, FrameCount(Ani2)-1), 174)
...The goal is to have all static images calculated once only and cached.

Also depending on what you are actual images looks like you might be better combining all your blend elements into a single clip, FreezeFrame() the non-changing frames and then use only a single Overlay() call on the main video.


An issue when dealing with very large frame sizes is the L1/L2/L3 cache performance of the processor. Most Avisynth code has been written and optimised with the assumption that the processor caches are big enough. When this assumption is invalidated speed plummets and MT does not usually help because the limit becomes main memory speed and with multiple cores all bashing the main memory very hard at once, it is a real bottleneck.

Skid
11th June 2012, 18:56
Hmm, well I have 8MB of L3 cache, but if it was an issue with speed on the hardware I wouldn't be able to run 3 instances at the same speed without impacting the others much, that said during single encoding one core gets hammered more then the others.

Edit: Having just checked it, improvements so far have mean I can only run two without losing to much speed, 20FPS on one instance 17.5 on two and 14 on three, but each instance is hammering the one core, so maybe it is an bottleneck with L1 cache.

The YV24 and Y8 formats work now, however it making part of the background grey, and later when the video cuts in, its adding a darker block where the icon is meant to stop moving. I'm grabbing some screen shots to show what its doing, I'll also upload the PNG I'm working with.

Edit2: Sorry forgot to grab these yesterday.
http://www.skid-inc.net/stuff/avisynth_1.jpg
http://www.skid-inc.net/stuff/avisynth_2.jpg<-- This anomaly disappears once the logo reaches its end position.