View Full Version : 32-bit filters from 64-bit avisynth
squid_80
23rd September 2007, 19:29
I thought I'd try and come up with something to do this, mainly just for the challenge (since it's probably always going to produce an end result that runs slower than 32-bit native) but also to help me visually compare the output of original 32-bit filters vs. those I have ported to make sure everything's correct. Here's what I've got so far:
- a 64-bit filter called Filter32bit that takes a string argument (the 32-bit filter to be called).
- In that filter's constructor, it spawns a 32-bit process and sets up shared memory.
- The 32-bit process (avs32server) loads avisynth.dll and calls CreateScriptEnvironment.
- VideoInfo is passed from Filter32bit to avs32server.
- avs32server invokes a source filter, eval (with the argument being the string passed to Filter32bit) and a sink filter. VideoInfo from the sink filter is passed to Filter32bit.
- Filter32bit's constructor finishes.
From there, any calls to filter32bit's getframe/getparity are bounced to avs32server's sink filter. Likewise calls to the avs32server's source filter functions are bounced to filter32bit's child.
(TODO: Implement GetAudio. Also have avs32server create a separate shared memory object for passing back frames since they may be significantly larger than the source frames.)
Obviously there's a cost associated with copying data from/to shared memory/VideoFrameBuffers. What I'm wondering is if there's an easy way I could modify the IScriptEnvironment used in avs32server so any new frames obtained using NewVideoFrame are allocated from the shared memory pool directly, thus avoiding at least one BitBlt?
IanB
24th September 2007, 00:44
IScriptEnvironment is a virtual Class the physical class is really ScriptEnvironment. You could define a new class SqScriptEnvironment that reimplements NewVideoFrame, MakeWriteable, etc as you need them, the rest you just stub back to the original ScriptEnvironment. As you pass your SqScriptEnvironment to the filters they will call your methods.
In your alternate code you call the real NewVideoFrame, in the return path you check if the vfb.data is already shared if not, free the vfb.data and shared_malloc a replacement.
MakeWriteable, etc might internally sneak a new vfb directly, you would completely implement it, but it is trivial code.
squid_80
27th September 2007, 13:18
New problem: Since I'm using CreateScriptEnvironment and env->Invoke to create the filter chain, the filters don't seem to be getting caches. Is this:
A) expected behaviour; stop being lazy and create the caches myself
B) an oversight; Invoke should probably create the cache
C) a bug; something ain't right cause this shouldn't be happening
IanB
27th September 2007, 14:43
A) expected behaviour;
If you env->Invoke the filters individually and externally chain them there is no cache added. This provides maximum flexibility.
The auto cache insertion is inside Evaluate. If you env->Invoke("Eval", ...) then you will get caches.
Have a look at Import in core\parser\script.cpp
sh0dan
27th September 2007, 17:16
You can insert cache filters, by invoking InternalCache, see more at:
http://avisynth.org/mediawiki/Filter_SDK/Env_Invoke
squid_80
27th September 2007, 18:28
That's what I meant by create them myself, although I was using Cache; looks like Cache/InternalCache are the same.
(Just for completeness, another issue with Invoke-ing is that last is not updated. I just setvar it to my manually created cache.)
The wiki page did just give me an idea though; catch NotFound errors when creating the user-defined filter and try and find them in the 64-bit host process. That would enable support for user defined variables and such.
IanB
27th September 2007, 23:46
Given you wanted to just stub a single 32bit filter from 64bit avisynth, I would have thought lack of 32bit cache and updating the Last variable would have been a big plus!
I envisioned a normal graph with your magic filter would be like this :-
...-[cache64]-[STU.b32>-<filter32>-<stu.B64]-[cache64]-...
I would have expected all 32bit getFrame calls are deflected straight back to the next 64bit cache in the 64bit graph.
squid_80
28th September 2007, 07:44
Having the Last variable set correctly is the easiest way to support whatever bizarre filter string the user has specified, for example consider these cases:
- trim(2, 10)
- last.trim(2, 10)
- trim(last, 2, 10)
- avisource("whatever.avi") #Source filters work too!
I envisioned a normal graph with your magic filter would be like this :-
...-[cache64]-[STU.b32>-<filter32>-<stu.B64]-[cache64]-...
I would have expected all 32bit getFrame calls are deflected straight back to the next 64bit cache in the 64bit graph.But the deflection uses IPC which is slow. It's much better if STU.b32 has a cache. stu.B64 on the other hand definitely doesn't want a 32-bit cache since it wouldn't serve any purpose (except screw things up, the code to communicate with the 64-bit process is in GetFrame).
IanB
28th September 2007, 15:43
Okay, I can see how a 32bit cache on the input PClips to the 32bit filter might just be handy. So the mythical graph would look like this :-
...-[cache64]-[STU.b32>-<filter32>-<cache32>-<stu.B64]-[cache64]-...
The green [cache64] is a bit redundant but it won't hurt. If it offends you to much, SetCacheHints(CACHE_NONE) it.
Last should not be an issue, it is only a lexical resource for the parser to use. Filters in general should be getting their input thru their calling arguments, which you should be seeing as resolved PClips and of course you have to be stubbing.
If you are using shared memory to hoike the data around, IPC speed should not be an issue, Loopback network I/O on the one machine can do 10,000's of transactions per second and thats hardly the most optimal form of IPC.
vBulletin® v3.8.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.