View Full Version : Direct call to AviSynth.dll (without VfW)
dimzon
24th November 2005, 16:46
Is it possible? Can anybody provide clear sample?
Inc
24th November 2005, 22:03
Im also looking for the exlanation of the approach.
There do exist in the www ... "avsredirect.dll" and "avswarp.dll", 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 "import". 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:)
tritical
24th November 2005, 23:50
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: http://forum.doom9.org/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.
#include <windows.h>
#include <stdio.h>
#include "internal.h"
int main(int argc, char* argv[])
{
HINSTANCE hDLL;
IScriptEnvironment* (__stdcall *CreateEnv)(int);
IScriptEnvironment *env;
PClip *Video;
PVideoFrame src;
// load avisynth.dll
hDLL = LoadLibrary("avisynth");
if (!hDLL)
{
fprintf(stderr,"Couldn't load Avisynth.dll\n");
exit(1);
}
// retrieve address of createscriptenvironment function
CreateEnv = (IScriptEnvironment *(__stdcall *)(int))GetProcAddress(hDLL,
"CreateScriptEnvironment");
if (!CreateEnv)
{
fprintf(stderr, "Couldn't access CreateScriptEnvironment\n");
exit(1);
}
// create a new scriptenvironment
env = CreateEnv(AVISYNTH_INTERFACE_VERSION);
if (!env)
{
fprintf(stderr, "Couldn't create scriptenvironment\n");
exit(1);
}
// load the script and add converttorgb24 if not already outputting rgb24
AVSValue args[1] = { "script.avs" };
try {
Video = new PClip();
*Video = env->Invoke("Import",AVSValue(args,1)).AsClip();
if (!(*Video)->GetVideoInfo().IsRGB24())
{
AVSValue args_conv[1] = { *Video };
*Video = env->Invoke("ConvertToRGB24", AVSValue(args_conv, 1)).AsClip();
}
}
catch (AvisynthError e) {
fprintf(stderr, "Error (Avisynth Error) loading avisynth script!\n");
fprintf(stderr, "%s.\n", e.msg);
delete env;
exit(1);
}
catch (...) {
fprintf(stderr, "Error (Unknown) loading avisynth script!\n");
delete env;
exit(1);
}
// request a frame
src = (*Video)->GetFrame(frameNum, env);
// copy to output
env->BitBlt(bufferVidOut, outPitch, src->GetReadPtr(), src->GetPitch(),
src->GetRowSize(), src->GetHeight());
// request some audio samples (will be copied directly into output buffer)
if ((*Video)->GetVideoInfo().HasAudio())
(*Video)->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...
hank315
24th December 2005, 21:31
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:
#include "internal.h"
IScriptEnvironment* env;
AVSValue res;
HINSTANCE avsDLL;
void __cdecl main()
{
avsDLL = LoadLibrary("avisynth.dll");
if (!avsDLL) exit(1);
IScriptEnvironment* (* CreateScriptEnvironment)(int version)
= (IScriptEnvironment*(*)(int)) GetProcAddress(avsDLL, "CreateScriptEnvironment");
if (!CreateScriptEnvironment) exit(1);
env = CreateScriptEnvironment(AVISYNTH_INTERFACE_VERSION);
if (!env) exit(1);
AVSValue arg("yourAVSfile.avs");
try { res = env->Invoke("Import", AVSValue(&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:
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 :D
tritical
25th December 2005, 03:44
Your code looks fine to me (as long as you have the default calling convention set to __stdcall), what version of avisynth are you testing with? and how old is your internal.h? I've had some strange behavoir with avisynth 2.55 when accessing avisynth.dll in this way. For example, it would crash if trying to invoke converttorgb and then flipvertical but would be perfectly fine if invoking them in the opposite order. After some debugging it turned out to be due to the vc++ 6.0 ebx compiler bug and the problem didn't appear when using a build of 2.55 compiled with vs.net 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.
hank315
25th December 2005, 23:37
Calling convention is set to __stdcall.
Avisynth version used: 2.5.6a so the final release.
The internal.h used was already pretty old so I updated internal.h and avisynth.h with the versions from the latest Avisynth source.
It didn't make any difference, still the same behaviour.
If it is compiled with vs.net 2003 still the same...
What actually happens: if the exit statement is executed the error is in this line (avisynth.h):
void Release() { InterlockedDecrement((long *)&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 :confused:
Maybe it is caused by a race condition as decribed here:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/freelibraryandexitthread.asp
Such a race condition could explain the unpredictable behaviour of the memory errors and access violations.
dimzon
26th December 2005, 10:16
I want to provide script body (no file ) into AviSynth
Something like
AVS_OpenScript("AviSource(\"c:\\my.avi\")\nUndot()\n.....\nreturn last");
Inc
26th December 2005, 11:07
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.
http://forum.doom9.org/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 "import" command stores the text content into memory?
sh0dan
26th December 2005, 12:02
@dimzon: You can construct your own filtergraph, by calling env->Invoke with the functions and parameters you need.
in C++:
PClip res;
AVSValue arg("myfile.avi");
try { res = env->Invoke("AviSource", AVSValue(&arg, 1)); }
catch(...) { exit(1); }
AVSValue arg2(res);
try { res = env->Invoke("Undot", AVSValue(&arg2, 1)); }
catch() { exit(1); }
AVSValue arg3(res, false);
try { res = env->Invoke("ConvertToRGB", AVSValue(&arg3, 2)); }
catch(...) { exit(1); }
"res" now contains the filtered AVI in RGB.
dimzon
26th December 2005, 12:08
@dimzon: You can construct your own filtergraph, by calling env->Invoke with the functions and parameters you need.
Unfortunally I'm using C# and can't call C++ classes directly...
Thanx!
tritical
26th December 2005, 18:27
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:
#include <windows.h>
#include "internal.h"
IScriptEnvironment* env;
AVSValue *res;
HINSTANCE avsDLL;
void __cdecl main()
{
avsDLL = LoadLibrary("avisynth.dll");
if (!avsDLL) exit(1);
IScriptEnvironment* (* CreateScriptEnvironment)(int version)
= (IScriptEnvironment*(*)(int)) GetProcAddress(avsDLL, "CreateScriptEnvironment");
if (!CreateScriptEnvironment) exit(1);
env = CreateScriptEnvironment(AVISYNTH_INTERFACE_VERSION);
if (!env) exit(1);
AVSValue arg("yourAVSfile.avs");
try {
res = new AVSValue();
*res = env->Invoke("Import", AVSValue(&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.
hank315
27th December 2005, 23:13
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...
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.