|
|
Direct call to AviSynth.dll (without VfW)
Is it possible? Can anybody provide clear sample?
Im also looking for the exlanation of the approach.
There do exist in the www ... quot;avsredirect.dllquot; and quot;avswarp.dllquot;, the last can be found from aquaplaning. avsredirect is also a wrapper like avswarp but just forces the user to use a presaved avs as the invoke is a simple quot;importquot;. avswarp.dll does call the steps one by one but doesnt support audio.
So it would be really interesting which steps (one by one) are needed to end up in a pointer to a frame and a pointer to an audioframe/stream which could be processed finally in an own application
One example you could look at is the source code for dgvfapi (from dgmpgdec v1.4.5). It uses avisynth.dll via loadlibrary() and getprocaddress()... then creates a scriptenvironment (createscriptenvironment()) and imports a script using invoke(). At that point you will have a clip from which you can call getframe() and getaudio(). There is a thread describing the same method (with some code) at: showthread.php?t=64431.
Here is brief c++ example hacked together with some code from dgvfapi and the other thread... it loads a script, converts to rgb24 if the script isn't already outputting rgb24, grabs a frame and some audio samples, and then copies that data to some output buffers.Code:
#include lt;windows.hgt;
#include lt;stdio.hgt;
#include quot;internal.hquot;
int main(int argc, char* argv[])
{ HINSTANCE hDLL; IScriptEnvironment* (__stdcall *CreateEnv)(int); IScriptEnvironment *env; PClip *Video; PVideoFrame src;
// load avisynth.dll hDLL = LoadLibrary(quot;avisynthquot;); if (!hDLL) { fprintf(stderr,quot;Couldn't load Avisynth.dll\nquot;); exit(1); }
// retrieve address of createscriptenvironment function CreateEnv = (IScriptEnvironment *(__stdcall *)(int))GetProcAddress(hDLL, quot;CreateScriptEnvironmentquot;); if (!CreateEnv) { fprintf(stderr, quot;Couldn't access CreateScriptEnvironment\nquot;); exit(1); }
// create a new scriptenvironment env = CreateEnv(AVISYNTH_INTERFACE_VERSION); if (!env) { fprintf(stderr, quot;Couldn't create scriptenvironment\nquot;); exit(1); }
// load the script and add converttorgb24 if not already outputting rgb24 AVSValue args[1] = { quot;script.avsquot; }; try { Video = new PClip(); *Video = env-gt;Invoke(quot;Importquot;,AVSValue(args,1)).AsClip(); if (!(*Video)-gt;GetVideoInfo().IsRGB24()) { AVSValue args_conv[1] = { *Video }; *Video = env-gt;Invoke(quot;ConvertToRGB24quot;, AVSValue(args_conv, 1)).AsClip(); } } catch (AvisynthError e) { fprintf(stderr, quot;Error (Avisynth Error) loading avisynth script!\nquot;); fprintf(stderr, quot;%s.\nquot;, e.msg); delete env; exit(1); } catch (...) { fprintf(stderr, quot;Error (Unknown) loading avisynth script!\nquot;); delete env; exit(1); }
// request a frame src = (*Video)-gt;GetFrame(frameNum, env); // copy to output env-gt;BitBlt(bufferVidOut, outPitch, src-gt;GetReadPtr(), src-gt;GetPitch(), src-gt;GetRowSize(), src-gt;GetHeight());
// request some audio samples (will be copied directly into output buffer) if ((*Video)-gt;GetVideoInfo().HasAudio()) (*Video)-gt;GetAudio(bufferAudOut, SamplePos, SampleCount, env);
// clean up and finish delete Video; delete env; FreeLibrary(hDLL); exit(0);
}
The above example wont compile since I didn't define all the variables, but it gives the basic approach to how to do it. If you don't have an actual script to import you can invoke the filters you want one by one. Hope this helps...
Calling Avisynth direct can be very useful if you want to call it from other programming languages.
For HC I also use something similar as tritical posted but it sometimes produces unpredictable memory errors or access violations.
Here's some code which is the most simple code for calling Avisynth direct:
Code:
#include quot;internal.hquot;
IScriptEnvironment* env;
AVSValue res;
HINSTANCE avsDLL;
void __cdecl main()
{
avsDLL = LoadLibrary(quot;avisynth.dllquot;);
if (!avsDLL) exit(1);
IScriptEnvironment* (* CreateScriptEnvironment)(int version) = (IScriptEnvironment*(*)(int)) GetProcAddress(avsDLL, quot;CreateScriptEnvironmentquot;);
if (!CreateScriptEnvironment) exit(1);
env = CreateScriptEnvironment(AVISYNTH_INTERFACE_VERSION);
if (!env) exit(1);
AVSValue arg(quot;yourAVSfile.avsquot;);
try { res = env-gt;Invoke(quot;Importquot;, AVSValue(amp;arg, 1)); }
catch(...) { exit(1); }
// all kind of code here....
delete env;
int iret = FreeLibrary(avsDLL); exit(0);
}
This can be compiled with VS6 and seems to run fine but if it's run in debug mode it produces an access violation:
Code:
Unhandled exception in AVStestC.exe: 0xC0000005: Access Violation
If the delete env and FreeLibrary are dumped it runs OK.
The error appears when the program exits, anybody has any idea ??
I'm not an expierenced C programmer so maybe there's a very basic error in it
2003. That said, I never noticed any access violations or other problems when closing the scriptenvironment. There were a few builds of avisynth 2.56 that had close down problems, but that was corrected before avisynth 2.56 final was released.
2003 still the same...
What actually happens: if the exit statement is executed the error is in this line (avisynth.h):Code: void Release() { InterlockedDecrement((long *)amp;refcnt); if (!refcnt) delete this; }
IMHO it shouldn't get to this line if the program exits.
Because refcnt = 0 (as it should be) the program tries to delete this (whatever it may be in this state).
Of course this fails causing the access violation.
Just found that using FreeLibraryAndExitThread instead of FreeLibrary solves it
Maybe it is caused by a race condition as decribed here:
library/de...exitthread.asp
Such a race condition could explain the unpredictable behaviour of the memory errors and access violations.
I want to provide script body (no file ) into AviSynth
Something like
AVS_OpenScript(quot;AviSource(\quot;c:\\my.avi\quot;)\nUndot()\n.....\nreturn lastquot;);
Dimzon, it seems you're not accessing the dll via c++ code right?
Thats also my case, so maybe this thread is more interesting for you as it deals about the usage of the avisynth.dll via the avisynth_c interface of Kevin Atkinson.
showthread.php?t=104291
The most comfortable would be a command in the avisynth API like ParseScript( Int *mem), where ParseScript( *memorypointer) looks at the *memorypointer for a null-terminating string which includes a script in a line by line syntax in a way we used to build.
So somewhere in the code the quot;importquot; command stores the text content into memory?
@dimzon: You can construct your own filtergraph, by calling env-gt;Invoke with the functions and parameters you need.
in C++:
Code: PClip res;
AVSValue arg(quot;myfile.aviquot;);
try { res = env-gt;Invoke(quot;AviSourcequot;, AVSValue(amp;arg, 1)); }
catch(...) { exit(1); }
AVSValue arg2(res);
try { res = env-gt;Invoke(quot;Undotquot;, AVSValue(amp;arg2, 1)); }
catch() { exit(1); }
AVSValue arg3(res, false);
try { res = env-gt;Invoke(quot;ConvertToRGBquot;, AVSValue(amp;arg3, 2)); }
catch(...) { exit(1); }
quot;resquot; now contains the filtered AVI in RGB.
Originally Posted by sh0dan@dimzon: You can construct your own filtergraph, by calling env-gt;Invoke with the functions and parameters you need.
Unfortunally I'm using C# and can't call C++ classes directly...
Thanx!
Alright, I'm dumb. The reason you're getting an error on close is because res is declared as a global. Therefore, its destructor is not called until after you do delete env, but for a clean exit it needs to be deleted before env is deleted. A possible fix is to use this code:Code:
#include lt;windows.hgt;
#include quot;internal.hquot;
IScriptEnvironment* env;
AVSValue *res;
HINSTANCE avsDLL;
void __cdecl main()
{
avsDLL = LoadLibrary(quot;avisynth.dllquot;);
if (!avsDLL) exit(1);
IScriptEnvironment* (* CreateScriptEnvironment)(int version) = (IScriptEnvironment*(*)(int)) GetProcAddress(avsDLL, quot;CreateScriptEnvironmentquot;);
if (!CreateScriptEnvironment) exit(1);
env = CreateScriptEnvironment(AVISYNTH_INTERFACE_VERSION);
if (!env) exit(1);
AVSValue arg(quot;yourAVSfile.avsquot;);
try {
res = new AVSValue();
*res = env-gt;Invoke(quot;Importquot;, AVSValue(amp;arg, 1));
}
catch(...) { exit(1); }
// all kind of code here....
delete res;
delete env;
int iret = FreeLibrary(avsDLL); exit(0);
}
There are many other possible ways to do it. The main point is that any open clips need to be closed/deleted before the scriptenvironment in which they were created is closed.
The reason you're getting an error on close is because res is declared as a global. Therefore, its destructor is not called until after you do delete env, but for a clean exit it needs to be deleted before env is deleted.
Indeed, this solves the access violations, did a lot of tests, always a clean exit.
Very BIG thanks... |
|