Log in

View Full Version : FrameStore v0.03 - Avs+ x86/x64 - 15 Jan 2019


StainlessS
21st January 2018, 20:43
FrameStore()
Requires VS 2008 runtimes.

An Avisynth v2.58, v2.6 x86 & x64, Filter to both take and produce a single frame.
All standard AVS v2.6 Colorspaces.


FrameStore(clip c,Int "n") # by StainlessS: https://forum.doom9.org/showthread.php?t=175212

An Avisynth v2.58, v2.6 x86 & x64, Filter to both take and produce a single frame.
All standard AVS v2.6 Colorspaces.

The function creates a store for FRAME n of the input clip c.
The function is intended to sever the link between a frame and any clips that it is reliant upon.

FrameStore(clip c, Int "n")

Where:-
n suppied, then get frame n.
else
runtime script, n=current_frame
not runtime script, n=0
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
A=Colorbars.trim(0,-1) # 1 frame
B=A.FlipVertical # B is reliant upon clip A
C=A.Overlay(B,Opacity=0.5) # C is reliant upon clips A and B

D=C.FrameStore # D is not reliant upon A, or B, or C. (Not runtime script, n=0)

return D
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


FrameStore_Test.avs

# FrameStore(clip c,Int "n")

A=Colorbars.trim(0,-1) # 1 frame
B=A.FlipVertical # B is reliant upon clip A
C=A.Overlay(B,Opacity=0.5) # C is reliant upon clips A and B

D=C.FrameStore # D is not reliant upon A, or B, or C. (Not runtime script n=0)

return D


Multi-Instance capable function, SBX_MI.avs [Despite Global Vars, multiple instances, do not interfere with each other]

Function SBX_MI(clip c,int Factor, string "Mode", float "Opacity") {
# Requires:- RT_Stats, FrameStore (c) StainlessS. GSCript, Grunt, (c) Gavino.
c
myName = "SBX_MI: "
Mode = Default(Mode,"lighten")
Opacity = Default(Opacity,1.0)
Limit = (Factor<=0) ? 1 : Max(1, FrameCount/Factor)
FuncS="""
Function Fn@@@(clip c,Int factor,String mode,Float opacity,Int limit) {
n=current_frame
if(Prev@@@ != n) {
c
cf=c.Trim(n,-1) # current frame
if(Prev@@@ != n-1) {
Global B@@@ = cf # First Frame OR User Jumping, Init/Reset to current frame
} else {
if(limit > 1) {
Global B@@@ = Overlay(B@@@,cf, opacity=float(limit)/FrameCount)
} # Else, B@@@ = Previous B@@@

# REMOVE '.FrameStore' from end of next line to remove FrameStore and crash this function when out of memory.
Global B@@@=Overlay(B@@@,cf,mode=Mode,opacity=Opacity).FrameStore

}
Global Prev@@@=n # REM for next time
} # Else, Cache failure, repeat request for current frame, just return same as last time
Return B@@@
}
#######################################
# Unique Global Variables Initialization
#######################################
Global Prev@@@=-666 # Init, Impossible frame.
#######################################
# Unique Runtime Call, GScriptClip must be a one-liner:
#######################################
ARGS = "Factor,Mode,Opacity,Limit"
c.GScriptClip("Fn@@@(last, "+ARGS+")", local=true, args=ARGS)
"""
#######################################
# Unique Identifier Definition
#######################################
GIFunc="SBX_MI" # Function Name, Supply unique name for your multi-instance function.
GIName=GIFunc+"_InstanceNumber" # Name of the Instance number Global
RT_IncrGlobal(GIName) # Increment Instance Global (init to 1 if not already exists)
GID = GIFunc + "_" + String(Eval(GIName))
InstS = RT_StrReplace(FuncS,"@@@","_"+GID)
# RT_WriteFile("DEBUG_"+GID+".TXT","%s",InstS) # Uncomment to write this instance script to file.
FrameCount!=1 ? GScript(InstS) : Last
Return Last
}

AviSource("Parade.avi") # Some clip

A=SBX_MI(10,"lighten") # Instance 1
B=SBX_MI(20,"lighten") # Instance 2
Return StackHorizontal(A,B)

EDIT: Above function based on script function by Real.Finder, here:- https://forum.doom9.org/showthread.php?p=1831013#post1831013

FrameStore.cpp [Should work with any avs+ colorspace, incl stacked etc]

See MediaFire or SendSpace below this post in my sig.
Including v2.58 & v2.60/+ x86/x64 dll's and source + full VS2008 project files (~68KB).

real.finder
23rd January 2018, 13:09
thanks StainlessS


