View Full Version : Memory: Magick vs. Imagesource
tin3tin
5th July 2010, 07:03
I've testet how Magick and Imagesource uses memory when importing a lot of big downscaled/unscaled images.
LoadPlugin("gscript.dll")
LoadPlugin("immaavs.dll")
# Script 1
p= Immaread("5MB_Photo.jpg", size_x=10, size_y=10, magick_home="")
GScript("""
for (i=1, 50) {
p=p+ Immaread("5MB_Photo.jpg", size_x=10, size_y=10, magick_home="")
}
""")
# Script 2
#~ p= Immaread("5MB_Photo.jpg", magick_home="")
#~ GScript("""
#~ for (i=1, 50) {
#~ p=p+ Immaread("5MB_Photo.jpg", magick_home="")
#~ }
#~ """)
# Script 3
#~ p= Imagesource("5MB_Photo.jpg",0,0)
#~ GScript("""
#~ for (i=1, 50) {
#~ p=p+ Imagesource("5MB_Photo.jpg",0,0)
#~ }
#~ """)
# Script 4
#~ p= Imagesource("5MB_Photo.jpg",0,0).LanczosResize(10,10)
#~ GScript("""
#~ for (i=1, 50) {
#~ p=p+ Imagesource("5MB_Photo.jpg",0,0).LanczosResize(10,10)
#~ }
#~ """)
p
http://download.videohelp.com/tin2tin/Scaled.jpg
http://download.videohelp.com/tin2tin/Originalsize.jpg
It seems that Magick only loads the downscaled image into the memory.
Imagesource keeps the full image in the memory and uses the memory faster with the resize function than the unscaled, but ends a little lower.
Magick and Imagesource behaves the same when loading full sized images, but Imagesource loads a little faster.
What do you guys think? Wouldn't it be useful if Imagesource would be able to import images downscaled and only using the memory of the downscaled image like Magick?
foxyshadis
6th July 2010, 04:33
If you use SetMemoryMax(512) or 1024 at the beginning of the script, avisynth shouldn't continue to cache the full size image; it'll release it as soon as it's used and no longer needed (or even if potentially needed but beyond the set max, in a more complex script, where it'll have to go back and decode it again on demand).
This is drivel ->Yep, ImageSource() is real dumb! Each instance allocates a class static PVideoFrame of the size of the input image. And allocating static PVideoFrames will override the SetMemoryMax value.<- end drivel
The most successful trick I have is to use Conditional execution to only load one ImageSource() instance at a time at runtime instead of all instances at once at script load time.
Something like this :-Function SelectName(Int N) {
return Select(N,
\ "One.jpg",
\ "Two.jpg",
\ "Three.jpg",
\ "Four.jpg" )
}
ScriptClip("ImageSource(SelectName(current_frame), end=current_frame).Spline16Resize(720, 576)")
..more script ...The helper function SelectName() returns the appropriate file name for each required frame. And if the images are of differing sizes you can resize them to a common size as part of the ScriptClip(). If you need to cope with different aspect ratios for the images put the resize into another helper function.
Gavino
6th July 2010, 10:47
Yep, ImageSource() is real dumb! Each instance allocates a class static PVideoFrame of the size of the input image.
I must be missing something as I can't see this in the code. Can you point me to it?
What I do see is that for a static image, each instance generates additional instances of Cache and FreezeFrame.
For the ScriptClip trick
ScriptClip("ImageSource(SelectName(current_frame), end=current_frame).Spline16Resize(720, 576)")
you also need an input to ScriptClip to set the clip properties, including length and frame size, eg
...
BlankClip(4, 720, 576, pixel_type="rgb24") # 4 frames for this example
ScriptClip("ImageSource(SelectName(current_frame), end=current_frame).Spline16Resize(720, 576)")
@Gavino,
Yes I am misremembering the code. Prior to 2.5.7 it used a static frame, which it allocated on the first GetFrame call and deallocated on script close. The ScriptClip idea was good for this case.
Now it uses the Cache to try to hold onto the PVideoFrame and FreezeFrame() to steer all GetFrame calls to frame 0. From the 2nd GetFrame call the Cache will defend ownership of the PVideoFrame. The PVideoFrame is not static and can be stolen when SetMemoryMax is being exceeded.
Seeing the cache grow to the SetMemoryMax values is the expected behaviour. In a simple case the ScriptClip idea may stop the big PVideoFrames occupying the Cache.
Gavino
7th July 2010, 00:14
In a simple case the ScriptClip idea may stop the big PVideoFrames occupying the Cache.
Are there some cases then where this trick would not help, even where the ScriptClip result is a smaller frame than the source image? (Perhaps when the downsizing is done by Crop rather than a resizer, retaining a pointer to the full image?)
It's not really a case of helping, more a case of avoiding. The expected behaviour is that the Cache manage VideoFrameBuffers and grow to the SetMemoryMax value. There are some optimisations that short circuit this and allow early reuse of some buffers. In these cases when the graph is simple enough the cache does not grow as expected. At least 1 big VideoFrameBuffer will always be allocated.
Gavino
7th July 2010, 10:08
What is the lifetime of the intermediate frames allocated inside ScriptClip? Are they released at the end of GetFrame or do they persist in some global store?
In something like ScriptClip("ImageSource("BigImage.jpg").Spline16Resize(40,30)"), a big frame will be allocated and cached during each GetFrame. The Cache instance will be freed when the run-time filter graph is released - does this get rid of the frame buffer too or is this storage managed at a global level?
Class LinkedVideoFrameBuffer globally manages VideoFrameBuffer's.
ScriptEnvironment::GetFrameBuffer2 manages finding a free VideoFrameBuffer for use within env->NewVideoFrame().
A VideoFrameBuffer once new'd generally is not released until the IScriptEnvironment is deleted, except if SetMemoryMax is exceeded by too much then not in use VideoFrameBuffer's are forcible delete'd until SetMemoryMax is satisfied.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.