View Full Version : avisynth in visual studio
fenomeno83
9th November 2010, 21:38
can be avisynth filters used in a visual studio 2005 c++ project?
for example apply a denoise filter to an image using an avisynth filter writing code from visual studio project?
TheFluff
9th November 2010, 23:54
yes they can
fenomeno83
10th November 2010, 11:08
yes they can
can you give me an easy example?
foe example If I want use removegrain filter in a jpg image, so which dll must I import? which is result of filter? (an object image, I don't know)
Gavino
10th November 2010, 12:51
Basically, you would use the Avisynth plugin API (http://avisynth.org/mediawiki/Filter_SDK), but instead of creating a plugin, you use Avisynth as a library (you call it, instead of it calling you).
Use this code to create the script environment which would normally be passed to a plugin when called by Avisynth:
IScriptEnvironment* env = CreateScriptEnvironment();
You can then invoke filters using env->Invoke(), etc, and manipulate the results as clips, using the Avisynth data structures defined in avisynth.h. For input and output of jpg images, you can invoke ImageSource and ImageWriter.
Link your code with avisynth.lib (found in the Extras folder of your Avisynth installation, if you have installed the plugin SDK).
fenomeno83
10th November 2010, 14:50
Basically, you would use the Avisynth plugin API (http://avisynth.org/mediawiki/Filter_SDK), but instead of creating a plugin, you use Avisynth as a library (you call it, instead of it calling you).
Use this code to create the script environment which would normally be passed to a plugin when called by Avisynth:
IScriptEnvironment* env = CreateScriptEnvironment();
You can then invoke filters using env->Invoke(), etc, and manipulate the results as clips, using the Avisynth data structures defined in avisynth.h. For input and output of jpg images, you can invoke ImageSource and ImageWriter.
Link your code with avisynth.lib (found in the Extras folder of your Avisynth installation, if you have installed the plugin SDK).
so, for example, if I want reproduce in a image RemoveGrain(17)
So, in a script avs I use:
DirectShowSource("image.jpg")
RemoveGrain(17)
In a visual studio c++ project, I must import avisynth libraries, removegrain libraries, add #include avisynth.h, #include removegrain.h(??)
in code
IScriptEnvironment* env = CreateScriptEnvironment();
after?
I didn't understand very well..
thanks
Gavino
10th November 2010, 16:51
As I said...
You can then invoke filters using env->Invoke(), etc, and manipulate the results as clips, using the Avisynth data structures defined in avisynth.h.
You need to read through the SDK documentation, especially
http://avisynth.org/mediawiki/Filter_SDK/Env_Invoke
You don't need to include anything but avisynth.h. You don't talk directly to the code of RemoveGrain, you merely invoke it through Avisynth. Of course, the RemoveGrain dll must be available at run-time for Avisynth to load (most easily through being in the plugins folder).
fenomeno83
10th November 2010, 23:45
so,
sure I made error in this code..
image is not saved..
this is example
#include "stdafx.h"
#include "windows.h"
#include "avisynth.h"
int _tmain(int argc, _TCHAR* argv[])
{
IScriptEnvironment* env = CreateScriptEnvironment();
AVSValue up_args1[1] = {"C:/Immagine-di-un-Gatto-562056.jpeg"};
AVSValue input = env->Invoke("ImageReader", AVSValue(up_args1,1));
AVSValue up_args3[3] = {input, 384, 288 }; //args of LanczosResize
AVSValue resized = env->Invoke("LanczosResize", AVSValue(up_args3,3));
AVSValue up_args2[2] = {resized, "C:/testale.bmp"};
env->Invoke("ImageWriter", AVSValue(up_args2,2));
return 0;
}
Groucho2004
11th November 2010, 00:27
so,
sure I made error in this code..
image is not saved..
this is example
#include "stdafx.h"
#include "windows.h"
#include "avisynth.h"
int _tmain(int argc, _TCHAR* argv[])
{
IScriptEnvironment* env = CreateScriptEnvironment();
AVSValue up_args1[1] = {"C:/Immagine-di-un-Gatto-562056.jpeg"};
AVSValue input = env->Invoke("ImageReader", AVSValue(up_args1,1));
AVSValue up_args3[3] = {input, 384, 288 }; //args of LanczosResize
AVSValue resized = env->Invoke("LanczosResize", AVSValue(up_args3,3));
AVSValue up_args2[2] = {resized, "C:/testale.bmp"};
env->Invoke("ImageWriter", AVSValue(up_args2,2));
return 0;
}
Wrap your code in try/catch statements to enable exception handling. <AvisynthError> will tell you what's wrong.
Example:
IScriptEnvironment *env = CreateScriptEnvironment(AVISYNTH_INTERFACE_VERSION);
AVSValue Arg0 = AVSValue(argv[1]);
AVSValue Args = AVSValue(&Arg0, 1);
AVSValue val;
PClip clip;
VideoInfo vidinfo;
PVideoFrame frame;
try
{
val = env->Invoke("Import", Args, 0);
clip= val.AsClip();
vidinfo = clip->GetVideoInfo();
...
...
}
catch (AvisynthError err)
{
_tprintf(_T("%s\n"), err.msg);
}
frame = 0;
clip = 0;
val = 0;
Gavino
11th November 2010, 01:35
image is not saved..
ImageWriter doesn't write anything till the frame is rendered, so you need to call GetFrame on the result clip.
AVSValue writer = env->Invoke("ImageWriter", AVSValue(up_args2,2));
writer.AsClip()->GetFrame(0, env);
Also, as Groucho2004 says, best to wrap calls in try/catch.
fenomeno83
11th November 2010, 23:31
thanks!! now I can use avisynth internal filters in c++!!
but, now I want use also external filters..
so, if I want use an external filter as removegrain, I copied dll in plugins folder of avisynth..
my code is:
#include "stdafx.h"
#include "windows.h"
#include "avisynth.h"
int _tmain(int argc, _TCHAR* argv[])
{
IScriptEnvironment* env = CreateScriptEnvironment();
AVSValue up_args1[1] = {"C:/1.jpg"};
AVSValue input = env->Invoke("ImageReader", AVSValue(up_args1,1));
try
{
AVSValue up_args3[2] = {input,17};
AVSValue denoise = env->Invoke("RemoveGrain", AVSValue(up_args3,2));
AVSValue up_args2[5] = {denoise, "C:/", 0, 0, "jpg"};
PClip clip = env->Invoke("ImageWriter", AVSValue(up_args2,5)).AsClip();
clip->GetFrame(0,env);
}
catch (AvisynthError err)
{
_tprintf(_T("%s\n"), err.msg);
}
return 0;
}
My exception return the string "?????????????d"
So, maybe must I import dll in visual studio 2005? how? (I know how link lib files, but don't know how import dll)
another question: if I want set for example only the second paramether of removegrain without the first, (for example I want RemoveGrain(mode=17) and not Removegrain(input,17)) how can I say it to AvsValue array?
thanks
Gavino
12th November 2010, 01:08
So, maybe must I import dll in visual studio 2005? how? (I know how link lib files, but don't know how import dll)
You shouldn't need to do anything extra to call external plugins, as long as the dll is in the Avisynth plugins folder at run-time. (If it isn't, you can use env->Invoke("LoadPlugin", ...) to load it.)
Your problem may be that your input clip is RGB, which RemoveGrain does not handle directly. Also, there are several RemoveGrain dll's - make sure you have the right one for your CPU. Also test the equivalent of your sequence of commands in a normal script to check they work.
another question: if I want set for example only the second paramether of removegrain without the first, (for example I want RemoveGrain(mode=17) and not Removegrain(input,17)) how can I say it to AvsValue array?
Your specific example doesn't make much sense, since input is a required parameter. However, to use Invoke with named arguments, you can use the 'arg_names' parameter (the optional third parameter to Invoke). This is an array of strings (char *) which has the same number of elements as 'args' - if a given element of 'arg_names' is non-null, it specifies the name to be associated with the corresponding element of 'args'.
fenomeno83
15th November 2010, 01:19
thanks!! problems was colorspace..so, removegrain, as ma\ny script, want yv12..after to save in file must be rgb...
for example, here I apply hdr to balance brighness
this works fine
#include "stdafx.h"
#include "windows.h"
#include "avisynth.h"
int _tmain(int argc, _TCHAR* argv[])
{
try
{
IScriptEnvironment* env = CreateScriptEnvironment();
AVSValue up_args1[1] = {"C:/0000000003.jpg"};
AVSValue input = env->Invoke("ImageReader", AVSValue(up_args1,1));
AVSValue up_args2[1] = {input};
AVSValue yv12 = env->Invoke("ConvertToYV12", AVSValue(up_args2,1));
AVSValue up_args6[1] = {yv12};
AVSValue hdr = env->Invoke("HDRAGC", AVSValue(up_args6,1));
AVSValue up_args5[1] = {hdr};
AVSValue rgb = env->Invoke("ConvertToRGB", AVSValue(up_args5,1));
AVSValue up_args4[5] = {rgb, "C:/",0,0,"jpg"};
PClip clip = env->Invoke("ImageWriter", AVSValue(up_args4,5)).AsClip();
clip->GetFrame(0,env);
}
catch (AvisynthError err)
{
printf("%s\n", err.msg);
}
return 0;
}
for who don't know how to do:
1-install avisynth(Full installation, so will be installed also sdk)
2- copy external filters dll e/o avs/avsi that you want use in avisynth/plugins folder (as you must do when you want call them from script)
3- in visual studio c++ project use #include and method to invoke internal filters(you can see a list here: http://avisynth.org/mediawiki/Category:Internal_filters ) or external filters(copied in plugins folder.. you can see a list here: http://avisynth.org/mediawiki/Category:External_filters ) as in my code
4-in tools-options-project & solutions-vc++ directiories- in show directory for select include files and add FilterSdk\include folder of avisynth; then select libraries files and add Extras folder of avisynth
5-in project-(project name)properties-configuration propiertes-linker-input-additional dipendencies, add this string: avisynth.lib
kemuri-_9
15th November 2010, 02:37
technically you should wrap all invokes with try-catches, and you should also wrap the CreateScriptEnvironment() call with one as well (yes this can throw an exception).
also, Avisynth does not support wide chars, so the _tprintf you have on the error message will fail to work properly if your program is compiled for unicode
Groucho2004
15th November 2010, 09:41
Avisynth does not support wide chars, so the _tprintf you have on the error message will fail to work properly if your program is compiled for unicode
I guess he took that from my example. Considering that all newer versions of Visual Studio default to Unicode explains the garbage returned from AvisynthError.
fenomeno83, make sure you set your configuration to MBCS and/or change the line with the error message to printf("%s\n", err.msg);
fenomeno83
15th November 2010, 10:05
i modified code :)
Gavino
15th November 2010, 11:01
AVSValue up_args1[1] = {"C:/0000000003.jpg"};
AVSValue input = env->Invoke("ImageReader", AVSValue(up_args1,1));
Note that if there is only a single argument (as here), you can also pass it it directly to Invoke instead of creating an array:
AVSValue input = env->Invoke("ImageReader", "C:/0000000003.jpg");
This is because AVSValue provides an implicit conversion from single element to array.
Also, when invoking a long chain of filters, it may be simpler to write them in script language and just invoke Eval:
const char* s = "ImageReader(\"C:/0000000003.jpg\").ConvertToYV12().HDRAGC().ConvertToRGB().ImageWriter(\"C:/\",0,0,\"jpg\")";
PClip clip = env->Invoke("Eval", s).AsClip();
clip->GetFrame(0,env);
(with an appropriate try/catch, of course. ;))
fenomeno83
16th November 2010, 12:05
I want share a function that convert a Avisynth frame(BGR) 24 or 32 bit in opencv IplImage BGR 24bit (in case of 32->24, last 8 bits are deleted)
IplImage* AvsToOpcv (PVideoFrame pf, bool is32bit)
{
int factor;
if ( is32bit==true)
factor=4;
else
factor=3;
IplImage *imOPCV = cvCreateImage(cvSize((pf->GetRowSize())/factor,pf->GetHeight()),8, 3);
int k = pf->GetHeight()-1;
int j=0, temp=0;
const BYTE * b = pf->GetReadPtr();
CvScalar s;
for (int i=0; i < pf->GetHeight()*pf->GetRowSize();i++)
{
temp++;
if (temp == 1)
{
s.val[0] = (int) b[i];
}
else if (temp == 2)
{
s.val[1] = (int) b [i];
}
else if (temp==3)
{
s.val[2] = (int) b[i];
cvSet2D(imOPCV,k,j,s);
j++;
}
else
{
temp = 0;
}
if ( (i+1) % pf->GetRowSize()==0)
{
k--;
j=0;
}
}
return imOPCV;
}
fenomeno83
16th November 2010, 12:54
so, now I want make IplImageToAvs
after my algorithm I get a Byte*
but I don't understand how write it in a newframe of a new Pclip..
and after that i have pclip with pvideoframe, I want manage it with others avisynth filters, so maybe I need convert Pclip to AVSValue?
so, how can I create a new pclip, set into it a newframe from Byte* and use PClip as AVSValue to apply others filters?
thanks
Gavino
16th November 2010, 13:37
so, how can I create a new pclip, set into it a newframe from Byte* and use PClip as AVSValue to apply others filters?
You need to create a new class derived from IClip, and in that class provide appropriate implementations of (among other things) GetVideoInfo() and GetFrame().
You could give your class a constructor with the Byte* as an argument. In that constructor, use env->NewVideoFrame() to create the PVideoFrame and write its data using the frame->GetWritePtr(). Your GetFrame() would return the PVideoFrame saved in the constructor.
Essentially, what you are doing is creating a new specialised source filter - you might find it useful to look at the AviSynth source code (eg ImageSource) to see how it is done there.
and after that i have pclip with pvideoframe, I want manage it with others avisynth filters, so maybe I need convert Pclip to AVSValue?
PClip is automatically converted to AVSValue in contexts that require it, so you can usually just use the PClip directly.
fenomeno83
16th November 2010, 14:35
so, I didn't understand something.
why Must I create a derivated class of IClip?
Cannot I use PClip ?
I image that I create a new PClip with a resolution and some paramters, create a new frame as
PVideoFrame vf= env->NewVideoFrame()
use getwriteptr
unsigned char* buf = vf->GetWritePtr();
and write buffer
*buf = *inputbuf
Gavino
16th November 2010, 15:17
so, I didn't understand something.
why Must I create a derivated class of IClip?
Cannot I use PClip ?
PClip is (basically) just a pointer to an IClip, and IClip is a generic abstract class. The clip functionality must be provided by some concrete subclass which implements the functions GetFrame(), etc.
So you cannot create a PClip without having an appropriate IClip subclass. For most filters, the GenericVideoFilter class provides the basis for this, but 'source' filters (which is basically what you have) do not have a parent clip and so GenericVideoFilter is not appropriate.
write buffer
*buf = *inputbuf
If you meant this code literally, note that it doesn't copy all the data, just the first byte.
fenomeno83
19th November 2010, 00:27
thankyou..I will try
fenomeno83
23rd November 2010, 22:09
another question..
I want release all avisynth resource used here
http://forum.doom9.org/showpost.php?p=1457688&postcount=12
(after I pass PVideoFrame to this custom function http://forum.doom9.org/showpost.php?p=1458016&postcount=17 )
because with many avisynth filters and many images on which apply . memory can be saturated
how can clean memory after that I have already stored PVideoFrame in a new type of image format (using my custom function)?
pvideoframe occupies about 80mb AND OTHER 80 after hdr filter..how clean memory?
Gavino
24th November 2010, 00:35
PVideoFrame, PClip and AVSValue are implemented using a 'smart pointer' mechanism with reference counts which means the underlying resources are automatically freed when nothing references them any more.
Resources associated with a local PVideoFrame variable will be freed when a new value is assigned to the variable or it goes out of scope.
Consequently, on exit from your try block in post #12, all resources will be freed, except for the script environment itself, for which you need to add "delete env;"
If you are creating a number of clips/frames, etc, you would normally create just one script environment and use it for everything, deleting it when you've finished with it.
Gavino
24th November 2010, 11:09
Actually, I think what I said is not true as far as PVideoFrame is concerned. To quote IanB:
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.
So memory associated with video frames is retained even when not referenced, up to (or a bit beyond) the limit set by SetMemoryMax.
fenomeno83
24th November 2010, 12:32
thankyou very much!
fenomeno83
25th April 2017, 08:27
Hi all. Is there a way to invoke loadvirtualdubplugin from visual studio c++.
I'm not able to get working
Thanks
StainlessS
25th April 2017, 10:13
Is stuff in blue at bottom of this code block of any use:- https://forum.doom9.org/showthread.php?p=1776368#post1776368
Suggest use fullpath to plugin, supplying all args (3, I think).
If no joy, then at least post what you've tried.
EDIT: Ignore me, probably talking rubbish as usual :(
Invoke returns AVSValue, I'm kinda curious to see what it does/ if it works, probably will not.
EDIT: I'm givin it a go, I may need to use Invoke on "Eval()", but should be able to I think (possibly, maybe, perhaps).
fenomeno83
25th April 2017, 11:56
Thanks..I'm able to Load generic Avisynth plugins, but not VirtualDub plugins...
for example
IScriptEnvironment* env = CreateScriptEnvironment();
env->Invoke("LoadPlugin", "AGC.dll");
.........
input = env->Invoke("HDRAGC", input);
...........
THAT WORKS!
But for example
env->Invoke("LoadVirtualDubPlugin", "msu_sharpen.vdf");
IT DOESN'T WORK!
I need to execute this script in c++ env:
LoadVirtualDubPlugin("...msu_sharpen.vdf","MSUSmartSharpen", 0)
....
clip.ConvertToRGB32.MSUSmartSharpen(4)
Can you help me?
StainlessS
25th April 2017, 12:08
You do not have a full path, where are dll's located ?
I just tried this (curious to see what it returned, if anything).
Colorbars.killaudio
q=LoadPlugin("C:\zz\Grid.dll")
RT_Subtitle("'%s'",String(q))
Grid
return last
Shows Grid and text "Grid Plugin" on frame.
So now I know what that string is for in AvisynthPluginInit2/3.
Colorbars.killaudio
q=LoadVirtualDubPlugin("C:\zz\MSharpen.vdf","MSharpenXXX",1)
RT_Subtitle("'%s'",String(q))
return last
Just displays '' on frame, ie empty string, but no error.
Dont offhand know what args to that plugin are, but it seems to have loaded without error.
You tried with full path ?
Maybe Avisynth plugins directory is in your Environment Path (in which case not necessary to manual load),
and VDub plugins is NOT in Environment Path.
EDIT: Adding an extra letter to the end of Vdub plugin filename fails with error message, so your path needs setting.
EDIT: Not sure but think Preroll may have to be at least 1.
StainlessS
25th April 2017, 12:30
Here VD use in avisynth:- http://avisynth.nl/index.php/FAQ_using_virtualdub_plugins
It usually involves a little bit of work trying to figure out arguments to use,
Have you got it working OK in script, if not then do experimentation in script.
I do not have that plugin, MSU VD plugins quite often are awkward and sometimes dont even write all settings
to the VDub settings file, and so cannot always work properley in Avisynth, only MSU plugs seem to suffer from that
problem,and more than a couple of plugs are guilty (eg MSU_OldCinema, about 9 args missing IIRC).
StainlessS
25th April 2017, 12:46
But for example
env->Invoke("LoadVirtualDubPlugin", "msu_sharpen.vdf");
IT DOESN'T WORK!
I need to execute this script in c++ env:
LoadVirtualDubPlugin("...msu_sharpen.vdf","MSUSmartSharpen", 0)
....
clip.ConvertToRGB32.MSUSmartSharpen(4)
Your script has fullpath (well '...' ) and your LoadVirtualDubPlugin does not.
You also need to supply a filter name as in your script "MSUSmartSharpen", and a Preroll.
Example use of names in original link I posted.
or something like this (untested)
PClip inputClip = args[0].AsClip();
const char * filename = args[1].AsString();
const char * filtername = args[2].AsString();
int Preroll = args[3].AsInt(1);
int matrix = args[4].AsInt(0);
bool interlaced = args[5].AsBool(false);
const char * ChromaInPlacement = args[6].AsString("MPEG2");
const char * chromaresample = args[7].AsString("bicubic");
int SharpArg = args[8].AsInt(4);
// LoadVirtualDubPlugin ("filename", "filtername", preroll)
const char *namesVd[]={NULL,NULL,"Preroll"};
AVSValue argsVd[3]={filename,filtername,1};
const char * StrRet = env->Invoke("LoadVirtualDubPlugin", AVSValue(argsVd, 3),namesVd).AsString();
// ConvertToRGB32 (clip [,string "matrix"] [,bool "interlaced"] [,string "ChromaInPlacement"] [,string "chromaresample"])
const char *namesRgb32[]={NULL,"matrix","interlaced","ChromaInPlacement","chromaresample"};
AVSValue argsRgb32[5]={inputClip,matrix,interlaced,ChromaInPlacement,chromaresample};
PClip RGBRet = env->Invoke("ConvertToRGB32", AVSValue(argsRgb32, 5),namesRgb32).AsClip();
// MSUSmartSharpen(clip, Int)
const char *namesMsu[]={NULL,NULL};
AVSValue argsMsu[2]={RGBRet, SharpArg};
PClip MsuRet = env->Invoke("MSUSmartSharpen", AVSValue(argsMsu, 2),namesMsu).AsClip();
EDIT: Above NULL's show where args are not named (not optional).
EDIT: Above updated, and not tested in any way. Might want to add some kind of Try/Catch stuff for errors.
EDIT: Just supply all optional args same as defaults (if no preference), but all are given above to be easier to change if necessary.
(No idea what other args MSU thing has).
EDIT: Oops, several cockups corrected.
fenomeno83
25th April 2017, 14:14
thankyou very much.it works!!
I don't need to pass char* name vector..for example
AVSValue StrRet = env->Invoke("LoadVirtualDubPlugin", AVSValue(argsVd, 3)) works!
StainlessS
25th April 2017, 14:23
Good to hear.
Names are handy when you want to give a single arg at end of long list of optional args, I do not usually use them myself either.
EDIT: Subtitle has quite a long list of args, used names in 1st given link code, so as only to choose a few of them.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.