A=Colorbars.trim(0,-1) # 1 frame
B=A.FlipVertical # B is reliant upon clip A
C=A.Overlay(B,Opacity=0.5) # C is reliant upon clips A and B

D=C.FrameStore # D is not reliant upon A, or B, or C.

return D


if I replaced D=C.FrameStore with only D=C

I didn't see any difference! what FrameStore should did in this case?

StainlessS
23rd January 2018, 14:47
Well you will not see anything, only when you got lots and lots of frames not being able to be released due to multiple dependance, eg in your
crashing function a few threads earlier. I dont really have the time or patience to write a whole long list of a few hundred or thousand
lines similar to the ones you quoted.


A=Colorbars.trim(0,-1) # 1 frame
B=A.FlipVertical # B is reliant upon clip A
C=A.Overlay(B,Opacity=0.5) # C is reliant upon clips A and B

D=C

A=0
B=0
C=0

return D


Above, I was kinda hoping (but did not expect) any problem, even though the variables are nullified, the clips all remain
open (just not 'attached' to the variables A, B, & C) because here, D references C, and C references B, and B references A,
so all three of them are held pending destruction of D (the clips can exist independent of the script variables which also hold references
to them [EDIT: that is until they were nullified, where their references were released and the reference counts on them reduced by 1,
They can only be released when reference count goes to zero, or when crash occurs or Aviisynth goes into shut down]).

EDIT: I'm sure that others could explain better than I with my guesswork.
EDIT: Cache will also play a part, I assume that even though frames may be cached that the cache still hold reference
to frames [EDIT: and also to the filters] in use, its just that they have already been constructed by the previous filter, and held in memory in case required again,
but if a cache is required for other duty, then I guess that the previous filter will have another request made of it and will have to
re-create the frame, so its pretty lucky to have still a reference to the filter/frame prior to it, so it can do that yet again.

EDIT:
the clips can exist independent of the script variables
I think during frame serving, the variables all go in the rubbish bin, no longer exist, except where entering a runtime filter eg Scriptclip
where they can then pop into existence. During frame serving it is the filter chain, ie chain of filter all linked to the previous ones all of the way back to the source filter, that is what keeps it all working.

As far as FrameStore is concerned, if you want to see the effect you were asking about, go back and try your script function again,
or better still, try the SBX_MI function, both without and then with the FrameStore thing doing what it does (And watch the graphs in Task Manager).

EDIT: Changed my mind, I think the cache's sit beteen filters [EDIT: and intercepts and references the frames being passed to following filter, and then at a later request] jumps in and provides the cached frame and avoids/stops the request for that frame being passed back to the prevous filter, but if the cache is required for use elsewhere, then the frame has to come from the previous filter after all.

EDIT: Something like that, maybe, perhaps. I guess what I am trying to say is, your guess is as good as mine, perhaps better :)
Unless someone in the know comes along and corrects all of my guesswork errors, then it may just have to remain a mystery.

StainlessS
24th January 2018, 01:17
EDIT: Below from previous post of source that has since been deleted from post.


static AVSValue __cdecl Create_FrameStore(AVSValue args, void*, IScriptEnvironment* env) {
PClip child = args[0].AsClip(); // clip compulsory arg
const VideoInfo &InVi = child->GetVideoInfo();
if(!InVi.HasVideo() || InVi.num_frames<=0) env->ThrowError("FrameStore: No Video");
VideoInfo vi = InVi;
bool parity = child->GetParity(0);
vi.audio_samples_per_second = 0; // 0 means no audio
vi.sample_type = 0; // as of 2.5
vi.num_audio_samples = 0; // changed as of 2.5
vi.nchannels = 0; // as of 2.5
vi.num_frames = 1; // We only store a single frame
PVideoFrame dst = child->GetFrame(0, env); // Get Frame 0 (we only have 1 frame)
env->MakeWritable(&dst); // Let Avisynth (whatever version) make a copy of any valid colorspace frame.
return new FrameStore(vi,dst, parity);
}


For those concened about the above line in BLUE


#include <windows.h>
#include "avisynth.h"

AVSValue __cdecl FrameTest(AVSValue args, void* user_data, IScriptEnvironment* env) {
if(!args[0].IsClip()) env->ThrowError("%sMust have a clip",myName);
PClip child = args[0].AsClip();
const VideoInfo &vi = child->GetVideoInfo();
if(!vi.HasVideo() || vi.num_frames<=0) env->ThrowError("FrameTest: No Video");
PVideoFrame dst = child->GetFrame(0,env);
return dst->IsWritable();
}

const AVS_Linkage *AVS_linkage = 0;
extern "C" __declspec(dllexport) const char* __stdcall
AvisynthPluginInit3(IScriptEnvironment* env, const AVS_Linkage* const vectors) {
AVS_linkage = vectors;
env->AddFunction("FrameTest", "c", FrameTest, 0);
return "`FrameTest' FrameTest plugin"; // A freeform name of the plugin.
}


Returns False on a FrameStore frame, dont know how the mechanism works, but a frame requested from FrameStore is not already writable.
I guess that it makes sense as when a filter creates a writable frame, and then passes it on to the following filter, it does not remain writable to that following filter.

EDIT: Of course, child->GetFrame(0,env), returns a read only frame, you have to use NewVideoFrame for writable frame, and then copy to it yourself, obvious really :)

StainlessS
24th January 2018, 03:43
@Real.Finder,

EDIT: You original script

Function SFrameBlendX(clip C, int blendfactor, string "blend_mode", float "blend_opacity") {
C
limit = (blendfactor<=0) ? 1 : Max(1, FrameCount/blendfactor)
FrameCount!=1 ? ScriptClip("""
try{bb=isclip(b)} catch(error_msg) {bb=false}
b = bb ? limit>1 ? Overlay(b.Loop(2,0,0),last,opacity=float(limit)/FrameCount) : b.Loop(2,0,0) : nop()
#b = !bb ? nop : limit>1 ? Overlay(b.Loop(2,0,0),last,opacity=float(limit)/FrameCount) : b.Loop(2,0,0) # ABOVE same as this
b = bb ? b.Overlay(last, mode=blend_mode, opacity=blend_opacity) : last
return b
""",args="blend_mode, blend_opacity, limit", local=false) : last
}


Here, mod of your script function.

Function SFrameBlendX_Mod(clip C, int blendfactor, string "blend_mode", float "blend_opacity") {
C
limit = (blendfactor<=0) ? 1 : Max(1, FrameCount/blendfactor)
FrameCount!=1 ? ScriptClip("""
cf = Last.Trim(current_frame,-1)
try{isclip(b)} catch(error_msg) { b=cf }
b = limit>1 ? b.Overlay(cf,opacity=float(limit)/FrameCount) : b
b = b.Overlay(cf, mode=blend_mode, opacity=blend_opacity).FrameStore
return b
""",args="blend_mode, blend_opacity, limit", local=false) : last
}


AviSource("Parade.avi")

# No FrameStore, stutter @ 1641, crash @ ~2400 frames
# FrameStore after last line, no stutter, crash @ ~6000 frames

SFrameBlendX_Mod(10,"lighten",0.5)


A sort of cross between your function and my MI function. Still crashes with/without FrameStore, but does survive for longer with FrameStore. [try removing FrameStore]

# No FrameStore, stutter @ 1641, crash @ ~2400 frames
# FrameStore after last line, no stutter, crash @ ~6000 frames

Here, showing stutter (without FrameStore), were some pagefile freed and continues, till crash. [actually looks like two stutters]
https://s20.postimg.cc/eqaey7cbh/crash.jpg (https://postimages.cc/)
With FrameStore, steady rise in Pagefile usage, no stutters, but still crash.
Inserting several more FrameStore's make no diffence (may make worst).

Here, a few comments inserted into [part of] my MI version of your script function, with some comments.

Function Fn@@@(clip c,Int factor,String mode,Float opacity,Int limit) {
n=current_frame
if(Prev@@@ != n) {
c
cf=c.Trim(n,-1) # current frame
if(Prev@@@ != n-1) { # b = !bb ? nop() # ::: # We Initialize when B@@@ does not already exist, same as assignment from Last
Global B@@@ = cf # First Frame OR User Jumping, Init/Reset to current frame
} else {

# Below b.Loop(2,0,0) just inserts a duplicate frame at frame zero, ie shift entire clip 1 frame later, ie current
# frame b would duplicate of b(current_frame - 1)
# Instead of shifting clip to 1 frame later, we use a single frame accumulator B@@@, which does the same thing.
# limit>1 ? Overlay(b.Loop(2,0,0),last,opacity=float(limit)/FrameCount)
if(limit > 1) {
Global B@@@ = Overlay(B@@@,cf, opacity=float(limit)/FrameCount)
} # Else, b.Loop(2,0,0) # ::: # B@@@ = Previous B@@@, ie for us a simple NOP

# b = bb ? b.Overlay(last, mode=blend_mode, opacity=blend_opacity) : last
# b = bb ? ... : Last # ::: # We already dealt with that in above line --- Global B@@@ = cf
# b.Overlay(last, mode=blend_mode, opacity=blend_opacity)
# B@@@ is b(current_frame) and cf is Last(current_frame)
Global B@@@=Overlay(B@@@,cf,mode=Mode,opacity=Opacity).FrameStore
# REMOVE above '.FrameStore' from end of next line to crash this function.

}
Global Prev@@@=n # REM for next time
} # Else, Cache failure, repeat request for current frame, just return same as last time
Return B@@@
}

real.finder
25th January 2018, 15:11
can FrameStore() have framenum parameter? it will make sense

so we can store the specific frame in realtime

and since Gavino seems don't have interest in update grunt can we also have variablestore() or something like that?

and if they work in local=true it will be better :)

something like

function SFrameBlendX(clip C, int blendfactor, string "blend_mode", float "blend_opacity")
{
C
limit = (blendfactor<=0) ? 1 : Max(1, FrameCount/blendfactor)
FrameCount!=1 ? ScriptClip("""
try{bb=isclip(b)} catch(error_msg) {bb=false}
b = bb ? limit>1 ? Overlay(b.Loop(2,0,0),last,opacity=float(limit)/FrameCount) : b.Loop(2,0,0) : nop()
b = bb ? b.Overlay(last, mode=blend_mode, opacity=blend_opacity) : last
return b
b=b.FrameStore(current_frame) #other frames will be ignored in ram or will be null
""",args="blend_mode, blend_opacity, limit") : last
}


the MI version need many plugins, I tend to minimize required plugins, and plan for Public general purpose use function so if there many plugins mean many problems and complaints

StainlessS
25th January 2018, 15:24
I guess that I could add frame number arg to FrameStore, would do no harm.
Yes, the MI version does req a number of plugins, but has one major advantage, it works.

EDIT: You still keep adding quotes around "blendfactor" arg, that arg is not optional and will crash function
if called without explicit blendfactor, remove quotes, to make it not optional.

real.finder
25th January 2018, 15:33
I guess that I could add frame number arg to FrameStore, would do no harm.
Yes, the MI version does req a nunber of plugins, but has one main advantage, it works.

what you think will be faster?

store one frame then use trim(0,current_frame-1) ++ *the storedframe* ++ trim(current_frame+1,0)

or make other frames null/duplicate same frame all times?

I think the 2nd one faster, and also can added another parameter to shift the frame so we don't even need anything like loop(2,0,0) edit: if it duplicate same frame all times it will not even need another parameter for shifting

same goes for variablestore

real.finder
25th January 2018, 15:35
EDIT: You still keep adding quotes around "blendfactor" arg, that arg is not optional and will crash function
if called without explicit blendfactor, remove quotes, to make it not optional.

yes that right, will edit it now

StainlessS
25th January 2018, 15:47
I dont see any advantage to trying to maintain a multi-frame b clip, you only need a single frame, the loop thing is [EDIT: probably] part cause of crash in you original script, the mod I made lasts longer before crash, but does still crash, dont know why. (even with FrameStore).

EDIT: Mobile

real.finder
25th January 2018, 16:03
the mod I made lasts longer before crash, but does still crash, dont know why. (even with FrameStore).

don't know if you can try mod grunt and made something between local=false and local=true, like semilocal=true that use or keep only one previous frame data in ram

StainlessS
25th January 2018, 16:12
I would not dare try to mod anything that the chosen one gifted to the race of men, that would require someone of a more saintly
disposition than this lowly sinner.
I dont really see Grunt as playing any part in the problem here, it remains blameless and not sure that any semi-local or whatever,
would do anything useful. [EDIT And I would not have a clue how to mod Grunt, probably not understand it]

real.finder
25th January 2018, 16:24
I dont really see Grunt as playing any part in the problem here, it remains blameless and not sure that any semi-local or whatever,
would do anything useful.

it's not the problem indeed, I suggested "update" not "fix" for it, update to make it fix this runtime problem

I think it will help, the local=true seems to remove everything from previous frame data in ram so you didn't make it work back then https://forum.doom9.org/showthread.php?p=1831028#post1831028

the local=false will behave as avs runtime so it work but crash after some frames

StainlessS
25th January 2018, 16:36
I could not guess as to what a semi-local thing would do, local = false uses variables in a sort of main/top level, where they
can really interfere with each other, as I found earlier when my main B clip cause problems with your function b var.
At the very least, you must give b a more unique name, that will be unlikely chosen by a user script.
Two instances of the script or a similar script will cause problems, even if you can get it to work flawlessly using only one instance.

StainlessS
26th January 2018, 17:16
FrameStore v0.02, update post 1, added frame number arg n. Framestore(clip c,Int "n")

StainlessS
16th January 2019, 21:32
FrameStore() v0.03, new version see 1st post.

Moved to VS2008, added version Resource, 3 dll's, 2.58, 2.60/+ x86 and x64.